252 kind=wx.ITEM_NORMAL, text=u'New\tCTRL+N') |
252 kind=wx.ITEM_NORMAL, text=u'New\tCTRL+N') |
253 parent.Append(help='', id=wx.ID_OPEN, |
253 parent.Append(help='', id=wx.ID_OPEN, |
254 kind=wx.ITEM_NORMAL, text=u'Open\tCTRL+O') |
254 kind=wx.ITEM_NORMAL, text=u'Open\tCTRL+O') |
255 parent.Append(help='', id=wx.ID_SAVE, |
255 parent.Append(help='', id=wx.ID_SAVE, |
256 kind=wx.ITEM_NORMAL, text=u'Save\tCTRL+S') |
256 kind=wx.ITEM_NORMAL, text=u'Save\tCTRL+S') |
257 parent.Append(help='', id=wx.ID_CLOSE, |
257 parent.Append(help='', id=wx.ID_CLOSE_ALL, |
258 kind=wx.ITEM_NORMAL, text=u'Close Project') |
258 kind=wx.ITEM_NORMAL, text=u'Close Project') |
259 parent.AppendSeparator() |
259 parent.AppendSeparator() |
260 parent.Append(help='', id=wx.ID_PROPERTIES, |
260 parent.Append(help='', id=wx.ID_PROPERTIES, |
261 kind=wx.ITEM_NORMAL, text=u'Properties') |
261 kind=wx.ITEM_NORMAL, text=u'Properties') |
262 parent.AppendSeparator() |
262 parent.AppendSeparator() |
410 self.Log = LogPseudoFile(self.LogConsole) |
410 self.Log = LogPseudoFile(self.LogConsole) |
411 |
411 |
412 # create temporary directory for runtime working directory |
412 # create temporary directory for runtime working directory |
413 self.local_runtime_tmpdir = tempfile.mkdtemp() |
413 self.local_runtime_tmpdir = tempfile.mkdtemp() |
414 # choose an arbitrary random port for runtime |
414 # choose an arbitrary random port for runtime |
415 runtime_port = int(random.random() * 1000) + 61131 |
415 self.runtime_port = int(random.random() * 1000) + 61131 |
416 # launch local runtime |
416 # launch local runtime |
417 self.local_runtime = ProcessLogger(self.Log, |
417 self.local_runtime = ProcessLogger(self.Log, |
418 "\"%s\" \"%s\" -p %s -i localhost %s"%(sys.executable, |
418 "\"%s\" \"%s\" -p %s -i localhost %s"%(sys.executable, |
419 Bpath("Beremiz_service.py"), |
419 Bpath("Beremiz_service.py"), |
420 runtime_port, |
420 self.runtime_port, |
421 self.local_runtime_tmpdir), |
421 self.local_runtime_tmpdir), |
422 no_gui=False) |
422 no_gui=False) |
423 |
423 |
424 # Add beremiz's icon in top left corner of the frame |
424 # Add beremiz's icon in top left corner of the frame |
425 self.SetIcon(wx.Icon(Bpath( "images", "brz.ico"), wx.BITMAP_TYPE_ICO)) |
425 self.SetIcon(wx.Icon(Bpath( "images", "brz.ico"), wx.BITMAP_TYPE_ICO)) |
426 |
426 |
427 self.PluginRoot = PluginsRoot(self, self.Log, runtime_port) |
|
428 self.DisableEvents = False |
427 self.DisableEvents = False |
429 |
428 |
430 self.PluginInfos = {} |
429 self.PluginInfos = {} |
431 |
430 |
432 if projectOpen: |
431 if projectOpen: |
|
432 self.PluginRoot = PluginsRoot(self, self.Log, self.runtime_port) |
433 self.PluginRoot.LoadProject(projectOpen) |
433 self.PluginRoot.LoadProject(projectOpen) |
434 self.RefreshPLCParams() |
434 self.RefreshPLCParams() |
435 self.RefreshPluginTree() |
435 self.RefreshPluginTree() |
|
436 else: |
|
437 self.PluginRoot = None |
436 |
438 |
437 self.RefreshMainMenu() |
439 self.RefreshMainMenu() |
438 |
440 |
439 def OnOpenWidgetInspector(self, evt): |
441 def OnOpenWidgetInspector(self, evt): |
440 # Activate the widget inspection tool |
442 # Activate the widget inspection tool |
452 def OnLogConsoleDClick(self, event): |
454 def OnLogConsoleDClick(self, event): |
453 wx.CallAfter(self.SearchLineForError) |
455 wx.CallAfter(self.SearchLineForError) |
454 event.Skip() |
456 event.Skip() |
455 |
457 |
456 def SearchLineForError(self): |
458 def SearchLineForError(self): |
457 text = self.LogConsole.GetRange(0, self.LogConsole.GetInsertionPoint()) |
459 if self.PluginRoot is not None: |
458 line = self.LogConsole.GetLineText(len(text.splitlines()) - 1) |
460 text = self.LogConsole.GetRange(0, self.LogConsole.GetInsertionPoint()) |
459 result = MATIEC_ERROR_MODEL.match(line) |
461 line = self.LogConsole.GetLineText(len(text.splitlines()) - 1) |
460 if result is not None: |
462 result = MATIEC_ERROR_MODEL.match(line) |
461 first_line, first_column, last_line, last_column, error = result.groups() |
463 if result is not None: |
462 infos = self.PluginRoot.ShowError(self.Log, |
464 first_line, first_column, last_line, last_column, error = result.groups() |
463 (int(first_line), int(first_column)), |
465 infos = self.PluginRoot.ShowError(self.Log, |
464 (int(last_line), int(last_column))) |
466 (int(first_line), int(first_column)), |
|
467 (int(last_line), int(last_column))) |
465 |
468 |
466 def OnCloseFrame(self, event): |
469 def OnCloseFrame(self, event): |
467 |
470 if self.PluginRoot is not None: |
468 if self.PluginRoot.HasProjectOpened(): |
|
469 if self.PluginRoot.ProjectTestModified(): |
471 if self.PluginRoot.ProjectTestModified(): |
470 dialog = wx.MessageDialog(self, |
472 dialog = wx.MessageDialog(self, |
471 "Save changes ?", |
473 "Save changes ?", |
472 "Close Application", |
474 "Close Application", |
473 wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) |
475 wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) |
494 self.GetBestSize() |
496 self.GetBestSize() |
495 self.RefreshScrollBars() |
497 self.RefreshScrollBars() |
496 event.Skip() |
498 event.Skip() |
497 |
499 |
498 def OnFrameActivated(self, event): |
500 def OnFrameActivated(self, event): |
499 if not event.GetActive(): |
501 if not event.GetActive() and self.PluginRoot is not None: |
500 self.PluginRoot.RefreshPluginsBlockLists() |
502 self.PluginRoot.RefreshPluginsBlockLists() |
501 |
503 |
502 def RefreshMainMenu(self): |
504 def RefreshMainMenu(self): |
503 if self.MenuBar: |
505 if self.PluginRoot is not None: |
504 if self.PluginRoot.HasProjectOpened(): |
506 ## self.MenuBar.EnableTop(1, True) |
505 ## self.MenuBar.EnableTop(1, True) |
507 ## self.MenuBar.EnableTop(2, True) |
506 ## self.MenuBar.EnableTop(2, True) |
508 self.FileMenu.Enable(wx.ID_SAVE, True) |
507 self.FileMenu.Enable(wx.ID_SAVE, True) |
509 self.FileMenu.Enable(wx.ID_CLOSE, True) |
508 self.FileMenu.Enable(wx.ID_CLOSE, True) |
510 self.FileMenu.Enable(wx.ID_PROPERTIES, True) |
509 self.FileMenu.Enable(wx.ID_PROPERTIES, True) |
511 else: |
510 else: |
512 ## self.MenuBar.EnableTop(1, False) |
511 ## self.MenuBar.EnableTop(1, False) |
513 ## self.MenuBar.EnableTop(2, False) |
512 ## self.MenuBar.EnableTop(2, False) |
514 self.FileMenu.Enable(wx.ID_SAVE, False) |
513 self.FileMenu.Enable(wx.ID_SAVE, False) |
515 self.FileMenu.Enable(wx.ID_CLOSE, False) |
514 self.FileMenu.Enable(wx.ID_CLOSE, False) |
516 self.FileMenu.Enable(wx.ID_PROPERTIES, False) |
515 self.FileMenu.Enable(wx.ID_PROPERTIES, False) |
|
516 |
517 |
517 def RefreshScrollBars(self): |
518 def RefreshScrollBars(self): |
518 xstart, ystart = self.PLCConfig.GetViewStart() |
519 xstart, ystart = self.PLCConfig.GetViewStart() |
519 window_size = self.PLCConfig.GetClientSize() |
520 window_size = self.PLCConfig.GetClientSize() |
520 sizer = self.PLCConfig.GetSizer() |
521 sizer = self.PLCConfig.GetSizer() |
527 |
528 |
528 def RefreshPLCParams(self): |
529 def RefreshPLCParams(self): |
529 self.Freeze() |
530 self.Freeze() |
530 self.ClearSizer(self.PLCParamsSizer) |
531 self.ClearSizer(self.PLCParamsSizer) |
531 |
532 |
532 if self.PluginRoot.HasProjectOpened(): |
533 if self.PluginRoot is not None: |
533 plcwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1)) |
534 plcwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1)) |
534 if self.PluginRoot.PlugTestModified(): |
535 if self.PluginRoot.PlugTestModified(): |
535 bkgdclr = CHANGED_TITLE_COLOUR |
536 bkgdclr = CHANGED_TITLE_COLOUR |
536 else: |
537 else: |
537 bkgdclr = TITLE_COLOUR |
538 bkgdclr = TITLE_COLOUR |
671 return msizer |
672 return msizer |
672 |
673 |
673 def RefreshPluginTree(self): |
674 def RefreshPluginTree(self): |
674 self.Freeze() |
675 self.Freeze() |
675 self.ClearSizer(self.PluginTreeSizer) |
676 self.ClearSizer(self.PluginTreeSizer) |
676 if self.PluginRoot.HasProjectOpened(): |
677 if self.PluginRoot is not None: |
677 for child in self.PluginRoot.IECSortedChilds(): |
678 for child in self.PluginRoot.IECSortedChilds(): |
678 self.GenerateTreeBranch(child) |
679 self.GenerateTreeBranch(child) |
679 if not self.PluginInfos[child]["expanded"]: |
680 if not self.PluginInfos[child]["expanded"]: |
680 self.CollapsePlugin(child) |
681 self.CollapsePlugin(child) |
681 self.PLCConfigMainSizer.Layout() |
682 self.PLCConfigMainSizer.Layout() |
1170 textctrl.ChangeValue(str(element_infos["value"])) |
1171 textctrl.ChangeValue(str(element_infos["value"])) |
1171 textctrl.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(textctrl, plugin, element_path)) |
1172 textctrl.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(textctrl, plugin, element_path)) |
1172 first = False |
1173 first = False |
1173 |
1174 |
1174 def OnNewProjectMenu(self, event): |
1175 def OnNewProjectMenu(self, event): |
1175 defaultpath = self.PluginRoot.GetProjectPath() |
1176 defaultpath = "" |
|
1177 if self.PluginRoot is not None: |
|
1178 defaultpath = self.PluginRoot.GetProjectPath() |
1176 if not defaultpath: |
1179 if not defaultpath: |
1177 defaultpath = os.getcwd() |
1180 defaultpath = os.getcwd() |
1178 dialog = wx.DirDialog(self , "Choose a project", defaultpath, wx.DD_NEW_DIR_BUTTON) |
1181 dialog = wx.DirDialog(self , "Choose a project", defaultpath, wx.DD_NEW_DIR_BUTTON) |
1179 if dialog.ShowModal() == wx.ID_OK: |
1182 if dialog.ShowModal() == wx.ID_OK: |
1180 projectpath = dialog.GetPath() |
1183 projectpath = dialog.GetPath() |
1181 dialog.Destroy() |
1184 dialog.Destroy() |
|
1185 self.PluginRoot = PluginsRoot(self, self.Log, self.runtime_port) |
1182 res = self.PluginRoot.NewProject(projectpath) |
1186 res = self.PluginRoot.NewProject(projectpath) |
1183 if not res : |
1187 if not res : |
1184 self.RefreshPLCParams() |
1188 self.RefreshPLCParams() |
1185 self.RefreshPluginTree() |
1189 self.RefreshPluginTree() |
1186 self.RefreshMainMenu() |
1190 self.RefreshMainMenu() |
1189 message.ShowModal() |
1193 message.ShowModal() |
1190 message.Destroy() |
1194 message.Destroy() |
1191 event.Skip() |
1195 event.Skip() |
1192 |
1196 |
1193 def OnOpenProjectMenu(self, event): |
1197 def OnOpenProjectMenu(self, event): |
1194 defaultpath = self.PluginRoot.GetProjectPath() |
1198 defaultpath = "" |
|
1199 if self.PluginRoot is not None: |
|
1200 defaultpath = self.PluginRoot.GetProjectPath() |
1195 if not defaultpath: |
1201 if not defaultpath: |
1196 defaultpath = os.getcwd() |
1202 defaultpath = os.getcwd() |
1197 dialog = wx.DirDialog(self , "Choose a project", defaultpath, wx.DD_NEW_DIR_BUTTON) |
1203 dialog = wx.DirDialog(self , "Choose a project", defaultpath, wx.DD_NEW_DIR_BUTTON) |
1198 if dialog.ShowModal() == wx.ID_OK: |
1204 if dialog.ShowModal() == wx.ID_OK: |
1199 projectpath = dialog.GetPath() |
1205 projectpath = dialog.GetPath() |
1200 if os.path.isdir(projectpath): |
1206 if os.path.isdir(projectpath): |
|
1207 self.PluginRoot = PluginsRoot(self, self.Log, self.runtime_port) |
1201 result = self.PluginRoot.LoadProject(projectpath) |
1208 result = self.PluginRoot.LoadProject(projectpath) |
1202 if not result: |
1209 if not result: |
1203 self.RefreshPLCParams() |
1210 self.RefreshPLCParams() |
1204 self.RefreshPluginTree() |
1211 self.RefreshPluginTree() |
1205 self.RefreshMainMenu() |
1212 self.RefreshMainMenu() |
1213 message.Destroy() |
1220 message.Destroy() |
1214 dialog.Destroy() |
1221 dialog.Destroy() |
1215 event.Skip() |
1222 event.Skip() |
1216 |
1223 |
1217 def OnCloseProjectMenu(self, event): |
1224 def OnCloseProjectMenu(self, event): |
1218 self.PluginInfos = {} |
1225 if self.PluginRoot is not None: |
1219 self.PluginRoot.CloseProject() |
1226 if self.PluginRoot.ProjectTestModified(): |
1220 self.Log.flush() |
1227 dialog = wx.MessageDialog(self, |
1221 self.RefreshPLCParams() |
1228 "Save changes ?", |
1222 self.RefreshPluginTree() |
1229 "Close Application", |
1223 self.RefreshMainMenu() |
1230 wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) |
|
1231 answer = dialog.ShowModal() |
|
1232 dialog.Destroy() |
|
1233 if answer == wx.ID_YES: |
|
1234 self.PluginRoot.SaveProject() |
|
1235 elif answer == wx.ID_CANCEL: |
|
1236 return |
|
1237 self.PluginInfos = {} |
|
1238 self.PluginRoot = None |
|
1239 self.Log.flush() |
|
1240 self.RefreshPLCParams() |
|
1241 self.RefreshPluginTree() |
|
1242 self.RefreshMainMenu() |
1224 event.Skip() |
1243 event.Skip() |
1225 |
1244 |
1226 def OnSaveProjectMenu(self, event): |
1245 def OnSaveProjectMenu(self, event): |
1227 if self.PluginRoot.HasProjectOpened(): |
1246 if self.PluginRoot is not None: |
1228 self.PluginRoot.SaveProject() |
1247 self.PluginRoot.SaveProject() |
1229 self.RefreshAll() |
1248 self.RefreshAll() |
1230 event.Skip() |
1249 event.Skip() |
1231 |
1250 |
1232 def OnPropertiesMenu(self, event): |
1251 def OnPropertiesMenu(self, event): |