77 self.output.SetValue("") |
78 self.output.SetValue("") |
78 |
79 |
79 def isatty(self): |
80 def isatty(self): |
80 return false |
81 return false |
81 |
82 |
82 [ID_BEREMIZ, ID_BEREMIZLOGCONSOLE, ID_BEREMIZEDITPLCBUTTON, |
83 class AttributesTable(wx.grid.PyGridTableBase): |
83 ID_BEREMIZBUILDBUTTON, ID_BEREMIZSIMULATEBUTTON, |
84 |
84 ID_BEREMIZRUNBUTTON, ID_BEREMIZBUSLIST, |
85 """ |
85 ID_BEREMIZADDBUSBUTTON, ID_BEREMIZDELETEBUSBUTTON, |
86 A custom wxGrid Table using user supplied data |
86 ] = [wx.NewId() for _init_ctrls in range(9)] |
87 """ |
|
88 def __init__(self, parent, data, colnames): |
|
89 # The base class must be initialized *first* |
|
90 wx.grid.PyGridTableBase.__init__(self) |
|
91 self.data = data |
|
92 self.colnames = colnames |
|
93 self.Parent = parent |
|
94 # XXX |
|
95 # we need to store the row length and collength to |
|
96 # see if the table has changed size |
|
97 self._rows = self.GetNumberRows() |
|
98 self._cols = self.GetNumberCols() |
|
99 |
|
100 def GetNumberCols(self): |
|
101 return len(self.colnames) |
|
102 |
|
103 def GetNumberRows(self): |
|
104 return len(self.data) |
|
105 |
|
106 def GetColLabelValue(self, col): |
|
107 if col < len(self.colnames): |
|
108 return self.colnames[col] |
|
109 |
|
110 def GetRowLabelValues(self, row): |
|
111 return row |
|
112 |
|
113 def GetValue(self, row, col): |
|
114 if row < self.GetNumberRows(): |
|
115 name = str(self.data[row].get(self.GetColLabelValue(col), "")) |
|
116 return name |
|
117 |
|
118 def GetValueByName(self, row, colname): |
|
119 return self.data[row].get(colname) |
|
120 |
|
121 def SetValue(self, row, col, value): |
|
122 if col < len(self.colnames): |
|
123 self.data[row][self.GetColLabelValue(col)] = value |
|
124 |
|
125 def ResetView(self, grid): |
|
126 """ |
|
127 (wxGrid) -> Reset the grid view. Call this to |
|
128 update the grid if rows and columns have been added or deleted |
|
129 """ |
|
130 grid.BeginBatch() |
|
131 for current, new, delmsg, addmsg in [ |
|
132 (self._rows, self.GetNumberRows(), wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED), |
|
133 (self._cols, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED), |
|
134 ]: |
|
135 if new < current: |
|
136 msg = wx.grid.GridTableMessage(self,delmsg,new,current-new) |
|
137 grid.ProcessTableMessage(msg) |
|
138 elif new > current: |
|
139 msg = wx.grid.GridTableMessage(self,addmsg,new-current) |
|
140 grid.ProcessTableMessage(msg) |
|
141 self.UpdateValues(grid) |
|
142 grid.EndBatch() |
|
143 |
|
144 self._rows = self.GetNumberRows() |
|
145 self._cols = self.GetNumberCols() |
|
146 # update the column rendering scheme |
|
147 self._updateColAttrs(grid) |
|
148 |
|
149 # update the scrollbars and the displayed part of the grid |
|
150 grid.AdjustScrollbars() |
|
151 grid.ForceRefresh() |
|
152 |
|
153 def UpdateValues(self, grid): |
|
154 """Update all displayed values""" |
|
155 # This sends an event to the grid table to update all of the values |
|
156 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES) |
|
157 grid.ProcessTableMessage(msg) |
|
158 |
|
159 def _updateColAttrs(self, grid): |
|
160 """ |
|
161 wxGrid -> update the column attributes to add the |
|
162 appropriate renderer given the column name. |
|
163 |
|
164 Otherwise default to the default renderer. |
|
165 """ |
|
166 |
|
167 for row in range(self.GetNumberRows()): |
|
168 for col in range(self.GetNumberCols()): |
|
169 editor = None |
|
170 renderer = None |
|
171 align = wx.ALIGN_LEFT |
|
172 colname = self.GetColLabelValue(col) |
|
173 grid.SetReadOnly(row, col, False) |
|
174 |
|
175 if colname == "Value": |
|
176 colSize = 100 |
|
177 value_type = self.data[row]["Type"] |
|
178 if isinstance(value_type, types.ListType): |
|
179 editor = wx.grid.GridCellChoiceEditor() |
|
180 editor.SetParameters(",".join(value_type)) |
|
181 elif value_type == "boolean": |
|
182 editor = wx.grid.GridCellChoiceEditor() |
|
183 editor.SetParameters("True,False") |
|
184 elif value_type in ["unsignedLong","long","integer"]: |
|
185 editor = wx.grid.GridCellNumberEditor() |
|
186 align = wx.ALIGN_RIGHT |
|
187 elif value_type == "decimal": |
|
188 editor = wx.grid.GridCellFloatEditor() |
|
189 align = wx.ALIGN_RIGHT |
|
190 else: |
|
191 editor = wx.grid.GridCellTextEditor() |
|
192 else: |
|
193 colSize = 120 |
|
194 grid.SetReadOnly(row, col, True) |
|
195 |
|
196 attr = wx.grid.GridCellAttr() |
|
197 attr.SetAlignment(align, wx.ALIGN_CENTRE) |
|
198 grid.SetColAttr(col, attr) |
|
199 grid.SetColSize(col, colSize) |
|
200 |
|
201 grid.SetCellEditor(row, col, editor) |
|
202 grid.SetCellRenderer(row, col, renderer) |
|
203 |
|
204 grid.SetCellBackgroundColour(row, col, wx.WHITE) |
|
205 |
|
206 def SetData(self, data): |
|
207 self.data = data |
|
208 |
|
209 def GetData(self): |
|
210 return self.data |
|
211 |
|
212 def AppendRow(self, row_content): |
|
213 self.data.append(row_content) |
|
214 |
|
215 def RemoveRow(self, row_index): |
|
216 self.data.pop(row_index) |
|
217 |
|
218 def GetRow(self, row_index): |
|
219 return self.data[row_index] |
|
220 |
|
221 def Empty(self): |
|
222 self.data = [] |
|
223 |
|
224 [ID_BEREMIZ, ID_BEREMIZMAINSPLITTER, |
|
225 ID_BEREMIZSECONDSPLITTER, ID_BEREMIZLEFTPANEL, |
|
226 ID_BEREMIZPARAMSPANEL, ID_BEREMIZLOGCONSOLE, |
|
227 ID_BEREMIZPLUGINTREE, ID_BEREMIZPLUGINCHILDS, |
|
228 ID_BEREMIZADDBUTTON, ID_BEREMIZDELETEBUTTON, |
|
229 ID_BEREMIZPARAMSSTATICBOX, ID_BEREMIZPARAMSENABLE, |
|
230 ID_BEREMIZPARAMSTARGETTYPE, ID_BEREMIZPARAMSIECCHANNEL, |
|
231 ID_BEREMIZPARAMSSTATICTEXT1, ID_BEREMIZPARAMSSTATICTEXT2, |
|
232 ID_BEREMIZPARAMSATTRIBUTESGRID, |
|
233 ] = [wx.NewId() for _init_ctrls in range(17)] |
87 |
234 |
88 [ID_BEREMIZFILEMENUITEMS0, ID_BEREMIZFILEMENUITEMS1, |
235 [ID_BEREMIZFILEMENUITEMS0, ID_BEREMIZFILEMENUITEMS1, |
89 ID_BEREMIZFILEMENUITEMS2, ID_BEREMIZFILEMENUITEMS3, |
236 ID_BEREMIZFILEMENUITEMS2, ID_BEREMIZFILEMENUITEMS3, |
90 ID_BEREMIZFILEMENUITEMS5, ID_BEREMIZFILEMENUITEMS7, |
237 ID_BEREMIZFILEMENUITEMS5, ID_BEREMIZFILEMENUITEMS7, |
91 ] = [wx.NewId() for _init_coll_FileMenu_Items in range(6)] |
238 ] = [wx.NewId() for _init_coll_FileMenu_Items in range(6)] |
193 self._init_coll_FileMenu_Items(self.FileMenu) |
340 self._init_coll_FileMenu_Items(self.FileMenu) |
194 self._init_coll_EditMenu_Items(self.EditMenu) |
341 self._init_coll_EditMenu_Items(self.EditMenu) |
195 self._init_coll_RunMenu_Items(self.RunMenu) |
342 self._init_coll_RunMenu_Items(self.RunMenu) |
196 self._init_coll_HelpMenu_Items(self.HelpMenu) |
343 self._init_coll_HelpMenu_Items(self.HelpMenu) |
197 |
344 |
198 def _init_coll_MainGridSizer_Items(self, parent): |
345 def _init_coll_LeftGridSizer_Items(self, parent): |
199 parent.AddSizer(self.ControlPanelSizer, 0, border=0, flag=wx.GROW) |
346 parent.AddWindow(self.PluginTree, 0, border=0, flag=wx.GROW) |
200 parent.AddWindow(self.LogConsole, 0, border=0, flag=wx.GROW) |
347 parent.AddSizer(self.ButtonGridSizer, 0, border=0, flag=wx.GROW) |
201 |
348 |
202 def _init_coll_MainGridSizer_Growables(self, parent): |
349 def _init_coll_LeftGridSizer_Growables(self, parent): |
203 parent.AddGrowableCol(0) |
350 parent.AddGrowableCol(0) |
204 parent.AddGrowableRow(1) |
|
205 |
|
206 def _init_coll_ControlPanelSizer_Items(self, parent): |
|
207 parent.AddSizer(self.ControlButtonSizer, 0, border=0, flag=0) |
|
208 parent.AddWindow(self.BusList, 0, border=0, flag=wx.GROW) |
|
209 parent.AddSizer(self.BusButtonSizer, 0, border=0, flag=0) |
|
210 |
|
211 |
|
212 def _init_coll_ControlPanelSizer_Growables(self, parent): |
|
213 parent.AddGrowableCol(1) |
|
214 parent.AddGrowableRow(0) |
351 parent.AddGrowableRow(0) |
215 |
352 |
216 def _init_coll_ControlButtonSizer_Items(self, parent): |
353 def _init_coll_ButtonGridSizer_Items(self, parent): |
217 parent.AddWindow(self.EditPLCButton, 0, border=0, flag=0) |
354 parent.AddWindow(self.PluginChilds, 0, border=0, flag=wx.GROW) |
218 parent.AddWindow(self.BuildButton, 0, border=0, flag=0) |
355 parent.AddWindow(self.AddButton, 0, border=0, flag=0) |
219 parent.AddWindow(self.SimulateButton, 0, border=0, flag=0) |
356 parent.AddWindow(self.DeleteButton, 0, border=0, flag=0) |
220 parent.AddWindow(self.RunButton, 0, border=0, flag=0) |
357 |
221 |
358 def _init_coll_ButtonGridSizer_Growables(self, parent): |
222 def _init_coll_BusButtonSizer_Items(self, parent): |
359 parent.AddGrowableCol(0) |
223 parent.AddWindow(self.AddBusButton, 0, border=0, flag=0) |
360 parent.AddGrowableRow(0) |
224 parent.AddWindow(self.DeleteBusButton, 0, border=0, flag=0) |
361 |
|
362 def _init_coll_ParamsPanelMainSizer_Items(self, parent): |
|
363 parent.AddSizer(self.ParamsPanelChildSizer, 1, border=10, flag=wx.GROW|wx.ALL) |
|
364 parent.AddSizer(self.ParamsPanelPluginSizer, 1, border=10, flag=wx.GROW|wx.ALL) |
|
365 parent.AddWindow(self.AttributesGrid, 2, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT|wx.BOTTOM) |
|
366 |
|
367 def _init_coll_ParamsPanelChildSizer_Items(self, parent): |
|
368 parent.AddWindow(self.ParamsEnable, 0, border=5, flag=wx.GROW|wx.BOTTOM) |
|
369 parent.AddWindow(self.ParamsStaticText1, 0, border=5, flag=wx.GROW|wx.BOTTOM) |
|
370 parent.AddWindow(self.ParamsIECChannel, 0, border=0, flag=wx.GROW) |
|
371 |
|
372 def _init_coll_ParamsPanelPluginSizer_Items(self, parent): |
|
373 parent.AddWindow(self.ParamsStaticText2, 0, border=5, flag=wx.GROW|wx.BOTTOM) |
|
374 parent.AddWindow(self.ParamsTargetType, 0, border=0, flag=wx.GROW) |
225 |
375 |
226 def _init_sizers(self): |
376 def _init_sizers(self): |
227 self.MainGridSizer = wx.FlexGridSizer(cols=1, hgap=2, rows=2, vgap=2) |
377 self.LeftGridSizer = wx.FlexGridSizer(cols=1, hgap=2, rows=2, vgap=2) |
228 self.ControlPanelSizer = wx.FlexGridSizer(cols=3, hgap=2, rows=1, vgap=2) |
378 self.ButtonGridSizer = wx.FlexGridSizer(cols=3, hgap=2, rows=1, vgap=2) |
229 self.ControlButtonSizer = wx.GridSizer(cols=2, hgap=2, rows=2, vgap=2) |
379 self.ParamsPanelMainSizer = wx.StaticBoxSizer(self.ParamsStaticBox, wx.HORIZONTAL) |
230 self.BusButtonSizer = wx.BoxSizer(wx.VERTICAL) |
380 self.ParamsPanelChildSizer = wx.BoxSizer(wx.VERTICAL) |
231 |
381 self.ParamsPanelPluginSizer = wx.BoxSizer(wx.VERTICAL) |
232 self._init_coll_MainGridSizer_Growables(self.MainGridSizer) |
382 |
233 self._init_coll_MainGridSizer_Items(self.MainGridSizer) |
383 self._init_coll_LeftGridSizer_Growables(self.LeftGridSizer) |
234 self._init_coll_ControlPanelSizer_Growables(self.ControlPanelSizer) |
384 self._init_coll_LeftGridSizer_Items(self.LeftGridSizer) |
235 self._init_coll_ControlPanelSizer_Items(self.ControlPanelSizer) |
385 self._init_coll_ButtonGridSizer_Growables(self.ButtonGridSizer) |
236 self._init_coll_ControlButtonSizer_Items(self.ControlButtonSizer) |
386 self._init_coll_ButtonGridSizer_Items(self.ButtonGridSizer) |
237 self._init_coll_BusButtonSizer_Items(self.BusButtonSizer) |
387 self._init_coll_ParamsPanelMainSizer_Items(self.ParamsPanelMainSizer) |
238 |
388 self._init_coll_ParamsPanelChildSizer_Items(self.ParamsPanelChildSizer) |
239 self.SetSizer(self.MainGridSizer) |
389 self._init_coll_ParamsPanelPluginSizer_Items(self.ParamsPanelPluginSizer) |
|
390 |
|
391 self.LeftPanel.SetSizer(self.LeftGridSizer) |
|
392 self.ParamsPanel.SetSizer(self.ParamsPanelMainSizer) |
240 |
393 |
241 def _init_ctrls(self, prnt): |
394 def _init_ctrls(self, prnt): |
242 wx.Frame.__init__(self, id=ID_BEREMIZ, name=u'Beremiz', |
395 wx.Frame.__init__(self, id=ID_BEREMIZ, name=u'Beremiz', |
243 parent=prnt, pos=wx.Point(0, 0), size=wx.Size(600, 300), |
396 parent=prnt, pos=wx.Point(0, 0), size=wx.Size(1000, 600), |
244 style=wx.DEFAULT_FRAME_STYLE, title=u'Beremiz') |
397 style=wx.DEFAULT_FRAME_STYLE, title=u'Beremiz') |
245 self._init_utils() |
398 self._init_utils() |
246 self.SetClientSize(wx.Size(600, 300)) |
399 self.SetClientSize(wx.Size(1000, 600)) |
247 self.SetMenuBar(self.menuBar1) |
400 self.SetMenuBar(self.menuBar1) |
248 |
401 |
|
402 self.MainSplitter = wx.SplitterWindow(id=ID_BEREMIZMAINSPLITTER, |
|
403 name='MainSplitter', parent=self, point=wx.Point(0, 0), |
|
404 size=wx.Size(0, 0), style=wx.SP_3D) |
|
405 self.MainSplitter.SetNeedUpdating(True) |
|
406 self.MainSplitter.SetMinimumPaneSize(1) |
|
407 |
|
408 self.LeftPanel = wx.Panel(id=ID_BEREMIZLEFTPANEL, |
|
409 name='LeftPanel', parent=self.MainSplitter, pos=wx.Point(0, 0), |
|
410 size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) |
|
411 |
|
412 self.PluginTree = wx.TreeCtrl(id=ID_BEREMIZPLUGINTREE, |
|
413 name='PluginTree', parent=self.LeftPanel, pos=wx.Point(0, 0), |
|
414 size=wx.Size(-1, -1), style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER) |
|
415 self.PluginTree.Bind(wx.EVT_RIGHT_UP, self.OnPluginTreeRightUp) |
|
416 self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnPluginTreeItemSelected, |
|
417 id=ID_BEREMIZPLUGINTREE) |
|
418 |
|
419 self.PluginChilds = wx.Choice(id=ID_BEREMIZPLUGINCHILDS, |
|
420 name='PluginChilds', parent=self.LeftPanel, pos=wx.Point(0, 0), |
|
421 size=wx.Size(-1, -1), style=0) |
|
422 |
|
423 self.AddButton = wx.Button(id=ID_BEREMIZADDBUTTON, label='Add', |
|
424 name='AddBusButton', parent=self.LeftPanel, pos=wx.Point(0, 0), |
|
425 size=wx.Size(48, 30), style=0) |
|
426 self.AddButton.Bind(wx.EVT_BUTTON, self.OnAddButton, |
|
427 id=ID_BEREMIZADDBUTTON) |
|
428 |
|
429 self.DeleteButton = wx.Button(id=ID_BEREMIZDELETEBUTTON, label='Delete', |
|
430 name='DeleteBusButton', parent=self.LeftPanel, pos=wx.Point(0, 0), |
|
431 size=wx.Size(64, 30), style=0) |
|
432 self.DeleteButton.Bind(wx.EVT_BUTTON, self.OnDeleteButton, |
|
433 id=ID_BEREMIZDELETEBUTTON) |
|
434 |
|
435 self.SecondSplitter = wx.SplitterWindow(id=ID_BEREMIZSECONDSPLITTER, |
|
436 name='SecondSplitter', parent=self.MainSplitter, point=wx.Point(0, 0), |
|
437 size=wx.Size(0, 0), style=wx.SP_3D) |
|
438 self.SecondSplitter.SetNeedUpdating(True) |
|
439 self.SecondSplitter.SetMinimumPaneSize(1) |
|
440 |
|
441 self.MainSplitter.SplitVertically(self.LeftPanel, self.SecondSplitter, |
|
442 300) |
|
443 |
|
444 self.ParamsPanel = wx.Panel(id=ID_BEREMIZPARAMSPANEL, |
|
445 name='ParamsPanel', parent=self.SecondSplitter, pos=wx.Point(0, 0), |
|
446 size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) |
|
447 |
|
448 self.ParamsStaticBox = wx.StaticBox(id=ID_BEREMIZPARAMSSTATICBOX, |
|
449 label='', name='staticBox1', parent=self.ParamsPanel, |
|
450 pos=wx.Point(0, 0), size=wx.Size(0, 0), style=0) |
|
451 |
|
452 self.ParamsEnable = wx.CheckBox(id=ID_BEREMIZPARAMSENABLE, |
|
453 label='Plugin enabled', name='ParamsEnable', parent=self.ParamsPanel, |
|
454 pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) |
|
455 self.Bind(wx.EVT_CHECKBOX, self.OnParamsEnableChanged, id=ID_BEREMIZPARAMSENABLE) |
|
456 |
|
457 self.ParamsStaticText1 = wx.StaticText(id=ID_BEREMIZPARAMSSTATICTEXT1, |
|
458 label='IEC Channel:', name='ParamsStaticText1', parent=self.ParamsPanel, |
|
459 pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) |
|
460 |
|
461 self.ParamsIECChannel = wx.SpinCtrl(id=ID_BEREMIZPARAMSIECCHANNEL, |
|
462 name='ParamsIECChannel', parent=self.ParamsPanel, pos=wx.Point(0, 0), |
|
463 size=wx.Size(0, 24), style=wx.SP_ARROW_KEYS, min=0) |
|
464 self.Bind(wx.EVT_SPINCTRL, self.OnParamsIECChannelChanged, id=ID_BEREMIZPARAMSIECCHANNEL) |
|
465 |
|
466 self.ParamsStaticText2 = wx.StaticText(id=ID_BEREMIZPARAMSSTATICTEXT2, |
|
467 label='Target Type:', name='ParamsStaticText2', parent=self.ParamsPanel, |
|
468 pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) |
|
469 |
|
470 self.ParamsTargetType = wx.Choice(id=ID_BEREMIZPARAMSTARGETTYPE, |
|
471 name='TargetType', choices=[""], parent=self.ParamsPanel, |
|
472 pos=wx.Point(0, 0), size=wx.Size(0, 24), style=wx.LB_SINGLE) |
|
473 self.Bind(wx.EVT_CHOICE, self.OnParamsTargetTypeChanged, id=ID_BEREMIZPARAMSTARGETTYPE) |
|
474 |
|
475 self.AttributesGrid = wx.grid.Grid(id=ID_BEREMIZPARAMSATTRIBUTESGRID, |
|
476 name='AttributesGrid', parent=self.ParamsPanel, pos=wx.Point(0, 0), |
|
477 size=wx.Size(0, 150), style=wx.VSCROLL) |
|
478 self.AttributesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False, |
|
479 'Sans')) |
|
480 self.AttributesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL, |
|
481 False, 'Sans')) |
|
482 self.AttributesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnAttributesGridCellChange) |
|
483 |
249 self.LogConsole = wx.TextCtrl(id=ID_BEREMIZLOGCONSOLE, value='', |
484 self.LogConsole = wx.TextCtrl(id=ID_BEREMIZLOGCONSOLE, value='', |
250 name='LogConsole', parent=self, pos=wx.Point(0, 0), |
485 name='LogConsole', parent=self.SecondSplitter, pos=wx.Point(0, 0), |
251 size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2) |
486 size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2) |
252 |
487 |
253 self.EditPLCButton = wx.Button(id=ID_BEREMIZEDITPLCBUTTON, label='Edit\nPLC', |
488 self.SecondSplitter.SplitHorizontally(self.ParamsPanel, self.LogConsole, |
254 name='EditPLCButton', parent=self, pos=wx.Point(0, 0), |
489 -250) |
255 size=wx.Size(48, 48), style=0) |
|
256 self.EditPLCButton.Bind(wx.EVT_BUTTON, self.OnEditPLCButton, |
|
257 id=ID_BEREMIZEDITPLCBUTTON) |
|
258 |
|
259 self.BuildButton = wx.Button(id=ID_BEREMIZBUILDBUTTON, label='Build', |
|
260 name='BuildButton', parent=self, pos=wx.Point(0, 0), |
|
261 size=wx.Size(48, 48), style=0) |
|
262 self.BuildButton.Bind(wx.EVT_BUTTON, self.OnBuildButton, |
|
263 id=ID_BEREMIZBUILDBUTTON) |
|
264 |
|
265 self.SimulateButton = wx.Button(id=ID_BEREMIZSIMULATEBUTTON, label='Simul', |
|
266 name='SimulateButton', parent=self, pos=wx.Point(0, 0), |
|
267 size=wx.Size(48, 48), style=0) |
|
268 self.EditPLCButton.Bind(wx.EVT_BUTTON, self.OnSimulateButton, |
|
269 id=ID_BEREMIZSIMULATEBUTTON) |
|
270 |
|
271 self.RunButton = wx.Button(id=ID_BEREMIZRUNBUTTON, label='Run', |
|
272 name='RunButton', parent=self, pos=wx.Point(0, 0), |
|
273 size=wx.Size(48, 48), style=0) |
|
274 self.RunButton.Bind(wx.EVT_BUTTON, self.OnRunButton, |
|
275 id=ID_BEREMIZRUNBUTTON) |
|
276 |
|
277 self.BusList = wx.ListBox(choices=[], id=ID_BEREMIZBUSLIST, |
|
278 name='BusList', parent=self, pos=wx.Point(0, 0), |
|
279 size=wx.Size(-1, -1), style=wx.LB_SINGLE|wx.LB_NEEDED_SB) |
|
280 self.BusList.Bind(wx.EVT_LISTBOX_DCLICK, self.OnBusListDClick, |
|
281 id=ID_BEREMIZBUSLIST) |
|
282 |
|
283 self.AddBusButton = wx.Button(id=ID_BEREMIZADDBUSBUTTON, label='Add', |
|
284 name='AddBusButton', parent=self, pos=wx.Point(0, 0), |
|
285 size=wx.Size(48, 48), style=0) |
|
286 self.AddBusButton.Bind(wx.EVT_BUTTON, self.OnAddBusButton, |
|
287 id=ID_BEREMIZADDBUSBUTTON) |
|
288 |
|
289 self.DeleteBusButton = wx.Button(id=ID_BEREMIZDELETEBUSBUTTON, label='Delete', |
|
290 name='DeleteBusButton', parent=self, pos=wx.Point(0, 0), |
|
291 size=wx.Size(48, 48), style=0) |
|
292 self.DeleteBusButton.Bind(wx.EVT_BUTTON, self.OnDeleteBusButton, |
|
293 id=ID_BEREMIZDELETEBUSBUTTON) |
|
294 |
490 |
295 self._init_sizers() |
491 self._init_sizers() |
296 |
492 |
297 def __init__(self, parent, projectOpen): |
493 def __init__(self, parent, projectOpen): |
298 self._init_ctrls(parent) |
494 self._init_ctrls(parent) |
299 |
495 |
300 for name in plugins.__all__: |
496 self.Log = LogPseudoFile(self.LogConsole) |
301 module = getattr(plugins, name) |
497 |
302 |
498 self.PluginRoot = PluginsRoot() |
303 #AddPlugin(module.GetBlockGenerationFunction(self)) |
499 for value in self.PluginRoot.GetTargetTypes(): |
304 |
500 self.ParamsTargetType.Append(value) |
305 self.CurrentProjectPath = "" |
501 |
306 |
502 self.Table = AttributesTable(self, [], ["Attribute", "Value"]) |
307 self.PLCManager = None |
503 self.AttributesGrid.SetTable(self.Table) |
|
504 self.AttributesGrid.SetRowLabelSize(0) |
|
505 |
|
506 if projectOpen: |
|
507 self.PluginRoot.LoadProject(projectOpen) |
|
508 self.RefreshPluginTree() |
|
509 |
308 self.PLCEditor = None |
510 self.PLCEditor = None |
309 self.BusManagers = {} |
511 |
310 |
512 self.RefreshPluginParams() |
311 self.Log = LogPseudoFile(self.LogConsole) |
|
312 |
|
313 if projectOpen: |
|
314 self.OpenProject(projectOpen) |
|
315 |
|
316 self.RefreshButtons() |
513 self.RefreshButtons() |
317 self.RefreshMainMenu() |
514 self.RefreshMainMenu() |
318 |
515 |
319 def RefreshButtons(self): |
516 def RefreshButtons(self): |
320 if self.CurrentProjectPath == "": |
517 if self.PluginRoot.HasProjectOpened(): |
321 self.LogConsole.Enable(False) |
518 self.PluginChilds.Enable(True) |
322 self.EditPLCButton.Enable(False) |
519 self.AddButton.Enable(True) |
323 self.BuildButton.Enable(False) |
520 self.DeleteButton.Enable(True) |
324 self.SimulateButton.Enable(False) |
|
325 self.RunButton.Enable(False) |
|
326 self.BusList.Enable(False) |
|
327 self.AddBusButton.Enable(False) |
|
328 self.DeleteBusButton.Enable(False) |
|
329 else: |
521 else: |
330 self.LogConsole.Enable(True) |
522 self.PluginChilds.Enable(False) |
331 self.EditPLCButton.Enable(True) |
523 self.AddButton.Enable(False) |
332 self.BuildButton.Enable(True) |
524 self.DeleteButton.Enable(False) |
333 self.SimulateButton.Enable(True) |
525 |
334 self.RunButton.Enable(True) |
|
335 self.BusList.Enable(True) |
|
336 self.AddBusButton.Enable(True) |
|
337 self.DeleteBusButton.Enable(True) |
|
338 |
|
339 def RefreshBusList(self): |
|
340 selected = self.BusList.GetStringSelection() |
|
341 self.BusList.Clear() |
|
342 busidlist = self.BusManagers.keys() |
|
343 busidlist.sort() |
|
344 for id in busidlist: |
|
345 bus_infos = self.BusManagers[id] |
|
346 self.BusList.Append("0x%2.2X\t%s\t%s"%(id, bus_infos["Type"], bus_infos["Name"])) |
|
347 if selected != "": |
|
348 self.BusList.SetStringSelection(selected) |
|
349 |
|
350 def RefreshMainMenu(self): |
526 def RefreshMainMenu(self): |
351 if self.menuBar1: |
527 if self.menuBar1: |
352 if self.CurrentProjectPath == "": |
528 if self.PluginRoot.HasProjectOpened(): |
|
529 self.menuBar1.EnableTop(1, True) |
|
530 self.menuBar1.EnableTop(2, True) |
|
531 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS2, True) |
|
532 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS3, True) |
|
533 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS5, True) |
|
534 else: |
353 self.menuBar1.EnableTop(1, False) |
535 self.menuBar1.EnableTop(1, False) |
354 self.menuBar1.EnableTop(2, False) |
536 self.menuBar1.EnableTop(2, False) |
355 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS2, False) |
537 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS2, False) |
356 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS3, False) |
538 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS3, False) |
357 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS5, False) |
539 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS5, False) |
|
540 |
|
541 def RefreshPluginTree(self): |
|
542 infos = self.PluginRoot.GetPlugInfos() |
|
543 root = self.PluginTree.GetRootItem() |
|
544 self.GenerateTreeBranch(root, infos) |
|
545 self.PluginTree.Expand(self.PluginTree.GetRootItem()) |
|
546 self.RefreshPluginParams() |
|
547 |
|
548 def GenerateTreeBranch(self, root, infos): |
|
549 to_delete = [] |
|
550 if root.IsOk(): |
|
551 self.PluginTree.SetItemText(root, infos["name"]) |
|
552 else: |
|
553 root = self.PluginTree.AddRoot(infos["name"]) |
|
554 self.PluginTree.SetPyData(root, infos["type"]) |
|
555 item, root_cookie = self.PluginTree.GetFirstChild(root) |
|
556 if len(infos["values"]) > 0: |
|
557 for values in infos["values"]: |
|
558 if not item.IsOk(): |
|
559 item = self.PluginTree.AppendItem(root, "") |
|
560 item, root_cookie = self.PluginTree.GetNextChild(root, root_cookie) |
|
561 self.GenerateTreeBranch(item, values) |
|
562 item, root_cookie = self.PluginTree.GetNextChild(root, root_cookie) |
|
563 while item.IsOk(): |
|
564 to_delete.append(item) |
|
565 item, root_cookie = self.PluginTree.GetNextChild(root, root_cookie) |
|
566 for item in to_delete: |
|
567 self.PluginTree.Delete(item) |
|
568 |
|
569 def GetSelectedPlugin(self): |
|
570 selected = self.PluginTree.GetSelection() |
|
571 if not selected.IsOk(): |
|
572 return None |
|
573 if selected == self.PluginTree.GetRootItem(): |
|
574 return self.PluginRoot |
|
575 else: |
|
576 name = self.PluginTree.GetItemText(selected) |
|
577 item = self.PluginTree.GetItemParent(selected) |
|
578 while item.IsOk() and item != self.PluginTree.GetRootItem(): |
|
579 name = "%s.%s"%(self.PluginTree.GetItemText(item), name) |
|
580 item = self.PluginTree.GetItemParent(item) |
|
581 return self.PluginRoot.GetChildByName(name) |
|
582 |
|
583 def OnPluginTreeItemSelected(self, event): |
|
584 wx.CallAfter(self.RefreshPluginParams) |
|
585 event.Skip() |
|
586 |
|
587 def _GetAddPluginFunction(self, name): |
|
588 def OnPluginMenu(event): |
|
589 self.AddPlugin(name) |
|
590 event.Skip() |
|
591 return OnPluginMenu |
|
592 |
|
593 def OnPluginTreeRightUp(self, event): |
|
594 plugin = self.GetSelectedPlugin() |
|
595 if plugin: |
|
596 main_menu = wx.Menu(title='') |
|
597 if len(plugin.PlugChildsTypes) > 0: |
|
598 plugin_menu = wx.Menu(title='') |
|
599 for name, XSDClass in self.GetSelectedPlugin().PlugChildsTypes: |
|
600 new_id = wx.NewId() |
|
601 plugin_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=name) |
|
602 self.Bind(wx.EVT_MENU, self._GetAddPluginFunction(name), id=new_id) |
|
603 main_menu.AppendMenu(-1, "Add", plugin_menu, '') |
|
604 new_id = wx.NewId() |
|
605 main_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text="Delete") |
|
606 self.Bind(wx.EVT_MENU, self.OnDeleteButton, id=new_id) |
|
607 rect = self.PluginTree.GetBoundingRect(self.PluginTree.GetSelection()) |
|
608 self.PluginTree.PopupMenuXY(main_menu, rect.x + rect.width, rect.y) |
|
609 event.Skip() |
|
610 |
|
611 def RefreshPluginParams(self): |
|
612 plugin = self.GetSelectedPlugin() |
|
613 if not plugin: |
|
614 # Refresh ParamsPanel |
|
615 self.ParamsPanel.Hide() |
|
616 |
|
617 # Refresh PluginChilds |
|
618 self.PluginChilds.Clear() |
|
619 self.PluginChilds.Enable(False) |
|
620 self.AddButton.Enable(False) |
|
621 self.DeleteButton.Enable(False) |
|
622 else: |
|
623 # Refresh ParamsPanel |
|
624 self.ParamsPanel.Show() |
|
625 self.ParamsStaticBox.SetLabel(plugin.BaseParams.getName()) |
|
626 if plugin == self.PluginRoot: |
|
627 self.ParamsPanelMainSizer.Hide(self.ParamsPanelChildSizer) |
|
628 self.ParamsPanelMainSizer.Show(self.ParamsPanelPluginSizer) |
|
629 self.ParamsTargetType.SetStringSelection(self.PluginRoot.GetTargetType()) |
358 else: |
630 else: |
359 self.menuBar1.EnableTop(1, True) |
631 self.ParamsPanelMainSizer.Show(self.ParamsPanelChildSizer) |
360 self.menuBar1.EnableTop(2, True) |
632 self.ParamsPanelMainSizer.Hide(self.ParamsPanelPluginSizer) |
361 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS2, True) |
633 self.ParamsEnable.SetValue(plugin.BaseParams.getEnabled()) |
362 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS3, True) |
634 self.ParamsEnable.Enable(True) |
363 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS5, True) |
635 self.ParamsStaticText1.Enable(True) |
364 |
636 self.ParamsIECChannel.SetValue(plugin.BaseParams.getIEC_Channel()) |
|
637 self.ParamsIECChannel.Enable(True) |
|
638 self.ParamsPanelMainSizer.Layout() |
|
639 self.RefreshAttributesGrid() |
|
640 |
|
641 # Refresh PluginChilds |
|
642 self.PluginChilds.Clear() |
|
643 if len(plugin.PlugChildsTypes) > 0: |
|
644 self.PluginChilds.Append("") |
|
645 for name, XSDClass in plugin.PlugChildsTypes: |
|
646 self.PluginChilds.Append(name) |
|
647 self.PluginChilds.Enable(True) |
|
648 self.AddButton.Enable(True) |
|
649 else: |
|
650 self.PluginChilds.Enable(False) |
|
651 self.AddButton.Enable(False) |
|
652 self.DeleteButton.Enable(True) |
|
653 |
|
654 def RefreshAttributesGrid(self): |
|
655 plugin = self.GetSelectedPlugin() |
|
656 if not plugin: |
|
657 self.Table.Empty() |
|
658 else: |
|
659 if plugin == self.PluginRoot: |
|
660 attr_infos = self.PluginRoot.GetTargetAttributes() |
|
661 else: |
|
662 attr_infos = plugin.GetPlugParamsAttributes() |
|
663 data = [] |
|
664 for infos in attr_infos: |
|
665 data.append({"Attribute" : infos["name"], "Value" : infos["value"], |
|
666 "Type" : infos["type"]}) |
|
667 self.Table.SetData(data) |
|
668 self.Table.ResetView(self.AttributesGrid) |
|
669 |
|
670 def OnParamsEnableChanged(self, event): |
|
671 plugin = self.GetSelectedPlugin() |
|
672 if plugin and plugin != self.PluginRoot: |
|
673 plugin.BaseParams.setEnabled(event.Checked()) |
|
674 event.Skip() |
|
675 |
|
676 def OnParamsIECChannelChanged(self, event): |
|
677 plugin = self.GetSelectedPlugin() |
|
678 if plugin and plugin != self.PluginRoot: |
|
679 plugin.BaseParams.setIEC_Channel(self.ParamsIECChannel.GetValue()) |
|
680 event.Skip() |
|
681 |
|
682 def OnParamsTargetTypeChanged(self, event): |
|
683 plugin = self.GetSelectedPlugin() |
|
684 if plugin and plugin == self.PluginRoot: |
|
685 self.PluginRoot.ChangeTargetType(self.ParamsTargetType.GetStringSelection()) |
|
686 self.RefreshAttributesGrid() |
|
687 event.Skip() |
|
688 |
|
689 def OnAttributesGridCellChange(self, event): |
|
690 row = event.GetRow() |
|
691 plugin = self.GetSelectedPlugin() |
|
692 if plugin: |
|
693 name = self.Table.GetValueByName(row, "Attribute") |
|
694 value = self.Table.GetValueByName(row, "Value") |
|
695 if plugin == self.PluginRoot: |
|
696 self.PluginRoot.SetTargetAttribute(name, value) |
|
697 else: |
|
698 plugin.SetPlugParamsAttribute(name, value) |
|
699 event.Skip() |
|
700 |
365 def OnNewProjectMenu(self, event): |
701 def OnNewProjectMenu(self, event): |
366 if self.CurrentProjectPath != "": |
702 defaultpath = self.PluginRoot.GetProjectPath() |
367 defaultpath = self.CurrentProjectPath |
703 if defaultpath == "": |
368 else: |
|
369 defaultpath = os.getcwd() |
704 defaultpath = os.getcwd() |
370 dialog = wx.DirDialog(self , "Choose a project", defaultpath, wx.DD_NEW_DIR_BUTTON) |
705 dialog = wx.DirDialog(self , "Choose a project", defaultpath, wx.DD_NEW_DIR_BUTTON) |
371 if dialog.ShowModal() == wx.ID_OK: |
706 if dialog.ShowModal() == wx.ID_OK: |
372 projectpath = dialog.GetPath() |
707 projectpath = dialog.GetPath() |
373 dialog.Destroy() |
708 dialog.Destroy() |
374 if os.path.isdir(projectpath) and len(os.listdir(projectpath)) == 0: |
709 if os.path.isdir(projectpath) and len(os.listdir(projectpath)) == 0: |
375 os.mkdir(os.path.join(projectpath, "eds")) |
|
376 self.PLCManager = PLCControler() |
|
377 plc_file = os.path.join(projectpath, "plc.xml") |
|
378 dialog = ProjectDialog(self) |
710 dialog = ProjectDialog(self) |
379 if dialog.ShowModal() == wx.ID_OK: |
711 if dialog.ShowModal() == wx.ID_OK: |
380 values = dialog.GetValues() |
712 values = dialog.GetValues() |
381 values["creationDateTime"] = datetime(*localtime()[:6]) |
713 values["creationDateTime"] = datetime(*localtime()[:6]) |
382 self.PLCManager.CreateNewProject(values.pop("projectName")) |
714 self.PluginRoot.NewProject(projectpath, values) |
383 self.PLCManager.SetProjectProperties(properties=values) |
715 self.RefreshPluginTree() |
384 self.PLCManager.SaveXMLFile(plc_file) |
716 self.RefreshButtons() |
385 self.CurrentProjectPath = projectpath |
717 self.RefreshMainMenu() |
386 dialog.Destroy() |
718 dialog.Destroy() |
387 self.RefreshButtons() |
|
388 self.RefreshMainMenu() |
|
389 else: |
719 else: |
390 message = wx.MessageDialog(self, "Folder choosen isn't empty. You can't use it for a new project!", "ERROR", wx.OK|wx.ICON_ERROR) |
720 message = wx.MessageDialog(self, "Folder choosen isn't empty. You can't use it for a new project!", "ERROR", wx.OK|wx.ICON_ERROR) |
391 message.ShowModal() |
721 message.ShowModal() |
392 message.Destroy() |
722 message.Destroy() |
393 event.Skip() |
723 event.Skip() |
394 |
724 |
395 def OpenProject(self, projectpath): |
|
396 try: |
|
397 if not os.path.isdir(projectpath): |
|
398 raise Exception |
|
399 self.BusManagers = {} |
|
400 configpath = os.path.join(projectpath, ".project") |
|
401 if not os.path.isfile(configpath): |
|
402 raise Exception |
|
403 file = open(configpath, "r") |
|
404 lines = [line.strip() for line in file.readlines() if line.strip() != ""] |
|
405 if lines[0] != "Beremiz": |
|
406 file.close() |
|
407 raise Exception |
|
408 for bus_id, bus_type, bus_name in [line.split(" ") for line in lines[1:]]: |
|
409 id = int(bus_id, 16) |
|
410 controller = getattr(plugins, bus_type).controller |
|
411 if controller != None: |
|
412 manager = controller() |
|
413 result = manager.LoadProject(projectpath, bus_name) |
|
414 if not result: |
|
415 self.BusManagers[id] = {"Name" : bus_name, "Type" : bus_type, "Manager" : manager, "Editor" : None} |
|
416 else: |
|
417 message = wx.MessageDialog(self, result, "Error", wx.OK|wx.ICON_ERROR) |
|
418 message.ShowModal() |
|
419 message.Destroy() |
|
420 else: |
|
421 self.BusManagers[id] = {"Name" : bus_name, "Type" : bus_type, "Manager" : None, "Editor" : None} |
|
422 file.close() |
|
423 self.PLCManager = PLCControler() |
|
424 plc_file = os.path.join(projectpath, "plc.xml") |
|
425 if os.path.isfile(plc_file): |
|
426 self.PLCManager.OpenXMLFile(plc_file) |
|
427 self.CurrentProjectPath = projectpath |
|
428 else: |
|
429 dialog = ProjectDialog(self) |
|
430 if dialog.ShowModal() == wx.ID_OK: |
|
431 values = dialog.GetValues() |
|
432 projectname = values.pop("projectName") |
|
433 values["creationDateTime"] = datetime(*localtime()[:6]) |
|
434 self.PLCManager.CreateNewProject(projectname) |
|
435 self.PLCManager.SetProjectProperties(values) |
|
436 self.PLCManager.SaveXMLFile(plc_file) |
|
437 self.CurrentProjectPath = projectpath |
|
438 dialog.Destroy() |
|
439 self.RefreshBusList() |
|
440 self.RefreshButtons() |
|
441 self.RefreshMainMenu() |
|
442 except Exception, message: |
|
443 message = wx.MessageDialog(self, "\"%s\" folder is not a valid Beremiz project\n%s"%(projectpath,message), "Error", wx.OK|wx.ICON_ERROR) |
|
444 message.ShowModal() |
|
445 message.Destroy() |
|
446 |
|
447 def OnOpenProjectMenu(self, event): |
725 def OnOpenProjectMenu(self, event): |
448 if self.CurrentProjectPath != "": |
726 defaultpath = self.PluginRoot.GetProjectPath() |
449 defaultpath = self.CurrentProjectPath |
727 if defaultpath == "": |
450 else: |
|
451 defaultpath = os.getcwd() |
728 defaultpath = os.getcwd() |
452 dialog = wx.DirDialog(self , "Choose a project", defaultpath, wx.DD_NEW_DIR_BUTTON) |
729 dialog = wx.DirDialog(self , "Choose a project", defaultpath, wx.DD_NEW_DIR_BUTTON) |
453 if dialog.ShowModal() == wx.ID_OK: |
730 if dialog.ShowModal() == wx.ID_OK: |
454 self.OpenProject(dialog.GetPath()) |
731 projectpath = dialog.GetPath() |
|
732 if os.path.isdir(projectpath): |
|
733 result = self.PluginRoot.LoadProject(projectpath) |
|
734 if not result: |
|
735 self.RefreshPluginTree() |
|
736 self.RefreshButtons() |
|
737 self.RefreshMainMenu() |
|
738 else: |
|
739 message = wx.MessageDialog(self, result, "Error", wx.OK|wx.ICON_ERROR) |
|
740 message.ShowModal() |
|
741 message.Destroy() |
|
742 else: |
|
743 message = wx.MessageDialog(self, "\"%s\" folder is not a valid Beremiz project\n"%projectpath, "Error", wx.OK|wx.ICON_ERROR) |
|
744 message.ShowModal() |
|
745 message.Destroy() |
455 dialog.Destroy() |
746 dialog.Destroy() |
456 event.Skip() |
747 event.Skip() |
457 |
748 |
458 def OnCloseProjectMenu(self, event): |
749 def OnCloseProjectMenu(self, event): |
459 self.PLCManager = None |
750 self.PLCManager = None |