# HG changeset patch # User mjsousa # Date 1402075849 -3600 # Node ID f65ab5ff91d1c852461cb9f4bc92c8cf55e3743c # Parent 86797748c2a2afe45cea61ce0e657a2497a69066# Parent 8a3998d10b8115e9ceab0ac4bc7120be64786023 merge diff -r 86797748c2a2 -r f65ab5ff91d1 Beremiz.py --- a/Beremiz.py Mon May 26 14:44:03 2014 +0100 +++ b/Beremiz.py Fri Jun 06 18:30:49 2014 +0100 @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- #This file is part of Beremiz, a Integrated Development Environment for -#programming IEC 61131-3 automates supporting plcopen standard and CanFestival. +#programming IEC 61131-3 automates supporting plcopen standard and CanFestival. # #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD # @@ -43,7 +43,7 @@ def usage(): print "\nUsage of Beremiz.py :" print "\n %s [Projectpath] [Buildpath]\n"%sys.argv[0] - + try: opts, args = getopt.getopt(sys.argv[1:], "hu:e:", ["help", "updatecheck=", "extend="]) except getopt.GetoptError: @@ -52,7 +52,7 @@ sys.exit(2) extensions=[] - + for o, a in opts: if o in ("-h", "--help"): usage() @@ -61,7 +61,7 @@ updateinfo_url = a if o in ("-e", "--extend"): extensions.append(a) - + if len(args) > 2: usage() sys.exit() @@ -74,7 +74,7 @@ else: projectOpen = None buildpath = None - + if os.path.exists("BEREMIZ_DEBUG"): __builtin__.__dict__["BMZ_DBG"] = True else : @@ -83,7 +83,7 @@ app = wx.PySimpleApp(redirect=BMZ_DBG) app.SetAppName('beremiz') wx.InitAllImageHandlers() - + # popup splash bmp = wx.Image(Bpath("images", "splash.png")).ConvertToBitmap() #splash=AdvancedSplash(None, bitmap=bmp, style=wx.SPLASH_CENTRE_ON_SCREEN, timeout=4000) @@ -99,8 +99,8 @@ import urllib2 updateinfo = urllib2.urlopen(updateinfo_url,None).read() except : - updateinfo = "update info unavailable." - + updateinfo = "update info unavailable." + from threading import Thread splash.SetText(text=updateinfo) wx.Yield() @@ -222,15 +222,15 @@ if style is None : style=self.black_white if style != self.black_white: self.output.StartStyling(self.output.GetLength(), 0xff) - + # Temporary deactivate read only mode on StyledTextCtrl for - # adding text. It seems that text modifications, even + # adding text. It seems that text modifications, even # programmatically, are disabled in StyledTextCtrl when read - # only is active + # only is active self.output.SetReadOnly(False) self.output.AppendText(s) self.output.SetReadOnly(True) - + if style != self.black_white: self.output.SetStyling(len(s), style) self.stack = [] @@ -245,7 +245,7 @@ if newtime - self.rising_timer > 1: self.risecall(self.output) self.rising_timer = newtime - + def write_warning(self, s): self.write(s,self.red_white) @@ -259,11 +259,11 @@ def flush(self): # Temporary deactivate read only mode on StyledTextCtrl for clearing # text. It seems that text modifications, even programmatically, are - # disabled in StyledTextCtrl when read only is active + # disabled in StyledTextCtrl when read only is active self.output.SetReadOnly(False) self.output.SetText("") self.output.SetReadOnly(True) - + def isatty(self): return False @@ -284,13 +284,13 @@ from util.BitmapLibrary import GetBitmap class Beremiz(IDEFrame): - + def _init_utils(self): self.ConfNodeMenu = wx.Menu(title='') self.RecentProjectsMenu = wx.Menu(title='') - + IDEFrame._init_utils(self) - + def _init_coll_FileMenu_Items(self, parent): AppendMenu(parent, help='', id=wx.ID_NEW, kind=wx.ITEM_NORMAL, text=_(u'New') + '\tCTRL+N') @@ -316,7 +316,7 @@ parent.AppendSeparator() AppendMenu(parent, help='', id=wx.ID_EXIT, kind=wx.ITEM_NORMAL, text=_(u'Quit') + '\tCTRL+Q') - + self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, id=wx.ID_NEW) self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu, id=wx.ID_OPEN) self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE) @@ -327,13 +327,13 @@ self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW) self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT) self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT) - + self.AddToMenuToolBar([(wx.ID_NEW, "new", _(u'New'), None), (wx.ID_OPEN, "open", _(u'Open'), None), (wx.ID_SAVE, "save", _(u'Save'), None), (wx.ID_SAVEAS, "saveas", _(u'Save As...'), None), (wx.ID_PRINT, "print", _(u'Print'), None)]) - + def _RecursiveAddMenuItems(self, menu, items): for name, text, help, children in items: new_id = wx.NewId() @@ -342,20 +342,20 @@ menu.AppendMenu(new_id, text, new_menu) self._RecursiveAddMenuItems(new_menu, children) else: - AppendMenu(menu, help=help, id=new_id, + AppendMenu(menu, help=help, id=new_id, kind=wx.ITEM_NORMAL, text=text) - self.Bind(wx.EVT_MENU, self.GetAddConfNodeFunction(name), - id=new_id) - + self.Bind(wx.EVT_MENU, self.GetAddConfNodeFunction(name), + id=new_id) + def _init_coll_AddMenu_Items(self, parent): IDEFrame._init_coll_AddMenu_Items(self, parent, False) self._RecursiveAddMenuItems(parent, GetAddMenuItems()) - + def _init_coll_HelpMenu_Items(self, parent): parent.Append(help='', id=wx.ID_ABOUT, kind=wx.ITEM_NORMAL, text=_(u'About')) self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT) - + def _init_coll_ConnectionStatusBar_Fields(self, parent): parent.SetFieldsCount(3) @@ -364,12 +364,12 @@ parent.SetStatusText(number=2, text='') parent.SetStatusWidths([-1, 300, 200]) - + def _init_ctrls(self, prnt): IDEFrame._init_ctrls(self, prnt) - + self.EditMenuSize = self.EditMenu.GetMenuItemCount() - + inspectorID = wx.NewId() self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, id=inspectorID) accels = [wx.AcceleratorEntry(wx.ACCEL_CTRL|wx.ACCEL_ALT, ord('I'), inspectorID)] @@ -387,9 +387,9 @@ newid = wx.NewId() self.Bind(wx.EVT_MENU, OnMethodGen(self,method), id=newid) accels += [wx.AcceleratorEntry(wx.ACCEL_NORMAL, shortcut,newid)] - + self.SetAcceleratorTable(wx.AcceleratorTable(accels)) - + self.LogConsole = CustomStyledTextCtrl( name='LogConsole', parent=self.BottomNoteBook, pos=wx.Point(0, 0), size=wx.Size(0, 0)) @@ -398,32 +398,32 @@ self.LogConsole.Bind(wx.stc.EVT_STC_UPDATEUI, self.OnLogConsoleUpdateUI) self.LogConsole.SetReadOnly(True) self.LogConsole.SetWrapMode(wx.stc.STC_WRAP_CHAR) - + # Define Log Console styles self.LogConsole.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) self.LogConsole.StyleClearAll() self.LogConsole.StyleSetSpec(1, "face:%(mono)s,fore:#FF0000,size:%(size)d" % faces) self.LogConsole.StyleSetSpec(2, "face:%(mono)s,fore:#FF0000,back:#FFFF00,size:%(size)d" % faces) - + # Define Log Console markers self.LogConsole.SetMarginSensitive(1, True) self.LogConsole.SetMarginType(1, wx.stc.STC_MARGIN_SYMBOL) self.LogConsole.MarkerDefine(0, wx.stc.STC_MARK_CIRCLE, "BLACK", "RED") - + self.LogConsole.SetModEventMask(wx.stc.STC_MOD_INSERTTEXT) - + self.LogConsole.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnLogConsoleMarginClick) self.LogConsole.Bind(wx.stc.EVT_STC_MODIFIED, self.OnLogConsoleModified) - + self.MainTabs["LogConsole"] = (self.LogConsole, _("Console")) self.BottomNoteBook.AddPage(*self.MainTabs["LogConsole"]) #self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogConsole), wx.RIGHT) - + self.LogViewer = LogViewer(self.BottomNoteBook, self) self.MainTabs["LogViewer"] = (self.LogViewer, _("PLC Log")) self.BottomNoteBook.AddPage(*self.MainTabs["LogViewer"]) #self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogViewer), wx.RIGHT) - + StatusToolBar = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER) StatusToolBar.SetToolBitmapSize(wx.Size(25, 25)) @@ -433,27 +433,27 @@ Name("StatusToolBar").Caption(_("Status ToolBar")). ToolbarPane().Top().Position(1). LeftDockable(False).RightDockable(False)) - + self.AUIManager.Update() - + self.ConnectionStatusBar = wx.StatusBar(self, style=wx.ST_SIZEGRIP) self._init_coll_ConnectionStatusBar_Fields(self.ConnectionStatusBar) self.SetStatusBar(self.ConnectionStatusBar) - + def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True): IDEFrame.__init__(self, parent, debug) self.Log = LogPseudoFile(self.LogConsole,self.SelectTab) - + self.local_runtime = None self.runtime_port = None self.local_runtime_tmpdir = None - + self.LastPanelSelected = None - + # Define Tree item icon list self.LocationImageList = wx.ImageList(16, 16) self.LocationImageDict = {} - + # Icons for location items for imgname, itemtype in [ ("CONFIGURATION", LOCATION_CONFNODE), @@ -463,18 +463,18 @@ ("VAR_OUTPUT", LOCATION_VAR_OUTPUT), ("VAR_LOCAL", LOCATION_VAR_MEMORY)]: self.LocationImageDict[itemtype] = self.LocationImageList.Add(GetBitmap(imgname)) - + # Icons for other items for imgname, itemtype in [ ("Extension", ITEM_CONFNODE)]: self.TreeImageDict[itemtype] = self.TreeImageList.Add(GetBitmap(imgname)) - + # Add beremiz's icon in top left corner of the frame self.SetIcon(wx.Icon(Bpath("images", "brz.ico"), wx.BITMAP_TYPE_ICO)) - + if projectOpen is not None: projectOpen = DecodeFileSystemPath(projectOpen, False) - + if projectOpen is not None and os.path.isdir(projectOpen): self.CTR = ProjectController(self, self.Log) self.Controler = self.CTR @@ -498,9 +498,9 @@ self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) if self.EnableDebug: self.DebugVariablePanel.SetDataProducer(self.CTR) - + self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) - + self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) self.RefreshAll() self.LogConsole.SetFocus() @@ -534,14 +534,14 @@ cwd = self.local_runtime_tmpdir) self.local_runtime.spin() return self.runtime_port - + def KillLocalRuntime(self): if self.local_runtime is not None: # shutdown local runtime self.local_runtime.kill(gently=False) # clear temp dir shutil.rmtree(self.local_runtime_tmpdir) - + self.local_runtime = None def OnOpenWidgetInspector(self, evt): @@ -569,7 +569,7 @@ line_idx = self.LogConsole.LineFromPosition(event.GetPosition()) wx.CallAfter(self.SearchLineForError, self.LogConsole.GetLine(line_idx)) event.Skip() - + def OnLogConsoleModified(self, event): line_idx = self.LogConsole.LineFromPosition(event.GetPosition()) line = self.LogConsole.GetLine(line_idx) @@ -585,9 +585,9 @@ if result is not None: first_line, first_column, last_line, last_column, error = result.groups() infos = self.CTR.ShowError(self.Log, - (int(first_line), int(first_column)), + (int(first_line), int(first_column)), (int(last_line), int(last_column))) - + ## Function displaying an Error dialog in PLCOpenEditor. # @return False if closing cancelled. def CheckSaveBeforeClosing(self, title=_("Close Project")): @@ -602,28 +602,28 @@ self.CTR.SaveProject() elif answer == wx.ID_CANCEL: return False - + for idx in xrange(self.TabsOpened.GetPageCount()): window = self.TabsOpened.GetPage(idx) if not window.CheckSaveBeforeClosing(): return False - + return True - + def GetTabInfos(self, tab): - if (isinstance(tab, EditorPanel) and - not isinstance(tab, (Viewer, - TextViewer, - ResourceEditor, - ConfigurationEditor, + if (isinstance(tab, EditorPanel) and + not isinstance(tab, (Viewer, + TextViewer, + ResourceEditor, + ConfigurationEditor, DataTypeEditor))): return ("confnode", tab.Controler.CTNFullName(), tab.GetTagName()) - elif (isinstance(tab, TextViewer) and + elif (isinstance(tab, TextViewer) and (tab.Controler is None or isinstance(tab.Controler, MiniTextControler))): return ("confnode", None, tab.GetInstancePath()) else: return IDEFrame.GetTabInfos(self, tab) - + def LoadTab(self, notebook, page_infos): if page_infos[0] == "confnode": if page_infos[1] is None: @@ -633,26 +633,26 @@ return notebook.GetPageIndex(confnode._OpenView(*page_infos[2:])) else: return IDEFrame.LoadTab(self, notebook, page_infos) - + def OnCloseFrame(self, event): - for evt_type in [wx.EVT_SET_FOCUS, - wx.EVT_KILL_FOCUS, + for evt_type in [wx.EVT_SET_FOCUS, + wx.EVT_KILL_FOCUS, wx.stc.EVT_STC_UPDATEUI]: self.LogConsole.Unbind(evt_type) if self.CTR is None or self.CheckSaveBeforeClosing(_("Close Application")): if self.CTR is not None: self.CTR.KillDebugThread() self.KillLocalRuntime() - + self.SaveLastState() - + event.Skip() else: event.Veto() - + def RefreshFileMenu(self): self.RefreshRecentProjectsMenu() - + MenuToolBar = self.Panes["MenuToolBar"] if self.CTR is not None: selected = self.TabsOpened.GetSelection() @@ -695,17 +695,17 @@ self.FileMenu.Enable(wx.ID_SAVEAS, False) MenuToolBar.EnableTool(wx.ID_SAVEAS, False) self.FileMenu.Enable(wx.ID_CLOSE_ALL, False) - + def RefreshRecentProjectsMenu(self): try: - recent_projects = map(DecodeFileSystemPath, + recent_projects = map(DecodeFileSystemPath, self.GetConfigEntry("RecentProjects", [])) except: recent_projects = [] self.FileMenu.Enable(ID_FILEMENURECENTPROJECTS, len(recent_projects) > 0) for idx, projectpath in enumerate(recent_projects): text = u'%d: %s' % (idx + 1, projectpath) - + if idx < self.RecentProjectsMenu.GetMenuItemCount(): item = self.RecentProjectsMenu.FindItemByPosition(idx) id = item.GetId() @@ -713,18 +713,18 @@ self.Disconnect(id, id, wx.EVT_BUTTON._getEvtType()) else: id = wx.NewId() - AppendMenu(self.RecentProjectsMenu, help='', id=id, + AppendMenu(self.RecentProjectsMenu, help='', id=id, kind=wx.ITEM_NORMAL, text=text) self.Bind(wx.EVT_MENU, self.GenerateOpenRecentProjectFunction(projectpath), id=id) - + def GenerateOpenRecentProjectFunction(self, projectpath): def OpenRecentProject(event): if self.CTR is not None and not self.CheckSaveBeforeClosing(): return - + self.OpenProject(projectpath) return OpenRecentProject - + def GenerateMenuRecursive(self, items, menu): for kind, infos in items: if isinstance(kind, ListType): @@ -739,27 +739,27 @@ AppendMenu(menu, help='', id=id, kind=kind, text=text) if callback is not None: self.Bind(wx.EVT_MENU, callback, id=id) - + def RefreshEditorToolBar(self): IDEFrame.RefreshEditorToolBar(self) self.AUIManager.GetPane("EditorToolBar").Position(2) self.AUIManager.GetPane("StatusToolBar").Position(1) self.AUIManager.Update() - + def RefreshStatusToolBar(self): StatusToolBar = self.Panes["StatusToolBar"] StatusToolBar.ClearTools() - + if self.CTR is not None: - + for confnode_method in self.CTR.StatusMethods: if "method" in confnode_method and confnode_method.get("shown",True): id = wx.NewId() - StatusToolBar.AddSimpleTool(id, - GetBitmap(confnode_method.get("bitmap", "Unknown")), + StatusToolBar.AddSimpleTool(id, + GetBitmap(confnode_method.get("bitmap", "Unknown")), confnode_method["tooltip"]) self.Bind(wx.EVT_MENU, self.GetMenuCallBackFunction(confnode_method["method"]), id=id) - + StatusToolBar.Realize() self.AUIManager.GetPane("StatusToolBar").BestSize(StatusToolBar.GetBestSize()).Show() else: @@ -767,13 +767,13 @@ self.AUIManager.GetPane("EditorToolBar").Position(2) self.AUIManager.GetPane("StatusToolBar").Position(1) self.AUIManager.Update() - + def RefreshEditMenu(self): IDEFrame.RefreshEditMenu(self) if self.FindFocus() == self.LogConsole: self.EditMenu.Enable(wx.ID_COPY, True) self.Panes["MenuToolBar"].EnableTool(wx.ID_COPY, True) - + if self.CTR is not None: selected = self.TabsOpened.GetSelection() if selected >= 0: @@ -808,28 +808,28 @@ self.EditMenu.Delete(item.GetId()) self.LastPanelSelected = None self.MenuBar.UpdateMenus() - + def RefreshAll(self): self.RefreshStatusToolBar() - + def GetMenuCallBackFunction(self, method): """ Generate the callbackfunc for a given CTR method""" def OnMenu(event): - # Disable button to prevent re-entrant call + # Disable button to prevent re-entrant call event.GetEventObject().Disable() # Call getattr(self.CTR, method)() - # Re-enable button + # Re-enable button event.GetEventObject().Enable() return OnMenu - + def GetConfigEntry(self, entry_name, default): return cPickle.loads(str(self.Config.Read(entry_name, cPickle.dumps(default)))) - + def ResetConnectionStatusBar(self): for field in xrange(self.ConnectionStatusBar.GetFieldsCount()): self.ConnectionStatusBar.SetStatusText('', field) - + def ResetView(self): IDEFrame.ResetView(self) self.ConfNodeInfos = {} @@ -840,10 +840,10 @@ if self.EnableDebug: self.DebugVariablePanel.SetDataProducer(None) self.ResetConnectionStatusBar() - + def RefreshConfigRecentProjects(self, projectpath): try: - recent_projects = map(DecodeFileSystemPath, + recent_projects = map(DecodeFileSystemPath, self.GetConfigEntry("RecentProjects", [])) except: recent_projects = [] @@ -853,24 +853,24 @@ self.Config.Write("RecentProjects", cPickle.dumps( map(EncodeFileSystemPath, recent_projects[:MAX_RECENT_PROJECTS]))) self.Config.Flush() - + def ResetPerspective(self): IDEFrame.ResetPerspective(self) self.RefreshStatusToolBar() - + def OnNewProjectMenu(self, event): if self.CTR is not None and not self.CheckSaveBeforeClosing(): return - + try: defaultpath = DecodeFileSystemPath(self.Config.Read("lastopenedfolder")) except: defaultpath = os.path.expanduser("~") - + dialog = wx.DirDialog(self , _("Choose a project"), defaultpath) if dialog.ShowModal() == wx.ID_OK: projectpath = dialog.GetPath() - self.Config.Write("lastopenedfolder", + self.Config.Write("lastopenedfolder", EncodeFileSystemPath(os.path.dirname(projectpath))) self.Config.Flush() self.ResetView() @@ -892,25 +892,25 @@ self.RefreshAll() self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) dialog.Destroy() - + def OnOpenProjectMenu(self, event): if self.CTR is not None and not self.CheckSaveBeforeClosing(): return - + try: defaultpath = DecodeFileSystemPath(self.Config.Read("lastopenedfolder")) except: defaultpath = os.path.expanduser("~") - + dialog = wx.DirDialog(self , _("Choose a project"), defaultpath, style=wx.DEFAULT_DIALOG_STYLE| wx.RESIZE_BORDER) if dialog.ShowModal() == wx.ID_OK: self.OpenProject(dialog.GetPath()) dialog.Destroy() - + def OpenProject(self, projectpath): if os.path.isdir(projectpath): - self.Config.Write("lastopenedfolder", + self.Config.Write("lastopenedfolder", EncodeFileSystemPath(os.path.dirname(projectpath))) self.Config.Flush() self.ResetView() @@ -932,15 +932,15 @@ else: self.ShowErrorMessage(_("\"%s\" folder is not a valid Beremiz project\n") % projectpath) self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) - + def OnCloseProjectMenu(self, event): if self.CTR is not None and not self.CheckSaveBeforeClosing(): return - + self.ResetView() self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) self.RefreshAll() - + def OnSaveProjectMenu(self, event): selected = self.TabsOpened.GetSelection() if selected != -1: @@ -950,7 +950,7 @@ self.CTR.SaveProject() self.RefreshAll() self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES) - + def OnSaveProjectAsMenu(self, event): selected = self.TabsOpened.GetSelection() if selected != -1: @@ -960,27 +960,27 @@ self.CTR.SaveProjectAs() self.RefreshAll() self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES) - + def OnQuitMenu(self, event): self.Close() - + def OnAboutMenu(self, event): OpenHtmlFrame(self,_("About Beremiz"), Bpath("doc", "about.html"), wx.Size(550, 500)) - + def OnProjectTreeItemBeginEdit(self, event): selected = event.GetItem() if self.ProjectTree.GetPyData(selected)["type"] == ITEM_CONFNODE: event.Veto() else: IDEFrame.OnProjectTreeItemBeginEdit(self, event) - + def OnProjectTreeRightUp(self, event): item = event.GetItem() item_infos = self.ProjectTree.GetPyData(item) - + if item_infos["type"] == ITEM_CONFNODE: confnode_menu = wx.Menu(title='') - + confnode = item_infos["confnode"] if confnode is not None: menu_items = confnode.GetContextualMenuItems() @@ -998,10 +998,10 @@ new_id = wx.NewId() AppendMenu(confnode_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Delete")) self.Bind(wx.EVT_MENU, self.GetDeleteMenuFunction(confnode), id=new_id) - + self.PopupMenu(confnode_menu) confnode_menu.Destroy() - + event.Skip() elif item_infos["type"] == ITEM_RESOURCE: # prevent last resource to be delted @@ -1011,7 +1011,7 @@ IDEFrame.OnProjectTreeRightUp(self, event) else: IDEFrame.OnProjectTreeRightUp(self, event) - + def OnProjectTreeItemActivated(self, event): selected = event.GetItem() name = self.ProjectTree.GetItemText(selected) @@ -1023,7 +1023,7 @@ self.CTR._OpenView() else: IDEFrame.OnProjectTreeItemActivated(self, event) - + def ProjectTreeItemSelect(self, select_item): if select_item is not None and select_item.IsOk(): name = self.ProjectTree.GetItemText(select_item) @@ -1034,7 +1034,7 @@ self.CTR._OpenView(onlyopened=True) else: IDEFrame.ProjectTreeItemSelect(self, select_item) - + def SelectProjectTreeItem(self, tagname): if self.ProjectTree is not None: root = self.ProjectTree.GetRootItem() @@ -1046,31 +1046,23 @@ self.ProjectTree.SelectItem(root) self.ResetSelectedItem() else: - return self.RecursiveProjectTreeItemSelection(root, + return self.RecursiveProjectTreeItemSelection(root, [(word, ITEM_CONFNODE) for word in tagname.split(".")]) elif words[0] == "R": return self.RecursiveProjectTreeItemSelection(root, [(words[2], ITEM_RESOURCE)]) elif not os.path.exists(words[0]): IDEFrame.SelectProjectTreeItem(self, tagname) - + def GetAddConfNodeFunction(self, name, confnode=None): def AddConfNodeMenuFunction(event): wx.CallAfter(self.AddConfNode, name, confnode) return AddConfNodeMenuFunction - + def GetDeleteMenuFunction(self, confnode): def DeleteMenuFunction(event): wx.CallAfter(self.DeleteConfNode, confnode) return DeleteMenuFunction - - def AddResourceMenu(self, event): - config_names = self.CTR.GetProjectConfigNames() - if len(config_names) > 0: - tagname = self.Controler.ProjectAddConfigurationResource(config_names[0]) - if tagname is not None: - self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL) - self.EditProjectElement(ITEM_RESOURCE, tagname) - + def AddConfNode(self, ConfNodeType, confnode=None): if self.CTR.CheckProjectPathPerm(): ConfNodeName = "%s_0" % ConfNodeType @@ -1079,12 +1071,12 @@ else: self.CTR.CTNAddChild(ConfNodeName, ConfNodeType) self._Refresh(TITLE, FILEMENU, PROJECTTREE) - + def DeleteConfNode(self, confnode): if self.CTR.CheckProjectPathPerm(): - dialog = wx.MessageDialog(self, - _("Really delete node '%s'?") % confnode.CTNName(), - _("Remove %s node") % confnode.CTNType, + dialog = wx.MessageDialog(self, + _("Really delete node '%s'?") % confnode.CTNName(), + _("Remove %s node") % confnode.CTNType, wx.YES_NO|wx.NO_DEFAULT) if dialog.ShowModal() == wx.ID_YES: confnode.CTNRemove() @@ -1124,13 +1116,13 @@ trcbck += "file : " + str(line[0][len(os.getcwd()):]) + ", " trcbck += "line : " + str(line[1]) + ", " + "function : " + str(line[2]) trcbck_lst.append(trcbck) - + # Allow clicking.... cap = wx.Window_GetCapture() if cap: cap.ReleaseMouse() - dlg = wx.SingleChoiceDialog(None, + dlg = wx.SingleChoiceDialog(None, _(""" An unhandled exception (bug) occured. Bug report saved at : (%s) @@ -1142,7 +1134,7 @@ Traceback: """) % bug_report_path + - repr(e_type) + " : " + repr(e_value), + repr(e_type) + " : " + repr(e_value), _("Error"), trcbck_lst) try: @@ -1165,7 +1157,7 @@ ignored_exceptions = [] # a problem with a line in a module is only reported once per session def AddExceptHook(path, app_version='[No version]'):#, ignored_exceptions=[]): - + def handle_exception(e_type, e_value, e_traceback): traceback.print_exception(e_type, e_value, e_traceback) # this is very helpful when there's an exception in the rest of this func last_tb = get_last_traceback(e_traceback) @@ -1198,7 +1190,7 @@ info['self'] = format_namespace(exception_locals['self'].__dict__) except : pass - + output = open(bug_report_path,'w') lst = info.keys() lst.sort() @@ -1225,7 +1217,7 @@ if __name__ == '__main__': # Install a exception handle for bug reports AddExceptHook(os.getcwd(),updateinfo_url) - + frame = Beremiz(None, projectOpen, buildpath) if splash: splash.Close() diff -r 86797748c2a2 -r f65ab5ff91d1 IDEFrame.py --- a/IDEFrame.py Mon May 26 14:44:03 2014 +0100 +++ b/IDEFrame.py Fri Jun 06 18:30:49 2014 +0100 @@ -20,27 +20,27 @@ from util.BitmapLibrary import GetBitmap # Define PLCOpenEditor controls id -[ID_PLCOPENEDITOR, ID_PLCOPENEDITORLEFTNOTEBOOK, - ID_PLCOPENEDITORBOTTOMNOTEBOOK, ID_PLCOPENEDITORRIGHTNOTEBOOK, - ID_PLCOPENEDITORPROJECTTREE, ID_PLCOPENEDITORMAINSPLITTER, - ID_PLCOPENEDITORSECONDSPLITTER, ID_PLCOPENEDITORTHIRDSPLITTER, - ID_PLCOPENEDITORLIBRARYPANEL, ID_PLCOPENEDITORLIBRARYSEARCHCTRL, - ID_PLCOPENEDITORLIBRARYTREE, ID_PLCOPENEDITORLIBRARYCOMMENT, - ID_PLCOPENEDITORTABSOPENED, ID_PLCOPENEDITORTABSOPENED, - ID_PLCOPENEDITOREDITORMENUTOOLBAR, ID_PLCOPENEDITOREDITORTOOLBAR, - ID_PLCOPENEDITORPROJECTPANEL, +[ID_PLCOPENEDITOR, ID_PLCOPENEDITORLEFTNOTEBOOK, + ID_PLCOPENEDITORBOTTOMNOTEBOOK, ID_PLCOPENEDITORRIGHTNOTEBOOK, + ID_PLCOPENEDITORPROJECTTREE, ID_PLCOPENEDITORMAINSPLITTER, + ID_PLCOPENEDITORSECONDSPLITTER, ID_PLCOPENEDITORTHIRDSPLITTER, + ID_PLCOPENEDITORLIBRARYPANEL, ID_PLCOPENEDITORLIBRARYSEARCHCTRL, + ID_PLCOPENEDITORLIBRARYTREE, ID_PLCOPENEDITORLIBRARYCOMMENT, + ID_PLCOPENEDITORTABSOPENED, ID_PLCOPENEDITORTABSOPENED, + ID_PLCOPENEDITOREDITORMENUTOOLBAR, ID_PLCOPENEDITOREDITORTOOLBAR, + ID_PLCOPENEDITORPROJECTPANEL, ] = [wx.NewId() for _init_ctrls in range(17)] # Define PLCOpenEditor EditMenu extra items id -[ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, ID_PLCOPENEDITOREDITMENUADDDATATYPE, - ID_PLCOPENEDITOREDITMENUADDFUNCTION, ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK, +[ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, ID_PLCOPENEDITOREDITMENUADDDATATYPE, + ID_PLCOPENEDITOREDITMENUADDFUNCTION, ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK, ID_PLCOPENEDITOREDITMENUADDPROGRAM, ID_PLCOPENEDITOREDITMENUADDCONFIGURATION, ID_PLCOPENEDITOREDITMENUFINDNEXT, ID_PLCOPENEDITOREDITMENUFINDPREVIOUS, ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, ID_PLCOPENEDITOREDITMENUADDRESOURCE ] = [wx.NewId() for _init_coll_EditMenu_Items in range(10)] # Define PLCOpenEditor DisplayMenu extra items id -[ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE, +[ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE, ] = [wx.NewId() for _init_coll_DisplayMenu_Items in range(1)] #------------------------------------------------------------------------------- @@ -56,12 +56,12 @@ ID_PLCOPENEDITOREDITORTOOLBARBRANCH, ID_PLCOPENEDITOREDITORTOOLBARINITIALSTEP, ID_PLCOPENEDITOREDITORTOOLBARSTEP, ID_PLCOPENEDITOREDITORTOOLBARTRANSITION, ID_PLCOPENEDITOREDITORTOOLBARACTIONBLOCK, ID_PLCOPENEDITOREDITORTOOLBARDIVERGENCE, - ID_PLCOPENEDITOREDITORTOOLBARJUMP, ID_PLCOPENEDITOREDITORTOOLBARMOTION, + ID_PLCOPENEDITOREDITORTOOLBARJUMP, ID_PLCOPENEDITOREDITORTOOLBARMOTION, ] = [wx.NewId() for _init_coll_DefaultEditorToolBar_Items in range(18)] -# Define behaviour of each Toolbar item according to current POU body type +# Define behaviour of each Toolbar item according to current POU body type # Informations meaning are in this order: # - Item is toggled # - PLCOpenEditor mode where item is displayed (could be more then one) @@ -82,77 +82,77 @@ (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool", "add_block", _("Create a new block")), - (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, "OnConnectionTool", + (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, "OnConnectionTool", "add_connection", _("Create a new connection"))], "LD" : [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITOREDITORTOOLBARMOTION, "OnMotionTool", "move", _("Move the view")), - (True, FREEDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARCOMMENT, "OnCommentTool", + (True, FREEDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARCOMMENT, "OnCommentTool", "add_comment", _("Create a new comment")), - (True, FREEDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL, "OnPowerRailTool", + (True, FREEDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL, "OnPowerRailTool", "add_powerrail", _("Create a new power rail")), - (False, DRIVENDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARRUNG, "OnRungTool", + (False, DRIVENDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARRUNG, "OnRungTool", "add_rung", _("Create a new rung")), - (True, FREEDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARCOIL, "OnCoilTool", + (True, FREEDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARCOIL, "OnCoilTool", "add_coil", _("Create a new coil")), - (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARCONTACT, "OnContactTool", + (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARCONTACT, "OnContactTool", "add_contact", _("Create a new contact")), - (False, DRIVENDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARBRANCH, "OnBranchTool", + (False, DRIVENDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARBRANCH, "OnBranchTool", "add_branch", _("Create a new branch")), - (True, FREEDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, "OnVariableTool", + (True, FREEDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, "OnVariableTool", "add_variable", _("Create a new variable")), - (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool", + (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool", "add_block", _("Create a new block")), - (True, FREEDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, "OnConnectionTool", + (True, FREEDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, "OnConnectionTool", "add_connection", _("Create a new connection"))], "SFC" : [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITOREDITORTOOLBARMOTION, "OnMotionTool", "move", _("Move the view")), - (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARCOMMENT, "OnCommentTool", + (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARCOMMENT, "OnCommentTool", "add_comment", _("Create a new comment")), - (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARINITIALSTEP, "OnInitialStepTool", + (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARINITIALSTEP, "OnInitialStepTool", "add_initial_step", _("Create a new initial step")), - (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARSTEP, "OnStepTool", + (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARSTEP, "OnStepTool", "add_step", _("Create a new step")), - (True, FREEDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARTRANSITION, "OnTransitionTool", + (True, FREEDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARTRANSITION, "OnTransitionTool", "add_transition", _("Create a new transition")), - (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARACTIONBLOCK, "OnActionBlockTool", + (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARACTIONBLOCK, "OnActionBlockTool", "add_action", _("Create a new action block")), - (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARDIVERGENCE, "OnDivergenceTool", + (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARDIVERGENCE, "OnDivergenceTool", "add_divergence", _("Create a new divergence")), - (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARJUMP, "OnJumpTool", + (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARJUMP, "OnJumpTool", "add_jump", _("Create a new jump")), - (True, FREEDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, "OnVariableTool", + (True, FREEDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, "OnVariableTool", "add_variable", _("Create a new variable")), - (True, FREEDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool", + (True, FREEDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool", "add_block", _("Create a new block")), - (True, FREEDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, "OnConnectionTool", + (True, FREEDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, "OnConnectionTool", "add_connection", _("Create a new connection")), - (True, FREEDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL, "OnPowerRailTool", + (True, FREEDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL, "OnPowerRailTool", "add_powerrail", _("Create a new power rail")), - (True, FREEDRAWING_MODE, - ID_PLCOPENEDITOREDITORTOOLBARCONTACT, "OnContactTool", + (True, FREEDRAWING_MODE, + ID_PLCOPENEDITOREDITORTOOLBARCONTACT, "OnContactTool", "add_contact", _("Create a new contact"))], "ST" : [], "IL" : [], @@ -185,7 +185,7 @@ else: parent.Append(helpString=help, id=id, kind=kind, item=text) -[TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, +[TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES ] = range(10) @@ -225,33 +225,33 @@ others = [t for t in tabs if t != tab] others.sort(lambda x,y: cmp(x["pos"][0], y["pos"][0])) for other in others: - if (other["pos"][1] == tab["pos"][1] and + if (other["pos"][1] == tab["pos"][1] and other["size"][1] == tab["size"][1] and other["pos"][0] == tab["pos"][0] + tab["size"][0] + TAB_BORDER): - + tab["size"] = (tab["size"][0] + other["size"][0] + TAB_BORDER, tab["size"][1]) tab["pages"].extend(other["pages"]) tabs.remove(other) - + if tab["size"][0] == rect.width: return True - + elif tab["pos"][1] == rect.y: others = [t for t in tabs if t != tab] others.sort(lambda x,y: cmp(x["pos"][1], y["pos"][1])) for other in others: - if (other["pos"][0] == tab["pos"][0] and + if (other["pos"][0] == tab["pos"][0] and other["size"][0] == tab["size"][0] and other["pos"][1] == tab["pos"][1] + tab["size"][1] + TAB_BORDER): - + tab["size"] = (tab["size"][0], tab["size"][1] + other["size"][1] + TAB_BORDER) tab["pages"].extend(other["pages"]) tabs.remove(other) - + if tab["size"][1] == rect.height: return True return False - + def ComputeTabsLayout(tabs, rect): if len(tabs) == 0: return tabs @@ -264,27 +264,27 @@ if tab["size"][0] == rect.width: if tab["pos"][1] == rect.y: split = (wx.TOP, float(tab["size"][1]) / float(rect.height)) - split_rect = wx.Rect(rect.x, rect.y + tab["size"][1] + TAB_BORDER, + split_rect = wx.Rect(rect.x, rect.y + tab["size"][1] + TAB_BORDER, rect.width, rect.height - tab["size"][1] - TAB_BORDER) elif tab["pos"][1] == rect.height + 1 - tab["size"][1]: split = (wx.BOTTOM, 1.0 - float(tab["size"][1]) / float(rect.height)) - split_rect = wx.Rect(rect.x, rect.y, + split_rect = wx.Rect(rect.x, rect.y, rect.width, rect.height - tab["size"][1] - TAB_BORDER) break elif tab["size"][1] == rect.height: if tab["pos"][0] == rect.x: split = (wx.LEFT, float(tab["size"][0]) / float(rect.width)) - split_rect = wx.Rect(rect.x + tab["size"][0] + TAB_BORDER, rect.y, + split_rect = wx.Rect(rect.x + tab["size"][0] + TAB_BORDER, rect.y, rect.width - tab["size"][0] - TAB_BORDER, rect.height) elif tab["pos"][0] == rect.width + 1 - tab["size"][0]: split = (wx.RIGHT, 1.0 - float(tab["size"][0]) / float(rect.width)) - split_rect = wx.Rect(rect.x, rect.y, + split_rect = wx.Rect(rect.x, rect.y, rect.width - tab["size"][0] - TAB_BORDER, rect.height) break if split != None: split_tab = tabs.pop(idx) return {"split": split, - "tab": split_tab, + "tab": split_tab, "others": ComputeTabsLayout(tabs, split_rect)} else: if SimplifyTabLayout(tabs, rect): @@ -298,7 +298,7 @@ UNEDITABLE_NAMES_DICT = dict([(_(name), name) for name in UNEDITABLE_NAMES]) class IDEFrame(wx.Frame): - + # Compatibility function for wx versions < 2.6 if wx.VERSION < (2, 6, 0): def Bind(self, event, function, id = None): @@ -306,7 +306,7 @@ event(self, id, function) else: event(self, function) - + def _init_coll_MenuBar_Menus(self, parent): parent.Append(menu=self.FileMenu, title=_(u'&File')) parent.Append(menu=self.EditMenu, title=_(u'&Edit')) @@ -315,7 +315,7 @@ def _init_coll_FileMenu_Items(self, parent): pass - + def _init_coll_AddMenu_Items(self, parent, add_config=True): AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDDATATYPE, kind=wx.ITEM_NORMAL, text=_(u'&Data Type')) @@ -330,7 +330,7 @@ if add_config: AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDCONFIGURATION, kind=wx.ITEM_NORMAL, text=_(u'&Configuration')) - + def _init_coll_EditMenu_Items(self, parent): AppendMenu(parent, help='', id=wx.ID_UNDO, kind=wx.ITEM_NORMAL, text=_(u'Undo') + '\tCTRL+Z') @@ -371,13 +371,13 @@ self.Bind(wx.EVT_MENU, self.OnCopyMenu, id=wx.ID_COPY) self.Bind(wx.EVT_MENU, self.OnPasteMenu, id=wx.ID_PASTE) self.Bind(wx.EVT_MENU, self.OnFindMenu, id=wx.ID_FIND) - self.Bind(wx.EVT_MENU, self.OnFindNextMenu, + self.Bind(wx.EVT_MENU, self.OnFindNextMenu, id=ID_PLCOPENEDITOREDITMENUFINDNEXT) - self.Bind(wx.EVT_MENU, self.OnFindPreviousMenu, + self.Bind(wx.EVT_MENU, self.OnFindPreviousMenu, id=ID_PLCOPENEDITOREDITMENUFINDPREVIOUS) - self.Bind(wx.EVT_MENU, self.OnSearchInProjectMenu, + self.Bind(wx.EVT_MENU, self.OnSearchInProjectMenu, id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT) - self.Bind(wx.EVT_MENU, self.OnSearchInProjectMenu, + self.Bind(wx.EVT_MENU, self.OnSearchInProjectMenu, id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT) self.Bind(wx.EVT_MENU, self.OnAddDataTypeMenu, id=ID_PLCOPENEDITOREDITMENUADDDATATYPE) @@ -387,13 +387,13 @@ id=ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK) self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction("program"), id=ID_PLCOPENEDITOREDITMENUADDPROGRAM) - self.Bind(wx.EVT_MENU, self.AddResourceMenu, + self.Bind(wx.EVT_MENU, self.AddResourceMenu, id=ID_PLCOPENEDITOREDITMENUADDRESOURCE) self.Bind(wx.EVT_MENU, self.OnAddConfigurationMenu, id=ID_PLCOPENEDITOREDITMENUADDCONFIGURATION) self.Bind(wx.EVT_MENU, self.OnSelectAllMenu, id=wx.ID_SELECTALL) self.Bind(wx.EVT_MENU, self.OnDeleteMenu, id=wx.ID_DELETE) - + self.AddToMenuToolBar([(wx.ID_UNDO, "undo", _(u'Undo'), None), (wx.ID_REDO, "redo", _(u'Redo'), None), None, @@ -417,16 +417,16 @@ AppendMenu(zoommenu, help='', id=new_id, kind=wx.ITEM_RADIO, text=str(int(round(value * 100))) + "%") self.Bind(wx.EVT_MENU, self.GenerateZoomFunction(idx), id=new_id) - + parent.AppendSeparator() AppendMenu(parent, help='', id=ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE, kind=wx.ITEM_NORMAL, text=_(u'Reset Perspective')) self.Bind(wx.EVT_MENU, self.OnResetPerspective, id=ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE) - + self.Bind(wx.EVT_MENU, self.OnRefreshMenu, id=wx.ID_REFRESH) if self.EnableDebug: self.Bind(wx.EVT_MENU, self.OnClearErrorsMenu, id=wx.ID_CLEAR) - + def _init_coll_HelpMenu_Items(self, parent): pass @@ -437,7 +437,7 @@ self.EditMenu = wx.Menu(title='') self.DisplayMenu = wx.Menu(title='') self.HelpMenu = wx.Menu(title='') - + self._init_coll_MenuBar_Menus(self.MenuBar) self._init_coll_FileMenu_Items(self.FileMenu) self._init_coll_EditMenu_Items(self.EditMenu) @@ -450,49 +450,49 @@ style=wx.DEFAULT_FRAME_STYLE) self.SetClientSize(wx.Size(1000, 600)) self.Bind(wx.EVT_ACTIVATE, self.OnActivated) - + self.TabsImageList = wx.ImageList(31, 16) self.TabsImageListIndexes = {} - + #----------------------------------------------------------------------- # Creating main structure #----------------------------------------------------------------------- - + self.AUIManager = wx.aui.AuiManager(self) self.AUIManager.SetDockSizeConstraint(0.5, 0.5) self.Panes = {} - + self.LeftNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORLEFTNOTEBOOK, style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE| wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE) - self.LeftNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND, + self.LeftNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND, self.OnAllowNotebookDnD) - self.AUIManager.AddPane(self.LeftNoteBook, + self.AUIManager.AddPane(self.LeftNoteBook, wx.aui.AuiPaneInfo().Name("ProjectPane"). Left().Layer(1). BestSize(wx.Size(300, 500)).CloseButton(False)) - + self.BottomNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORBOTTOMNOTEBOOK, style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE| wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE) - self.BottomNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND, + self.BottomNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND, self.OnAllowNotebookDnD) - self.AUIManager.AddPane(self.BottomNoteBook, + self.AUIManager.AddPane(self.BottomNoteBook, wx.aui.AuiPaneInfo().Name("ResultPane"). Bottom().Layer(0). BestSize(wx.Size(800, 300)).CloseButton(False)) - + self.RightNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORRIGHTNOTEBOOK, style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE| wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE) - self.RightNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND, + self.RightNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND, self.OnAllowNotebookDnD) - self.AUIManager.AddPane(self.RightNoteBook, + self.AUIManager.AddPane(self.RightNoteBook, wx.aui.AuiPaneInfo().Name("LibraryPane"). Right().Layer(0). BestSize(wx.Size(250, 400)).CloseButton(False)) - - self.TabsOpened = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORTABSOPENED, + + self.TabsOpened = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORTABSOPENED, style=wx.aui.AUI_NB_DEFAULT_STYLE|wx.aui.AUI_NB_WINDOWLIST_BUTTON) self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGING, self.OnPouSelectedChanging) @@ -502,21 +502,21 @@ self.OnPageClose) self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_END_DRAG, self.OnPageDragged) - self.AUIManager.AddPane(self.TabsOpened, + self.AUIManager.AddPane(self.TabsOpened, wx.aui.AuiPaneInfo().CentrePane().Name("TabsPane")) - + #----------------------------------------------------------------------- # Creating PLCopen Project Types Tree #----------------------------------------------------------------------- - + self.MainTabs = {} - + self.ProjectPanel = wx.SplitterWindow(id=ID_PLCOPENEDITORPROJECTPANEL, name='ProjectPanel', parent=self.LeftNoteBook, point=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.SP_3D) - + self.ProjectTree = CustomTree(id=ID_PLCOPENEDITORPROJECTTREE, - name='ProjectTree', parent=self.ProjectPanel, + name='ProjectTree', parent=self.ProjectPanel, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.SUNKEN_BORDER, agwStyle=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.TR_EDIT_LABELS) @@ -539,22 +539,22 @@ self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnProjectTreeItemActivated, id=ID_PLCOPENEDITORPROJECTTREE) self.ProjectTree.Bind(wx.EVT_MOTION, self.OnProjectTreeMotion) - + #----------------------------------------------------------------------- # Creating PLCopen Project POU Instance Variables Panel #----------------------------------------------------------------------- - + self.PouInstanceVariablesPanel = PouInstanceVariablesPanel(self.ProjectPanel, self, self.Controler, self.EnableDebug) - + self.MainTabs["ProjectPanel"] = (self.ProjectPanel, _("Project")) self.LeftNoteBook.AddPage(*self.MainTabs["ProjectPanel"]) - + self.ProjectPanel.SplitHorizontally(self.ProjectTree, self.PouInstanceVariablesPanel, 300) - + #----------------------------------------------------------------------- # Creating Tool Bar #----------------------------------------------------------------------- - + MenuToolBar = wx.ToolBar(self, ID_PLCOPENEDITOREDITORMENUTOOLBAR, wx.DefaultPosition, wx.DefaultSize, wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER) MenuToolBar.SetToolBitmapSize(wx.Size(25, 25)) @@ -564,11 +564,11 @@ Name("MenuToolBar").Caption(_("Menu ToolBar")). ToolbarPane().Top(). LeftDockable(False).RightDockable(False)) - + EditorToolBar = wx.ToolBar(self, ID_PLCOPENEDITOREDITORTOOLBAR, wx.DefaultPosition, wx.DefaultSize, wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER) EditorToolBar.SetToolBitmapSize(wx.Size(25, 25)) - EditorToolBar.AddRadioTool(ID_PLCOPENEDITOREDITORTOOLBARSELECTION, + EditorToolBar.AddRadioTool(ID_PLCOPENEDITOREDITORTOOLBARSELECTION, GetBitmap("select"), wx.NullBitmap, _("Select an object")) EditorToolBar.Realize() self.Panes["EditorToolBar"] = EditorToolBar @@ -576,39 +576,39 @@ Name("EditorToolBar").Caption(_("Editor ToolBar")). ToolbarPane().Top().Position(1). LeftDockable(False).RightDockable(False)) - - self.Bind(wx.EVT_MENU, self.OnSelectionTool, + + self.Bind(wx.EVT_MENU, self.OnSelectionTool, id=ID_PLCOPENEDITOREDITORTOOLBARSELECTION) - + #----------------------------------------------------------------------- # Creating Search Panel #----------------------------------------------------------------------- - + self.SearchResultPanel = SearchResultPanel(self.BottomNoteBook, self) self.MainTabs["SearchResultPanel"] = (self.SearchResultPanel, _("Search")) self.BottomNoteBook.AddPage(*self.MainTabs["SearchResultPanel"]) - + #----------------------------------------------------------------------- # Creating Library Panel #----------------------------------------------------------------------- - + self.LibraryPanel = LibraryPanel(self, True) self.MainTabs["LibraryPanel"] = (self.LibraryPanel, _("Library")) self.RightNoteBook.AddPage(*self.MainTabs["LibraryPanel"]) - + self._init_utils() self.SetMenuBar(self.MenuBar) - + if self.EnableDebug: self.DebugVariablePanel = DebugVariablePanel(self.RightNoteBook, self.Controler, self) self.MainTabs["DebugVariablePanel"] = (self.DebugVariablePanel, _("Debugger")) self.RightNoteBook.AddPage(*self.MainTabs["DebugVariablePanel"]) - + self.AUIManager.Update() - + self.FindDialog = FindInPouDialog(self) self.FindDialog.Hide() - + ## Constructor of the PLCOpenEditor class. # @param parent The parent window. # @param controler The controler been used by PLCOpenEditor (default: None). @@ -618,17 +618,17 @@ self.Controler = None self.Config = wx.ConfigBase.Get() self.EnableDebug = enable_debug - + self._init_ctrls(parent) - + # Define Tree item icon list self.TreeImageList = wx.ImageList(16, 16) self.TreeImageDict = {} - + # Icons for languages for language in LANGUAGES: self.TreeImageDict[language] = self.TreeImageList.Add(GetBitmap(language)) - + # Icons for other items for imgname, itemtype in [ #editables @@ -658,11 +658,11 @@ ("RESOURCES", ITEM_RESOURCES), ("PROPERTIES", ITEM_PROPERTIES)]: self.TreeImageDict[itemtype] = self.TreeImageList.Add(GetBitmap(imgname)) - + # Assign icon list to TreeCtrls self.ProjectTree.SetImageList(self.TreeImageList) self.PouInstanceVariablesPanel.SetTreeImageList(self.TreeImageList) - + self.CurrentEditorToolBar = [] self.CurrentMenu = None self.SelectedItem = None @@ -672,7 +672,7 @@ self.DrawingMode = FREEDRAWING_MODE #self.DrawingMode = DRIVENDRAWING_MODE self.AuiTabCtrl = [] - + # Save default perspective notebooks = {} for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"), @@ -683,8 +683,8 @@ "perspective": self.AUIManager.SavePerspective(), "notebooks": notebooks, } - - + + # Initialize Printing configuring elements self.PrintData = wx.PrintData() self.PrintData.SetPaperId(wx.PAPER_A4) @@ -692,17 +692,17 @@ self.PageSetupData = wx.PageSetupDialogData(self.PrintData) self.PageSetupData.SetMarginTopLeft(wx.Point(10, 15)) self.PageSetupData.SetMarginBottomRight(wx.Point(10, 20)) - + self.SetRefreshFunctions() self.SetDeleteFunctions() - + def __del__(self): self.FindDialog.Destroy() - + def Show(self): wx.Frame.Show(self) wx.CallAfter(self.RestoreLastState) - + def OnActivated(self, event): if event.GetActive(): wx.CallAfter(self._Refresh, TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) @@ -724,7 +724,7 @@ if page_ref == tab: return ("main", page_name) return None - + def SaveTabLayout(self, notebook): tabs = [] for child in notebook.GetChildren(): @@ -744,7 +744,7 @@ tabs.sort(lambda x, y: cmp(x["pos"], y["pos"])) size = notebook.GetSize() return ComputeTabsLayout(tabs, wx.Rect(1, 1, size[0] - NOTEBOOK_BORDER, size[1] - NOTEBOOK_BORDER)) - + def LoadTab(self, notebook, page_infos): if page_infos[0] == "main": infos = self.MainTabs.get(page_infos[1]) @@ -764,21 +764,21 @@ if instance_infos is not None: return notebook.GetPageIndex(self.OpenDebugViewer(instance_infos["class"], instance_path, instance_infos["type"])) return None - + def LoadTabLayout(self, notebook, tabs, mode="all", first_index=None): if isinstance(tabs, ListType): if len(tabs) == 0: return raise ValueError, "Not supported" - + if tabs.has_key("split"): self.LoadTabLayout(notebook, tabs["others"]) - + split_dir, split_ratio = tabs["split"] first_index = self.LoadTabLayout(notebook, tabs["tab"], mode="first") notebook.Split(first_index, split_dir) self.LoadTabLayout(notebook, tabs["tab"], mode="others", first_index=first_index) - + elif mode == "first": return self.LoadTab(notebook, tabs["pages"][0][0]) else: @@ -793,39 +793,39 @@ selected = page_idx if selected is not None: wx.CallAfter(notebook.SetSelection, selected) - + def ResetPerspective(self): if self.DefaultPerspective is not None: self.AUIManager.LoadPerspective(self.DefaultPerspective["perspective"]) - + for notebook in [self.LeftNoteBook, self.BottomNoteBook, self.RightNoteBook]: for idx in xrange(notebook.GetPageCount()): notebook.RemovePage(0) - + notebooks = self.DefaultPerspective["notebooks"] for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"), (self.BottomNoteBook, "bottomnotebook"), (self.RightNoteBook, "rightnotebook")]: self.LoadTabLayout(notebook, notebooks.get(entry_name)) - + self._Refresh(EDITORTOOLBAR) - + def RestoreLastState(self): frame_size = None if self.Config.HasEntry("framesize"): frame_size = cPickle.loads(str(self.Config.Read("framesize"))) - + if frame_size is None: self.Maximize() else: self.SetClientSize(frame_size) - + def SaveLastState(self): if not self.IsMaximized(): self.Config.Write("framesize", cPickle.dumps(self.GetClientSize())) elif self.Config.HasEntry("framesize"): self.Config.DeleteEntry("framesize") - + self.Config.Flush() #------------------------------------------------------------------------------- @@ -840,7 +840,7 @@ EDITMENU : self.RefreshEditMenu, DISPLAYMENU : self.RefreshDisplayMenu, PROJECTTREE : self.RefreshProjectTree, - POUINSTANCEVARIABLESPANEL : self.RefreshPouInstanceVariablesPanel, + POUINSTANCEVARIABLESPANEL : self.RefreshPouInstanceVariablesPanel, LIBRARYTREE : self.RefreshLibraryPanel, SCALING : self.RefreshScaling, PAGETITLES: self.RefreshPageTitles} @@ -861,9 +861,9 @@ selected = self.TabsOpened.GetSelection() if selected > -1: window = self.TabsOpened.GetPage(selected) - + if window.CheckSaveBeforeClosing(): - + # Refresh all window elements that have changed wx.CallAfter(self._Refresh, TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) wx.CallAfter(self.RefreshTabCtrlEvent) @@ -871,7 +871,7 @@ event.Skip() else: event.Veto() - + def GetCopyBuffer(self, primary_selection=False): data = None @@ -885,7 +885,7 @@ data = dataobj.GetText() wx.TheClipboard.Close() return data - + def SetCopyBuffer(self, text, primary_selection=False): if primary_selection and wx.Platform == '__WXMSW__': return @@ -916,14 +916,14 @@ new_values["creationDateTime"] = old_values["creationDateTime"] if new_values != old_values: self.Controler.SetProjectProperties(None, new_values) - self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, + self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, SCALING) dialog.Destroy() #------------------------------------------------------------------------------- # Notebook Unified Functions #------------------------------------------------------------------------------- - + ## Function that add a tab in Notebook, calling refresh for tab DClick event # for wx.aui.AUINotebook. # @param window Panel to display in tab. @@ -931,7 +931,7 @@ def AddPage(self, window, text): self.TabsOpened.AddPage(window, text) self.RefreshTabCtrlEvent() - + ## Function that add a tab in Notebook, calling refresh for tab DClick event # for wx.aui.AUINotebook. # @param window Panel to display in tab. @@ -941,16 +941,16 @@ if self.TabsOpened.GetPage(idx) == window: self.TabsOpened.DeletePage(idx) self.RefreshTabCtrlEvent() - return - - ## Function that fix difference in deleting all tabs between + return + + ## Function that fix difference in deleting all tabs between # wx.Notebook and wx.aui.AUINotebook. def DeleteAllPages(self): for idx in xrange(self.TabsOpened.GetPageCount()): self.TabsOpened.DeletePage(0) self.RefreshTabCtrlEvent() - ## Function that fix difference in setting picture on tab between + ## Function that fix difference in setting picture on tab between # wx.Notebook and wx.aui.AUINotebook. # @param idx Tab index. # @param bitmap wx.Bitmap to define on tab. @@ -980,12 +980,12 @@ self.SaveProject() elif answer == wx.ID_CANCEL: return False - + for idx in xrange(self.TabsOpened.GetPageCount()): window = self.TabsOpened.GetPage(idx) if not window.CheckSaveBeforeClosing(): return False - + return True #------------------------------------------------------------------------------- @@ -1025,7 +1025,7 @@ dialog.Destroy() def OnPreviewMenu(self, event): - selected = self.TabsOpened.GetSelection() + selected = self.TabsOpened.GetSelection() if selected != -1: window = self.TabsOpened.GetPage(selected) data = wx.PrintDialogData(self.PrintData) @@ -1040,15 +1040,15 @@ preview_frame = wx.PreviewFrame(preview, self, _("Print preview"), style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_FLOAT_ON_PARENT) preview_frame.Initialize() - + preview_canvas = preview.GetCanvas() preview_canvas.SetMinSize(preview_canvas.GetVirtualSize()) preview_frame.Fit() - + preview_frame.Show(True) def OnPrintMenu(self, event): - selected = self.TabsOpened.GetSelection() + selected = self.TabsOpened.GetSelection() if selected != -1: window = self.TabsOpened.GetPage(selected) dialog_data = wx.PrintDialogData(self.PrintData) @@ -1058,7 +1058,7 @@ margins = (self.PageSetupData.GetMarginTopLeft(), self.PageSetupData.GetMarginBottomRight()) printer = wx.Printer(dialog_data) printout = GraphicPrintout(window, page_size, margins) - + if not printer.Print(self, printout, True) and printer.GetLastError() != wx.PRINTER_CANCELLED: self.ShowErrorMessage(_("There was a problem printing.\nPerhaps your current printer is not set correctly?")) printout.Destroy() @@ -1087,12 +1087,12 @@ self.EditMenu.Enable(wx.ID_REDO, redo) MenuToolBar.EnableTool(wx.ID_REDO, redo) #self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, True) - #self.EditMenu.Check(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, + #self.EditMenu.Check(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, # self.Controler.IsProjectBufferEnabled()) self.EditMenu.Enable(wx.ID_FIND, selected > -1) - self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDNEXT, + self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDNEXT, selected > -1 and self.SearchParams is not None) - self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDPREVIOUS, + self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDPREVIOUS, selected > -1 and self.SearchParams is not None) self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, True) MenuToolBar.EnableTool(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, True) @@ -1138,7 +1138,7 @@ MenuToolBar.EnableTool(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, False) self.EditMenu.Enable(wx.ID_ADD, False) self.EditMenu.Enable(wx.ID_DELETE, False) - + def CloseTabsWithoutModel(self, refresh=True): idxs = range(self.TabsOpened.GetPageCount()) idxs.reverse() @@ -1156,9 +1156,9 @@ window.Undo() else: self.Controler.LoadPrevious() - self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, - SCALING, PAGETITLES) - + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, + SCALING, PAGETITLES) + def OnRedoMenu(self, event): selected = self.TabsOpened.GetSelection() if selected != -1: @@ -1166,9 +1166,9 @@ window.Redo() else: self.Controler.LoadNext() - self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES) - + def OnEnableUndoRedoMenu(self, event): self.Controler.EnableProjectBuffer(event.IsChecked()) self.RefreshEditMenu() @@ -1187,14 +1187,14 @@ control.SetSelection(0, control.GetLastPosition()) elif isinstance(control, wx.ComboBox): control.SetMark(0, control.GetLastPosition() + 1) - + def SetDeleteFunctions(self): self.DeleteFunctions = { ITEM_DATATYPE: GetDeleteElementFunction( - PLCControler.ProjectRemoveDataType, + PLCControler.ProjectRemoveDataType, check_function=self.CheckDataTypeIsUsedBeforeDeletion), ITEM_POU: GetDeleteElementFunction( - PLCControler.ProjectRemovePou, + PLCControler.ProjectRemovePou, check_function=self.CheckPouIsUsedBeforeDeletion), ITEM_TRANSITION: GetDeleteElementFunction( PLCControler.ProjectRemovePouTransition, ITEM_POU), @@ -1205,7 +1205,7 @@ ITEM_RESOURCE: GetDeleteElementFunction( PLCControler.ProjectRemoveConfigurationResource, ITEM_CONFIGURATION) } - + def OnDeleteMenu(self, event): window = self.FindFocus() if window == self.ProjectTree or window is None: @@ -1215,7 +1215,7 @@ if function is not None: function(self, selected) self.CloseTabsWithoutModel() - self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, + self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) elif isinstance(window, (Viewer, TextViewer)): event = wx.KeyEvent(wx.EVT_CHAR._getEvtType()) @@ -1225,18 +1225,18 @@ def OnFindMenu(self, event): if not self.FindDialog.IsShown(): self.FindDialog.Show() - + def CloseFindInPouDialog(self): selected = self.TabsOpened.GetSelection() if selected == -1 and self.FindDialog.IsShown(): self.FindDialog.Hide() - + def OnFindNextMenu(self, event): self.FindInPou(1) - + def OnFindPreviousMenu(self, event): self.FindInPou(-1) - + def FindInPou(self, direction, search_params=None): if search_params is not None: self.SearchParams = search_params @@ -1244,7 +1244,7 @@ if selected != -1: window = self.TabsOpened.GetPage(selected) window.Find(direction, self.SearchParams) - + def OnSearchInProjectMenu(self, event): dialog = SearchInProjectDialog(self) if dialog.ShowModal() == wx.ID_OK: @@ -1253,7 +1253,7 @@ self.ClearSearchResults() self.SearchResultPanel.SetSearchResults(criteria, result) self.SelectTab(self.SearchResultPanel) - + #------------------------------------------------------------------------------- # Display Menu Functions #------------------------------------------------------------------------------- @@ -1284,7 +1284,7 @@ if self.EnableDebug: self.DisplayMenu.Enable(wx.ID_CLEAR, False) self.DisplayMenu.Enable(wx.ID_ZOOM_FIT, False) - + def OnRefreshMenu(self, event): self.RefreshEditor() @@ -1308,14 +1308,14 @@ #------------------------------------------------------------------------------- # Project Editor Panels Management Functions #------------------------------------------------------------------------------- - + def OnPageDragged(self, event): wx.CallAfter(self.RefreshTabCtrlEvent) event.Skip() - + def OnAllowNotebookDnD(self, event): event.Allow() - + def RefreshTabCtrlEvent(self): auitabctrl = [] for child in self.TabsOpened.GetChildren(): @@ -1329,11 +1329,11 @@ if pane.IsMaximized(): self.AUIManager.RestorePane(pane) self.AUIManager.Update() - + def EnsureTabVisible(self, tab): notebook = tab.GetParent() notebook.SetSelection(notebook.GetPageIndex(tab)) - + def OnPouSelectedChanging(self, event): selected = self.TabsOpened.GetSelection() if selected >= 0: @@ -1341,7 +1341,7 @@ if not window.IsDebugging(): window.ResetBuffer() event.Skip() - + def OnPouSelectedChanged(self, event): selected = self.TabsOpened.GetSelection() if selected >= 0: @@ -1361,7 +1361,7 @@ wx.CallAfter(self.PouInstanceVariablesPanel.SetPouType, tagname, instance_path) wx.CallAfter(self._Refresh, FILEMENU, EDITMENU, DISPLAYMENU, EDITORTOOLBAR) event.Skip() - + def RefreshEditor(self): selected = self.TabsOpened.GetSelection() if selected >= 0: @@ -1383,13 +1383,13 @@ window = child.GetWindowFromIdx(active_page) window.RefreshView() self._Refresh(FILEMENU, EDITMENU, DISPLAYMENU, EDITORTOOLBAR) - + def RefreshEditorNames(self, old_tagname, new_tagname): for i in xrange(self.TabsOpened.GetPageCount()): editor = self.TabsOpened.GetPage(i) if editor.GetTagName() == old_tagname: editor.SetTagName(new_tagname) - + def IsOpened(self, tagname): for idx in xrange(self.TabsOpened.GetPageCount()): if self.TabsOpened.GetPage(idx).IsViewing(tagname): @@ -1429,7 +1429,7 @@ tagname = item_infos.get("tagname", None) else: tagname = None - + # Refresh treectrl items according to project infos infos = self.Controler.GetProjectInfos() root = self.ProjectTree.GetRootItem() @@ -1437,7 +1437,7 @@ root = self.ProjectTree.AddRoot(infos["name"]) self.GenerateProjectTreeBranch(root, infos) self.ProjectTree.Expand(root) - + # Select new item corresponding to previous selected item if tagname is not None: self.SelectProjectTreeItem(tagname) @@ -1456,7 +1456,7 @@ self.ProjectTree.SetItemTextColour(root, highlight_colours[1]) self.ProjectTree.SetItemExtraImage(root, None) if infos["type"] == ITEM_POU: - self.ProjectTree.SetItemImage(root, + self.ProjectTree.SetItemImage(root, self.TreeImageDict[self.Controler.GetPouBodyType(infos["name"])]) if item_alone: self.ProjectTree.SetItemExtraImage(root, self.Controler.GetPouType(infos["name"])) @@ -1466,8 +1466,8 @@ self.TreeImageDict[icon_name] = self.TreeImageList.Add(GetBitmap(icon_name)) self.ProjectTree.SetItemImage(root, self.TreeImageDict[icon_name]) elif self.TreeImageDict.has_key(infos["type"]): - self.ProjectTree.SetItemImage(root, self.TreeImageDict[infos["type"]]) - + self.ProjectTree.SetItemImage(root, self.TreeImageDict[infos["type"]]) + item, root_cookie = self.ProjectTree.GetFirstChild(root) for values in infos["values"]: if values["type"] not in ITEMS_UNEDITABLE or len(values["values"]) > 0: @@ -1522,7 +1522,7 @@ self.SelectedItem = None def OnProjectTreeBeginDrag(self, event): - selected_item = (self.SelectedItem + selected_item = (self.SelectedItem if self.SelectedItem is not None else event.GetItem()) if selected_item.IsOk() and self.ProjectTree.GetPyData(selected_item)["type"] == ITEM_POU: @@ -1563,7 +1563,7 @@ abort = True if not abort: self.Controler.ChangeDataTypeName(old_name, new_name) - self.RefreshEditorNames(self.Controler.ComputeDataTypeName(old_name), + self.RefreshEditorNames(self.Controler.ComputeDataTypeName(old_name), self.Controler.ComputeDataTypeName(new_name)) self.RefreshPageTitles() elif item_infos["type"] == ITEM_POU: @@ -1577,7 +1577,7 @@ messageDialog.Destroy() if not abort: self.Controler.ChangePouName(old_name, new_name) - self.RefreshEditorNames(self.Controler.ComputePouName(old_name), + self.RefreshEditorNames(self.Controler.ComputePouName(old_name), self.Controler.ComputePouName(new_name)) self.RefreshLibraryPanel() self.RefreshPageTitles() @@ -1589,7 +1589,7 @@ else: words = item_infos["tagname"].split("::") self.Controler.ChangePouTransitionName(words[1], old_name, new_name) - self.RefreshEditorNames(self.Controler.ComputePouTransitionName(words[1], old_name), + self.RefreshEditorNames(self.Controler.ComputePouTransitionName(words[1], old_name), self.Controler.ComputePouTransitionName(words[1], new_name)) self.RefreshPageTitles() elif item_infos["type"] == ITEM_ACTION: @@ -1600,7 +1600,7 @@ else: words = item_infos["tagname"].split("::") self.Controler.ChangePouActionName(words[1], old_name, new_name) - self.RefreshEditorNames(self.Controler.ComputePouActionName(words[1], old_name), + self.RefreshEditorNames(self.Controler.ComputePouActionName(words[1], old_name), self.Controler.ComputePouActionName(words[1], new_name)) self.RefreshPageTitles() elif item_infos["type"] == ITEM_CONFIGURATION: @@ -1619,7 +1619,7 @@ messageDialog.Destroy() if not abort: self.Controler.ChangeConfigurationName(old_name, new_name) - self.RefreshEditorNames(self.Controler.ComputeConfigurationName(old_name), + self.RefreshEditorNames(self.Controler.ComputeConfigurationName(old_name), self.Controler.ComputeConfigurationName(new_name)) self.RefreshPageTitles() elif item_infos["type"] == ITEM_RESOURCE: @@ -1639,7 +1639,7 @@ if not abort: words = item_infos["tagname"].split("::") self.Controler.ChangeConfigurationResourceName(words[1], old_name, new_name) - self.RefreshEditorNames(self.Controler.ComputeConfigurationResourceName(words[1], old_name), + self.RefreshEditorNames(self.Controler.ComputeConfigurationResourceName(words[1], old_name), self.Controler.ComputeConfigurationResourceName(words[1], new_name)) self.RefreshPageTitles() if message or abort: @@ -1653,7 +1653,7 @@ self.RefreshEditor() self._Refresh(TITLE, FILEMENU, EDITMENU) event.Skip() - + def OnProjectTreeItemActivated(self, event): selected = event.GetItem() name = self.ProjectTree.GetItemText(selected) @@ -1666,7 +1666,7 @@ ITEM_TRANSITION, ITEM_ACTION]: self.EditProjectElement(item_infos["type"], item_infos["tagname"]) event.Skip() - + def ProjectTreeItemSelect(self, select_item): if select_item is not None and select_item.IsOk(): name = self.ProjectTree.GetItemText(select_item) @@ -1676,14 +1676,14 @@ ITEM_TRANSITION, ITEM_ACTION]: self.EditProjectElement(item_infos["type"], item_infos["tagname"], True) self.PouInstanceVariablesPanel.SetPouType(item_infos["tagname"]) - + def OnProjectTreeLeftUp(self, event): if self.SelectedItem is not None: self.ProjectTree.SelectItem(self.SelectedItem) self.ProjectTreeItemSelect(self.SelectedItem) self.ResetSelectedItem() event.Skip() - + def OnProjectTreeMotion(self, event): if not event.Dragging(): pt = wx.Point(event.GetX(), event.GetY()) @@ -1693,7 +1693,7 @@ if item != self.LastToolTipItem and self.LastToolTipItem is not None: self.ProjectTree.SetToolTip(None) self.LastToolTipItem = None - if (self.LastToolTipItem != item and + if (self.LastToolTipItem != item and item_infos["type"] in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]): bodytype = self.Controler.GetEditedElementBodyType( item_infos["tagname"]) @@ -1708,21 +1708,21 @@ else: block_type = "Action" self.LastToolTipItem = item - wx.CallAfter(self.ProjectTree.SetToolTipString, + wx.CallAfter(self.ProjectTree.SetToolTipString, "%s : %s : %s" % ( block_type, bodytype, item_infos["name"])) elif self.LastToolTipItem is not None: self.ProjectTree.SetToolTip(None) self.LastToolTipItem = None event.Skip() - + def OnProjectTreeItemChanging(self, event): if self.ProjectTree.GetPyData(event.GetItem())["type"] not in ITEMS_UNEDITABLE and self.SelectedItem is None: self.SelectedItem = event.GetItem() event.Veto() else: event.Skip() - + def EditProjectElement(self, element, tagname, onlyopened = False): openedidx = self.IsOpened(tagname) if openedidx is not None: @@ -1790,30 +1790,30 @@ window.SetFocus() self.RefreshPageTitles() return new_window - + def OnProjectTreeRightUp(self, event): item = event.GetItem() self.ProjectTree.SelectItem(item) self.ProjectTreeItemSelect(item) name = self.ProjectTree.GetItemText(item) item_infos = self.ProjectTree.GetPyData(item) - + menu = None if item_infos["type"] in ITEMS_UNEDITABLE + [ITEM_PROJECT]: if item_infos["type"] == ITEM_PROJECT: name = "Project" else: name = UNEDITABLE_NAMES_DICT[name] - + if name == "Data Types": menu = wx.Menu(title='') new_id = wx.NewId() AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add DataType")) self.Bind(wx.EVT_MENU, self.OnAddDataTypeMenu, id=new_id) - + elif name in ["Functions", "Function Blocks", "Programs", "Project"]: menu = wx.Menu(title='') - + if name != "Project": new_id = wx.NewId() AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add POU")) @@ -1830,7 +1830,7 @@ new_id = wx.NewId() AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Configuration")) self.Bind(wx.EVT_MENU, self.OnAddConfigurationMenu, id=new_id) - + elif name == "Transitions": menu = wx.Menu(title='') new_id = wx.NewId() @@ -1841,7 +1841,7 @@ parent = self.ProjectTree.GetItemParent(parent) parent_type = self.ProjectTree.GetPyData(parent)["type"] self.Bind(wx.EVT_MENU, self.GenerateAddTransitionFunction(self.ProjectTree.GetItemText(parent)), id=new_id) - + elif name == "Actions": menu = wx.Menu(title='') new_id = wx.NewId() @@ -1852,7 +1852,7 @@ parent = self.ProjectTree.GetItemParent(parent) parent_type = self.ProjectTree.GetPyData(parent)["type"] self.Bind(wx.EVT_MENU, self.GenerateAddActionFunction(self.ProjectTree.GetItemText(parent)), id=new_id) - + elif name == "Resources": menu = wx.Menu(title='') new_id = wx.NewId() @@ -1871,7 +1871,7 @@ parent_name = self.ProjectTree.GetItemText(parent) if parent_name is not None: self.Bind(wx.EVT_MENU, self.GenerateAddResourceFunction(parent_name), id=new_id) - + else: if item_infos["type"] == ITEM_POU: menu = wx.Menu(title='') @@ -1883,11 +1883,11 @@ AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Action")) self.Bind(wx.EVT_MENU, self.GenerateAddActionFunction(name), id=new_id) menu.AppendSeparator() - + new_id = wx.NewId() AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Copy POU")) self.Bind(wx.EVT_MENU, self.OnCopyPou, id=new_id) - + pou_type = self.Controler.GetPouType(name) if pou_type in ["function", "functionBlock"]: change_menu = wx.Menu(title='') @@ -1902,27 +1902,27 @@ new_id = wx.NewId() AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Rename")) self.Bind(wx.EVT_MENU, self.OnRenamePouMenu, id=new_id) - + elif item_infos["type"] == ITEM_CONFIGURATION: menu = wx.Menu(title='') new_id = wx.NewId() AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Resource")) self.Bind(wx.EVT_MENU, self.GenerateAddResourceFunction(name), id=new_id) - + elif item_infos["type"] in [ITEM_DATATYPE, ITEM_TRANSITION, ITEM_ACTION, ITEM_RESOURCE]: menu = wx.Menu(title='') - + if menu is not None: new_id = wx.NewId() AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Delete")) self.Bind(wx.EVT_MENU, self.OnDeleteMenu, id=new_id) - + if menu is not None: self.PopupMenu(menu) menu.Destroy() - + self.ResetSelectedItem() - + event.Skip() @@ -1932,7 +1932,7 @@ def GetTreeImage(self, var_class): return self.TreeImageDict[var_class] - + def RefreshPouInstanceVariablesPanel(self): self.PouInstanceVariablesPanel.RefreshView() @@ -1945,11 +1945,11 @@ if old_selected >= 0: self.TabsOpened.GetPage(old_selected).ResetBuffer() self.TabsOpened.SetSelection(openedidx) - + elif instance_category in ITEMS_VARIABLE: if self.Controler.IsNumType(instance_type, True): self.AddDebugVariable(instance_path, True) - + else: bodytype = self.Controler.GetEditedElementBodyType(instance_type, True) if bodytype == "FBD": @@ -1968,7 +1968,7 @@ new_window.SetKeywords(IL_KEYWORDS) else: new_window.SetKeywords(ST_KEYWORDS) - + if new_window is not None: if instance_category in [ITEM_FUNCTIONBLOCK, ITEM_PROGRAM]: pou_type = self.Controler.GetEditedElementType(instance_type, True)[1].upper() @@ -1977,7 +1977,7 @@ icon = GetBitmap("TRANSITION", bodytype) elif instance_category == ITEM_ACTION: icon = GetBitmap("ACTION", bodytype) - + if new_window is not None: new_window.SetIcon(icon) self.AddPage(new_window, "") @@ -2005,19 +2005,19 @@ elif editor.IsDebugging(): editor.SubscribeAllDataConsumers() self.DebugVariablePanel.SubscribeAllDataConsumers() - + def AddDebugVariable(self, iec_path, force=False, graph=False): if self.EnableDebug: self.DebugVariablePanel.InsertValue(iec_path, force=force, graph=graph) self.EnsureTabVisible(self.DebugVariablePanel) - + #------------------------------------------------------------------------------- # Library Panel Management Function #------------------------------------------------------------------------------- def RefreshLibraryPanel(self): self.LibraryPanel.RefreshTree() - + #------------------------------------------------------------------------------- # ToolBars Management Functions #------------------------------------------------------------------------------- @@ -2039,16 +2039,16 @@ def ResetEditorToolBar(self): EditorToolBar = self.Panes["EditorToolBar"] - + for item in self.CurrentEditorToolBar: if wx.VERSION >= (2, 6, 0): self.Unbind(wx.EVT_MENU, id=item) else: - self.Disconnect(id=item, eventType=wx.wxEVT_COMMAND_MENU_SELECTED) - + self.Disconnect(id=item, eventType=wx.wxEVT_COMMAND_MENU_SELECTED) + if EditorToolBar: EditorToolBar.DeleteTool(item) - + if EditorToolBar: EditorToolBar.Realize() self.AUIManager.GetPane("EditorToolBar").BestSize(EditorToolBar.GetBestSize()) @@ -2102,7 +2102,7 @@ if EditorToolBar: EditorToolBar.ToggleTool(ID_PLCOPENEDITOREDITORTOOLBARSELECTION, False) EditorToolBar.ToggleTool(ID_PLCOPENEDITOREDITORTOOLBARSELECTION, True) - + def ResetToolToggle(self, id): tool = self.Panes["EditorToolBar"].FindById(id) tool.SetToggle(False) @@ -2111,55 +2111,55 @@ selected = self.TabsOpened.GetSelection() if selected != -1: self.TabsOpened.GetPage(selected).SetMode(MODE_SELECTION) - + def OnMotionTool(self, event): selected = self.TabsOpened.GetSelection() if selected != -1: self.TabsOpened.GetPage(selected).SetMode(MODE_MOTION) - + def OnCommentTool(self, event): self.ResetToolToggle(ID_PLCOPENEDITOREDITORTOOLBARCOMMENT) selected = self.TabsOpened.GetSelection() if selected != -1: self.TabsOpened.GetPage(selected).SetMode(MODE_COMMENT) - + def OnVariableTool(self, event): self.ResetToolToggle(ID_PLCOPENEDITOREDITORTOOLBARVARIABLE) selected = self.TabsOpened.GetSelection() if selected != -1: self.TabsOpened.GetPage(selected).SetMode(MODE_VARIABLE) - + def OnBlockTool(self, event): self.ResetToolToggle(ID_PLCOPENEDITOREDITORTOOLBARBLOCK) selected = self.TabsOpened.GetSelection() if selected != -1: self.TabsOpened.GetPage(selected).SetMode(MODE_BLOCK) - + def OnConnectionTool(self, event): self.ResetToolToggle(ID_PLCOPENEDITOREDITORTOOLBARCONNECTION) selected = self.TabsOpened.GetSelection() if selected != -1: self.TabsOpened.GetPage(selected).SetMode(MODE_CONNECTION) - + def OnPowerRailTool(self, event): self.ResetToolToggle(ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL) selected = self.TabsOpened.GetSelection() if selected != -1: self.TabsOpened.GetPage(selected).SetMode(MODE_POWERRAIL) - + def OnRungTool(self, event): selected = self.TabsOpened.GetSelection() if selected != -1: self.TabsOpened.GetPage(selected).AddLadderRung() event.Skip() - + def OnCoilTool(self, event): self.ResetToolToggle(ID_PLCOPENEDITOREDITORTOOLBARCOIL) selected = self.TabsOpened.GetSelection() if selected != -1: self.TabsOpened.GetPage(selected).SetMode(MODE_COIL) event.Skip() - + def OnContactTool(self, event): if self.DrawingMode == FREEDRAWING_MODE: self.ResetToolToggle(ID_PLCOPENEDITOREDITORTOOLBARCONTACT) @@ -2169,18 +2169,18 @@ self.TabsOpened.GetPage(selected).SetMode(MODE_CONTACT) else: self.TabsOpened.GetPage(selected).AddLadderContact() - - def OnBranchTool(self, event): + + def OnBranchTool(self, event): selected = self.TabsOpened.GetSelection() if selected != -1: self.TabsOpened.GetPage(selected).AddLadderBranch() - + def OnInitialStepTool(self, event): self.ResetToolToggle(ID_PLCOPENEDITOREDITORTOOLBARINITIALSTEP) selected = self.TabsOpened.GetSelection() if selected != -1: self.TabsOpened.GetPage(selected).SetMode(MODE_INITIALSTEP) - + def OnStepTool(self, event): if self.GetDrawingMode() == FREEDRAWING_MODE: self.ResetToolToggle(ID_PLCOPENEDITOREDITORTOOLBARSTEP) @@ -2190,7 +2190,7 @@ self.TabsOpened.GetPage(selected).SetMode(MODE_STEP) else: self.TabsOpened.GetPage(selected).AddStep() - + def OnActionBlockTool(self, event): if self.GetDrawingMode() == FREEDRAWING_MODE: self.ResetToolToggle(ID_PLCOPENEDITOREDITORTOOLBARACTIONBLOCK) @@ -2200,13 +2200,13 @@ self.TabsOpened.GetPage(selected).SetMode(MODE_ACTION) else: self.TabsOpened.GetPage(selected).AddStepAction() - + def OnTransitionTool(self, event): self.ResetToolToggle(ID_PLCOPENEDITOREDITORTOOLBARTRANSITION) selected = self.TabsOpened.GetSelection() if selected != -1: self.TabsOpened.GetPage(selected).SetMode(MODE_TRANSITION) - + def OnDivergenceTool(self, event): if self.GetDrawingMode() == FREEDRAWING_MODE: self.ResetToolToggle(ID_PLCOPENEDITOREDITORTOOLBARDIVERGENCE) @@ -2216,7 +2216,7 @@ self.TabsOpened.GetPage(selected).SetMode(MODE_DIVERGENCE) else: self.TabsOpened.GetPage(selected).AddDivergence() - + def OnJumpTool(self, event): if self.GetDrawingMode() == FREEDRAWING_MODE: self.ResetToolToggle(ID_PLCOPENEDITOREDITORTOOLBARJUMP) @@ -2226,7 +2226,7 @@ self.TabsOpened.GetPage(selected).SetMode(MODE_JUMP) else: self.TabsOpened.GetPage(selected).AddJump() - + #------------------------------------------------------------------------------- # Add Project Elements Functions @@ -2237,7 +2237,7 @@ if tagname is not None: self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE) self.EditProjectElement(ITEM_DATATYPE, tagname) - + def GenerateAddPouFunction(self, pou_type): def OnAddPouMenu(event): dialog = PouDialog(self, pou_type) @@ -2259,7 +2259,7 @@ dialog.SetPouNames(self.Controler.GetProjectPouNames()) dialog.SetPouElementNames(self.Controler.GetProjectPouVariableNames(pou_name)) dialog.SetValues({"transitionName": self.Controler.GenerateNewName(None, None, "transition%d")}) - if dialog.ShowModal() == wx.ID_OK: + if dialog.ShowModal() == wx.ID_OK: values = dialog.GetValues() tagname = self.Controler.ProjectAddPouTransition(pou_name, values["transitionName"], values["language"]) if tagname is not None: @@ -2289,6 +2289,14 @@ self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL) self.EditProjectElement(ITEM_CONFIGURATION, tagname) + def AddResourceMenu(self, event): + config_names = self.Controler.GetProjectConfigNames() + if len(config_names) > 0: + tagname = self.Controler.ProjectAddConfigurationResource(config_names[0]) + if tagname is not None: + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL) + self.EditProjectElement(ITEM_RESOURCE, tagname) + def GenerateAddResourceFunction(self, config_name): def OnAddResourceMenu(event): tagname = self.Controler.ProjectAddConfigurationResource(config_name) @@ -2300,7 +2308,7 @@ def GenerateChangePouTypeFunction(self, name, new_type): def OnChangePouTypeMenu(event): selected = self.ProjectTree.GetSelection() - if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU: + if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU: self.Controler.ProjectChangePouType(name, new_type) self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, LIBRARYTREE) return OnChangePouTypeMenu @@ -2308,7 +2316,7 @@ def OnCopyPou(self, event): selected = self.ProjectTree.GetSelection() pou_name = self.ProjectTree.GetItemText(selected) - + pou_xml = self.Controler.GetPouXml(pou_name) if pou_xml is not None: self.SetCopyBuffer(pou_xml) @@ -2316,14 +2324,14 @@ def OnPastePou(self, event): selected = self.ProjectTree.GetSelection() - - if self.ProjectTree.GetPyData(selected)["type"] != ITEM_PROJECT: + + if self.ProjectTree.GetPyData(selected)["type"] != ITEM_PROJECT: pou_type = self.ProjectTree.GetItemText(selected) pou_type = UNEDITABLE_NAMES_DICT[pou_type] # one of 'Functions', 'Function Blocks' or 'Programs' pou_type = {'Functions': 'function', 'Function Blocks': 'functionBlock', 'Programs': 'program'}[pou_type] else: pou_type = None - + pou_xml = self.GetCopyBuffer() result = self.Controler.PastePou(pou_type, pou_xml) @@ -2341,9 +2349,9 @@ def CheckElementIsUsedBeforeDeletion(self, check_function, title, name): if not check_function(name): return True - - dialog = wx.MessageDialog(self, - _("\"%s\" is used by one or more POUs. Do you wish to continue?") % name, + + dialog = wx.MessageDialog(self, + _("\"%s\" is used by one or more POUs. Do you wish to continue?") % name, title, wx.YES_NO|wx.ICON_QUESTION) answer = dialog.ShowModal() dialog.Destroy() @@ -2353,12 +2361,12 @@ return self.CheckElementIsUsedBeforeDeletion( self.Controler.DataTypeIsUsed, _("Remove Datatype"), name) - + def CheckPouIsUsedBeforeDeletion(self, name): return self.CheckElementIsUsedBeforeDeletion( self.Controler.PouIsUsed, _("Remove Pou"), name) - + def OnRemoveDataTypeMenu(self, event): selected = self.ProjectTree.GetSelection() if self.ProjectTree.GetPyData(selected)["type"] == ITEM_DATATYPE: @@ -2370,10 +2378,10 @@ if idx is not None: self.TabsOpened.DeletePage(idx) self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE) - + def OnRenamePouMenu(self, event): selected = self.ProjectTree.GetSelection() - if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU: + if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU: wx.CallAfter(self.ProjectTree.EditLabel, selected) def OnRemovePouMenu(self, event): @@ -2391,7 +2399,7 @@ def OnRemoveTransitionMenu(self, event): selected = self.ProjectTree.GetSelection() item_infos = self.ProjectTree.GetPyData(selected) - if item_infos["type"] == ITEM_TRANSITION: + if item_infos["type"] == ITEM_TRANSITION: transition = self.ProjectTree.GetItemText(selected) pou_name = item_infos["tagname"].split("::")[1] self.Controler.ProjectRemovePouTransition(pou_name, transition) @@ -2404,7 +2412,7 @@ def OnRemoveActionMenu(self, event): selected = self.ProjectTree.GetSelection() item_infos = self.ProjectTree.GetPyData(selected) - if item_infos["type"] == ITEM_ACTION: + if item_infos["type"] == ITEM_ACTION: action = self.ProjectTree.GetItemText(selected) pou_name = item_infos["tagname"].split("::")[1] self.Controler.ProjectRemovePouAction(pou_name, action) @@ -2416,7 +2424,7 @@ def OnRemoveConfigurationMenu(self, event): selected = self.ProjectTree.GetSelection() - if self.ProjectTree.GetPyData(selected)["type"] == ITEM_CONFIGURATION: + if self.ProjectTree.GetPyData(selected)["type"] == ITEM_CONFIGURATION: name = self.ProjectTree.GetItemText(selected) self.Controler.ProjectRemoveConfiguration(name) tagname = self.Controler.ComputeConfigurationName(name) @@ -2494,17 +2502,17 @@ self.Margins = margins self.FontSize = 5 self.TextMargin = 3 - + maxx, maxy = viewer.GetMaxSize() - self.PageGrid = (UPPER_DIV(maxx, self.PageSize[0]), + self.PageGrid = (UPPER_DIV(maxx, self.PageSize[0]), UPPER_DIV(maxy, self.PageSize[1])) - + def GetPageNumber(self): return self.PageGrid[0] * self.PageGrid[1] - + def HasPage(self, page): return page <= self.GetPageNumber() - + def GetPageInfo(self): page_number = self.GetPageNumber() return (1, page_number, 1, page_number) @@ -2520,7 +2528,7 @@ dc.SetUserScale(1.0, 1.0) dc.SetDeviceOrigin(0, 0) dc.printing = not self.Preview - + # Get the size of the DC in pixels ppiPrinterX, ppiPrinterY = self.GetPPIPrinter() ppiScreenX, ppiScreenY = self.GetPPIScreen() @@ -2528,26 +2536,26 @@ dw, dh = dc.GetSizeTuple() Xscale = (float(dw) * float(ppiPrinterX)) / (float(pw) * 25.4) Yscale = (float(dh) * float(ppiPrinterY)) / (float(ph) * 25.4) - + fontsize = self.FontSize * Yscale text_margin = self.TextMargin * Yscale - + margin_left = self.Margins[0].x * Xscale margin_top = self.Margins[0].y * Yscale area_width = dw - self.Margins[1].x * Xscale - margin_left area_height = dh - self.Margins[1].y * Yscale - margin_top - + dc.SetPen(MiterPen(wx.BLACK)) - dc.SetBrush(wx.TRANSPARENT_BRUSH) + dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.DrawRectangle(margin_left, margin_top, area_width, area_height) - + dc.SetFont(wx.Font(fontsize, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) dc.SetTextForeground(wx.BLACK) block_name = " - ".join(self.Viewer.GetTagName().split("::")[1:]) text_width, text_height = dc.GetTextExtent(block_name) dc.DrawText(block_name, margin_left, margin_top - text_height - self.TextMargin) dc.DrawText(_("Page: %d") % page, margin_left, margin_top + area_height + self.TextMargin) - + # Calculate the position on the DC for centering the graphic posX = area_width * ((page - 1) % self.PageGrid[0]) posY = area_height * ((page - 1) / self.PageGrid[0]) @@ -2560,10 +2568,10 @@ dc.SetDeviceOrigin(-posX + margin_left, -posY + margin_top) dc.SetClippingRegion(posX, posY, self.PageSize[0] * scale, self.PageSize[1] * scale) dc.SetUserScale(scale, scale) - + #------------------------------------------- - + self.Viewer.DoDrawing(dc, True) - + return True diff -r 86797748c2a2 -r f65ab5ff91d1 PLCControler.py --- a/PLCControler.py Mon May 26 14:44:03 2014 +0100 +++ b/PLCControler.py Fri Jun 06 18:30:49 2014 +0100 @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor -#based on the plcopen standard. +#based on the plcopen standard. # #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD # @@ -57,7 +57,7 @@ ITEM_RESOURCES, ITEM_PROPERTIES ] = range(8, 17) - + ITEMS_VARIABLE = [ITEM_VAR_LOCAL, ITEM_VAR_GLOBAL, ITEM_VAR_EXTERNAL, @@ -92,12 +92,12 @@ def GetUneditableNames(): _ = lambda x:x - return [_("User-defined POUs"), _("Functions"), _("Function Blocks"), - _("Programs"), _("Data Types"), _("Transitions"), _("Actions"), + return [_("User-defined POUs"), _("Functions"), _("Function Blocks"), + _("Programs"), _("Data Types"), _("Transitions"), _("Actions"), _("Configurations"), _("Resources"), _("Properties")] UNEDITABLE_NAMES = GetUneditableNames() -[USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS, - DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS, +[USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS, + DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS, RESOURCES, PROPERTIES] = UNEDITABLE_NAMES #------------------------------------------------------------------------------- @@ -133,7 +133,7 @@ _BoolValue = lambda x: x in ["true", "0"] def _translate_args(translations, args): - return [translate(arg[0]) if len(arg) > 0 else None + return [translate(arg[0]) if len(arg) > 0 else None for translate, arg in zip(translations, args)] @@ -142,7 +142,7 @@ #------------------------------------------------------------------------------- class _VariableInfos(object): - __slots__ = ["Name", "Class", "Option", "Location", "InitialValue", + __slots__ = ["Name", "Class", "Option", "Location", "InitialValue", "Edit", "Documentation", "Type", "Tree", "Number"] def __init__(self, *args): for attr, value in zip(self.__slots__, args): @@ -151,39 +151,39 @@ return _VariableInfos(*[getattr(self, attr) for attr in self.__slots__]) class VariablesInfosFactory: - + def __init__(self, variables): self.Variables = variables self.TreeStack = [] self.Type = None self.Dimensions = None - + def SetType(self, context, *args): self.Type = args[0][0] - + def GetType(self): if len(self.Dimensions) > 0: return ("array", self.Type, self.Dimensions) return self.Type - + def GetTree(self): return (self.TreeStack.pop(-1), self.Dimensions) - + def AddDimension(self, context, *args): self.Dimensions.append(tuple( _translate_args([_StringValue] * 2, args))) - + def AddTree(self, context, *args): self.TreeStack.append([]) self.Dimensions = [] - + def AddVarToTree(self, context, *args): var = (args[0][0], self.Type, self.GetTree()) self.TreeStack[-1].append(var) - + def AddVariable(self, context, *args): self.Variables.append(_VariableInfos(*(_translate_args( - [_StringValue] * 5 + [_BoolValue] + [_StringValue], args) + + [_StringValue] * 5 + [_BoolValue] + [_StringValue], args) + [self.GetType(), self.GetTree()]))) #------------------------------------------------------------------------------- @@ -199,15 +199,15 @@ "program": ITEM_PROGRAM}.get(value) if class_type is not None: return class_type - + pou_type = POU_TYPES.get(value) if pou_type is not None: return pou_type - + var_type = VAR_CLASS_INFOS.get(value) if var_type is not None: return var_type[1] - + return None class _VariablesTreeItemInfos(object): @@ -219,24 +219,24 @@ return _VariableTreeItem(*[getattr(self, attr) for attr in self.__slots__]) class VariablesTreeInfosFactory: - + def __init__(self): self.Root = None - + def GetRoot(self): return self.Root - + def SetRoot(self, context, *args): self.Root = _VariablesTreeItemInfos( *([''] + _translate_args( - [class_extraction, _StringValue] + [_BoolValue] * 2, + [class_extraction, _StringValue] + [_BoolValue] * 2, args) + [[]])) def AddVariable(self, context, *args): if self.Root is not None: self.Root.variables.append(_VariablesTreeItemInfos( *(_translate_args( - [_StringValue, class_extraction, _StringValue] + + [_StringValue, class_extraction, _StringValue] + [_BoolValue] * 2, args) + [[]]))) #------------------------------------------------------------------------------- @@ -244,10 +244,10 @@ #------------------------------------------------------------------------------- class InstancesPathFactory: - + def __init__(self, instances): self.Instances = instances - + def AddInstance(self, context, *args): self.Instances.append(args[0][0]) @@ -260,13 +260,13 @@ def __init__(self, controller): self.Controller = controller self.TagName = None - + def GetTagName(self): return self.TagName - + def ConfigTagName(self, context, *args): self.TagName = self.Controller.ComputeConfigurationName(args[0][0]) - + def ResourceTagName(self, context, *args): self.TagName = self.Controller.ComputeConfigurationResourceName(args[0][0], args[1][0]) @@ -285,15 +285,15 @@ _Point = namedtuple("Point", ["x", "y"]) -_BlockInstanceInfos = namedtuple("BlockInstanceInfos", +_BlockInstanceInfos = namedtuple("BlockInstanceInfos", ["type", "id", "x", "y", "width", "height", "specific_values", "inputs", "outputs"]) _BlockSpecificValues = ( - namedtuple("BlockSpecificValues", + namedtuple("BlockSpecificValues", ["name", "execution_order"]), [_StringValue, int]) _VariableSpecificValues = ( - namedtuple("VariableSpecificValues", + namedtuple("VariableSpecificValues", ["name", "value_type", "execution_order"]), [_StringValue, _StringValue, int]) _ConnectionSpecificValues = ( @@ -305,7 +305,7 @@ [int]) _LDElementSpecificValues = ( - namedtuple("LDElementSpecificValues", + namedtuple("LDElementSpecificValues", ["name", "negated", "edge", "storage", "execution_order"]), [_StringValue, _BoolValue, _StringValue, _StringValue, int]) @@ -330,7 +330,7 @@ namedtuple("StepSpecificValues", ["name", "initial", "action"]), [_StringValue, _BoolValue, lambda x: x]), "transition": ( - namedtuple("TransitionSpecificValues", + namedtuple("TransitionSpecificValues", ["priority", "condition_type", "condition", "connection"]), [int, _StringValue, _StringValue, lambda x: x]), "selectionDivergence": _DivergenceSpecificValues, @@ -360,24 +360,24 @@ return _ActionInfos(*[getattr(self, attr) for attr in self.__slots__]) class BlockInstanceFactory: - + def __init__(self, block_instances): self.BlockInstances = block_instances self.CurrentInstance = None self.SpecificValues = None self.CurrentConnection = None self.CurrentLink = None - + def SetSpecificValues(self, context, *args): self.SpecificValues = list(args) self.CurrentInstance = None self.CurrentConnection = None self.CurrentLink = None - + def AddBlockInstance(self, context, *args): specific_values_tuple, specific_values_translation = \ _SpecificValuesTuples.get(args[0][0], _BlockSpecificValues) - + if (args[0][0] == "step" and len(self.SpecificValues) < 3 or args[0][0] == "transition" and len(self.SpecificValues) < 4): self.SpecificValues.append([None]) @@ -386,21 +386,21 @@ specific_values = specific_values_tuple(*_translate_args( specific_values_translation, self.SpecificValues)) self.SpecificValues = None - + self.CurrentInstance = _BlockInstanceInfos( - *(_translate_args([_StringValue, int] + [float] * 4, args) + + *(_translate_args([_StringValue, int] + [float] * 4, args) + [specific_values, [], []])) - + self.BlockInstances[self.CurrentInstance.id] = self.CurrentInstance - + def AddInstanceConnection(self, context, *args): connection_args = _translate_args( [_StringValue] * 2 + [_BoolValue, _StringValue] + [float] * 2, args) - + self.CurrentConnection = _InstanceConnectionInfos( *(connection_args[1:4] + [ _Point(*connection_args[4:6]), []])) - + if self.CurrentInstance is not None: if connection_args[0] == "input": self.CurrentInstance.inputs.append(self.CurrentConnection) @@ -408,22 +408,22 @@ self.CurrentInstance.outputs.append(self.CurrentConnection) else: self.SpecificValues.append([self.CurrentConnection]) - + def AddConnectionLink(self, context, *args): self.CurrentLink = _ConnectionLinkInfos( *(_translate_args([int, _StringValue], args) + [[]])) self.CurrentConnection.links.append(self.CurrentLink) - + def AddLinkPoint(self, context, *args): self.CurrentLink.points.append(_Point( *_translate_args([float] * 2, args))) - + def AddAction(self, context, *args): if len(self.SpecificValues) == 0: self.SpecificValues.append([[]]) translated_args = _translate_args([_StringValue] * 5, args) self.SpecificValues[0][0].append(_ActionInfos(*translated_args)) - + pou_block_instances_xslt = etree.parse( os.path.join(ScriptDirectory, "plcopen", "pou_block_instances.xslt")) @@ -461,7 +461,7 @@ self.LastSave = 0 else: self.LastSave = -1 - + # Add a new state in buffer def Buffering(self, currentstate): self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH @@ -474,29 +474,29 @@ self.LastSave = -1 self.MinIndex = (self.MinIndex + 1) % UNDO_BUFFER_LENGTH self.MinIndex = max(self.MinIndex, 0) - + # Return current state of buffer def Current(self): return self.Buffer[self.CurrentIndex] - + # Change current state to previous in buffer and return new current state def Previous(self): if self.CurrentIndex != self.MinIndex: self.CurrentIndex = (self.CurrentIndex - 1) % UNDO_BUFFER_LENGTH return self.Buffer[self.CurrentIndex] return None - + # Change current state to next in buffer and return new current state def Next(self): if self.CurrentIndex != self.MaxIndex: self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH return self.Buffer[self.CurrentIndex] return None - + # Return True if current state is the first in buffer def IsFirst(self): return self.CurrentIndex == self.MinIndex - + # Return True if current state is the last in buffer def IsLast(self): return self.CurrentIndex == self.MaxIndex @@ -504,7 +504,7 @@ # Note that current state is saved def CurrentSaved(self): self.LastSave = self.CurrentIndex - + # Return True if current state is saved def IsCurrentSaved(self): return self.LastSave == self.CurrentIndex @@ -518,12 +518,12 @@ Class which controls the operations made on the plcopen model and answers to view requests """ class PLCControler: - + # Create a new PLCControler def __init__(self): self.LastNewIndex = 0 self.Reset() - + # Reset PLCControler internal variables def Reset(self): self.Project = None @@ -541,7 +541,7 @@ self.TotalTypesDict = StdBlckDct.copy() self.TotalTypes = StdBlckLst[:] self.ProgramFilePath = "" - + def GetQualifierTypes(self): return QualifierList @@ -567,7 +567,7 @@ self.Project.setfileHeader(properties) self.Project.setcontentHeader(properties) self.SetFilePath("") - + # Initialize the project buffer self.CreateProjectBuffer(False) self.ProgramChunks = [] @@ -575,28 +575,28 @@ self.NextCompiledProject = self.Copy(self.Project) self.CurrentCompiledProject = None self.Buffering = False - + # Return project data type names def GetProjectDataTypeNames(self, debug = False): project = self.GetProject(debug) if project is not None: return [datatype.getname() for datatype in project.getdataTypes()] return [] - + # Return project pou names def GetProjectPouNames(self, debug = False): project = self.GetProject(debug) if project is not None: return [pou.getname() for pou in project.getpous()] return [] - + # Return project pou names def GetProjectConfigNames(self, debug = False): project = self.GetProject(debug) if project is not None: return [config.getname() for config in project.getconfigurations()] return [] - + # Return project pou variable names def GetProjectPouVariableNames(self, pou_name = None, debug = False): variables = [] @@ -610,15 +610,15 @@ for action in pou.getactionList(): variables.append(action.getname()) return variables - + # Return file path if project is an open file def GetFilePath(self): return self.FilePath - + # Return file path if project is an open file def GetProgramFilePath(self): return self.ProgramFilePath - + # Return file name and point out if file is up to date def GetFilename(self): if self.Project is not None: @@ -627,7 +627,7 @@ else: return "~%s~"%self.FileName return "" - + # Change file path and save file name or create a default one if file path not defined def SetFilePath(self, filepath): self.FilePath = filepath @@ -636,7 +636,7 @@ self.FileName = _("Unnamed%d")%self.LastNewIndex else: self.FileName = os.path.splitext(os.path.basename(filepath))[0] - + # Change project properties def SetProjectProperties(self, name = None, properties = None, buffer = True): if self.Project is not None: @@ -647,14 +647,14 @@ self.Project.setcontentHeader(properties) if buffer and (name is not None or properties is not None): self.BufferProject() - + # Return project name def GetProjectName(self, debug=False): project = self.GetProject(debug) if project is not None: return project.getname() return None - + # Return project properties def GetProjectProperties(self, debug = False): project = self.GetProject(debug) @@ -663,7 +663,7 @@ properties.update(project.getcontentHeader()) return properties return None - + # Return project informations def GetProjectInfos(self, debug = False): project = self.GetProject(debug) @@ -671,7 +671,7 @@ infos = {"name": project.getname(), "type": ITEM_PROJECT} datatypes = {"name": DATA_TYPES, "type": ITEM_DATATYPES, "values":[]} for datatype in project.getdataTypes(): - datatypes["values"].append({"name": datatype.getname(), "type": ITEM_DATATYPE, + datatypes["values"].append({"name": datatype.getname(), "type": ITEM_DATATYPE, "tagname": self.ComputeDataTypeName(datatype.getname()), "values": []}) pou_types = {"function": {"name": FUNCTIONS, "type": ITEM_FUNCTION, "values":[]}, "functionBlock": {"name": FUNCTION_BLOCKS, "type": ITEM_FUNCTIONBLOCK, "values":[]}, @@ -684,14 +684,14 @@ if pou.getbodyType() == "SFC": transitions = [] for transition in pou.gettransitionList(): - transitions.append({"name": transition.getname(), "type": ITEM_TRANSITION, - "tagname": self.ComputePouTransitionName(pou.getname(), transition.getname()), + transitions.append({"name": transition.getname(), "type": ITEM_TRANSITION, + "tagname": self.ComputePouTransitionName(pou.getname(), transition.getname()), "values": []}) pou_values.append({"name": TRANSITIONS, "type": ITEM_TRANSITIONS, "values": transitions}) actions = [] for action in pou.getactionList(): - actions.append({"name": action.getname(), "type": ITEM_ACTION, - "tagname": self.ComputePouActionName(pou.getname(), action.getname()), + actions.append({"name": action.getname(), "type": ITEM_ACTION, + "tagname": self.ComputePouActionName(pou.getname(), action.getname()), "values": []}) pou_values.append({"name": ACTIONS, "type": ITEM_ACTIONS, "values": actions}) if pou_type in pou_types: @@ -700,19 +700,19 @@ configurations = {"name": CONFIGURATIONS, "type": ITEM_CONFIGURATIONS, "values": []} for config in project.getconfigurations(): config_name = config.getname() - config_infos = {"name": config_name, "type": ITEM_CONFIGURATION, - "tagname": self.ComputeConfigurationName(config.getname()), + config_infos = {"name": config_name, "type": ITEM_CONFIGURATION, + "tagname": self.ComputeConfigurationName(config.getname()), "values": []} resources = {"name": RESOURCES, "type": ITEM_RESOURCES, "values": []} for resource in config.getresource(): resource_name = resource.getname() - resource_infos = {"name": resource_name, "type": ITEM_RESOURCE, - "tagname": self.ComputeConfigurationResourceName(config.getname(), resource.getname()), + resource_infos = {"name": resource_name, "type": ITEM_RESOURCE, + "tagname": self.ComputeConfigurationResourceName(config.getname(), resource.getname()), "values": []} resources["values"].append(resource_infos) config_infos["values"] = [resources] configurations["values"].append(config_infos) - infos["values"] = [datatypes, pou_types["function"], pou_types["functionBlock"], + infos["values"] = [datatypes, pou_types["function"], pou_types["functionBlock"], pou_types["program"], configurations] return infos return None @@ -722,17 +722,17 @@ project = self.GetProject(debug) if project is not None: factory = VariablesTreeInfosFactory() - + parser = etree.XMLParser() parser.resolvers.add(LibraryResolver(self, debug)) - + pou_variable_xslt_tree = etree.XSLT( etree.parse( os.path.join(ScriptDirectory, "plcopen", "pou_variables.xslt"), - parser), + parser), extensions = {("pou_vars_ns", name): getattr(factory, name) for name in ["SetRoot", "AddVariable"]}) - + obj = None words = tagname.split("::") if words[0] == "P": @@ -742,7 +742,7 @@ if obj is not None: pou_variable_xslt_tree(obj) return factory.GetRoot() - + return None def GetInstanceList(self, root, name, debug = False): @@ -750,22 +750,22 @@ project = self.GetProject(debug) if project is not None: factory = InstancesPathFactory(instances) - + parser = etree.XMLParser() parser.resolvers.add(LibraryResolver(self, debug)) - + instances_path_xslt_tree = etree.XSLT( etree.parse( os.path.join(ScriptDirectory, "plcopen", "instances_path.xslt"), - parser), + parser), extensions = { ("instances_ns", "AddInstance"): factory.AddInstance}) - - instances_path_xslt_tree(root, + + instances_path_xslt_tree(root, instance_type=etree.XSLT.strparam(name)) - + return instances - + def SearchPouInstances(self, tagname, debug = False): project = self.GetProject(debug) if project is not None: @@ -781,28 +781,28 @@ for instance in self.SearchPouInstances( self.ComputePouName(words[1]), debug)] return [] - + def GetPouInstanceTagName(self, instance_path, debug = False): project = self.GetProject(debug) factory = InstanceTagName(self) - + parser = etree.XMLParser() parser.resolvers.add(LibraryResolver(self, debug)) - + instance_tagname_xslt_tree = etree.XSLT( etree.parse( os.path.join(ScriptDirectory, "plcopen", "instance_tagname.xslt"), - parser), + parser), extensions = {("instance_tagname_ns", name): getattr(factory, name) for name in ["ConfigTagName", "ResourceTagName", - "PouTagName", "ActionTagName", + "PouTagName", "ActionTagName", "TransitionTagName"]}) - - instance_tagname_xslt_tree(project, + + instance_tagname_xslt_tree(project, instance_path=etree.XSLT.strparam(instance_path)) - + return factory.GetTagName() - + def GetInstanceInfos(self, instance_path, debug = False): tagname = self.GetPouInstanceTagName(instance_path) if tagname is not None: @@ -818,7 +818,7 @@ if var_infos.name == var_name: return var_infos return None - + # Return if data type given by name is used by another data type or pou def DataTypeIsUsed(self, name, debug = False): project = self.GetProject(debug) @@ -887,11 +887,11 @@ return infos row, col = next_row, next_col return infos - + #------------------------------------------------------------------------------- # Project Pous management functions #------------------------------------------------------------------------------- - + # Add a Data Type to Project def ProjectAddDataType(self, datatype_name=None): if self.Project is not None: @@ -902,13 +902,13 @@ self.BufferProject() return self.ComputeDataTypeName(datatype_name) return None - + # Remove a Data Type from project def ProjectRemoveDataType(self, datatype_name): if self.Project is not None: self.Project.removedataType(datatype_name) self.BufferProject() - + # Add a Pou to Project def ProjectAddPou(self, pou_name, pou_type, body_type): if self.Project is not None: @@ -919,21 +919,21 @@ self.BufferProject() return self.ComputePouName(pou_name) return None - + def ProjectChangePouType(self, name, pou_type): if self.Project is not None: pou = self.Project.getpou(name) if pou is not None: pou.setpouType(pou_type) self.BufferProject() - + def GetPouXml(self, pou_name): if self.Project is not None: pou = self.Project.getpou(pou_name) if pou is not None: return pou.tostring() return None - + def PastePou(self, pou_type, pou_xml): ''' Adds the POU defined by 'pou_xml' to the current project with type 'pou_type' @@ -944,21 +944,21 @@ error = "" if error is not None: return _("Couldn't paste non-POU object.") - + name = new_pou.getname() - + idx = 0 new_name = name - while self.Project.getpou(new_name): + while self.Project.getpou(new_name) is not None: # a POU with that name already exists. # make a new name and test if a POU with that name exists. # append an incrementing numeric suffix to the POU name. idx += 1 new_name = "%s%d" % (name, idx) - + # we've found a name that does not already exist, use it new_pou.setname(new_name) - + if pou_type is not None: orig_type = new_pou.getpouType() @@ -968,12 +968,12 @@ if orig_type == 'functionBlock' and pou_type == 'function' or \ orig_type == 'program' and pou_type in ['function', 'functionBlock']: return _('''%s "%s" can't be pasted as a %s.''') % (orig_type, name, pou_type) - + new_pou.setpouType(pou_type) - self.Project.insertpou(-1, new_pou) + self.Project.insertpou(0, new_pou) self.BufferProject() - + return self.ComputePouName(new_name), # Remove a Pou from project @@ -981,7 +981,7 @@ if self.Project is not None: self.Project.removepou(pou_name) self.BufferProject() - + # Return the name of the configuration if only one exist def GetProjectMainConfigurationName(self): if self.Project is not None: @@ -990,7 +990,7 @@ if len(configurations) == 1: return configurations[0].getname() return None - + # Add a configuration to Project def ProjectAddConfiguration(self, config_name=None): if self.Project is not None: @@ -1000,13 +1000,13 @@ self.BufferProject() return self.ComputeConfigurationName(config_name) return None - + # Remove a configuration from project def ProjectRemoveConfiguration(self, config_name): if self.Project is not None: self.Project.removeconfiguration(config_name) self.BufferProject() - + # Add a resource to a configuration of the Project def ProjectAddConfigurationResource(self, config_name, resource_name=None): if self.Project is not None: @@ -1016,13 +1016,13 @@ self.BufferProject() return self.ComputeConfigurationResourceName(config_name, resource_name) return None - + # Remove a resource from a configuration of the project def ProjectRemoveConfigurationResource(self, config_name, resource_name): if self.Project is not None: self.Project.removeconfigurationResource(config_name, resource_name) self.BufferProject() - + # Add a Transition to a Project Pou def ProjectAddPouTransition(self, pou_name, transition_name, transition_type): if self.Project is not None: @@ -1032,7 +1032,7 @@ self.BufferProject() return self.ComputePouTransitionName(pou_name, transition_name) return None - + # Remove a Transition from a Project Pou def ProjectRemovePouTransition(self, pou_name, transition_name): # Search if the pou removed is currently opened @@ -1041,7 +1041,7 @@ if pou is not None: pou.removetransition(transition_name) self.BufferProject() - + # Add an Action to a Project Pou def ProjectAddPouAction(self, pou_name, action_name, action_type): if self.Project is not None: @@ -1051,7 +1051,7 @@ self.BufferProject() return self.ComputePouActionName(pou_name, action_name) return None - + # Remove an Action from a Project Pou def ProjectRemovePouAction(self, pou_name, action_name): # Search if the pou removed is currently opened @@ -1060,7 +1060,7 @@ if pou is not None: pou.removeaction(action_name) self.BufferProject() - + # Change the name of a pou def ChangeDataTypeName(self, old_name, new_name): if self.Project is not None: @@ -1070,7 +1070,7 @@ datatype.setname(new_name) self.Project.updateElementName(old_name, new_name) self.BufferProject() - + # Change the name of a pou def ChangePouName(self, old_name, new_name): if self.Project is not None: @@ -1080,7 +1080,7 @@ pou.setname(new_name) self.Project.updateElementName(old_name, new_name) self.BufferProject() - + # Change the name of a pou transition def ChangePouTransitionName(self, pou_name, old_name, new_name): if self.Project is not None: @@ -1092,7 +1092,7 @@ transition.setname(new_name) pou.updateElementName(old_name, new_name) self.BufferProject() - + # Change the name of a pou action def ChangePouActionName(self, pou_name, old_name, new_name): if self.Project is not None: @@ -1104,7 +1104,7 @@ action.setname(new_name) pou.updateElementName(old_name, new_name) self.BufferProject() - + # Change the name of a pou variable def ChangePouVariableName(self, pou_name, old_name, new_name): if self.Project is not None: @@ -1116,7 +1116,7 @@ if var.getname() == old_name: var.setname(new_name) self.BufferProject() - + # Change the name of a configuration def ChangeConfigurationName(self, old_name, new_name): if self.Project is not None: @@ -1125,7 +1125,7 @@ if configuration is not None: configuration.setname(new_name) self.BufferProject() - + # Change the name of a configuration resource def ChangeConfigurationResourceName(self, config_name, old_name, new_name): if self.Project is not None: @@ -1134,7 +1134,7 @@ if resource is not None: resource.setname(new_name) self.BufferProject() - + # Return the description of the pou given by its name def GetPouDescription(self, name, debug = False): project = self.GetProject(debug) @@ -1144,7 +1144,7 @@ if pou is not None: return pou.getdescription() return "" - + # Return the description of the pou given by its name def SetPouDescription(self, name, description, debug = False): project = self.GetProject(debug) @@ -1154,7 +1154,7 @@ if pou is not None: pou.setdescription(description) self.BufferProject() - + # Return the type of the pou given by its name def GetPouType(self, name, debug = False): project = self.GetProject(debug) @@ -1164,7 +1164,7 @@ if pou is not None: return pou.getpouType() return None - + # Return pous with SFC language def GetSFCPous(self, debug = False): list = [] @@ -1174,7 +1174,7 @@ if pou.getBodyType() == "SFC": list.append(pou.getname()) return list - + # Return the body language of the pou given by its name def GetPouBodyType(self, name, debug = False): project = self.GetProject(debug) @@ -1184,7 +1184,7 @@ if pou is not None: return pou.getbodyType() return None - + # Return the actions of a pou def GetPouTransitions(self, pou_name, debug = False): transitions = [] @@ -1196,7 +1196,7 @@ for transition in pou.gettransitionList(): transitions.append(transition.getname()) return transitions - + # Return the body language of the transition given by its name def GetTransitionBodyType(self, pou_name, pou_transition, debug = False): project = self.GetProject(debug) @@ -1209,7 +1209,7 @@ if transition is not None: return transition.getbodyType() return None - + # Return the actions of a pou def GetPouActions(self, pou_name, debug = False): actions = [] @@ -1221,7 +1221,7 @@ for action in pou.getactionList(): actions.append(action.getname()) return actions - + # Return the body language of the pou given by its name def GetActionBodyType(self, pou_name, pou_action, debug = False): project = self.GetProject(debug) @@ -1233,18 +1233,18 @@ if action is not None: return action.getbodyType() return None - + # Extract varlists from a list of vars def ExtractVarLists(self, vars): varlist_list = [] current_varlist = None current_type = None for var in vars: - next_type = (var.Class, - var.Option, - var.Location in ["", None] or - # When declaring globals, located - # and not located variables are + next_type = (var.Class, + var.Option, + var.Location in ["", None] or + # When declaring globals, located + # and not located variables are # in the same declaration block var.Class == "Global") if current_type != next_type: @@ -1264,7 +1264,7 @@ # Create variable and change its properties tempvar = PLCOpenParser.CreateElement("variable", "varListPlain") tempvar.setname(var.Name) - + var_type = PLCOpenParser.CreateElement("type", "variable") if isinstance(var.Type, TupleType): if var.Type[0] == "array": @@ -1317,28 +1317,28 @@ # Add variable to varList current_varlist.appendvariable(tempvar) return varlist_list - + def GetVariableDictionary(self, object_with_vars, tree=False, debug=False): variables = [] factory = VariablesInfosFactory(variables) - + parser = etree.XMLParser() parser.resolvers.add(LibraryResolver(self, debug)) - + variables_infos_xslt_tree = etree.XSLT( etree.parse( os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt"), - parser), + parser), extensions = {("var_infos_ns", name): getattr(factory, name) for name in ["SetType", "AddDimension", "AddTree", "AddVarToTree", "AddVariable"]}) variables_infos_xslt_tree(object_with_vars, tree=etree.XSLT.strparam(str(tree))) - + return variables - + # Add a global var to configuration to configuration - def AddConfigurationGlobalVar(self, config_name, var_type, var_name, + def AddConfigurationGlobalVar(self, config_name, var_type, var_name, location="", description=""): if self.Project is not None: # Found the configuration corresponding to name @@ -1346,7 +1346,7 @@ if configuration is not None: # Set configuration global vars configuration.addglobalVar( - self.GetVarTypeObject(var_type), + self.GetVarTypeObject(var_type), var_name, location, description) # Replace the configuration globalvars by those given @@ -1359,7 +1359,7 @@ configuration.setglobalVars([ varlist for vartype, varlist in self.ExtractVarLists(vars)]) - + # Return the configuration globalvars def GetConfigurationGlobalVars(self, name, debug = False): project = self.GetProject(debug) @@ -1369,7 +1369,7 @@ if configuration is not None: # Extract variables defined in configuration return self.GetVariableDictionary(configuration, debug) - + return [] # Return configuration variable names @@ -1381,7 +1381,7 @@ if config_name is None or config_name == configuration.getname(): variables.extend( [var.getname() for var in reduce( - lambda x, y: x + y, [varlist.getvariable() + lambda x, y: x + y, [varlist.getvariable() for varlist in configuration.globalVars], [])]) return variables @@ -1396,7 +1396,7 @@ resource.setglobalVars([ varlist for vartype, varlist in self.ExtractVarLists(vars)]) - + # Return the resource globalvars def GetConfigurationResourceGlobalVars(self, config_name, name, debug = False): project = self.GetProject(debug) @@ -1406,11 +1406,11 @@ if resource is not None: # Extract variables defined in configuration return self.GetVariableDictionary(resource, debug) - + return [] - + # Return resource variable names - def GetConfigurationResourceVariableNames(self, + def GetConfigurationResourceVariableNames(self, config_name = None, resource_name = None, debug = False): variables = [] project = self.GetProject(debug) @@ -1421,7 +1421,7 @@ if resource_name is None or resource.getname() == resource_name: variables.extend( [var.getname() for var in reduce( - lambda x, y: x + y, [varlist.getvariable() + lambda x, y: x + y, [varlist.getvariable() for varlist in resource.globalVars], [])]) return variables @@ -1445,7 +1445,7 @@ pou.interface = PLCOpenParser.CreateElement("interface", "pou") # Set Pou interface pou.setvars([varlist for varlist_type, varlist in self.ExtractVarLists(vars)]) - + # Replace the return type of the pou given by its name (only for functions) def SetPouInterfaceReturnType(self, name, return_type): if self.Project is not None: @@ -1468,16 +1468,16 @@ derived_type = PLCOpenParser.CreateElement("derived", "dataType") derived_type.setname(return_type) return_type.setcontent(derived_type) - + def UpdateProjectUsedPous(self, old_name, new_name): if self.Project is not None: self.Project.updateElementName(old_name, new_name) - + def UpdateEditedElementUsedVariable(self, tagname, old_name, new_name): pou = self.GetEditedElement(tagname) if pou is not None: pou.updateElementName(old_name, new_name) - + # Return the return type of the given pou def GetPouInterfaceReturnType(self, pou, tree=False, debug=False): # Verify that the pou has an interface @@ -1486,23 +1486,23 @@ return_type = pou.interface.getreturnType() if return_type is not None: factory = VariablesInfosFactory([]) - + parser = etree.XMLParser() parser.resolvers.add(LibraryResolver(self)) - + return_type_infos_xslt_tree = etree.XSLT( etree.parse( os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt"), - parser), + parser), extensions = {("var_infos_ns", name): getattr(factory, name) - for name in ["SetType", "AddDimension", + for name in ["SetType", "AddDimension", "AddTree", "AddVarToTree"]}) return_type_infos_xslt_tree(return_type, tree=etree.XSLT.strparam(str(tree))) if tree: return [factory.GetType(), factory.GetTree()] return factory.GetType() - + if tree: return [None, ([], [])] return None @@ -1519,7 +1519,7 @@ for desc in cat["list"]: BlkLst = self.TotalTypesDict.setdefault(desc["name"],[]) BlkLst.append((section["name"], desc)) - + # Function that clear the confnode list def ClearConfNodeTypes(self): self.ConfNodeTypes = [] @@ -1529,11 +1529,11 @@ def GetConfNodeDataTypes(self, exclude = None, only_locatables = False): return [{"name": _("%s Data Types") % confnodetypes["name"], "list": [ - datatype.getname() + datatype.getname() for datatype in confnodetypes["types"].getdataTypes() if not only_locatables or self.IsLocatableDataType(datatype, debug)]} for confnodetypes in self.ConfNodeTypes] - + def GetVariableLocationTree(self): return [] @@ -1545,7 +1545,7 @@ for var_name, var_type, var_initial in self.GetConfNodeGlobalInstances(): tempvar = PLCOpenParser.CreateElement("variable", "globalVars") tempvar.setname(var_name) - + tempvartype = PLCOpenParser.CreateElement("type", "variable") if var_type in self.GetBaseTypes(): tempvartype.setcontent(PLCOpenParser.CreateElement( @@ -1557,12 +1557,12 @@ tempderivedtype.setname(var_type) tempvartype.setcontent(tempderivedtype) tempvar.settype(tempvartype) - + if var_initial != "": value = PLCOpenParser.CreateElement("initialValue", "variable") value.setvalue(var_initial) tempvar.setinitialValue(value) - + global_vars.append(tempvar) return global_vars @@ -1592,11 +1592,11 @@ blocktype_infos = blocktype.getblockInfos() if inputs in [None, "undefined"]: return blocktype_infos - - if inputs == tuple([var_type + + if inputs == tuple([var_type for name, var_type, modifier in blocktype_infos["inputs"]]): return blocktype_infos - + return None # Return Block types checking for recursion @@ -1610,18 +1610,18 @@ if words[0] in ["P","T","A"]: name = words[1] pou_type = self.GetPouType(name, debug) - filter = (["function"] - if pou_type == "function" or words[0] == "T" + filter = (["function"] + if pou_type == "function" or words[0] == "T" else ["functionBlock", "function"]) blocktypes = [ {"name": category["name"], "list": [block for block in category["list"] if block["type"] in filter]} for category in self.TotalTypes] - blocktypes.append({"name" : USER_DEFINED_POUS, + blocktypes.append({"name" : USER_DEFINED_POUS, "list": [pou.getblockInfos() for pou in project.getpous(name, filter) - if (name is None or + if (name is None or len(self.GetInstanceList(pou, name, debug)) == 0)]}) return blocktypes return self.TotalTypes @@ -1641,7 +1641,7 @@ if project is not None: blocktypes.extend([pou.getname() for pou in project.getpous(name, ["functionBlock"]) - if (name is None or + if (name is None or len(self.GetInstanceList(pou, name, debug)) == 0)]) return blocktypes @@ -1672,10 +1672,10 @@ if words[0] in ["D"]: name = words[1] datatypes.extend([ - datatype.getname() + datatype.getname() for datatype in project.getdataTypes(name) if (not only_locatables or self.IsLocatableDataType(datatype, debug)) - and (name is None or + and (name is None or len(self.GetInstanceList(datatype, name, debug)) == 0)]) if confnodetypes: for category in self.GetConfNodeDataTypes(name, only_locatables): @@ -1730,14 +1730,14 @@ def GetBaseType(self, typename, debug = False): if TypeHierarchy.has_key(typename): return typename - + datatype = self.GetDataType(typename, debug) if datatype is not None: basetype = self.GetDataTypeBaseType(datatype) if basetype is not None: return self.GetBaseType(basetype, debug) return typename - + return None def GetBaseTypes(self): @@ -1751,19 +1751,19 @@ def IsOfType(self, typename, reference, debug = False): if reference is None or typename == reference: return True - + basetype = TypeHierarchy.get(typename) if basetype is not None: return self.IsOfType(basetype, reference) - + datatype = self.GetDataType(typename, debug) if datatype is not None: basetype = self.GetDataTypeBaseType(datatype) if basetype is not None: return self.IsOfType(basetype, reference, debug) - + return False - + def IsEndType(self, typename): if typename is not None: return not typename.startswith("ANY") @@ -1781,16 +1781,16 @@ if array_base_type.getLocalTag() == "derived": return self.IsLocatableType(array_base_type.getname(), debug) return True - + def IsLocatableType(self, typename, debug = False): if isinstance(typename, TupleType) or self.GetBlockType(typename) is not None: return False - + datatype = self.GetDataType(typename, debug) if datatype is not None: return self.IsLocatableDataType(datatype) return True - + def IsEnumeratedType(self, typename, debug = False): if isinstance(typename, TupleType): typename = typename[1] @@ -1822,7 +1822,7 @@ def IsNumType(self, typename, debug = False): return self.IsOfType(typename, "ANY_NUM", debug) or\ self.IsOfType(typename, "ANY_BIT", debug) - + def GetDataTypeRange(self, typename, debug = False): range = DataTypeRange.get(typename) if range is not None: @@ -1837,7 +1837,7 @@ elif basetype_content_type == "derived": return self.GetDataTypeRange(basetype_content.getname(), debug) return None - + # Return Subrange types def GetSubrangeBaseTypes(self, exclude, debug = False): subrange_basetypes = DataTypeRange.keys() @@ -1851,7 +1851,7 @@ [datatype.getname() for datatype in confnodetype["types"].getdataTypes() if self.IsSubrangeType(datatype.getname(), exclude, debug)]) return subrange_basetypes - + # Return Enumerated Values def GetEnumeratedDataValues(self, typename = None, debug = False): values = [] @@ -1861,7 +1861,7 @@ basetype_content = datatype_obj.baseType.getcontent() basetype_content_type = basetype_content.getLocalTag() if basetype_content_type == "enum": - return [value.getname() + return [value.getname() for value in basetype_content.xpath( "ppx:values/ppx:value", namespaces=PLCOpenParser.NSMAP)] @@ -1878,19 +1878,19 @@ #------------------------------------------------------------------------------- # Project Element tag name computation functions #------------------------------------------------------------------------------- - + # Compute a data type name def ComputeDataTypeName(self, datatype): return "D::%s" % datatype - + # Compute a pou name def ComputePouName(self, pou): return "P::%s" % pou - + # Compute a pou transition name def ComputePouTransitionName(self, pou, transition): return "T::%s::%s" % (pou, transition) - + # Compute a pou action name def ComputePouActionName(self, pou, action): return "A::%s::%s" % (pou, action) @@ -1905,7 +1905,7 @@ def GetElementType(self, tagname): words = tagname.split("::") - return {"D" : ITEM_DATATYPE, "P" : ITEM_POU, + return {"D" : ITEM_DATATYPE, "P" : ITEM_POU, "T" : ITEM_TRANSITION, "A" : ITEM_ACTION, "C" : ITEM_CONFIGURATION, "R" : ITEM_RESOURCE}[words[0]] @@ -1963,7 +1963,7 @@ dimensions.append((dimension.getlower(), dimension.getupper())) base_type = element_type.baseType.getcontent() base_type_type = element_type.getLocalTag() - element_infos["Type"] = ("array", + element_infos["Type"] = ("array", base_type.getname() if base_type_type == "derived" else base_type_type.upper(), dimensions) @@ -1981,14 +1981,14 @@ infos["base_type"] = (basetype_content.getname() if basetype_content_type == "derived" else basetype_content_type.upper()) - + if datatype.initialValue is not None: infos["initial"] = str(datatype.initialValue.getvalue()) else: infos["initial"] = "" return infos return None - + # Change the data type informations def SetDataTypeInfos(self, tagname, infos): words = tagname.split("::") @@ -2006,7 +2006,7 @@ datatype.baseType.setcontent(derived_datatype) elif infos["type"] == "Subrange": subrange = PLCOpenParser.CreateElement( - "subrangeUnsigned" + "subrangeUnsigned" if infos["base_type"] in GetSubTypes("ANY_UINT") else "subrangeSigned", "dataType") datatype.baseType.setcontent(subrange) @@ -2106,7 +2106,7 @@ else: datatype.initialValue = None self.BufferProject() - + #------------------------------------------------------------------------------- # Project opened Pous management functions #------------------------------------------------------------------------------- @@ -2132,7 +2132,7 @@ elif words[0] == 'R': return project.getconfigurationResource(words[1], words[2]) return None - + # Return edited element name def GetEditedElementName(self, tagname): words = tagname.split("::") @@ -2141,7 +2141,7 @@ else: return words[2] return None - + # Return edited element name and type def GetEditedElementType(self, tagname, debug = False): words = tagname.split("::") @@ -2183,14 +2183,14 @@ elif words[0] == 'T': return "BOOL" return None - + # Change the edited element text def SetEditedElementText(self, tagname, text): if self.Project is not None: element = self.GetEditedElement(tagname) if element is not None: element.settext(text) - + # Return the edited element text def GetEditedElementText(self, tagname, debug = False): element = self.GetEditedElement(tagname, debug) @@ -2236,13 +2236,13 @@ if element is not None: return element.tostring() return "" - + def GetEditedElementInstancesCopy(self, tagname, blocks_id = None, wires = None, debug = False): element = self.GetEditedElement(tagname, debug) text = "" if element is not None: - wires = dict([(wire, True) - for wire in wires + wires = dict([(wire, True) + for wire in wires if wire[0] in blocks_id and wire[1] in blocks_id]) copy_body = PLCOpenParser.CreateElement("body", "pou") element.append(copy_body) @@ -2257,20 +2257,20 @@ text += instance_copy.tostring() element.remove(copy_body) return text - + def GenerateNewName(self, tagname, name, format, start_idx=0, exclude={}, debug=False): names = exclude.copy() if tagname is not None: - names.update(dict([(varname.upper(), True) + names.update(dict([(varname.upper(), True) for varname in self.GetEditedElementVariables(tagname, debug)])) words = tagname.split("::") if words[0] in ["P","T","A"]: element = self.GetEditedElement(tagname, debug) if element is not None and element.getbodyType() not in ["ST", "IL"]: for instance in element.getinstances(): - if isinstance(instance, - (PLCOpenParser.GetElementClass("step", "sfcObjects"), - PLCOpenParser.GetElementClass("connector", "commonObjects"), + if isinstance(instance, + (PLCOpenParser.GetElementClass("step", "sfcObjects"), + PLCOpenParser.GetElementClass("connector", "commonObjects"), PLCOpenParser.GetElementClass("continuation", "commonObjects"))): names[instance.getname().upper()] = True else: @@ -2290,37 +2290,37 @@ names[config.getname().upper()] = True for resource in config.getresource(): names[resource.getname().upper()] = True - + i = start_idx while name is None or names.get(name.upper(), False): name = (format%i) i += 1 return name - + def PasteEditedElementInstances(self, tagname, text, new_pos, middle=False, debug=False): element = self.GetEditedElement(tagname, debug) element_name, element_type = self.GetEditedElementType(tagname, debug) if element is not None: bodytype = element.getbodyType() - + # Get edited element type scaling scaling = None project = self.GetProject(debug) if project is not None: properties = project.getcontentHeader() scaling = properties["scaling"][bodytype] - + # Get ids already by all the instances in edited element used_id = dict([(instance.getlocalId(), True) for instance in element.getinstances()]) new_id = {} - + try: instances, error = LoadPouInstances(text.encode("utf-8"), bodytype) except: instances, error = [], "" if error is not None or len(instances) == 0: return _("Invalid plcopen element(s)!!!") - + exclude = {} for instance in instances: element.addinstance(instance) @@ -2332,25 +2332,25 @@ if blocktype_infos["type"] != "function" and blockname is not None: if element_type == "function": return _("FunctionBlock \"%s\" can't be pasted in a Function!!!")%blocktype - blockname = self.GenerateNewName(tagname, - blockname, - "%s%%d"%blocktype, + blockname = self.GenerateNewName(tagname, + blockname, + "%s%%d"%blocktype, debug=debug) exclude[blockname] = True instance.setinstanceName(blockname) self.AddEditedElementPouVar(tagname, blocktype, blockname) elif instance_type == "step": - stepname = self.GenerateNewName(tagname, - instance.getname(), - "Step%d", - exclude=exclude, + stepname = self.GenerateNewName(tagname, + instance.getname(), + "Step%d", + exclude=exclude, debug=debug) exclude[stepname] = True instance.setname(stepname) localid = instance.getlocalId() if not used_id.has_key(localid): new_id[localid] = True - + idx = 1 translate_id = {} bbox = rect() @@ -2363,7 +2363,7 @@ new_id[idx] = True instance.setlocalId(idx) translate_id[localId] = idx - + x, y, width, height = bbox.bounding_box() if middle: new_pos[0] -= width / 2 @@ -2385,43 +2385,43 @@ else: new_pos = (max(30, new_pos[0]), max(30, new_pos[1])) diff = (int(new_pos[0] - x), int(new_pos[1] - y)) - + connections = {} for instance in instances: connections.update(instance.updateConnectionsId(translate_id)) if getattr(instance, "setexecutionOrderId", None) is not None: instance.setexecutionOrderId(0) instance.translate(*diff) - + return new_id, connections - + def GetEditedElementInstancesInfos(self, tagname, debug = False): element_instances = OrderedDict() element = self.GetEditedElement(tagname, debug) if element is not None: factory = BlockInstanceFactory(element_instances) - + pou_block_instances_xslt_tree = etree.XSLT( - pou_block_instances_xslt, + pou_block_instances_xslt, extensions = { ("pou_block_instances_ns", name): getattr(factory, name) for name in ["AddBlockInstance", "SetSpecificValues", "AddInstanceConnection", "AddConnectionLink", "AddLinkPoint", "AddAction"]}) - + pou_block_instances_xslt_tree(element) return element_instances - + def ClearEditedElementExecutionOrder(self, tagname): element = self.GetEditedElement(tagname) if element is not None: element.resetexecutionOrder() - + def ResetEditedElementExecutionOrder(self, tagname): element = self.GetEditedElement(tagname) if element is not None: element.compileexecutionOrder() - + def SetConnectionWires(self, connection, connector): wires = connector.GetWires() idx = 0 @@ -2443,7 +2443,7 @@ else: connection.setconnectionParameter(idx, None) idx += 1 - + def GetVarTypeObject(self, var_type): var_type_obj = PLCOpenParser.CreateElement("type", "variable") if not var_type.startswith("ANY") and TypeHierarchy.get(var_type): @@ -2455,7 +2455,7 @@ derived_type.setname(var_type) var_type_obj.setcontent(derived_type) return var_type_obj - + def AddEditedElementPouVar(self, tagname, var_type, name,**args): if self.Project is not None: words = tagname.split("::") @@ -2463,9 +2463,9 @@ pou = self.Project.getpou(words[1]) if pou is not None: pou.addpouLocalVar( - self.GetVarTypeObject(var_type), + self.GetVarTypeObject(var_type), name, **args) - + def AddEditedElementPouExternalVar(self, tagname, var_type, name): if self.Project is not None: words = tagname.split("::") @@ -2474,7 +2474,7 @@ if pou is not None: pou.addpouExternalVar( self.GetVarTypeObject(var_type), name) - + def ChangeEditedElementPouVar(self, tagname, old_type, old_name, new_type, new_name): if self.Project is not None: words = tagname.split("::") @@ -2482,7 +2482,7 @@ pou = self.Project.getpou(words[1]) if pou is not None: pou.changepouVar(old_type, old_name, new_type, new_name) - + def RemoveEditedElementPouVar(self, tagname, type, name): if self.Project is not None: words = tagname.split("::") @@ -2490,7 +2490,7 @@ pou = self.Project.getpou(words[1]) if pou is not None: pou.removepouVar(type, name) - + def AddEditedElementBlock(self, tagname, id, blocktype, blockname = None): element = self.GetEditedElement(tagname) if element is not None: @@ -2502,13 +2502,13 @@ block.setinstanceName(blockname) self.AddEditedElementPouVar(tagname, blocktype, blockname) element.addinstance(block) - + def SetEditedElementBlockInfos(self, tagname, id, infos): element = self.GetEditedElement(tagname) if element is not None: block = element.getinstance(id) if block is None: - return + return old_name = block.getinstanceName() old_type = block.gettypeName() new_name = infos.get("name", old_name) @@ -2571,7 +2571,7 @@ variable.addconnectionPointOut() variable.connectionPointOut.setrelPositionXY(position.x, position.y) block.tostring() - + def AddEditedElementVariable(self, tagname, id, var_type): element = self.GetEditedElement(tagname) if element is not None: @@ -2581,13 +2581,13 @@ INOUT: "inOutVariable"}[var_type], "fbdObjects") variable.setlocalId(id) element.addinstance(variable) - + def SetEditedElementVariableInfos(self, tagname, id, infos): element = self.GetEditedElement(tagname) if element is not None: variable = element.getinstance(id) if variable is None: - return + return for param, value in infos.items(): if param == "name": variable.setexpression(value) @@ -2634,7 +2634,7 @@ CONTINUATION: "continuation"}[connection_type], "commonObjects") connection.setlocalId(id) element.addinstance(connection) - + def SetEditedElementConnectionInfos(self, tagname, id, infos): element = self.GetEditedElement(tagname) if element is not None: @@ -2643,7 +2643,7 @@ return for param, value in infos.items(): if param == "name": - connection.setname(value) + connection.setname(value) elif param == "height": connection.setheight(value) elif param == "width": @@ -2668,7 +2668,7 @@ comment = PLCOpenParser.CreateElement("comment", "commonObjects") comment.setlocalId(id) element.addinstance(comment) - + def SetEditedElementCommentInfos(self, tagname, id, infos): element = self.GetEditedElement(tagname) if element is not None: @@ -2693,7 +2693,7 @@ RIGHTRAIL: "rightPowerRail"}[powerrail_type], "ldObjects") powerrail.setlocalId(id) element.addinstance(powerrail) - + def SetEditedElementPowerRailInfos(self, tagname, id, infos): element = self.GetEditedElement(tagname) if element is not None: @@ -2725,7 +2725,7 @@ powerrail.appendconnectionPointIn(connection) connection.setrelPositionXY(position.x, position.y) self.SetConnectionWires(connection, connector) - + def AddEditedElementContact(self, tagname, id): element = self.GetEditedElement(tagname) if element is not None: @@ -2821,7 +2821,7 @@ step = PLCOpenParser.CreateElement("step", "sfcObjects") step.setlocalId(id) element.addinstance(step) - + def SetEditedElementStepInfos(self, tagname, id, infos): element = self.GetEditedElement(tagname) if element is not None: @@ -2864,14 +2864,14 @@ step.connectionPointOutAction.setrelPositionXY(position.x, position.y) else: step.deleteconnectionPointOutAction() - + def AddEditedElementTransition(self, tagname, id): element = self.GetEditedElement(tagname) if element is not None: transition = PLCOpenParser.CreateElement("transition", "sfcObjects") transition.setlocalId(id) element.addinstance(transition) - + def SetEditedElementTransitionInfos(self, tagname, id, infos): element = self.GetEditedElement(tagname) if element is not None: @@ -2907,7 +2907,7 @@ elif infos.get("type", None) == "connection" and param == "connection" and value: transition.setconditionContent("connection", None) self.SetConnectionWires(transition.condition.content, value) - + def AddEditedElementDivergence(self, tagname, id, divergence_type): element = self.GetEditedElement(tagname) if element is not None: @@ -2919,19 +2919,19 @@ divergence_type), "sfcObjects") divergence.setlocalId(id) element.addinstance(divergence) - + DivergenceTypes = [ - (divergence_type, + (divergence_type, PLCOpenParser.GetElementClass(divergence_type, "sfcObjects")) for divergence_type in ["selectionDivergence", "simultaneousDivergence", "selectionConvergence", "simultaneousConvergence"]] - + def GetDivergenceType(self, divergence): for divergence_type, divergence_class in self.DivergenceTypes: if isinstance(divergence, divergence_class): return divergence_type return None - + def SetEditedElementDivergenceInfos(self, tagname, id, infos): element = self.GetEditedElement(tagname) if element is not None: @@ -2975,14 +2975,14 @@ connection = PLCOpenParser.CreateElement("connectionPointOut", divergence_type) divergence.appendconnectionPointOut(connection) connection.setrelPositionXY(position.x, position.y) - + def AddEditedElementJump(self, tagname, id): element = self.GetEditedElement(tagname) if element is not None: jump = PLCOpenParser.CreateElement("jumpStep", "sfcObjects") jump.setlocalId(id) element.addinstance(jump) - + def SetEditedElementJumpInfos(self, tagname, id, infos): element = self.GetEditedElement(tagname) if element is not None: @@ -3005,14 +3005,14 @@ jump.addconnectionPointIn() jump.connectionPointIn.setrelPositionXY(position.x, position.y) self.SetConnectionWires(jump.connectionPointIn, value) - + def AddEditedElementActionBlock(self, tagname, id): element = self.GetEditedElement(tagname) if element is not None: actionBlock = PLCOpenParser.CreateElement("actionBlock", "commonObjects") actionBlock.setlocalId(id) element.addinstance(actionBlock) - + def SetEditedElementActionBlockInfos(self, tagname, id, infos): element = self.GetEditedElement(tagname) if element is not None: @@ -3035,7 +3035,7 @@ actionBlock.addconnectionPointIn() actionBlock.connectionPointIn.setrelPositionXY(position.x, position.y) self.SetConnectionWires(actionBlock.connectionPointIn, value) - + def RemoveEditedElementInstance(self, tagname, id): element = self.GetEditedElement(tagname) if element is not None: @@ -3162,19 +3162,19 @@ self.Buffering = False self.CurrentElementEditing = None return error - + def SaveXMLFile(self, filepath = None): if not filepath and self.FilePath == "": return False else: contentheader = {"modificationDateTime": datetime.datetime(*localtime()[:6])} self.Project.setcontentHeader(contentheader) - + if filepath: SaveProject(self.Project, filepath) else: SaveProject(self.Project, self.FilePath) - + self.MarkProjectAsSaved() if filepath: self.SetFilePath(filepath) @@ -3233,7 +3233,7 @@ self.Buffering = True else: self.ProjectSaved = False - + def EndBuffering(self): if self.ProjectBuffer is not None and self.Buffering: self.ProjectBuffer.Buffering(PLCOpenParser.Dumps(self.Project)) @@ -3245,7 +3245,7 @@ self.ProjectBuffer.CurrentSaved() else: self.ProjectSaved = True - + # Return if project is saved def ProjectIsSaved(self): if self.ProjectBuffer is not None: @@ -3257,11 +3257,11 @@ self.EndBuffering() if self.ProjectBuffer is not None: self.Project = PLCOpenParser.Loads(self.ProjectBuffer.Previous()) - + def LoadNext(self): if self.ProjectBuffer is not None: self.Project = PLCOpenParser.Loads(self.ProjectBuffer.Next()) - + def GetBufferState(self): if self.ProjectBuffer is not None: first = self.ProjectBuffer.IsFirst() and not self.Buffering diff -r 86797748c2a2 -r f65ab5ff91d1 ProjectController.py --- a/ProjectController.py Mon May 26 14:44:03 2014 +0100 +++ b/ProjectController.py Fri Jun 06 18:30:49 2014 +0100 @@ -1,5 +1,5 @@ """ -Beremiz Project Controller +Beremiz Project Controller """ import os,sys,traceback import time @@ -63,14 +63,14 @@ class ProjectController(ConfigTreeNode, PLCControler): """ - This class define Root object of the confnode tree. + This class define Root object of the confnode tree. It is responsible of : - Managing project directory - Building project - Handling PLCOpenEditor controler and view - Loading user confnodes and instanciante them as children - ... - + """ # For root object, available Children Types are modules of the confnode packages. @@ -87,15 +87,15 @@ """+targets.GetTargetChoices()+""" - - """+((""" + """+((""" + """+"\n".join(['' + 'type="xsd:boolean" use="optional" default="true"/>' for libname,lib in features.libraries])+""" - """) if len(features.libraries)>0 else '') + """ - + + """) if len(features.libraries)>0 else '') + """ @@ -104,7 +104,7 @@ """ EditorType = ProjectNodeEditor - + def __init__(self, frame, logger): PLCControler.__init__(self) @@ -115,10 +115,10 @@ self.DebugValuesBuffers = [] self.DebugTicks = [] self.SetAppFrame(frame, logger) - + self.iec2c_path = os.path.join(base_folder, "matiec", "iec2c"+(".exe" if wx.Platform == '__WXMSW__' else "")) self.ieclib_path = os.path.join(base_folder, "matiec", "lib") - + # Setup debug information self.IECdebug_datas = {} self.IECdebug_lock = Lock() @@ -147,7 +147,7 @@ if self.DebugTimer: self.DebugTimer.cancel() self.KillDebugThread() - + def LoadLibraries(self): self.Libraries = [] TypeStack=[] @@ -156,7 +156,7 @@ Lib = GetClassImporter(clsname)()(self, libname, TypeStack) TypeStack.append(Lib.GetTypes()) self.Libraries.append(Lib) - + def SetAppFrame(self, frame, logger): self.AppFrame = frame self.logger = logger @@ -164,23 +164,23 @@ if self.DispatchDebugValuesTimer is not None: self.DispatchDebugValuesTimer.Stop() self.DispatchDebugValuesTimer = None - + if frame is not None: - + # Timer to pull PLC status self.StatusTimer = wx.Timer(self.AppFrame, -1) - self.AppFrame.Bind(wx.EVT_TIMER, + self.AppFrame.Bind(wx.EVT_TIMER, self.PullPLCStatusProc, self.StatusTimer) if self._connector is not None: frame.LogViewer.SetLogSource(self._connector) self.StatusTimer.Start(milliseconds=500, oneShot=False) - + # Timer to dispatch debug values to consumers self.DispatchDebugValuesTimer = wx.Timer(self.AppFrame, -1) - self.AppFrame.Bind(wx.EVT_TIMER, + self.AppFrame.Bind(wx.EVT_TIMER, self.DispatchDebugValuesProc, self.DispatchDebugValuesTimer) - + self.RefreshConfNodesBlockLists() def ResetAppFrame(self, logger): @@ -188,7 +188,7 @@ self.AppFrame.Unbind(wx.EVT_TIMER, self.StatusTimer) self.StatusTimer = None self.AppFrame = None - + self.logger = logger def CTNName(self): @@ -205,16 +205,16 @@ def GetIECLibPath(self): return self.ieclib_path - + def GetIEC2cPath(self): return self.iec2c_path - + def GetCurrentLocation(self): return () def GetCurrentName(self): return "" - + def _GetCurrentName(self): return "" @@ -223,10 +223,10 @@ def GetProjectName(self): return os.path.split(self.ProjectPath)[1] - + def GetIconName(self): return "PROJECT" - + def GetDefaultTargetName(self): if wx.Platform == '__WXMSW__': return "Win32" @@ -242,15 +242,15 @@ target_name = self.GetDefaultTargetName() target.setcontent(self.Parser.CreateElement(target_name, "TargetType")) return target - + def GetParamsAttributes(self, path = None): params = ConfigTreeNode.GetParamsAttributes(self, path) if params[0]["name"] == "BeremizRoot": for child in params[0]["children"]: if child["name"] == "TargetType" and child["value"] == '': - child.update(self.GetTarget().getElementInfos("TargetType")) + child.update(self.GetTarget().getElementInfos("TargetType")) return params - + def SetParamsAttribute(self, path, value): if path.startswith("BeremizRoot.TargetType.") and self.BeremizRoot.getTargetType().getcontent() is None: self.BeremizRoot.setTargetType(self.GetTarget()) @@ -258,15 +258,15 @@ if path.startswith("BeremizRoot.Libraries."): wx.CallAfter(self.RefreshConfNodesBlockLists) return res - + # helper func to check project path write permission def CheckProjectPathPerm(self, dosave=True): if CheckPathPerm(self.ProjectPath): return True if self.AppFrame is not None: - dialog = wx.MessageDialog(self.AppFrame, + dialog = wx.MessageDialog(self.AppFrame, _('You must have permission to work on the project\nWork on a project copy ?'), - _('Error'), + _('Error'), wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) answer = dialog.ShowModal() dialog.Destroy() @@ -277,7 +277,7 @@ self.AppFrame.RefreshPageTitles() return True return False - + def _getProjectFilesPath(self, project_path=None): if project_path is not None: return os.path.join(project_path, "project_files") @@ -285,7 +285,7 @@ if not os.path.exists(projectfiles_path): os.mkdir(projectfiles_path) return projectfiles_path - + def AddProjectDefaultConfiguration(self, config_name="config", res_name="resource1"): self.ProjectAddConfiguration(config_name) self.ProjectAddConfigurationResource(config_name, res_name) @@ -299,7 +299,7 @@ # Verify that chosen folder is empty if not os.path.isdir(ProjectPath) or len(os.listdir(ProjectPath)) > 0: return _("Chosen folder isn't empty. You can't use it for a new project!") - + # Create PLCOpen program self.CreateNewProject( {"projectName": _("Unnamed"), @@ -308,7 +308,7 @@ "companyName": _("Unknown"), "creationDateTime": datetime(*localtime()[:6])}) self.AddProjectDefaultConfiguration() - + # Change XSD into class members self._AddParamsMembers() self.Children = {} @@ -320,7 +320,7 @@ # this will create files base XML files self.SaveProject() return None - + def LoadProject(self, ProjectPath, BuildPath=None): """ Load a project contained in a folder @@ -357,30 +357,30 @@ #Load and init all the children self.LoadChildren() self.RefreshConfNodesBlockLists() - + if os.path.exists(self._getBuildPath()): self.EnableMethod("_Clean", True) if os.path.isfile(self._getIECcodepath()): self.ShowMethod("_showIECcode", True) - + self.UpdateMethodsFromPLCStatus() - + return None - + def RecursiveConfNodeInfos(self, confnode): values = [] for CTNChild in confnode.IECSortedChildren(): values.append( {"name": "%s: %s" % (CTNChild.GetFullIEC_Channel(), - CTNChild.CTNName()), + CTNChild.CTNName()), "tagname": CTNChild.CTNFullName(), - "type": ITEM_CONFNODE, + "type": ITEM_CONFNODE, "confnode": CTNChild, "icon": CTNChild.GetIconName(), "values": self.RecursiveConfNodeInfos(CTNChild)}) return values - + def GetProjectInfos(self): infos = PLCControler.GetProjectInfos(self) configurations = infos["values"].pop(-1) @@ -394,23 +394,23 @@ infos["values"].append(resources) infos["values"].extend(self.RecursiveConfNodeInfos(self)) return infos - + def CloseProject(self): self.ClearChildren() self.ResetAppFrame(None) - + def SaveProject(self, from_project_path=None): if self.CheckProjectPathPerm(False): if from_project_path is not None: old_projectfiles_path = self._getProjectFilesPath(from_project_path) if os.path.isdir(old_projectfiles_path): - shutil.copytree(old_projectfiles_path, + shutil.copytree(old_projectfiles_path, self._getProjectFilesPath(self.ProjectPath)) self.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml')) result = self.CTNRequestSave(from_project_path) if result: self.logger.write_error(result) - + def SaveProjectAs(self): # Ask user to choose a path with write permissions if wx.Platform == '__WXMSW__': @@ -444,12 +444,12 @@ LocatedCCodeAndFlags=[] Extras=[] for lib in self.Libraries: - res=lib.Generate_C(buildpath,self._VariablesList,LibIECCflags) + res=lib.Generate_C(buildpath,self._VariablesList,LibIECCflags) LocatedCCodeAndFlags.append(res[:2]) if len(res)>2: Extras.extend(res[2:]) return map(list,zip(*LocatedCCodeAndFlags))+[tuple(Extras)] - + # Update PLCOpenEditor ConfNode Block types from loaded confnodes def RefreshConfNodesBlockLists(self): if getattr(self, "Children", None) is not None: @@ -458,7 +458,7 @@ if self.AppFrame is not None: self.AppFrame.RefreshLibraryPanel() self.AppFrame.RefreshEditor() - + # Update a PLCOpenEditor Pou variable location def UpdateProjectVariableLocation(self, old_leading, new_leading): self.Project.updateElementAddress(old_leading, new_leading) @@ -469,13 +469,13 @@ self.AppFrame.RefreshFileMenu() self.AppFrame.RefreshEditMenu() wx.CallAfter(self.AppFrame.RefreshEditor) - + def GetVariableLocationTree(self): ''' This function is meant to be overridden by confnodes. It should returns an list of dictionaries - + - IEC_type is an IEC type like BOOL/BYTE/SINT/... - location is a string of this variable's location, like "%IX0.0.0" ''' @@ -483,13 +483,13 @@ for child in self.IECSortedChildren(): children.append(child.GetVariableLocationTree()) return children - + def ConfNodePath(self): return os.path.split(__file__)[0] - + def CTNPath(self, CTNName=None): return self.ProjectPath - + def ConfNodeXmlFilePath(self, CTNName=None): return os.path.join(self.CTNPath(CTNName), "beremiz.xml") @@ -515,26 +515,26 @@ # Create a build path in temp folder else: self.DefaultBuildPath = os.path.join(tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build") - + if not os.path.exists(self.DefaultBuildPath): os.makedirs(self.DefaultBuildPath) return self.DefaultBuildPath - + def _getExtraFilesPath(self): return os.path.join(self._getBuildPath(), "extra_files") def _getIECcodepath(self): # define name for IEC code file return os.path.join(self._getBuildPath(), "plc.st") - + def _getIECgeneratedcodepath(self): # define name for IEC generated code file return os.path.join(self._getBuildPath(), "generated_plc.st") - + def _getIECrawcodepath(self): # define name for IEC raw code file return os.path.join(self.CTNPath(), "raw_plc.st") - + def GetLocations(self): locations = [] filepath = os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h") @@ -546,24 +546,29 @@ # This regular expression parses the lines genereated by IEC2C LOCATED_MODEL = re.compile("__LOCATED_VAR\((?P[A-Z]*),(?P[_A-Za-z0-9]*),(?P[QMI])(?:,(?P[XBWDL]))?,(?P[,0-9]*)\)") for line in lines: - # If line match RE, + # If line match RE, result = LOCATED_MODEL.match(line) if result: # Get the resulting dict resdict = result.groupdict() # rewrite string for variadic location as a tuple of integers resdict['LOC'] = tuple(map(int,resdict['LOC'].split(','))) - # set located size to 'X' if not given + # set located size to 'X' if not given if not resdict['SIZE']: resdict['SIZE'] = 'X' # finally store into located variable list locations.append(resdict) return locations - + def GetConfNodeGlobalInstances(self): return self._GlobalInstances() - + def _Generate_SoftPLC(self): + if self._Generate_PLC_ST(): + return self._Compile_ST_to_SoftPLC() + return False + + def _Generate_PLC_ST(self): """ Generate SoftPLC ST/IL/SFC code out of PLCOpenEditor controller, and compile it with IEC2C @param buildpath: path where files should be created @@ -571,9 +576,8 @@ # Update PLCOpenEditor ConfNode Block types before generate ST code self.RefreshConfNodesBlockLists() - + self.logger.write(_("Generating SoftPLC IEC-61131 ST/IL/SFC code...\n")) - buildpath = self._getBuildPath() # ask PLCOpenEditor controller to write ST/IL/SFC code file program, errors, warnings = self.GenerateProgram(self._getIECgeneratedcodepath()) if len(warnings) > 0: @@ -599,22 +603,25 @@ plc_file = open(self._getIECcodepath(), "a") plc_file.write(open(self._getIECgeneratedcodepath(), "r").read()) plc_file.close() - + return True + + def _Compile_ST_to_SoftPLC(self): self.logger.write(_("Compiling IEC Program into C code...\n")) + buildpath = self._getBuildPath() # Now compile IEC code into many C files - # files are listed to stdout, and errors to stderr. + # files are listed to stdout, and errors to stderr. status, result, err_result = ProcessLogger( self.logger, "\"%s\" -f -I \"%s\" -T \"%s\" \"%s\""%( self.iec2c_path, - self.ieclib_path, + self.ieclib_path, buildpath, self._getIECcodepath()), no_stdout=True, no_stderr=True).spin() if status: # Failed ! - + # parse iec2c's error message. if it contains a line number, # then print those lines from the generated IEC file. for err_line in err_result.split('\n'): @@ -624,7 +631,7 @@ if m_result is not None: first_line, first_column, last_line, last_column, error = m_result.groups() first_line, last_line = int(first_line), int(last_line) - + last_section = None f = open(self._getIECcodepath()) @@ -640,10 +647,10 @@ self.logger.write_warning("%04d: %s" % (i, line)) f.close() - + self.logger.write_error(_("Error : IEC to C compiler returned %d\n")%status) return False - + # Now extract C files of stdout C_files = [ fname for fname in result.splitlines() if fname[-2:]==".c" or fname[-2:]==".C" ] # remove those that are not to be compiled because included by others @@ -679,7 +686,7 @@ targetname = self.GetTarget().getcontent().getLocalTag() targetclass = targets.GetBuilder(targetname) - # if target already + # if target already if self._builder is None or not isinstance(self._builder,targetclass): # Get classname instance self._builder = targetclass(self) @@ -703,20 +710,20 @@ # C CODE GENERATION METHODS # ####################################################################### - + def CTNGenerate_C(self, buildpath, locations): """ - Return C code generated by iec2c compiler + Return C code generated by iec2c compiler when _generate_softPLC have been called @param locations: ignored @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND """ - return ([(C_file_name, self.plcCFLAGS) - for C_file_name in self.PLCGeneratedCFiles ], + return ([(C_file_name, self.plcCFLAGS) + for C_file_name in self.PLCGeneratedCFiles ], "", # no ldflags False) # do not expose retreive/publish calls - + def ResetIECProgramsAndVariables(self): """ Reset variable and program list that are parsed from @@ -743,7 +750,7 @@ self._ProgramList = [] self._VariablesList = [] self._IECPathToIdx = {} - + # Separate sections ListGroup = [] for line in open(csvfile,'r').xreadlines(): @@ -754,7 +761,7 @@ elif len(strippedline) > 0 and len(ListGroup) > 0: # append to this section ListGroup[-1].append(strippedline) - + # first section contains programs for line in ListGroup[0]: # Split and Maps each field to dictionnary entries @@ -763,7 +770,7 @@ attrs["C_path"] = '__'.join(attrs["C_path"].split(".",2)[1:]) # Push this dictionnary into result. self._ProgramList.append(attrs) - + # second section contains all variables config_FBs = {} for line in ListGroup[1]: @@ -776,7 +783,7 @@ if config_FB: parts = [config_FB] + parts[2:] attrs["C_path"] = '.'.join(parts) - else: + else: attrs["C_path"] = '__'.join(parts[1:]) else: attrs["C_path"] = '__'.join(parts) @@ -788,11 +795,11 @@ IEC_path=attrs["IEC_path"] Idx=int(attrs["num"]) self._IECPathToIdx[IEC_path]=(Idx, attrs["type"]) - + # third section contains ticktime if len(ListGroup) > 2: - self._Ticktime = int(ListGroup[2][0]) - + self._Ticktime = int(ListGroup[2][0]) + except Exception,e: self.logger.write_error(_("Cannot open/parse VARIABLES.csv!\n")) self.logger.write_error(traceback.format_exc()) @@ -818,7 +825,7 @@ "MEM":"extern __IEC_%(type)s_p %(C_path)s;", "OUT":"extern __IEC_%(type)s_p %(C_path)s;", "VAR":"extern __IEC_%(type)s_t %(C_path)s;", - "FB":"extern %(type)s %(C_path)s;"}[v["vartype"]]%v + "FB":"extern %(type)s %(C_path)s;"}[v["vartype"]]%v for v in self._VariablesList if v["C_path"].find('.')<0]), "for_each_variable_do_code":"\n".join([ {"EXT":" (*fp)((void*)&(%(C_path)s),%(type)s_P_ENUM);\n", @@ -836,9 +843,9 @@ "OUT":" return %(type)s_O_ENUM;\n", "VAR":" return %(type)s_ENUM;\n"}[v["vartype"]]%v for v in self._VariablesList if v["vartype"] != "FB" and v["type"] in DebugTypesSize ])} - + return debug_code - + def Generate_plc_main(self): """ Use confnodes layout given in LocationCFilesAndCFLAGS to @@ -848,7 +855,7 @@ # in retreive, publish, init, cleanup locstrs = map(lambda x:"_".join(map(str,x)), [loc for loc,Cfiles,DoCalls in self.LocationCFilesAndCFLAGS if loc and DoCalls]) - + # Generate main, based on template if not self.BeremizRoot.getDisable_Extensions(): plc_main_code = targets.GetCode("plc_main_head") % { @@ -882,7 +889,7 @@ plc_main_code += targets.GetCode("plc_main_tail") return plc_main_code - + def _Build(self): """ Method called by user to (re)build SoftPLC and confnode tree @@ -890,7 +897,7 @@ if self.AppFrame is not None: self.AppFrame.ClearErrors() self._CloseView(self._IECCodeView) - + buildpath = self._getBuildPath() # Eventually create build dir @@ -908,21 +915,52 @@ # If IEC code gen fail, bail out. if not IECGenRes: - self.logger.write_error(_("IEC-61131-3 code generation failed !\n")) + self.logger.write_error(_("PLC code generation failed !\n")) self.ResetBuildMD5() return False # Reset variable and program list that are parsed from # CSV file generated by IEC2C compiler. self.ResetIECProgramsAndVariables() - + + # Collect platform specific C code + # Code and other files from extension + if not self._Generate_runtime(): + return False + + # Get current or fresh builder + builder = self.GetBuilder() + if builder is None: + self.logger.write_error(_("Fatal : cannot get builder.\n")) + self.ResetBuildMD5() + return False + + # Build + try: + if not builder.build() : + self.logger.write_error(_("C Build failed.\n")) + return False + except Exception, exc: + self.logger.write_error(_("C Build crashed !\n")) + self.logger.write_error(traceback.format_exc()) + self.ResetBuildMD5() + return False + + self.logger.write(_("Successfully built.\n")) + # Update GUI status about need for transfer + self.CompareLocalAndRemotePLC() + return True + + def _Generate_runtime(self): + buildpath = self._getBuildPath() + # Generate C code and compilation params from confnode hierarchy try: CTNLocationCFilesAndCFLAGS, CTNLDFLAGS, CTNExtraFiles = self._Generate_C( - buildpath, + buildpath, self.PLCGeneratedLocatedVars) except Exception, exc: - self.logger.write_error(_("Runtime extensions C code generation failed !\n")) + self.logger.write_error(_("Runtime IO extensions C code generation failed !\n")) self.logger.write_error(traceback.format_exc()) self.ResetBuildMD5() return False @@ -931,7 +969,7 @@ try: LibCFilesAndCFLAGS, LibLDFLAGS, LibExtraFiles = self.GetLibrariesCCode(buildpath) except Exception, exc: - self.logger.write_error(_("Runtime extensions C code generation failed !\n")) + self.logger.write_error(_("Runtime library extensions C code generation failed !\n")) self.logger.write_error(traceback.format_exc()) self.ResetBuildMD5() return False @@ -939,7 +977,7 @@ self.LocationCFilesAndCFLAGS = CTNLocationCFilesAndCFLAGS + LibCFilesAndCFLAGS self.LDFLAGS = CTNLDFLAGS + LibLDFLAGS ExtraFiles = CTNExtraFiles + LibExtraFiles - + # Get temporary directory path extrafilespath = self._getExtraFilesPath() # Remove old directory @@ -953,7 +991,7 @@ open(fpath, "wb").write(fobject.read()) # Now we can forget ExtraFiles (will close files object) del ExtraFiles - + # Header file for extensions open(os.path.join(buildpath,"beremiz.h"), "w").write(targets.GetHeader()) @@ -978,32 +1016,9 @@ self.logger.write_error(traceback.format_exc()) self.ResetBuildMD5() return False - self.logger.write(_("C code generated successfully.\n")) - - # Get current or fresh builder - builder = self.GetBuilder() - if builder is None: - self.logger.write_error(_("Fatal : cannot get builder.\n")) - self.ResetBuildMD5() - return False - - # Build - try: - if not builder.build() : - self.logger.write_error(_("C Build failed.\n")) - return False - except Exception, exc: - self.logger.write_error(_("C Build crashed !\n")) - self.logger.write_error(traceback.format_exc()) - self.ResetBuildMD5() - return False - - self.logger.write(_("Successfully built.\n")) - # Update GUI status about need for transfer - self.CompareLocalAndRemotePLC() return True - + def ShowError(self, logger, from_location, to_location): chunk_infos = self.GetChunkInfos(from_location, to_location) for infos, (start_row, start_col) in chunk_infos: @@ -1011,7 +1026,7 @@ end = (to_location[0] - start_row, to_location[1] - start_col) if self.AppFrame is not None: self.AppFrame.ShowError(infos, start, end) - + _IECCodeView = None def _showIECcode(self): self._OpenView("IEC code") @@ -1019,20 +1034,20 @@ _IECRawCodeView = None def _editIECrawcode(self): self._OpenView("IEC raw code") - + _ProjectFilesView = None def _OpenProjectFiles(self): self._OpenView("Project Files") - + _FileEditors = {} def _OpenFileEditor(self, filepath): self._OpenView(filepath) - + def _OpenView(self, name=None, onlyopened=False): if name == "IEC code": if self._IECCodeView is None: plc_file = self._getIECcodepath() - + self._IECCodeView = IECCodeViewer(self.AppFrame.TabsOpened, "", self.AppFrame, None, instancepath=name) self._IECCodeView.SetTextSyntax("ALL") self._IECCodeView.SetKeywords(IEC_KEYWORDS) @@ -1043,78 +1058,78 @@ self._IECCodeView.SetText(text = text) self._IECCodeView.SetIcon(GetBitmap("ST")) setattr(self._IECCodeView, "_OnClose", self.OnCloseEditor) - + if self._IECCodeView is not None: self.AppFrame.EditProjectElement(self._IECCodeView, name) - + return self._IECCodeView - + elif name == "IEC raw code": if self._IECRawCodeView is None: controler = MiniTextControler(self._getIECrawcodepath(), self) - + self._IECRawCodeView = IECCodeViewer(self.AppFrame.TabsOpened, "", self.AppFrame, controler, instancepath=name) self._IECRawCodeView.SetTextSyntax("ALL") self._IECRawCodeView.SetKeywords(IEC_KEYWORDS) self._IECRawCodeView.RefreshView() self._IECRawCodeView.SetIcon(GetBitmap("ST")) setattr(self._IECRawCodeView, "_OnClose", self.OnCloseEditor) - + if self._IECRawCodeView is not None: self.AppFrame.EditProjectElement(self._IECRawCodeView, name) - + return self._IECRawCodeView - + elif name == "Project Files": if self._ProjectFilesView is None: self._ProjectFilesView = FileManagementPanel(self.AppFrame.TabsOpened, self, name, self._getProjectFilesPath(), True) - + extensions = [] for extension, name, editor in features.file_editors: if extension not in extensions: extensions.append(extension) - self._ProjectFilesView.SetEditableFileExtensions(extensions) - + self._ProjectFilesView.SetEditableFileExtensions(extensions) + if self._ProjectFilesView is not None: self.AppFrame.EditProjectElement(self._ProjectFilesView, name) - + return self._ProjectFilesView - + elif name is not None and name.find("::") != -1: filepath, editor_name = name.split("::") if not self._FileEditors.has_key(filepath): if os.path.isfile(filepath): file_extension = os.path.splitext(filepath)[1] - + editors = dict([(edit_name, edit_class) for extension, edit_name, edit_class in features.file_editors if extension == file_extension]) - + if editor_name == "": if len(editors) == 1: editor_name = editors.keys()[0] elif len(editors) > 0: names = editors.keys() - dialog = wx.SingleChoiceDialog(self.AppFrame, - _("Select an editor:"), _("Editor selection"), + dialog = wx.SingleChoiceDialog(self.AppFrame, + _("Select an editor:"), _("Editor selection"), names, wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL) if dialog.ShowModal() == wx.ID_OK: editor_name = names[dialog.GetSelection()] dialog.Destroy() - + if editor_name != "": name = "::".join([filepath, editor_name]) - + editor = editors[editor_name]() self._FileEditors[filepath] = editor(self.AppFrame.TabsOpened, self, name, self.AppFrame) self._FileEditors[filepath].SetIcon(GetBitmap("FILE")) if isinstance(self._FileEditors[filepath], DebugViewer): self._FileEditors[filepath].SetDataProducer(self) - + if self._FileEditors.has_key(filepath): editor = self._FileEditors[filepath] self.AppFrame.EditProjectElement(editor, editor.GetTagName()) - + return self._FileEditors.get(filepath) else: return ConfigTreeNode._OpenView(self, self.CTNName(), onlyopened) @@ -1147,7 +1162,7 @@ if log_count: if self.AppFrame is not None: self.AppFrame.LogViewer.SetLogCounters(log_count) - + def UpdateMethodsFromPLCStatus(self): status = None if self._connector is not None: @@ -1184,16 +1199,16 @@ self.AppFrame.ConnectionStatusBar.SetStatusText( _("Connected to URI: %s") % self.BeremizRoot.getURI_location().strip(), 1) self.AppFrame.ConnectionStatusBar.SetStatusText(_(status), 2) - + def PullPLCStatusProc(self, event): self.UpdateMethodsFromPLCStatus() - + def SnapshotAndResetDebugValuesBuffers(self): - buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers, + buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers, [list() for iec_path in self.TracedIECPath]) ticks, self.DebugTicks = self.DebugTicks, [] return ticks, buffers - + def RegisterDebugVarToConnector(self): self.DebugTimer=None Idxs = [] @@ -1208,10 +1223,10 @@ # This variable is not needed anymore! IECPathsToPop.append(IECPath) elif IECPath != "__tick__": - # Convert + # Convert Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None)) if Idx is not None: - if IEC_Type in DebugTypesSize: + if IEC_Type in DebugTypesSize: Idxs.append((Idx, IEC_Type, fvalue, IECPath)) else: self.logger.write_warning(_("Debug: Unsupported type to debug '%s'\n")%IEC_Type) @@ -1229,14 +1244,14 @@ self._connector.SetTraceVariablesList([]) self.SnapshotAndResetDebugValuesBuffers() self.IECdebug_lock.release() - + def IsPLCStarted(self): return self.previous_plcstate == "Started" - + def ReArmDebugRegisterTimer(self): if self.DebugTimer is not None: self.DebugTimer.cancel() - + # Prevent to call RegisterDebugVarToConnector when PLC is not started # If an output location var is forced it's leads to segmentation fault in runtime # Links between PLC located variables and real variables are not ready @@ -1250,16 +1265,16 @@ def GetDebugIECVariableType(self, IECPath): Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None)) return IEC_Type - + def SubscribeDebugIECVariable(self, IECPath, callableobj, buffer_list=False, *args, **kwargs): """ Dispatching use a dictionnary linking IEC variable paths - to a WeakKeyDictionary linking + to a WeakKeyDictionary linking weakly referenced callables to optionnal args """ if IECPath != "__tick__" and not self._IECPathToIdx.has_key(IECPath): return None - + self.IECdebug_lock.acquire() # If no entry exist, create a new one with a fresh WeakKeyDictionary IECdebug_data = self.IECdebug_datas.get(IECPath, None) @@ -1273,13 +1288,13 @@ self.IECdebug_datas[IECPath] = IECdebug_data else: IECdebug_data[4] |= buffer_list - + IECdebug_data[0][callableobj]=(buffer_list, args, kwargs) self.IECdebug_lock.release() - + self.ReArmDebugRegisterTimer() - + return IECdebug_data[1] def UnsubscribeDebugIECVariable(self, IECPath, callableobj): @@ -1292,7 +1307,7 @@ else: IECdebug_data[4] = reduce( lambda x, y: x|y, - [buffer_list for buffer_list,args,kwargs + [buffer_list for buffer_list,args,kwargs in IECdebug_data[0].itervalues()], False) self.IECdebug_lock.release() @@ -1309,33 +1324,33 @@ def ForceDebugIECVariable(self, IECPath, fvalue): if not self.IECdebug_datas.has_key(IECPath): return - + self.IECdebug_lock.acquire() - + # If no entry exist, create a new one with a fresh WeakKeyDictionary IECdebug_data = self.IECdebug_datas.get(IECPath, None) IECdebug_data[2] = "Forced" IECdebug_data[3] = fvalue - + self.IECdebug_lock.release() - + self.ReArmDebugRegisterTimer() - + def ReleaseDebugIECVariable(self, IECPath): if not self.IECdebug_datas.has_key(IECPath): return - + self.IECdebug_lock.acquire() - + # If no entry exist, create a new one with a fresh WeakKeyDictionary IECdebug_data = self.IECdebug_datas.get(IECPath, None) IECdebug_data[2] = "Registered" IECdebug_data[3] = None - + self.IECdebug_lock.release() - + self.ReArmDebugRegisterTimer() - + def CallWeakcallables(self, IECPath, function_name, *cargs): data_tuple = self.IECdebug_datas.get(IECPath, None) if data_tuple is not None: @@ -1415,7 +1430,7 @@ self.CallWeakcallables(IECPath, "NewValues", debug_ticks, values) if len(debug_ticks) > 0: self.CallWeakcallables("__tick__", "NewDataAvailable", debug_ticks) - + delay = time.time() - start_time next_refresh = max(REFRESH_PERIOD - delay, 0.2 * delay) if self.DispatchDebugValuesTimer is not None and self.DebugThread is not None: @@ -1437,7 +1452,7 @@ if self.DispatchDebugValuesTimer is not None: self.DispatchDebugValuesTimer.Stop() - def _connect_debug(self): + def _connect_debug(self): self.previous_plcstate = None if self.AppFrame: self.AppFrame.ResetGraphicViewers() @@ -1448,7 +1463,7 @@ if self.DebugThread is None: self.DebugThread = Thread(target=self.DebugThreadProc) self.DebugThread.start() - + def _Run(self): """ Start PLC @@ -1460,7 +1475,7 @@ else: self.logger.write_error(_("Couldn't start PLC !\n")) wx.CallAfter(self.UpdateMethodsFromPLCStatus) - + def _Stop(self): """ Stop PLC @@ -1470,7 +1485,7 @@ # debugthread should die on his own #self.KillDebugThread() - + wx.CallAfter(self.UpdateMethodsFromPLCStatus) def _SetConnector(self, connector, update_status=True): @@ -1493,7 +1508,7 @@ if self._connector is not None: self.logger.write_error(_("Already connected. Please disconnect\n")) return - + # Get connector uri uri = self.\ BeremizRoot.\ @@ -1512,7 +1527,7 @@ self.logger.write_error(_("Local service discovery failed!\n")) self.logger.write_error(traceback.format_exc()) uri = None - + # Nothing choosed or cancel button if uri is None or answer == wx.ID_CANCEL: self.logger.write_error(_("Connection canceled!\n")) @@ -1529,7 +1544,7 @@ self.AppFrame.RefreshFileMenu() self.AppFrame.RefreshEditMenu() self.AppFrame.RefreshPageTitles() - + # Get connector from uri try: self._SetConnector(connectors.ConnectorFactory(uri, self)) @@ -1547,7 +1562,7 @@ self.ShowMethod("_Transfer", True) self.CompareLocalAndRemotePLC() - + # Init with actual PLC status and print it self.UpdateMethodsFromPLCStatus() if self.previous_plcstate is not None: @@ -1556,7 +1571,7 @@ status = "" #self.logger.write(_("PLC is %s\n")%status) - + if self.previous_plcstate in ["Started","Stopped"]: if self.DebugAvailable() and self.GetIECProgramsAndVariables(): self.logger.write(_("Debugger ready\n")) @@ -1590,12 +1605,12 @@ def _Disconnect(self): self._SetConnector(None) - + def _Transfer(self): - # Get the last build PLC's + # Get the last build PLC's MD5 = self.GetLastBuildMD5() - - # Check if md5 file is empty : ask user to build PLC + + # Check if md5 file is empty : ask user to build PLC if MD5 is None : self.logger.write_error(_("Failed : Must build before transfer.\n")) return False @@ -1609,12 +1624,12 @@ extrafiles = [] for extrafilespath in [self._getExtraFilesPath(), self._getProjectFilesPath()]: - + extrafiles.extend( - [(name, open(os.path.join(extrafilespath, name), + [(name, open(os.path.join(extrafilespath, name), 'rb').read()) \ for name in os.listdir(extrafilespath)]) - + # Send PLC on target builder = self.GetBuilder() if builder is not None: diff -r 86797748c2a2 -r f65ab5ff91d1 controls/VariablePanel.py --- a/controls/VariablePanel.py Mon May 26 14:44:03 2014 +0100 +++ b/controls/VariablePanel.py Fri Jun 06 18:30:49 2014 +0100 @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor -#based on the plcopen standard. +#based on the plcopen standard. # #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD # @@ -30,7 +30,7 @@ import wx.grid import wx.lib.buttons -from plcopen.structures import LOCATIONDATATYPES, TestIdentifier, IEC_KEYWORDS +from plcopen.structures import LOCATIONDATATYPES, TestIdentifier, IEC_KEYWORDS, DefaultType from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD, ERROR_HIGHLIGHT from dialogs.ArrayTypeDialog import ArrayTypeDialog from CustomGrid import CustomGrid @@ -43,13 +43,7 @@ # Helpers #------------------------------------------------------------------------------- -def AppendMenu(parent, help, id, kind, text): - if wx.VERSION >= (2, 6, 0): - parent.Append(help=help, id=id, kind=kind, text=text) - else: - parent.Append(helpString=help, id=id, kind=kind, item=text) - -[TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, +[TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES ] = range(10) @@ -73,8 +67,8 @@ def GetFilterChoiceTransfer(): _ = lambda x : x - return {_("All"): _("All"), _("Interface"): _("Interface"), - _(" Input"): _("Input"), _(" Output"): _("Output"), _(" InOut"): _("InOut"), + return {_("All"): _("All"), _("Interface"): _("Interface"), + _(" Input"): _("Input"), _(" Output"): _("Output"), _(" InOut"): _("InOut"), _(" External"): _("External"), _("Variables"): _("Variables"), _(" Local"): _("Local"), _(" Temp"): _("Temp"), _("Global"): _("Global")}#, _("Access") : _("Access")} VARIABLE_CHOICES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().iterkeys()]) @@ -97,7 +91,7 @@ #------------------------------------------------------------------------------- class VariableTable(CustomTable): - + """ A custom wx.grid.Grid Table using user supplied data """ @@ -105,7 +99,7 @@ # The base class must be initialized *first* CustomTable.__init__(self, parent, data, colnames) self.old_value = None - + def GetValueByName(self, row, colname): if row < self.GetNumberRows(): return getattr(self.data[row], colname) @@ -113,7 +107,7 @@ def SetValueByName(self, row, colname, value): if row < self.GetNumberRows(): setattr(self.data[row], colname, value) - + def GetValue(self, row, col): if row < self.GetNumberRows(): if col == 0: @@ -130,7 +124,7 @@ if colname in ["Class", "Option"]: return _(value) return value - + def SetValue(self, row, col, value): if col < len(self.colnames): colname = self.GetColLabelValue(col, False) @@ -209,10 +203,10 @@ editor.SetParameters(",".join([_(choice) for choice in self.Parent.ClassList if choice not in excluded])) elif colname != "Documentation": grid.SetReadOnly(row, col, True) - + grid.SetCellEditor(row, col, editor) grid.SetCellRenderer(row, col, renderer) - + if colname == "Location" and LOCATION_MODEL.match(self.GetValueByName(row, colname)) is None: highlight_colours = ERROR_HIGHLIGHT else: @@ -223,23 +217,23 @@ #------------------------------------------------------------------------------- # Variable Panel Drop Target -#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- class VariableDropTarget(wx.TextDropTarget): ''' This allows dragging a variable location from somewhere to the Location column of a variable row. - + The drag source should be a TextDataObject containing a Python tuple like: ('%ID0.0.0', 'location', 'REAL') - + c_ext/CFileEditor.py has an example of this (you can drag a C extension variable to the Location column of the variable panel). ''' def __init__(self, parent): wx.TextDropTarget.__init__(self) self.ParentWindow = parent - + def OnDropText(self, x, y, data): self.ParentWindow.ParentWindow.Select() x, y = self.ParentWindow.VariablesGrid.CalcUnscrolledPosition(x, y) @@ -248,7 +242,7 @@ message = None element_type = self.ParentWindow.ElementType try: - values = eval(data) + values = eval(data) except: message = _("Invalid value \"%s\" for variable grid element")%data values = None @@ -267,12 +261,12 @@ location = values[0] variable_type = self.ParentWindow.Table.GetValueByName(row, "Type") base_type = self.ParentWindow.Controler.GetBaseType(variable_type) - + if values[2] is not None: base_location_type = self.ParentWindow.Controler.GetBaseType(values[2]) if values[2] != variable_type and base_type != base_location_type: message = _("Incompatible data types between \"%s\" and \"%s\"")%(values[2], variable_type) - + if message is None: if not location.startswith("%"): if location[0].isdigit() and base_type != "BOOL": @@ -282,9 +276,9 @@ elif base_type not in LOCATIONDATATYPES[location[0]]: message = _("Incompatible size of data between \"%s\" and \"%s\"")%(location, variable_type) else: - dialog = wx.SingleChoiceDialog(self.ParentWindow.ParentWindow.ParentWindow, - _("Select a variable class:"), _("Variable class"), - ["Input", "Output", "Memory"], + dialog = wx.SingleChoiceDialog(self.ParentWindow.ParentWindow.ParentWindow, + _("Select a variable class:"), _("Variable class"), + ["Input", "Output", "Memory"], wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL) if dialog.ShowModal() == wx.ID_OK: selected = dialog.GetSelection() @@ -299,7 +293,7 @@ location = "%Q" + location else: location = "%M" + location - + if message is None: self.ParentWindow.Table.SetValue(row, col, location) self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid) @@ -311,7 +305,7 @@ self.ParentWindow.Table.SetValue(row, col, values[0]) self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid) self.ParentWindow.SaveValues() - elif (element_type not in ["config", "resource", "function"] and values[1] == "Global" and + elif (element_type not in ["config", "resource", "function"] and values[1] == "Global" and self.ParentWindow.Filter in ["All", "Interface", "External"] or element_type != "function" and values[1] == "location"): if values[1] == "location": @@ -319,11 +313,11 @@ else: var_name = values[0] tagname = self.ParentWindow.GetTagName() - if var_name.upper() in [name.upper() + if var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.\ GetProjectPouNames(self.ParentWindow.Debug)]: message = _("\"%s\" pou already exists!")%var_name - elif not var_name.upper() in [name.upper() + elif not var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.\ GetEditedElementVariables(tagname, self.ParentWindow.Debug)]: var_infos = self.ParentWindow.DefaultValue.copy() @@ -332,9 +326,9 @@ if values[1] == "location": location = values[0] if not location.startswith("%"): - dialog = wx.SingleChoiceDialog(self.ParentWindow.ParentWindow.ParentWindow, - _("Select a variable class:"), _("Variable class"), - ["Input", "Output", "Memory"], + dialog = wx.SingleChoiceDialog(self.ParentWindow.ParentWindow.ParentWindow, + _("Select a variable class:"), _("Variable class"), + ["Input", "Output", "Memory"], wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL) if dialog.ShowModal() == wx.ID_OK: selected = dialog.GetSelection() @@ -354,7 +348,7 @@ self.ParentWindow.Debug) if len(configs) == 0: return - if not var_name.upper() in [name.upper() + if not var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.\ GetConfigurationVariableNames(configs[0])]: self.ParentWindow.Controler.AddConfigurationGlobalVar( @@ -372,10 +366,10 @@ self.ParentWindow.Values.append(var_infos) self.ParentWindow.SaveValues() self.ParentWindow.RefreshValues() - + if message is not None: wx.CallAfter(self.ShowMessage, message) - + def ShowMessage(self, message): message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() @@ -383,85 +377,85 @@ #------------------------------------------------------------------------------- # Variable Panel -#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- class VariablePanel(wx.Panel): - + def __init__(self, parent, window, controler, element_type, debug=False): wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL) - + self.MainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=0) self.MainSizer.AddGrowableCol(0) self.MainSizer.AddGrowableRow(1) - + controls_sizer = wx.FlexGridSizer(cols=10, hgap=5, rows=1, vgap=5) controls_sizer.AddGrowableCol(5) controls_sizer.AddGrowableRow(0) self.MainSizer.AddSizer(controls_sizer, border=5, flag=wx.GROW|wx.ALL) - + self.ReturnTypeLabel = wx.StaticText(self, label=_('Return Type:')) controls_sizer.AddWindow(self.ReturnTypeLabel, flag=wx.ALIGN_CENTER_VERTICAL) - + self.ReturnType = wx.ComboBox(self, size=wx.Size(145, -1), style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnReturnTypeChanged, self.ReturnType) controls_sizer.AddWindow(self.ReturnType) - + self.DescriptionLabel = wx.StaticText(self, label=_('Description:')) controls_sizer.AddWindow(self.DescriptionLabel, flag=wx.ALIGN_CENTER_VERTICAL) - + self.Description = wx.TextCtrl(self, size=wx.Size(250, -1), style=wx.TE_PROCESS_ENTER) self.Bind(wx.EVT_TEXT_ENTER, self.OnDescriptionChanged, self.Description) self.Description.Bind(wx.EVT_KILL_FOCUS, self.OnDescriptionChanged) - controls_sizer.AddWindow(self.Description) - + controls_sizer.AddWindow(self.Description) + class_filter_label = wx.StaticText(self, label=_('Class Filter:')) controls_sizer.AddWindow(class_filter_label, flag=wx.ALIGN_CENTER_VERTICAL) - - self.ClassFilter = wx.ComboBox(self, + + self.ClassFilter = wx.ComboBox(self, size=wx.Size(145, -1), style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnClassFilter, self.ClassFilter) controls_sizer.AddWindow(self.ClassFilter) - + for name, bitmap, help in [ ("AddButton", "add_element", _("Add variable")), ("DeleteButton", "remove_element", _("Remove variable")), ("UpButton", "up", _("Move variable up")), ("DownButton", "down", _("Move variable down"))]: - button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), + button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) button.SetToolTipString(help) setattr(self, name, button) controls_sizer.AddWindow(button) - + self.VariablesGrid = CustomGrid(self, style=wx.VSCROLL) self.VariablesGrid.SetDropTarget(VariableDropTarget(self)) - self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, + self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange) - self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, + self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) - self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, + self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) self.MainSizer.AddWindow(self.VariablesGrid, flag=wx.GROW) - + self.SetSizer(self.MainSizer) - + self.ParentWindow = window self.Controler = controler self.ElementType = element_type self.Debug = debug - + self.RefreshHighlightsTimer = wx.Timer(self, -1) - self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, + self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) - + self.Filter = "All" self.FilterChoices = [] self.FilterChoiceTransfer = GetFilterChoiceTransfer() - - self.DefaultValue = _VariableInfos("", "", "", "", "", True, "", "INT", ([], []), 0) - + + self.DefaultValue = _VariableInfos("", "", "", "", "", True, "", DefaultType, ([], []), 0) + if element_type in ["config", "resource"]: self.DefaultTypes = {"All" : "Global"} else: @@ -481,7 +475,7 @@ # these condense the ColAlignements list l = wx.ALIGN_LEFT - c = wx.ALIGN_CENTER + c = wx.ALIGN_CENTER # Num Name Class Type Loc Init Option Doc self.ColSizes = [40, 80, 70, 80, 80, 80, 100, 80] @@ -502,15 +496,15 @@ # these condense the ColAlignements list l = wx.ALIGN_LEFT - c = wx.ALIGN_CENTER + c = wx.ALIGN_CENTER # Num Name Class Type Init Option Doc self.ColSizes = [40, 80, 70, 80, 80, 100, 160] self.ColAlignements = [c, l, l, l, l, l, l] - + self.ElementType = element_type self.BodyType = None - + for choice in self.FilterChoices: self.ClassFilter.Append(_(choice)) @@ -526,11 +520,11 @@ "Up": self.UpButton, "Down": self.DownButton}) self.VariablesGrid.SetEditable(not self.Debug) - + def _AddVariable(new_row): if new_row > 0: row_content = self.Values[new_row - 1].copy() - + result = VARIABLE_NAME_SUFFIX_MODEL.search(row_content.Name) if result is not None: name = row_content.Name[:result.start(1)] @@ -546,8 +540,8 @@ row_content = None start_idx = 0 name = "LocalVar" - - if row_content is not None and row_content.Edit: + + if row_content is not None and row_content.Edit: row_content = self.Values[new_row - 1].copy() else: row_content = self.DefaultValue.copy() @@ -555,10 +549,10 @@ row_content.Class = self.DefaultTypes[self.Filter] else: row_content.Class = self.Filter - + row_content.Name = self.Controler.GenerateNewName( self.TagName, None, name + "%d", start_idx) - + if self.Filter == "All" and len(self.Values) > 0: self.Values.insert(new_row, row_content) else: @@ -568,7 +562,7 @@ self.RefreshValues() return new_row setattr(self.VariablesGrid, "_AddRow", _AddVariable) - + def _DeleteVariable(row): if self.Table.GetValueByName(row, "Edit"): self.Values.remove(self.Table.GetRow(row)) @@ -577,7 +571,7 @@ self.ParentWindow.RefreshView(variablepanel = False) self.RefreshValues() setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) - + def _MoveVariable(row, move): if self.Filter == "All": new_row = max(0, min(row + move, len(self.Values) - 1)) @@ -588,7 +582,7 @@ return new_row return row setattr(self.VariablesGrid, "_MoveRow", _MoveVariable) - + def _RefreshButtons(): if self: table_length = len(self.Table.data) @@ -603,7 +597,7 @@ self.UpButton.Enable(not self.Debug and (table_length > 0 and row > 0 and self.Filter == "All")) self.DownButton.Enable(not self.Debug and (table_length > 0 and row < table_length - 1 and self.Filter == "All")) setattr(self.VariablesGrid, "RefreshButtons", _RefreshButtons) - + self.VariablesGrid.SetRowLabelSize(0) for col in range(self.Table.GetNumberCols()): attr = wx.grid.GridCellAttr() @@ -611,29 +605,29 @@ self.VariablesGrid.SetColAttr(col, attr) self.VariablesGrid.SetColMinimalWidth(col, self.ColSizes[col]) self.VariablesGrid.AutoSizeColumn(col, False) - + def __del__(self): self.RefreshHighlightsTimer.Stop() - + def SetTagName(self, tagname): self.TagName = tagname self.BodyType = self.Controler.GetEditedElementBodyType(self.TagName) - + def GetTagName(self): return self.TagName - + def IsFunctionBlockType(self, name): - if (isinstance(name, TupleType) or + if (isinstance(name, TupleType) or self.ElementType != "function" and self.BodyType in ["ST", "IL"]): return False else: return self.Controler.GetBlockType(name, debug=self.Debug) is not None - + def RefreshView(self): self.PouNames = self.Controler.GetProjectPouNames(self.Debug) returnType = None description = None - + words = self.TagName.split("::") if self.ElementType == "config": self.Values = self.Controler.GetConfigurationGlobalVars(words[1], self.Debug) @@ -647,7 +641,7 @@ returnType = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, debug=self.Debug) description = self.Controler.GetPouDescription(words[1]) self.Values = self.Controler.GetEditedElementInterfaceVars(self.TagName, debug=self.Debug) - + if returnType is not None: self.ReturnType.SetStringSelection(returnType) self.ReturnType.Enable(not self.Debug) @@ -657,7 +651,7 @@ self.ReturnType.Enable(False) self.ReturnTypeLabel.Hide() self.ReturnType.Hide() - + if description is not None: self.Description.SetValue(description) self.Description.Enable(not self.Debug) @@ -667,11 +661,11 @@ self.Description.Enable(False) self.DescriptionLabel.Hide() self.Description.Hide() - + self.RefreshValues() self.VariablesGrid.RefreshButtons() self.MainSizer.Layout() - + def OnReturnTypeChanged(self, event): words = self.TagName.split("::") self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection()) @@ -679,7 +673,7 @@ self.ParentWindow.RefreshView(variablepanel = False) self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) event.Skip() - + def OnDescriptionChanged(self, event): words = self.TagName.split("::") old_description = self.Controler.GetPouDescription(words[1]) @@ -688,7 +682,7 @@ self.Controler.SetPouDescription(words[1], new_description) self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) event.Skip() - + def OnClassFilter(self, event): self.Filter = self.FilterChoiceTransfer[VARIABLE_CHOICES_DICT[self.ClassFilter.GetStringSelection()]] self.RefreshTypeList() @@ -711,7 +705,7 @@ colname = self.Table.GetColLabelValue(col, False) value = self.Table.GetValue(row, col) message = None - + if colname == "Name" and value != "": if not TestIdentifier(value): message = _("\"%s\" is not a valid identifier!") % value @@ -735,7 +729,7 @@ wx.CallAfter(self.ParentWindow.RefreshView, False) elif colname == "Location": wx.CallAfter(self.ParentWindow.RefreshView) - + if message is not None: dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR) dialog.ShowModal() @@ -743,64 +737,77 @@ event.Veto() else: event.Skip() - - def OnVariablesGridEditorShown(self, event): - row, col = event.GetRow(), event.GetCol() - - label_value = self.Table.GetColLabelValue(col, False) - if label_value == "Type": - type_menu = wx.Menu(title='') # the root menu - + + def BuildStdIECTypesMenu(self,type_menu): # build a submenu containing standard IEC types base_menu = wx.Menu(title='') for base_type in self.Controler.GetBaseTypes(): new_id = wx.NewId() - AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type) + base_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type) self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), id=new_id) type_menu.AppendMenu(wx.NewId(), _("Base Types"), base_menu) + def BuildUserTypesMenu(self,type_menu): # build a submenu containing user-defined types datatype_menu = wx.Menu(title='') datatypes = self.Controler.GetDataTypes(basetypes = False, confnodetypes = False) for datatype in datatypes: new_id = wx.NewId() - AppendMenu(datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype) + datatype_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype) self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id) type_menu.AppendMenu(wx.NewId(), _("User Data Types"), datatype_menu) - - for category in self.Controler.GetConfNodeDataTypes(): - - if len(category["list"]) > 0: - # build a submenu containing confnode types - confnode_datatype_menu = wx.Menu(title='') - for datatype in category["list"]: - new_id = wx.NewId() - AppendMenu(confnode_datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype) - self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id) - - type_menu.AppendMenu(wx.NewId(), category["name"], confnode_datatype_menu) - - # build a submenu containing function block types - bodytype = self.Controler.GetEditedElementBodyType(self.TagName) - pouname, poutype = self.Controler.GetEditedElementType(self.TagName) + + def BuildLibsTypesMenu(self, type_menu): + for category in self.Controler.GetConfNodeDataTypes(): + if len(category["list"]) > 0: + # build a submenu containing confnode types + confnode_datatype_menu = wx.Menu(title='') + for datatype in category["list"]: + new_id = wx.NewId() + confnode_datatype_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype) + self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id) + + type_menu.AppendMenu(wx.NewId(), category["name"], confnode_datatype_menu) + + def BuildProjectTypesMenu(self, type_menu, classtype): + # build a submenu containing function block types + bodytype = self.Controler.GetEditedElementBodyType(self.TagName) + pouname, poutype = self.Controler.GetEditedElementType(self.TagName) + if classtype in ["Input", "Output", "InOut", "External", "Global"] or \ + poutype != "function" and bodytype in ["ST", "IL"]: + functionblock_menu = wx.Menu(title='') + fbtypes = self.Controler.GetFunctionBlockTypes(self.TagName) + for functionblock_type in fbtypes: + new_id = wx.NewId() + functionblock_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=functionblock_type) + self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(functionblock_type), id=new_id) + + type_menu.AppendMenu(wx.NewId(), _("Function Block Types"), functionblock_menu) + + def BuildArrayTypesMenu(self, type_menu): + new_id = wx.NewId() + type_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Array")) + self.Bind(wx.EVT_MENU, self.VariableArrayTypeFunction, id=new_id) + + def OnVariablesGridEditorShown(self, event): + row, col = event.GetRow(), event.GetCol() + + label_value = self.Table.GetColLabelValue(col, False) + if label_value == "Type": classtype = self.Table.GetValueByName(row, "Class") - - new_id = wx.NewId() - AppendMenu(type_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Array")) - self.Bind(wx.EVT_MENU, self.VariableArrayTypeFunction, id=new_id) - - if classtype in ["Input", "Output", "InOut", "External", "Global"] or \ - poutype != "function" and bodytype in ["ST", "IL"]: - functionblock_menu = wx.Menu(title='') - fbtypes = self.Controler.GetFunctionBlockTypes(self.TagName) - for functionblock_type in fbtypes: - new_id = wx.NewId() - AppendMenu(functionblock_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=functionblock_type) - self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(functionblock_type), id=new_id) - - type_menu.AppendMenu(wx.NewId(), _("Function Block Types"), functionblock_menu) + type_menu = wx.Menu(title='') # the root menu + + self.BuildStdIECTypesMenu(type_menu) + + self.BuildUserTypesMenu(type_menu) + + self.BuildLibsTypesMenu(type_menu) + + self.BuildProjectTypesMenu(type_menu,classtype) + + self.BuildArrayTypesMenu(type_menu) rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col)) corner_x = rect.x + rect.width @@ -812,7 +819,7 @@ event.Veto() else: event.Skip() - + def GetVariableTypeFunction(self, base_type): def VariableTypeFunction(event): row = self.VariablesGrid.GetGridCursorRow() @@ -823,11 +830,11 @@ self.Controler.BufferProject() self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) return VariableTypeFunction - + def VariableArrayTypeFunction(self, event): row = self.VariablesGrid.GetGridCursorRow() - dialog = ArrayTypeDialog(self, - self.Controler.GetDataTypes(self.TagName), + dialog = ArrayTypeDialog(self, + self.Controler.GetDataTypes(self.TagName), self.Table.GetValueByName(row, "Type")) if dialog.ShowModal() == wx.ID_OK: self.Table.SetValueByName(row, "Type", dialog.GetValue()) @@ -837,7 +844,7 @@ self.Controler.BufferProject() self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) dialog.Destroy() - + def OnVariablesGridCellLeftClick(self, event): row = event.GetRow() if not self.Debug and (event.GetCol() == 0 and self.Table.GetValueByName(row, "Edit")): @@ -849,7 +856,7 @@ dragSource.SetData(data) dragSource.DoDragDrop() event.Skip() - + def RefreshValues(self): data = [] for num, variable in enumerate(self.Values): @@ -858,7 +865,7 @@ data.append(variable) self.Table.SetData(data) self.Table.ResetView(self.VariablesGrid) - + def SaveValues(self, buffer = True): words = self.TagName.split("::") if self.ElementType == "config": @@ -871,7 +878,7 @@ self.Controler.SetPouInterfaceVars(words[1], self.Values) if buffer: self.Controler.BufferProject() - self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) + self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) #------------------------------------------------------------------------------- # Highlights showing functions diff -r 86797748c2a2 -r f65ab5ff91d1 editors/CodeFileEditor.py --- a/editors/CodeFileEditor.py Mon May 26 14:44:03 2014 +0100 +++ b/editors/CodeFileEditor.py Fri Jun 06 18:30:49 2014 +0100 @@ -6,7 +6,7 @@ import wx.lib.buttons from plcopen.plcopen import TestTextElement -from plcopen.structures import TestIdentifier, IEC_KEYWORDS +from plcopen.structures import TestIdentifier, IEC_KEYWORDS, DefaultType from controls import CustomGrid, CustomTable from editors.ConfTreeNodeEditor import ConfTreeNodeEditor from util.BitmapLibrary import GetBitmap @@ -14,7 +14,7 @@ from controls.VariablePanel import VARIABLE_NAME_SUFFIX_MODEL from graphics.GraphicCommons import ERROR_HIGHLIGHT, SEARCH_RESULT_HIGHLIGHT, REFRESH_HIGHLIGHT_PERIOD -[STC_CODE_ERROR, STC_CODE_SEARCH_RESULT, +[STC_CODE_ERROR, STC_CODE_SEARCH_RESULT, STC_CODE_SECTION] = range(15, 18) HIGHLIGHT_TYPES = { @@ -25,14 +25,14 @@ EDGE_COLUMN = 80 class CodeEditor(CustomStyledTextCtrl): - + KEYWORDS = [] COMMENT_HEADER = "" def __init__(self, parent, window, controler): - CustomStyledTextCtrl.__init__(self, parent, -1, wx.DefaultPosition, + CustomStyledTextCtrl.__init__(self, parent, -1, wx.DefaultPosition, wx.Size(-1, 300), 0) - + self.SetMarginType(1, stc.STC_MARGIN_NUMBER) self.SetMarginWidth(1, 25) @@ -41,7 +41,7 @@ self.SetMargins(0,0) self.SetViewWhiteSpace(False) - + self.SetEdgeMode(stc.STC_EDGE_BACKGROUND) self.SetEdgeColumn(EDGE_COLUMN) @@ -59,7 +59,7 @@ self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080") - + self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI) self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick) self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) @@ -78,33 +78,33 @@ self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(mono)s" % faces) self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold") self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold") - + # Highlighting styles self.StyleSetSpec(STC_CODE_ERROR, 'fore:#FF0000,back:#FFFF00,size:%(size)d' % faces) self.StyleSetSpec(STC_CODE_SEARCH_RESULT, 'fore:#FFFFFF,back:#FFA500,size:%(size)d' % faces) - + # Section style self.StyleSetSpec(STC_CODE_SECTION, 'fore:#808080,size:%(size)d') self.StyleSetChangeable(STC_CODE_SECTION, False) - + # Indentation size self.SetTabWidth(4) self.SetUseTabs(0) - + self.SetCodeLexer() self.SetKeyWords(0, " ".join(self.KEYWORDS)) - + self.Controler = controler self.ParentWindow = window - + self.DisableEvents = True self.CurrentAction = None - + self.ResetSearchResults() - + self.RefreshHighlightsTimer = wx.Timer(self, -1) self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) - + self.SectionsComments = {} for section in self.Controler.SECTIONS_NAMES: section_comment = " %s section " % (section) @@ -112,11 +112,11 @@ section_comment = self.COMMENT_HEADER * (len_headers / 2) + \ section_comment + \ self.COMMENT_HEADER * (len_headers - len_headers / 2) - + self.SectionsComments[section] = { "comment": section_comment, } - + for i, section in enumerate(self.Controler.SECTIONS_NAMES): section_infos = self.SectionsComments[section] if i + 1 < len(self.Controler.SECTIONS_NAMES): @@ -125,24 +125,24 @@ else: section_end = "$" section_infos["pattern"] = re.compile( - section_infos["comment"] + "(.*)" + + section_infos["comment"] + "(.*)" + section_end, re.DOTALL) - + self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE) self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop) self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification) - + def SetCodeLexer(self): pass - + def ResetSearchResults(self): self.Highlights = [] self.SearchParams = None self.SearchResults = None self.CurrentFindHighlight = None - + def OnModification(self, event): if not self.DisableEvents: mod_type = event.GetModificationType() @@ -165,7 +165,7 @@ wx.CallAfter(self.RefreshModel) wx.CallAfter(self.RefreshSectionStyling) event.Skip() - + def OnDoDrop(self, event): try: values = eval(event.GetDragText()) @@ -192,7 +192,7 @@ self.ParentWindow.RefreshFileMenu() self.ParentWindow.RefreshEditMenu() self.ParentWindow.RefreshPageTitles() - + def StartBuffering(self): self.Controler.StartBuffering() if self.ParentWindow is not None: @@ -200,7 +200,7 @@ self.ParentWindow.RefreshFileMenu() self.ParentWindow.RefreshEditMenu() self.ParentWindow.RefreshPageTitles() - + def ResetBuffer(self): if self.CurrentAction != None: self.Controler.EndBuffering() @@ -240,18 +240,18 @@ self.GotoPos(old_cursor_pos) self.EmptyUndoBuffer() self.DisableEvents = False - + self.RefreshSectionStyling() - + self.ShowHighlights() - + def RefreshSectionStyling(self): self.Colourise(0, -1) - + text = self.GetText() for line in xrange(self.GetLineCount()): self.SetLineState(line, 0) - + for section in self.Controler.SECTIONS_NAMES: section_comments = self.SectionsComments[section] start_pos = text.find(section_comments["comment"]) @@ -259,7 +259,7 @@ self.StartStyling(start_pos, 0xff) self.SetStyling(end_pos - start_pos, STC_CODE_SECTION) self.SetLineState(self.LineFromPosition(start_pos), 1) - + self.StartStyling(end_pos, 0x00) self.SetStyling(len(self.GetText()) - end_pos, stc.STC_STYLE_DEFAULT) @@ -278,7 +278,7 @@ parts[section] = "" self.Controler.SetTextParts(parts) self.ResetSearchResults() - + def OnKeyPressed(self, event): if self.CallTipActive(): self.CallTipCancel() @@ -286,14 +286,14 @@ current_pos = self.GetCurrentPos() selected = self.GetSelection() text_selected = selected[0] != selected[1] - + # Test if caret is before Windows like new line text = self.GetText() if current_pos < len(text) and ord(text[current_pos]) == 13: newline_size = 2 else: newline_size = 1 - + # Disable to type any character in section header lines if (self.GetLineState(self.LineFromPosition(current_pos)) and not text_selected and @@ -301,7 +301,7 @@ wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]): return - + # Disable to delete line between code and header lines elif (self.GetCurLine()[0].strip() != "" and not text_selected and (key == wx.WXK_BACK and @@ -309,7 +309,7 @@ key in [wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE] and self.GetLineState(self.LineFromPosition(min(len(text), current_pos + newline_size))))): return - + elif key == 32 and event.ControlDown(): pos = self.GetCurrentPos() @@ -319,7 +319,7 @@ # Code completion else: self.AutoCompSetIgnoreCase(False) # so this needs to match - + keywords = self.KEYWORDS + [var["Name"] for var in self.Controler.GetVariables()] keywords.sort() @@ -361,11 +361,11 @@ self.BraceBadLight(braceAtCaret) else: self.BraceHighlight(braceAtCaret, braceOpposite) - + selected_text = self.GetSelectedText() if selected_text: self.ParentWindow.SetCopyBuffer(selected_text, True) - + def OnMarginClick(self, event): # fold and unfold as needed if evt.GetMargin() == 2: @@ -464,11 +464,11 @@ self.DisableEvents = False self.RefreshModel() self.RefreshBuffer() - + def Copy(self): self.CmdKeyExecute(wx.stc.STC_CMD_COPY) self.ParentWindow.RefreshEditMenu() - + def Paste(self): self.ResetBuffer() self.DisableEvents = True @@ -480,21 +480,21 @@ def Find(self, direction, search_params): if self.SearchParams != search_params: self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT) - + self.SearchParams = search_params criteria = { - "raw_pattern": search_params["find_pattern"], + "raw_pattern": search_params["find_pattern"], "pattern": re.compile(search_params["find_pattern"]), "case_sensitive": search_params["case_sensitive"], "regular_expression": search_params["regular_expression"], "filter": "all"} - + self.SearchResults = [ (start, end, SEARCH_RESULT_HIGHLIGHT) - for start, end, text in + for start, end, text in TestTextElement(self.GetText(), criteria)] self.CurrentFindHighlight = None - + if len(self.SearchResults) > 0: if self.CurrentFindHighlight is not None: old_idx = self.SearchResults.index(self.CurrentFindHighlight) @@ -522,9 +522,9 @@ break if self.CurrentFindHighlight is not None: self.AddHighlight(*self.CurrentFindHighlight) - + self.ScrollToLine(self.CurrentFindHighlight[0][0]) - + else: if self.CurrentFindHighlight is not None: self.RemoveHighlight(*self.CurrentFindHighlight) @@ -557,11 +557,11 @@ def RemoveHighlight(self, start, end, highlight_type): highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None) - if (highlight_type is not None and + if (highlight_type is not None and (start, end, highlight_type) in self.Highlights): self.Highlights.remove((start, end, highlight_type)) self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) - + def ShowHighlights(self): for start, end, highlight_type in self.Highlights: if start[0] == 0: @@ -583,14 +583,14 @@ #------------------------------------------------------------------------------- class VariablesTable(CustomTable): - + def GetValue(self, row, col): if row < self.GetNumberRows(): if col == 0: return row + 1 else: return str(self.data[row].get(self.GetColLabelValue(col, False), "")) - + def _updateColAttrs(self, grid): """ wxGrid -> update the column attributes to add the @@ -598,7 +598,7 @@ Otherwise default to the default renderer. """ - + typelist = None accesslist = None for row in range(self.GetNumberRows()): @@ -606,7 +606,7 @@ editor = None renderer = None colname = self.GetColLabelValue(col, False) - + if colname in ["Name", "Initial"]: editor = wx.grid.GridCellTextEditor() elif colname == "Class": @@ -616,49 +616,49 @@ pass else: grid.SetReadOnly(row, col, True) - + grid.SetCellEditor(row, col, editor) grid.SetCellRenderer(row, col, renderer) - + grid.SetCellBackgroundColour(row, col, wx.WHITE) self.ResizeRow(grid, row) class VariablesEditor(wx.Panel): - + def __init__(self, parent, window, controler): wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL) - + main_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=4) main_sizer.AddGrowableCol(1) main_sizer.AddGrowableRow(0) - + controls_sizer = wx.BoxSizer(wx.VERTICAL) main_sizer.AddSizer(controls_sizer, border=5, flag=wx.ALL) - + for name, bitmap, help in [ ("AddVariableButton", "add_element", _("Add variable")), ("DeleteVariableButton", "remove_element", _("Remove variable")), ("UpVariableButton", "up", _("Move variable up")), ("DownVariableButton", "down", _("Move variable down"))]: - button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), + button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) button.SetToolTipString(help) setattr(self, name, button) controls_sizer.AddWindow(button, border=5, flag=wx.BOTTOM) - + self.VariablesGrid = CustomGrid(self, style=wx.VSCROLL) self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange) self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) main_sizer.AddWindow(self.VariablesGrid, flag=wx.GROW) - + self.SetSizer(main_sizer) - + self.ParentWindow = window self.Controler = controler - - self.VariablesDefaultValue = {"Name" : "", "Type" : "INT", "Initial": ""} + + self.VariablesDefaultValue = {"Name" : "", "Type" : DefaultType, "Initial": ""} self.Table = VariablesTable(self, [], ["#", "Name", "Type", "Initial"]) self.ColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT] self.ColSizes = [40, 200, 150, 150] @@ -667,7 +667,7 @@ "Delete": self.DeleteVariableButton, "Up": self.UpVariableButton, "Down": self.DownVariableButton}) - + def _AddVariable(new_row): if new_row > 0: row_content = self.Table.data[new_row - 1].copy() @@ -691,13 +691,13 @@ self.RefreshView() return new_row setattr(self.VariablesGrid, "_AddRow", _AddVariable) - + def _DeleteVariable(row): self.Table.RemoveRow(row) self.RefreshModel() self.RefreshView() setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) - + def _MoveVariable(row, move): new_row = self.Table.MoveRow(row, move) if new_row != row: @@ -705,7 +705,7 @@ self.RefreshView() return new_row setattr(self.VariablesGrid, "_MoveRow", _MoveVariable) - + self.VariablesGrid.SetRowLabelSize(0) for col in range(self.Table.GetNumberCols()): attr = wx.grid.GridCellAttr() @@ -717,7 +717,7 @@ def RefreshModel(self): self.Controler.SetVariables(self.Table.GetData()) self.RefreshBuffer() - + # Buffer the last model state def RefreshBuffer(self): self.Controler.BufferCodeFile() @@ -730,23 +730,23 @@ self.Table.SetData(self.Controler.GetVariables()) self.Table.ResetView(self.VariablesGrid) self.VariablesGrid.RefreshButtons() - + def DoGetBestSize(self): return self.ParentWindow.GetPanelBestSize() - + def OnVariablesGridCellChange(self, event): row, col = event.GetRow(), event.GetCol() colname = self.Table.GetColLabelValue(col, False) value = self.Table.GetValue(row, col) message = None - + if colname == "Name" and value != "": if not TestIdentifier(value): message = _("\"%s\" is not a valid identifier!") % value elif value.upper() in IEC_KEYWORDS: message = _("\"%s\" is a keyword. It can't be used!") % value - elif value.upper() in [var["Name"].upper() - for var_row, var in enumerate(self.Table.data) + elif value.upper() in [var["Name"].upper() + for var_row, var in enumerate(self.Table.data) if var_row != row]: message = _("A variable with \"%s\" as name already exists!") % value else: @@ -755,7 +755,7 @@ else: self.RefreshModel() wx.CallAfter(self.RefreshView) - + if message is not None: dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR) dialog.ShowModal() @@ -765,7 +765,7 @@ event.Skip() def OnVariablesGridEditorShown(self, event): - row, col = event.GetRow(), event.GetCol() + row, col = event.GetRow(), event.GetCol() if self.Table.GetColLabelValue(col, False) == "Type": type_menu = wx.Menu(title='') base_menu = wx.Menu(title='') @@ -781,7 +781,7 @@ self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id) type_menu.AppendMenu(wx.NewId(), "User Data Types", datatype_menu) rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col)) - + self.VariablesGrid.PopupMenuXY(type_menu, rect.x + rect.width, rect.y + self.VariablesGrid.GetColLabelSize()) type_menu.Destroy() event.Veto() @@ -803,64 +803,64 @@ row = event.GetRow() data_type = self.Table.GetValueByName(row, "Type") var_name = self.Table.GetValueByName(row, "Name") - data = wx.TextDataObject(str((var_name, "Global", data_type, + data = wx.TextDataObject(str((var_name, "Global", data_type, self.Controler.GetCurrentLocation()))) dragSource = wx.DropSource(self.VariablesGrid) dragSource.SetData(data) dragSource.DoDragDrop() return event.Skip() - + #------------------------------------------------------------------------------- # CodeFileEditor Main Frame Class #------------------------------------------------------------------------------- class CodeFileEditor(ConfTreeNodeEditor): - + CONFNODEEDITOR_TABS = [] CODE_EDITOR = None - + def _create_CodePanel(self, prnt): self.CodeEditorPanel = wx.SplitterWindow(prnt) self.CodeEditorPanel.SetMinimumPaneSize(1) - - self.VariablesPanel = VariablesEditor(self.CodeEditorPanel, + + self.VariablesPanel = VariablesEditor(self.CodeEditorPanel, self.ParentWindow, self.Controler) - + if self.CODE_EDITOR is not None: - self.CodeEditor = self.CODE_EDITOR(self.CodeEditorPanel, + self.CodeEditor = self.CODE_EDITOR(self.CodeEditorPanel, self.ParentWindow, self.Controler) - - self.CodeEditorPanel.SplitHorizontally(self.VariablesPanel, + + self.CodeEditorPanel.SplitHorizontally(self.VariablesPanel, self.CodeEditor, 150) else: self.CodeEditorPanel.Initialize(self.VariablesPanel) - + return self.CodeEditorPanel - + def __init__(self, parent, controler, window): ConfTreeNodeEditor.__init__(self, parent, controler, window) - + wx.CallAfter(self.CodeEditorPanel.SetSashPosition, 150) - + def GetBufferState(self): return self.Controler.GetBufferState() - + def Undo(self): self.Controler.LoadPrevious() self.RefreshView() - + def Redo(self): self.Controler.LoadNext() self.RefreshView() - + def RefreshView(self): ConfTreeNodeEditor.RefreshView(self) - + self.VariablesPanel.RefreshView() self.CodeEditor.RefreshView() - + def Find(self, direction, search_params): self.CodeEditor.Find(direction, search_params) - \ No newline at end of file + diff -r 86797748c2a2 -r f65ab5ff91d1 editors/DataTypeEditor.py --- a/editors/DataTypeEditor.py Mon May 26 14:44:03 2014 +0100 +++ b/editors/DataTypeEditor.py Fri Jun 06 18:30:49 2014 +0100 @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor -#based on the plcopen standard. +#based on the plcopen standard. # #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD # @@ -29,7 +29,7 @@ import wx.grid import wx.lib.buttons -from plcopen.structures import IEC_KEYWORDS, TestIdentifier +from plcopen.structures import IEC_KEYWORDS, TestIdentifier, DefaultType from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD from controls import CustomEditableListBox, CustomGrid, CustomTable from dialogs import ArrayTypeDialog @@ -59,7 +59,7 @@ #------------------------------------------------------------------------------- class ElementsTable(CustomTable): - + """ A custom wx.grid.Grid Table using user supplied data """ @@ -67,7 +67,7 @@ # The base class must be initialized *first* CustomTable.__init__(self, parent, data, colnames) self.old_value = None - + def GetValue(self, row, col): if row < self.GetNumberRows(): if col == 0: @@ -78,17 +78,17 @@ if value[0] == "array": return "ARRAY [%s] OF %s" % (",".join(map(lambda x : "..".join(x), value[2])), value[1]) return str(value) - + def SetValue(self, row, col, value): if col < len(self.colnames): colname = self.GetColLabelValue(col, False) if colname == "Name": self.old_value = self.data[row][colname] self.data[row][colname] = value - + def GetOldValue(self): return self.old_value - + def _updateColAttrs(self, grid): """ wx.grid.Grid -> update the column attributes to add the @@ -96,7 +96,7 @@ Otherwise default to the default renderer. """ - + for row in range(self.GetNumberRows()): row_highlights = self.Highlights.get(row, {}) for col in range(self.GetNumberCols()): @@ -115,15 +115,15 @@ editor = wx.grid.GridCellTextEditor() else: grid.SetReadOnly(row, col, True) - + grid.SetCellEditor(row, col, editor) grid.SetCellRenderer(row, col, renderer) - + highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1] grid.SetCellBackgroundColour(row, col, highlight_colours[0]) grid.SetCellTextColour(row, col, highlight_colours[1]) self.ResizeRow(grid, row) - + def AddHighlight(self, infos, highlight_type): row_highlights = self.Highlights.setdefault(infos[0], {}) if infos[1] == "initial": @@ -137,216 +137,216 @@ #------------------------------------------------------------------------------- class DataTypeEditor(EditorPanel): - + def _init_Editor(self, parent): self.Editor = wx.Panel(parent, style=wx.SUNKEN_BORDER) - + self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) self.MainSizer.AddGrowableCol(0) self.MainSizer.AddGrowableRow(1) - + top_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.MainSizer.AddSizer(top_sizer, border=5, + self.MainSizer.AddSizer(top_sizer, border=5, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) - + derivation_type_label = wx.StaticText(self.Editor, label=_('Derivation Type:')) - top_sizer.AddWindow(derivation_type_label, border=5, + top_sizer.AddWindow(derivation_type_label, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT) - + self.DerivationType = wx.ComboBox(self.Editor, size=wx.Size(200, -1), style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnDerivationTypeChanged, self.DerivationType) top_sizer.AddWindow(self.DerivationType, border=5, flag=wx.GROW|wx.RIGHT) - + typeinfos_staticbox = wx.StaticBox(self.Editor, label=_('Type infos:')) typeinfos_sizer = wx.StaticBoxSizer(typeinfos_staticbox, wx.HORIZONTAL) - self.MainSizer.AddSizer(typeinfos_sizer, border=5, + self.MainSizer.AddSizer(typeinfos_sizer, border=5, flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT) - + # Panel for Directly derived data types self.DirectlyPanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) typeinfos_sizer.AddWindow(self.DirectlyPanel, 1) - + directly_panel_sizer = wx.BoxSizer(wx.HORIZONTAL) - - directly_basetype_label = wx.StaticText(self.DirectlyPanel, + + directly_basetype_label = wx.StaticText(self.DirectlyPanel, label=_('Base Type:')) - directly_panel_sizer.AddWindow(directly_basetype_label, 1, border=5, + directly_panel_sizer.AddWindow(directly_basetype_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) - + self.DirectlyBaseType = wx.ComboBox(self.DirectlyPanel, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.DirectlyBaseType) - directly_panel_sizer.AddWindow(self.DirectlyBaseType, 1, border=5, + directly_panel_sizer.AddWindow(self.DirectlyBaseType, 1, border=5, flag=wx.GROW|wx.ALL) - + directly_initialvalue_label = wx.StaticText(self.DirectlyPanel, label=_('Initial Value:')) - directly_panel_sizer.AddWindow(directly_initialvalue_label, 1, border=5, + directly_panel_sizer.AddWindow(directly_initialvalue_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) - - self.DirectlyInitialValue = wx.TextCtrl(self.DirectlyPanel, + + self.DirectlyInitialValue = wx.TextCtrl(self.DirectlyPanel, style=wx.TE_PROCESS_ENTER|wx.TE_RICH) self.Bind(wx.EVT_TEXT_ENTER, self.OnReturnKeyPressed, self.DirectlyInitialValue) - directly_panel_sizer.AddWindow(self.DirectlyInitialValue, 1, border=5, + directly_panel_sizer.AddWindow(self.DirectlyInitialValue, 1, border=5, flag=wx.ALL) - + self.DirectlyPanel.SetSizer(directly_panel_sizer) - + # Panel for Subrange data types self.SubrangePanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) typeinfos_sizer.AddWindow(self.SubrangePanel, 1) - + subrange_panel_sizer = wx.GridSizer(cols=4, hgap=5, rows=3, vgap=0) - + subrange_basetype_label = wx.StaticText(self.SubrangePanel, label=_('Base Type:')) - subrange_panel_sizer.AddWindow(subrange_basetype_label, 1, border=5, + subrange_panel_sizer.AddWindow(subrange_basetype_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) - + self.SubrangeBaseType = wx.ComboBox(self.SubrangePanel, style=wx.CB_READONLY) - self.Bind(wx.EVT_COMBOBOX, self.OnSubrangeBaseTypeChanged, + self.Bind(wx.EVT_COMBOBOX, self.OnSubrangeBaseTypeChanged, self.SubrangeBaseType) - subrange_panel_sizer.AddWindow(self.SubrangeBaseType, 1, border=5, + subrange_panel_sizer.AddWindow(self.SubrangeBaseType, 1, border=5, flag=wx.GROW|wx.ALL) - + subrange_initialvalue_label = wx.StaticText(self.SubrangePanel, label=_('Initial Value:')) - subrange_panel_sizer.AddWindow(subrange_initialvalue_label, 1, border=5, + subrange_panel_sizer.AddWindow(subrange_initialvalue_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) - - self.SubrangeInitialValue = wx.SpinCtrl(self.SubrangePanel, + + self.SubrangeInitialValue = wx.SpinCtrl(self.SubrangePanel, style=wx.TAB_TRAVERSAL) self.Bind(wx.EVT_SPINCTRL, self.OnInfosChanged, self.SubrangeInitialValue) - subrange_panel_sizer.AddWindow(self.SubrangeInitialValue, 1, border=5, + subrange_panel_sizer.AddWindow(self.SubrangeInitialValue, 1, border=5, flag=wx.GROW|wx.ALL) - + subrange_minimum_label = wx.StaticText(self.SubrangePanel, label=_('Minimum:')) - subrange_panel_sizer.AddWindow(subrange_minimum_label, 1, border=5, + subrange_panel_sizer.AddWindow(subrange_minimum_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) - + self.SubrangeMinimum = wx.SpinCtrl(self.SubrangePanel, style=wx.TAB_TRAVERSAL) self.Bind(wx.EVT_SPINCTRL, self.OnSubrangeMinimumChanged, self.SubrangeMinimum) - subrange_panel_sizer.AddWindow(self.SubrangeMinimum, 1, border=5, + subrange_panel_sizer.AddWindow(self.SubrangeMinimum, 1, border=5, flag=wx.GROW|wx.ALL) - + for i in xrange(2): subrange_panel_sizer.AddWindow(wx.Size(0, 0), 1) - + subrange_maximum_label = wx.StaticText(self.SubrangePanel, label=_('Maximum:')) - subrange_panel_sizer.AddWindow(subrange_maximum_label, 1, border=5, + subrange_panel_sizer.AddWindow(subrange_maximum_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) - + self.SubrangeMaximum = wx.SpinCtrl(self.SubrangePanel, style=wx.TAB_TRAVERSAL) self.Bind(wx.EVT_SPINCTRL, self.OnSubrangeMaximumChanged, self.SubrangeMaximum) - - subrange_panel_sizer.AddWindow(self.SubrangeMaximum, 1, border=5, + + subrange_panel_sizer.AddWindow(self.SubrangeMaximum, 1, border=5, flag=wx.GROW|wx.ALL) - + self.SubrangePanel.SetSizer(subrange_panel_sizer) - + # Panel for Enumerated data types - + self.EnumeratedPanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) typeinfos_sizer.AddWindow(self.EnumeratedPanel, 1) - + enumerated_panel_sizer = wx.BoxSizer(wx.HORIZONTAL) - - self.EnumeratedValues = CustomEditableListBox(self.EnumeratedPanel, - label=_("Values:"), style=wx.gizmos.EL_ALLOW_NEW| - wx.gizmos.EL_ALLOW_EDIT| + + self.EnumeratedValues = CustomEditableListBox(self.EnumeratedPanel, + label=_("Values:"), style=wx.gizmos.EL_ALLOW_NEW| + wx.gizmos.EL_ALLOW_EDIT| wx.gizmos.EL_ALLOW_DELETE) setattr(self.EnumeratedValues, "_OnLabelEndEdit", self.OnEnumeratedValueEndEdit) for func in ["_OnAddButton", "_OnDelButton", "_OnUpButton", "_OnDownButton"]: setattr(self.EnumeratedValues, func, self.OnEnumeratedValuesChanged) - enumerated_panel_sizer.AddWindow(self.EnumeratedValues, 1, border=5, + enumerated_panel_sizer.AddWindow(self.EnumeratedValues, 1, border=5, flag=wx.GROW|wx.ALL) - + enumerated_panel_rightsizer = wx.BoxSizer(wx.HORIZONTAL) enumerated_panel_sizer.AddSizer(enumerated_panel_rightsizer, 1) - + enumerated_initialvalue_label = wx.StaticText(self.EnumeratedPanel, label=_('Initial Value:')) - enumerated_panel_rightsizer.AddWindow(enumerated_initialvalue_label, 1, + enumerated_panel_rightsizer.AddWindow(enumerated_initialvalue_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) - - self.EnumeratedInitialValue = wx.ComboBox(self.EnumeratedPanel, + + self.EnumeratedInitialValue = wx.ComboBox(self.EnumeratedPanel, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.EnumeratedInitialValue) - enumerated_panel_rightsizer.AddWindow(self.EnumeratedInitialValue, 1, + enumerated_panel_rightsizer.AddWindow(self.EnumeratedInitialValue, 1, border=5, flag=wx.ALL) - + self.EnumeratedPanel.SetSizer(enumerated_panel_sizer) - + # Panel for Array data types self.ArrayPanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) typeinfos_sizer.AddWindow(self.ArrayPanel, 1) - + array_panel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=0) array_panel_sizer.AddGrowableCol(0) array_panel_sizer.AddGrowableCol(1) array_panel_sizer.AddGrowableRow(1) - + array_panel_leftSizer = wx.BoxSizer(wx.HORIZONTAL) array_panel_sizer.AddSizer(array_panel_leftSizer, flag=wx.GROW) - + array_basetype_label = wx.StaticText(self.ArrayPanel, label=_('Base Type:')) - array_panel_leftSizer.AddWindow(array_basetype_label, 1, border=5, + array_panel_leftSizer.AddWindow(array_basetype_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) - + self.ArrayBaseType = wx.ComboBox(self.ArrayPanel, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.ArrayBaseType) - array_panel_leftSizer.AddWindow(self.ArrayBaseType, 1, border=5, + array_panel_leftSizer.AddWindow(self.ArrayBaseType, 1, border=5, flag=wx.GROW|wx.ALL) - + array_panel_rightsizer = wx.BoxSizer(wx.HORIZONTAL) array_panel_sizer.AddSizer(array_panel_rightsizer, flag=wx.GROW) - + array_initialvalue_label = wx.StaticText(self.ArrayPanel, label=_('Initial Value:')) - array_panel_rightsizer.AddWindow(array_initialvalue_label, 1, border=5, + array_panel_rightsizer.AddWindow(array_initialvalue_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) - + self.ArrayInitialValue = wx.TextCtrl(self.ArrayPanel, style=wx.TE_PROCESS_ENTER|wx.TE_RICH) self.Bind(wx.EVT_TEXT_ENTER, self.OnReturnKeyPressed, self.ArrayInitialValue) - array_panel_rightsizer.AddWindow(self.ArrayInitialValue, 1, border=5, - flag=wx.ALL) - - self.ArrayDimensions = CustomEditableListBox(self.ArrayPanel, + array_panel_rightsizer.AddWindow(self.ArrayInitialValue, 1, border=5, + flag=wx.ALL) + + self.ArrayDimensions = CustomEditableListBox(self.ArrayPanel, label=_("Dimensions:"), style=wx.gizmos.EL_ALLOW_NEW| wx.gizmos.EL_ALLOW_EDIT| wx.gizmos.EL_ALLOW_DELETE) - for func in ["_OnLabelEndEdit", "_OnAddButton", "_OnDelButton", + for func in ["_OnLabelEndEdit", "_OnAddButton", "_OnDelButton", "_OnUpButton", "_OnDownButton"]: setattr(self.ArrayDimensions, func, self.OnDimensionsChanged) - array_panel_sizer.AddWindow(self.ArrayDimensions, 0, border=5, + array_panel_sizer.AddWindow(self.ArrayDimensions, 0, border=5, flag=wx.GROW|wx.ALL) - + self.ArrayPanel.SetSizer(array_panel_sizer) - + # Panel for Structure data types - + self.StructurePanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) typeinfos_sizer.AddWindow(self.StructurePanel, 1) - + structure_panel_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) structure_panel_sizer.AddGrowableCol(0) structure_panel_sizer.AddGrowableRow(1) - + structure_button_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) structure_button_sizer.AddGrowableCol(0) structure_button_sizer.AddGrowableRow(0) - structure_panel_sizer.AddSizer(structure_button_sizer, 0, border=5, + structure_panel_sizer.AddSizer(structure_button_sizer, 0, border=5, flag=wx.ALL|wx.GROW) - + structure_elements_label = wx.StaticText(self.StructurePanel, label=_('Elements :')) structure_button_sizer.AddWindow(structure_elements_label, flag=wx.ALIGN_BOTTOM) - + for name, bitmap, help in [ ("StructureAddButton", "add_element", _("Add element")), ("StructureDeleteButton", "remove_element", _("Remove element")), @@ -357,46 +357,46 @@ button.SetToolTipString(help) setattr(self, name, button) structure_button_sizer.AddWindow(button) - - self.StructureElementsGrid = CustomGrid(self.StructurePanel, + + self.StructureElementsGrid = CustomGrid(self.StructurePanel, size=wx.Size(0, 150), style=wx.VSCROLL) - self.StructureElementsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, + self.StructureElementsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnStructureElementsGridCellChange) - self.StructureElementsGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, + self.StructureElementsGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnStructureElementsGridEditorShown) structure_panel_sizer.AddWindow(self.StructureElementsGrid, flag=wx.GROW) - + self.StructurePanel.SetSizer(structure_panel_sizer) - + self.Editor.SetSizer(self.MainSizer) - + def __init__(self, parent, tagname, window, controler): EditorPanel.__init__(self, parent, tagname, window, controler) - - self.StructureElementDefaultValue = {"Name" : "", "Type" : "INT", "Initial Value" : ""} + + self.StructureElementDefaultValue = {"Name" : "", "Type" : DefaultType, "Initial Value" : ""} self.StructureElementsTable = ElementsTable(self, [], GetElementsTableColnames()) self.StructureColSizes = [40, 150, 100, 250] self.StructureColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT] - + self.StructureElementsGrid.SetTable(self.StructureElementsTable) self.StructureElementsGrid.SetButtons({"Add": self.StructureAddButton, "Delete": self.StructureDeleteButton, "Up": self.StructureUpButton, "Down": self.StructureDownButton}) - + def _AddStructureElement(new_row): self.StructureElementsTable.InsertRow(new_row, self.StructureElementDefaultValue.copy()) self.RefreshTypeInfos() self.StructureElementsTable.ResetView(self.StructureElementsGrid) return new_row setattr(self.StructureElementsGrid, "_AddRow", _AddStructureElement) - + def _DeleteStructureElement(row): self.StructureElementsTable.RemoveRow(row) self.RefreshTypeInfos() self.StructureElementsTable.ResetView(self.StructureElementsGrid) setattr(self.StructureElementsGrid, "_DeleteRow", _DeleteStructureElement) - + def _MoveStructureElement(row, move): new_row = self.StructureElementsTable.MoveRow(row, move) if new_row != row: @@ -404,7 +404,7 @@ self.StructureElementsTable.ResetView(self.StructureElementsGrid) return new_row setattr(self.StructureElementsGrid, "_MoveRow", _MoveStructureElement) - + self.StructureElementsGrid.SetRowLabelSize(0) for col in range(self.StructureElementsTable.GetNumberCols()): attr = wx.grid.GridCellAttr() @@ -413,7 +413,7 @@ self.StructureElementsGrid.SetColMinimalWidth(col, self.StructureColSizes[col]) self.StructureElementsGrid.AutoSizeColumn(col, False) self.StructureElementsGrid.RefreshButtons() - + for datatype in GetDatatypeTypes(): self.DerivationType.Append(_(datatype)) self.SubrangePanel.Hide() @@ -423,7 +423,7 @@ self.CurrentPanel = "Directly" self.Highlights = [] self.Initializing = False - + self.HighlightControls = { ("Directly", "base"): self.DirectlyBaseType, ("Directly", "initial"): self.DirectlyInitialValue, @@ -437,27 +437,27 @@ ("Array", "base"): self.ArrayBaseType, ("Array", "range"): self.ArrayDimensions, } - + self.RefreshHighlightsTimer = wx.Timer(self, -1) self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) - + def __del__(self): self.RefreshHighlightsTimer.Stop() - + def GetBufferState(self): return self.Controler.GetBufferState() - + def Undo(self): self.Controler.LoadPrevious() self.ParentWindow.CloseTabsWithoutModel() - + def Redo(self): self.Controler.LoadNext() self.ParentWindow.CloseTabsWithoutModel() - + def HasNoModel(self): return self.Controler.GetEditedElement(self.TagName) is None - + def RefreshView(self): self.Initializing = True self.DirectlyBaseType.Clear() @@ -504,7 +504,7 @@ self.StructureElementsTable.ResetView(self.StructureElementsGrid) self.StructureElementsGrid.RefreshButtons() self.Initializing = False - + def OnDerivationTypeChanged(self, event): wx.CallAfter(self.RefreshDisplayedInfos) wx.CallAfter(self.RefreshTypeInfos) @@ -512,7 +512,7 @@ def OnReturnKeyPressed(self, event): self.RefreshTypeInfos() - + def OnInfosChanged(self, event): self.RefreshTypeInfos() event.Skip() @@ -563,12 +563,12 @@ event.Skip() else: event.Skip() - + def OnEnumeratedValuesChanged(self, event): wx.CallAfter(self.RefreshEnumeratedValues) wx.CallAfter(self.RefreshTypeInfos) event.Skip() - + def OnStructureElementsGridCellChange(self, event): row, col = event.GetRow(), event.GetCol() colname = self.StructureElementsTable.GetColLabelValue(col, False) @@ -606,34 +606,34 @@ self.RefreshTypeInfos() wx.CallAfter(self.StructureElementsTable.ResetView, self.StructureElementsGrid) event.Skip() - + def OnStructureElementsGridSelectCell(self, event): wx.CallAfter(self.RefreshStructureButtons) event.Skip() - + def OnStructureElementsGridEditorShown(self, event): - row, col = event.GetRow(), event.GetCol() + row, col = event.GetRow(), event.GetCol() if self.StructureElementsTable.GetColLabelValue(col, False) == "Type": type_menu = wx.Menu(title='') - + base_menu = wx.Menu(title='') for base_type in self.Controler.GetBaseTypes(): new_id = wx.NewId() AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type) self.Bind(wx.EVT_MENU, self.GetElementTypeFunction(base_type), id=new_id) type_menu.AppendMenu(wx.NewId(), _("Base Types"), base_menu) - + datatype_menu = wx.Menu(title='') for datatype in self.Controler.GetDataTypes(self.TagName, False): new_id = wx.NewId() AppendMenu(datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype) self.Bind(wx.EVT_MENU, self.GetElementTypeFunction(datatype), id=new_id) type_menu.AppendMenu(wx.NewId(), _("User Data Types"), datatype_menu) - + new_id = wx.NewId() AppendMenu(type_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Array")) self.Bind(wx.EVT_MENU, self.ElementArrayTypeFunction, id=new_id) - + ## functionblock_menu = wx.Menu(title='') ## bodytype = self.Controler.GetEditedElementBodyType(self.TagName) ## pouname, poutype = self.Controler.GetEditedElementType(self.TagName) @@ -661,8 +661,8 @@ def ElementArrayTypeFunction(self, event): row = self.StructureElementsGrid.GetGridCursorRow() - dialog = ArrayTypeDialog(self, - self.Controler.GetDataTypes(self.TagName), + dialog = ArrayTypeDialog(self, + self.Controler.GetDataTypes(self.TagName), self.StructureElementsTable.GetValueByName(row, "Type")) if dialog.ShowModal() == wx.ID_OK: self.StructureElementsTable.SetValueByName(row, "Type", dialog.GetValue()) diff -r 86797748c2a2 -r f65ab5ff91d1 editors/TextViewer.py --- a/editors/TextViewer.py Mon May 26 14:44:03 2014 +0100 +++ b/editors/TextViewer.py Fri Jun 06 18:30:49 2014 +0100 @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor -#based on the plcopen standard. +#based on the plcopen standard. # #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD # @@ -45,8 +45,8 @@ LETTERS.append(chr(ord('a') + i)) LETTERS.append(chr(ord('A') + i)) -[STC_PLC_WORD, STC_PLC_COMMENT, STC_PLC_NUMBER, STC_PLC_STRING, - STC_PLC_VARIABLE, STC_PLC_PARAMETER, STC_PLC_FUNCTION, STC_PLC_JUMP, +[STC_PLC_WORD, STC_PLC_COMMENT, STC_PLC_NUMBER, STC_PLC_STRING, + STC_PLC_VARIABLE, STC_PLC_PARAMETER, STC_PLC_FUNCTION, STC_PLC_JUMP, STC_PLC_ERROR, STC_PLC_SEARCH_RESULT] = range(10) [SPACE, WORD, NUMBER, STRING, WSTRING, COMMENT, PRAGMA, DPRAGMA] = range(8) @@ -70,35 +70,35 @@ return reduce(lambda x, y: x or y, map(lambda x: line.startswith(x), symbols), False) class TextViewer(EditorPanel): - + ID = ID_TEXTVIEWER - + if wx.VERSION < (2, 6, 0): def Bind(self, event, function, id = None): if id is not None: event(self, id, function) else: event(self, function) - + def _init_Editor(self, prnt): - self.Editor = CustomStyledTextCtrl(id=ID_TEXTVIEWERTEXTCTRL, + self.Editor = CustomStyledTextCtrl(id=ID_TEXTVIEWERTEXTCTRL, parent=prnt, name="TextViewer", size=wx.Size(0, 0), style=0) self.Editor.ParentWindow = self - + self.Editor.CmdKeyAssign(ord('+'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMIN) self.Editor.CmdKeyAssign(ord('-'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMOUT) - + self.Editor.SetViewWhiteSpace(False) - + self.Editor.SetLexer(wx.stc.STC_LEX_CONTAINER) - + # Global default styles for all languages self.Editor.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) self.Editor.StyleClearAll() # Reset all to be like the default - + self.Editor.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,size:%(size)d" % faces) self.Editor.SetSelBackground(1, "#E0E0E0") - + # Highlighting styles self.Editor.StyleSetSpec(STC_PLC_WORD, "fore:#00007F,bold,size:%(size)d" % faces) self.Editor.StyleSetSpec(STC_PLC_VARIABLE, "fore:#7F0000,size:%(size)d" % faces) @@ -110,18 +110,18 @@ self.Editor.StyleSetSpec(STC_PLC_JUMP, "fore:#FF7FFF,size:%(size)d" % faces) self.Editor.StyleSetSpec(STC_PLC_ERROR, "fore:#FF0000,back:#FFFF00,size:%(size)d" % faces) self.Editor.StyleSetSpec(STC_PLC_SEARCH_RESULT, "fore:#FFFFFF,back:#FFA500,size:%(size)d" % faces) - + # Indicators styles self.Editor.IndicatorSetStyle(0, wx.stc.STC_INDIC_SQUIGGLE) if self.ParentWindow is not None and self.Controler is not None: self.Editor.IndicatorSetForeground(0, wx.RED) else: self.Editor.IndicatorSetForeground(0, wx.WHITE) - + # Line numbers in the margin self.Editor.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) self.Editor.SetMarginWidth(1, 50) - + # Folding self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPEN, wx.stc.STC_MARK_BOXMINUS, "white", "#808080") self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDER, wx.stc.STC_MARK_BOXPLUS, "white", "#808080") @@ -130,11 +130,11 @@ self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEREND, wx.stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPENMID, wx.stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERMIDTAIL, wx.stc.STC_MARK_TCORNER, "white", "#808080") - + # Indentation size self.Editor.SetTabWidth(2) self.Editor.SetUseTabs(0) - + self.Editor.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT| wx.stc.STC_MOD_BEFOREDELETE| wx.stc.STC_PERFORMED_USER) @@ -147,13 +147,13 @@ self.Editor.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_TEXTVIEWERTEXTCTRL) self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_TEXTVIEWERTEXTCTRL) - + def __init__(self, parent, tagname, window, controler, debug = False, instancepath = ""): if tagname != "" and controler is not None: self.VARIABLE_PANEL_TYPE = controler.GetPouType(tagname.split("::")[1]) - + EditorPanel.__init__(self, parent, tagname, window, controler, debug) - + self.Keywords = [] self.Variables = {} self.Functions = {} @@ -163,62 +163,62 @@ self.DisableEvents = True self.TextSyntax = None self.CurrentAction = None - + self.InstancePath = instancepath self.ContextStack = [] self.CallStack = [] - + self.ResetSearchResults() - + self.RefreshHighlightsTimer = wx.Timer(self, -1) self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) - + def __del__(self): self.RefreshHighlightsTimer.Stop() - + def GetTitle(self): if self.Debug or self.TagName == "": if len(self.InstancePath) > 15: return "..." + self.InstancePath[-12:] return self.InstancePath return EditorPanel.GetTitle(self) - + def GetInstancePath(self): return self.InstancePath - + def IsViewing(self, tagname): if self.Debug or self.TagName == "": return self.InstancePath == tagname else: return self.TagName == tagname - + def GetText(self): return self.Editor.GetText() - + def SetText(self, text): self.Editor.SetText(text) - + def SelectAll(self): self.Editor.SelectAll() - + def Colourise(self, start, end): self.Editor.Colourise(start, end) - + def StartStyling(self, pos, mask): self.Editor.StartStyling(pos, mask) - + def SetStyling(self, length, style): self.Editor.SetStyling(length, style) - + def GetCurrentPos(self): return self.Editor.GetCurrentPos() - + def ResetSearchResults(self): self.Highlights = [] self.SearchParams = None self.SearchResults = None self.CurrentFindHighlight = None - + def OnModification(self, event): if not self.DisableEvents: mod_type = event.GetModificationType() @@ -239,7 +239,7 @@ self.CurrentAction = ("Delete", event.GetPosition()) wx.CallAfter(self.RefreshModel) event.Skip() - + def OnDoDrop(self, event): try: values = eval(event.GetDragText()) @@ -256,7 +256,7 @@ blockinputs = values[3] else: blockinputs = None - if values[1] != "function": + if values[1] != "function": if blockname == "": dialog = wx.TextEntryDialog(self.ParentWindow, "Block name", "Please enter a block name", "", wx.OK|wx.CANCEL|wx.CENTRE) if dialog.ShowModal() == wx.ID_OK: @@ -291,9 +291,9 @@ else: location = values[0] if not location.startswith("%"): - dialog = wx.SingleChoiceDialog(self.ParentWindow, - _("Select a variable class:"), _("Variable class"), - ["Input", "Output", "Memory"], + dialog = wx.SingleChoiceDialog(self.ParentWindow, + _("Select a variable class:"), _("Variable class"), + ["Input", "Output", "Memory"], wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL) if dialog.ShowModal() == wx.ID_OK: selected = dialog.GetSelection() @@ -314,13 +314,30 @@ else: var_type = LOCATIONDATATYPES.get(location[2], ["BOOL"])[0] self.Controler.AddEditedElementPouVar(self.TagName, - var_type, var_name, + var_type, var_name, location=location, description=values[4]) self.RefreshVariablePanel() self.RefreshVariableTree() event.SetDragText(var_name) else: event.SetDragText("") + elif values[1] == "NamedConstant": + pou_name, pou_type = self.Controler.GetEditedElementType(self.TagName, self.Debug) + if pou_type == "program": + initval = values[0] + var_name = values[3] + if var_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]: + message = _("\"%s\" pou already exists!")%var_name + else: + var_type = values[2] + if not var_name.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]: + self.Controler.AddEditedElementPouVar(self.TagName, + var_type, + var_name, + description=values[4], initval=initval) + self.RefreshVariablePanel() + self.RefreshVariableTree() + event.SetDragText(var_name) elif values[1] == "Global": var_name = values[0] if var_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]: @@ -345,7 +362,7 @@ dialog.Destroy() event.SetDragText("") event.Skip() - + def SetTextSyntax(self, syntax): self.TextSyntax = syntax if syntax in ["ST", "ALL"]: @@ -362,16 +379,16 @@ else: self.BlockStartKeywords = [] self.BlockEndKeywords = [] - + def SetKeywords(self, keywords): self.Keywords = [keyword.upper() for keyword in keywords] self.Colourise(0, -1) - + def RefreshJumpList(self): if self.TextSyntax != "IL": self.Jumps = [jump.upper() for jump in LABEL_MODEL.findall(self.GetText())] self.Colourise(0, -1) - + # Buffer the last model state def RefreshBuffer(self): self.Controler.BufferProject() @@ -379,42 +396,42 @@ self.ParentWindow.RefreshTitle() self.ParentWindow.RefreshFileMenu() self.ParentWindow.RefreshEditMenu() - + def StartBuffering(self): self.Controler.StartBuffering() if self.ParentWindow: self.ParentWindow.RefreshTitle() self.ParentWindow.RefreshFileMenu() self.ParentWindow.RefreshEditMenu() - + def ResetBuffer(self): if self.CurrentAction != None: self.Controler.EndBuffering() self.CurrentAction = None - + def GetBufferState(self): if not self.Debug and self.TextSyntax != "ALL": return self.Controler.GetBufferState() return False, False - + def Undo(self): if not self.Debug and self.TextSyntax != "ALL": self.Controler.LoadPrevious() self.ParentWindow.CloseTabsWithoutModel() - + def Redo(self): if not self.Debug and self.TextSyntax != "ALL": self.Controler.LoadNext() self.ParentWindow.CloseTabsWithoutModel() - + def HasNoModel(self): if not self.Debug and self.TextSyntax != "ALL": return self.Controler.GetEditedElement(self.TagName) is None return False - + def RefreshView(self, variablepanel=True): EditorPanel.RefreshView(self, variablepanel) - + if self.Controler is not None: self.ResetBuffer() self.DisableEvents = True @@ -434,12 +451,12 @@ self.RefreshJumpList() self.Editor.EmptyUndoBuffer() self.DisableEvents = False - + self.RefreshVariableTree() - + self.TypeNames = [typename.upper() for typename in self.Controler.GetDataTypes(self.TagName, True, self.Debug)] self.EnumeratedValues = [value.upper() for value in self.Controler.GetEnumeratedDataValues()] - + self.Functions = {} for category in self.Controler.GetBlockTypes(self.TagName, self.Debug): for blocktype in category["list"]: @@ -455,13 +472,13 @@ else: self.Functions[blockname] = {"interface": interface, "extensible": blocktype["extensible"]} - + self.Colourise(0, -1) - + def RefreshVariableTree(self): words = self.TagName.split("::") self.Variables = self.GenerateVariableTree( - [(variable.Name, variable.Type, variable.Tree) + [(variable.Name, variable.Type, variable.Tree) for variable in self.Controler.GetEditedElementInterfaceVars( self.TagName, True, self.Debug)]) if self.Controler.GetEditedElementType(self.TagName, self.Debug)[1] == "function" or words[0] == "T" and self.TextSyntax == "IL": @@ -470,22 +487,22 @@ self.Variables[words[-1].upper()] = self.GenerateVariableTree(var_tree) else: self.Variables[words[-1].upper()] = {} - + def GenerateVariableTree(self, list): tree = {} for var_name, var_type, (var_tree, var_dimension) in list: tree[var_name.upper()] = self.GenerateVariableTree(var_tree) return tree - + def IsValidVariable(self, name, context): return context is not None and context.get(name, None) is not None def IsCallParameter(self, name, call): if call is not None: - return (call["interface"].get(name.upper(), None) is not None or + return (call["interface"].get(name.upper(), None) is not None or call["extensible"] and EXTENSIBLE_PARAMETER.match(name.upper()) is not None) return False - + def RefreshLineFolding(self, line_number): if self.TextSyntax in ["ST", "ALL"]: level = wx.stc.STC_FOLDLEVELBASE + self.Editor.GetLineIndentation(line_number) @@ -497,7 +514,7 @@ else: level = self.Editor.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK if level != wx.stc.STC_FOLDLEVELBASE: - level |= wx.stc.STC_FOLDLEVELWHITEFLAG + level |= wx.stc.STC_FOLDLEVELWHITEFLAG elif LineStartswith(line, self.BlockStartKeywords): level |= wx.stc.STC_FOLDLEVELHEADERFLAG elif LineStartswith(line, self.BlockEndKeywords): @@ -506,7 +523,7 @@ else: level = self.Editor.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK self.Editor.SetFoldLevel(line_number, level) - + def OnStyleNeeded(self, event): self.TextChanged = True line_number = self.Editor.LineFromPosition(self.Editor.GetEndStyled()) @@ -517,10 +534,10 @@ self.RefreshLineFolding(line_number) end_pos = event.GetPosition() self.StartStyling(start_pos, 0xff) - + current_context = self.Variables current_call = None - + current_pos = last_styled_pos state = SPACE line = "" @@ -642,7 +659,7 @@ elif self.IsCallParameter(word, current_call): self.SetStyling(current_pos - last_styled_pos, STC_PLC_PARAMETER) elif word in self.Functions: - self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION) + self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION) elif self.TextSyntax == "IL" and word in self.Jumps: self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP) elif word in self.EnumeratedValues: @@ -670,7 +687,7 @@ if char == '[' and current_context is not None: self.ContextStack.append(current_context.get(word, None)) current_context = self.Variables - + word = "" last_styled_pos = current_pos state = SPACE @@ -717,20 +734,20 @@ self.SetStyling(current_pos - start_pos, 31) self.ShowHighlights(start_pos, end_pos) event.Skip() - + def OnMarginClick(self, event): if event.GetMargin() == 2: line = self.Editor.LineFromPosition(event.GetPosition()) if self.Editor.GetFoldLevel(line) & wx.stc.STC_FOLDLEVELHEADERFLAG: self.Editor.ToggleFold(line) event.Skip() - + def OnUpdateUI(self, event): selected = self.Editor.GetSelectedText() if self.ParentWindow and selected != "": self.ParentWindow.SetCopyBuffer(selected, True) event.Skip() - + def Cut(self): self.ResetBuffer() self.DisableEvents = True @@ -738,12 +755,12 @@ self.DisableEvents = False self.RefreshModel() self.RefreshBuffer() - + def Copy(self): self.Editor.CmdKeyExecute(wx.stc.STC_CMD_COPY) if self.ParentWindow: self.ParentWindow.RefreshEditMenu() - + def Paste(self): self.ResetBuffer() self.DisableEvents = True @@ -751,28 +768,28 @@ self.DisableEvents = False self.RefreshModel() self.RefreshBuffer() - + def Search(self, criteria): return self.Controler.SearchInPou(self.TagName, criteria, self.Debug) - + def Find(self, direction, search_params): if self.SearchParams != search_params: self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT) - + self.SearchParams = search_params criteria = { - "raw_pattern": search_params["find_pattern"], + "raw_pattern": search_params["find_pattern"], "pattern": re.compile(search_params["find_pattern"]), "case_sensitive": search_params["case_sensitive"], "regular_expression": search_params["regular_expression"], "filter": "all"} - + self.SearchResults = [ (infos[1:], start, end, SEARCH_RESULT_HIGHLIGHT) - for infos, start, end, text in + for infos, start, end, text in self.Search(criteria)] self.CurrentFindHighlight = None - + if len(self.SearchResults) > 0: if self.CurrentFindHighlight is not None: old_idx = self.SearchResults.index(self.CurrentFindHighlight) @@ -787,24 +804,24 @@ else: self.CurrentFindHighlight = self.SearchResults[0] self.AddHighlight(*self.CurrentFindHighlight) - + else: if self.CurrentFindHighlight is not None: self.RemoveHighlight(*self.CurrentFindHighlight) self.CurrentFindHighlight = None - + def RefreshModel(self): self.RefreshJumpList() self.Controler.SetEditedElementText(self.TagName, self.GetText()) self.ResetSearchResults() - + def OnKeyDown(self, event): key = event.GetKeyCode() if self.Controler is not None: - + if self.Editor.CallTipActive(): self.Editor.CallTipCancel() - + key_handled = False line = self.Editor.GetCurrentLine() @@ -814,15 +831,15 @@ start_pos = self.Editor.GetLineEndPosition(line - 1) + 1 end_pos = self.GetCurrentPos() lineText = self.Editor.GetTextRange(start_pos, end_pos).replace("\t", " ") - + # Code completion if key == wx.WXK_SPACE and event.ControlDown(): - + words = lineText.split(" ") words = [word for i, word in enumerate(words) if word != '' or i == len(words) - 1] - + kw = [] - + if self.TextSyntax == "IL": if len(words) == 1: kw = self.Keywords @@ -875,7 +892,7 @@ def ClearHighlights(self, highlight_type=None): EditorPanel.ClearHighlights(self, highlight_type) - + if highlight_type is None: self.Highlights = [] else: @@ -886,7 +903,7 @@ def AddHighlight(self, infos, start, end, highlight_type): EditorPanel.AddHighlight(self, infos, start, end, highlight_type) - + highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None) if infos[0] == "body" and highlight_type is not None: self.Highlights.append((infos[1], start, end, highlight_type)) @@ -895,13 +912,13 @@ def RemoveHighlight(self, infos, start, end, highlight_type): EditorPanel.RemoveHighlight(self, infos, start, end, highlight_type) - + highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None) - if (infos[0] == "body" and highlight_type is not None and + if (infos[0] == "body" and highlight_type is not None and (infos[1], start, end, highlight_type) in self.Highlights): self.Highlights.remove((infos[1], start, end, highlight_type)) self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) - + def ShowHighlights(self, start_pos, end_pos): for indent, start, end, highlight_type in self.Highlights: if start[0] == 0: @@ -917,4 +934,4 @@ self.SetStyling(highlight_end_pos - highlight_start_pos, highlight_type) self.StartStyling(highlight_start_pos, 0x00) self.SetStyling(len(self.Editor.GetText()) - highlight_end_pos, wx.stc.STC_STYLE_DEFAULT) - + diff -r 86797748c2a2 -r f65ab5ff91d1 plcopen/definitions.py --- a/plcopen/definitions.py Mon May 26 14:44:03 2014 +0100 +++ b/plcopen/definitions.py Fri Jun 06 18:30:49 2014 +0100 @@ -12,7 +12,7 @@ "B" : ["SINT", "USINT", "BYTE", "STRING"], "W" : ["INT", "UINT", "WORD", "WSTRING"], "D" : ["DINT", "UDINT", "REAL", "DWORD"], - "L" : ["LINT", "ULINT", "LREAL", "LWORD"]} + "L" : ["LINT", "ULINT", "LREAL", "LWORD"]} #------------------------------------------------------------------------------- # Function Block Types definitions @@ -105,6 +105,8 @@ #("WSTRING", "ANY_STRING") # TODO ] +DefaultType = "DINT" + DataTypeRange_list = [ ("SINT", (-2**7, 2**7 - 1)), ("INT", (-2**15, 2**15 - 1)), diff -r 86797748c2a2 -r f65ab5ff91d1 py_ext/plc_python.c --- a/py_ext/plc_python.c Mon May 26 14:44:03 2014 +0100 +++ b/py_ext/plc_python.c Fri Jun 06 18:30:49 2014 +0100 @@ -119,7 +119,7 @@ /*printf("__PythonEvalFB pop %%d - %%*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ }else if(poll){ /* when in polling, no answer == ack down */ - __SET_VAR(data__->, ACK., 0); + __SET_VAR(data__->, ACK,, 0); } /* got the order to act ?*/ if(__GET_VAR(data__->TRIGGED) == 1 && diff -r 86797748c2a2 -r f65ab5ff91d1 util/ProcessLogger.py --- a/util/ProcessLogger.py Mon May 26 14:44:03 2014 +0100 +++ b/util/ProcessLogger.py Fri Jun 06 18:30:49 2014 +0100 @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- #This file is part of Beremiz, a Integrated Development Environment for -#programming IEC 61131-3 automates supporting plcopen standard and CanFestival. +#programming IEC 61131-3 automates supporting plcopen standard and CanFestival. # #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD # @@ -31,7 +31,7 @@ if os.name == 'posix': from signal import SIGTERM, SIGKILL - + class outputThread(Thread): """ Thread is used to print the output of a command to the stdout @@ -66,10 +66,10 @@ err = self.retval self.finished = True self.endcallback(self.Proc.pid, err) - + class ProcessLogger: - def __init__(self, logger, Command, finish_callback = None, - no_stdout = False, no_stderr = False, no_gui = True, + def __init__(self, logger, Command, finish_callback = None, + no_stdout = False, no_stderr = False, no_gui = True, timeout = None, outlimit = None, errlimit = None, endlog = None, keyword = None, kill_it = False, cwd = None): self.logger = logger @@ -86,10 +86,10 @@ else: self.Command = Command self.Command_str = subprocess.list2cmdline(self.Command) - + self.Command = map(lambda x: x.encode(sys.getfilesystemencoding()), self.Command) - + self.finish_callback = finish_callback self.no_stdout = no_stdout self.no_stderr = no_stderr @@ -105,27 +105,27 @@ self.kill_it = kill_it self.finishsem = Semaphore(0) self.endlock = Lock() - + popenargs= { "cwd":os.getcwd() if cwd is None else cwd, - "stdin":subprocess.PIPE, - "stdout":subprocess.PIPE, + "stdin":subprocess.PIPE, + "stdout":subprocess.PIPE, "stderr":subprocess.PIPE} - + if no_gui == True and wx.Platform == '__WXMSW__': self.startupinfo = subprocess.STARTUPINFO() self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW popenargs["startupinfo"] = self.startupinfo elif wx.Platform == '__WXGTK__': popenargs["shell"] = False - + self.Proc = subprocess.Popen( self.Command, **popenargs ) self.outt = outputThread( self.Proc, self.Proc.stdout, self.output, - self.finish) + self.finish) self.outt.start() self.errt = outputThread( @@ -147,7 +147,7 @@ self.logger.write(v) if (self.keyword and v.find(self.keyword)!=-1) or (self.outlimit and self.outlen > self.outlimit): self.endlog() - + def errors(self,v): self.errdata.append(v) self.errlen += 1 @@ -195,7 +195,7 @@ if not self.outt.finished and self.kill_it: self.kill() - + def spin(self): self.finishsem.acquire() return [self.exitcode, "".join(self.outdata), "".join(self.errdata)]