--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/IDEFrame.py Sun Sep 09 23:05:01 2012 +0200
@@ -0,0 +1,2553 @@
+
+import os, sys
+import cPickle
+from types import TupleType
+
+import wx, wx.grid
+import wx.aui
+
+from editors.EditorPanel import EditorPanel
+from editors.SFCViewer import SFC_Viewer
+from editors.LDViewer import LD_Viewer
+from editors.TextViewer import TextViewer
+from editors.Viewer import Viewer, ZOOM_FACTORS
+from editors.GraphicViewer import GraphicViewer
+from editors.ResourceEditor import ConfigurationEditor, ResourceEditor
+from editors.DataTypeEditor import DataTypeEditor
+from PLCControler import *
+from controls import CustomTree, LibraryPanel, PouInstanceVariablesPanel, DebugVariablePanel, SearchResultPanel
+from dialogs import ProjectDialog, PouTransitionDialog, PouActionDialog, FindInPouDialog
+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,
+] = [wx.NewId() for _init_ctrls in range(17)]
+
+# Define PLCOpenEditor EditMenu extra items id
+[ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, ID_PLCOPENEDITOREDITMENUADDDATATYPE,
+ ID_PLCOPENEDITOREDITMENUADDFUNCTION, ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK,
+ ID_PLCOPENEDITOREDITMENUADDPROGRAM, ID_PLCOPENEDITOREDITMENUADDCONFIGURATION,
+ ID_PLCOPENEDITOREDITMENUFINDNEXT, ID_PLCOPENEDITOREDITMENUFINDPREVIOUS,
+ ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT,
+] = [wx.NewId() for _init_coll_EditMenu_Items in range(9)]
+
+# Define PLCOpenEditor DisplayMenu extra items id
+[ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE,
+] = [wx.NewId() for _init_coll_DisplayMenu_Items in range(1)]
+
+#-------------------------------------------------------------------------------
+# EditorToolBar definitions
+#-------------------------------------------------------------------------------
+
+# Define PLCOpenEditor Toolbar items id
+[ID_PLCOPENEDITOREDITORTOOLBARSELECTION, ID_PLCOPENEDITOREDITORTOOLBARCOMMENT,
+ ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, ID_PLCOPENEDITOREDITORTOOLBARBLOCK,
+ ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, ID_PLCOPENEDITOREDITORTOOLBARWIRE,
+ ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL, ID_PLCOPENEDITOREDITORTOOLBARRUNG,
+ ID_PLCOPENEDITOREDITORTOOLBARCOIL, ID_PLCOPENEDITOREDITORTOOLBARCONTACT,
+ ID_PLCOPENEDITOREDITORTOOLBARBRANCH, ID_PLCOPENEDITOREDITORTOOLBARINITIALSTEP,
+ ID_PLCOPENEDITOREDITORTOOLBARSTEP, ID_PLCOPENEDITOREDITORTOOLBARTRANSITION,
+ ID_PLCOPENEDITOREDITORTOOLBARACTIONBLOCK, ID_PLCOPENEDITOREDITORTOOLBARDIVERGENCE,
+ 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
+# Informations meaning are in this order:
+# - Item is toggled
+# - PLCOpenEditor mode where item is displayed (could be more then one)
+# - Item id
+# - Item callback function name
+# - Item icon filename
+# - Item tooltip text
+EditorToolBarItems = {
+ "FBD" : [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARMOTION, "OnMotionTool",
+ "move", _("Move the view")),
+ (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCOMMENT, "OnCommentTool",
+ "add_comment", _("Create a new comment")),
+ (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, "OnVariableTool",
+ "add_variable", _("Create a new variable")),
+ (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool",
+ "add_block", _("Create a new block")),
+ (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",
+ "add_comment", _("Create a new comment")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL, "OnPowerRailTool",
+ "add_powerrail", _("Create a new power rail")),
+ (False, DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARRUNG, "OnRungTool",
+ "add_rung", _("Create a new rung")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCOIL, "OnCoilTool",
+ "add_coil", _("Create a new coil")),
+ (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCONTACT, "OnContactTool",
+ "add_contact", _("Create a new contact")),
+ (False, DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARBRANCH, "OnBranchTool",
+ "add_branch", _("Create a new branch")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, "OnVariableTool",
+ "add_variable", _("Create a new variable")),
+ (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool",
+ "add_block", _("Create a new block")),
+ (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",
+ "add_comment", _("Create a new comment")),
+ (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARINITIALSTEP, "OnInitialStepTool",
+ "add_initial_step", _("Create a new initial step")),
+ (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARSTEP, "OnStepTool",
+ "add_step", _("Create a new step")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARTRANSITION, "OnTransitionTool",
+ "add_transition", _("Create a new transition")),
+ (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARACTIONBLOCK, "OnActionBlockTool",
+ "add_action", _("Create a new action block")),
+ (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARDIVERGENCE, "OnDivergenceTool",
+ "add_divergence", _("Create a new divergence")),
+ (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARJUMP, "OnJumpTool",
+ "add_jump", _("Create a new jump")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, "OnVariableTool",
+ "add_variable", _("Create a new variable")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool",
+ "add_block", _("Create a new block")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, "OnConnectionTool",
+ "add_connection", _("Create a new connection")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL, "OnPowerRailTool",
+ "add_powerrail", _("Create a new power rail")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCONTACT, "OnContactTool",
+ "add_contact", _("Create a new contact"))],
+ "ST" : [],
+ "IL" : [],
+ "debug": [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARMOTION, "OnMotionTool",
+ "move", _("Move the view"))],
+}
+
+#-------------------------------------------------------------------------------
+# Helper Functions
+#-------------------------------------------------------------------------------
+
+import base64
+
+def EncodeFileSystemPath(path, use_base64=True):
+ path = path.encode(sys.getfilesystemencoding())
+ if use_base64:
+ return base64.encodestring(path)
+ return path
+
+def DecodeFileSystemPath(path, is_base64=True):
+ if is_base64:
+ path = base64.decodestring(path)
+ return unicode(path, sys.getfilesystemencoding())
+
+# Compatibility function for wx versions < 2.6
+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,
+ POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES
+] = range(10)
+
+def GetShortcutKeyCallbackFunction(viewer_function):
+ def ShortcutKeyFunction(self, event):
+ control = self.FindFocus()
+ if control is not None and control.GetName() in ["Viewer", "TextViewer"]:
+ getattr(control.ParentWindow, viewer_function)()
+ elif isinstance(control, wx.stc.StyledTextCtrl):
+ getattr(control, viewer_function)()
+ elif isinstance(control, wx.TextCtrl):
+ control.ProcessEvent(event)
+ return ShortcutKeyFunction
+
+def GetDeleteElementFunction(remove_function, parent_type=None, check_function=None):
+ def DeleteElementFunction(self, selected):
+ name = self.ProjectTree.GetItemText(selected)
+ if check_function is None or not check_function(self.Controler, name):
+ if parent_type is not None:
+ item_infos = self.ProjectTree.GetPyData(selected)
+ parent_name = item_infos["tagname"].split("::")[1]
+ remove_function(self.Controler, parent_name, name)
+ else:
+ remove_function(self.Controler, name)
+ else:
+ self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!")%name)
+ return DeleteElementFunction
+
+if wx.Platform == '__WXMSW__':
+ TAB_BORDER = 6
+ NOTEBOOK_BORDER = 6
+else:
+ TAB_BORDER = 7
+ NOTEBOOK_BORDER = 2
+
+def SimplifyTabLayout(tabs, rect):
+ for tab in tabs:
+ if tab["pos"][0] == rect.x:
+ 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
+ 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
+ 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
+ if len(tabs) == 1:
+ return tabs[0]
+ split = None
+ for idx, tab in enumerate(tabs):
+ if len(tab["pages"]) == 0:
+ raise ValueError, "Not possible"
+ 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,
+ 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,
+ 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,
+ 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,
+ rect.width - tab["size"][0] - TAB_BORDER, rect.height)
+ break
+ if split != None:
+ split_tab = tabs.pop(idx)
+ return {"split": split,
+ "tab": split_tab,
+ "others": ComputeTabsLayout(tabs, split_rect)}
+ else:
+ if SimplifyTabLayout(tabs, rect):
+ return ComputeTabsLayout(tabs, rect)
+ return tabs
+
+#-------------------------------------------------------------------------------
+# IDEFrame Base Class
+#-------------------------------------------------------------------------------
+
+UNEDITABLE_NAMES_DICT = dict([(_(name), name) for name in UNEDITABLE_NAMES])
+
+class IDEFrame(wx.Frame):
+
+ Starting = False
+
+ # Compatibility function for wx versions < 2.6
+ 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_coll_MenuBar_Menus(self, parent):
+ parent.Append(menu=self.FileMenu, title=_(u'&File'))
+ parent.Append(menu=self.EditMenu, title=_(u'&Edit'))
+ parent.Append(menu=self.DisplayMenu, title=_(u'&Display'))
+ parent.Append(menu=self.HelpMenu, title=_(u'&Help'))
+
+ 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'))
+ AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDFUNCTION,
+ kind=wx.ITEM_NORMAL, text=_(u'&Function'))
+ AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK,
+ kind=wx.ITEM_NORMAL, text=_(u'Function &Block'))
+ AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDPROGRAM,
+ kind=wx.ITEM_NORMAL, text=_(u'&Program'))
+ 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')
+ AppendMenu(parent, help='', id=wx.ID_REDO,
+ kind=wx.ITEM_NORMAL, text=_(u'Redo') + '\tCTRL+Y')
+ #AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO,
+ # kind=wx.ITEM_CHECK, text=_(u'Enable Undo/Redo'))
+ enable_undo_redo = _(u'Enable Undo/Redo') # Keeping text in translations for possible menu reactivation
+ parent.AppendSeparator()
+ AppendMenu(parent, help='', id=wx.ID_CUT,
+ kind=wx.ITEM_NORMAL, text=_(u'Cut') + '\tCTRL+X')
+ AppendMenu(parent, help='', id=wx.ID_COPY,
+ kind=wx.ITEM_NORMAL, text=_(u'Copy') + '\tCTRL+C')
+ AppendMenu(parent, help='', id=wx.ID_PASTE,
+ kind=wx.ITEM_NORMAL, text=_(u'Paste') + '\tCTRL+V')
+ parent.AppendSeparator()
+ AppendMenu(parent, help='', id=wx.ID_FIND,
+ kind=wx.ITEM_NORMAL, text=_(u'Find') + '\tCTRL+F')
+ AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUFINDNEXT,
+ kind=wx.ITEM_NORMAL, text=_(u'Find Next') + '\tCTRL+K')
+ AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUFINDPREVIOUS,
+ kind=wx.ITEM_NORMAL, text=_(u'Find Previous') + '\tCTRL+SHIFT+K')
+ parent.AppendSeparator()
+ AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT,
+ kind=wx.ITEM_NORMAL, text=_(u'Search in Project') + '\tCTRL+SHIFT+F')
+ parent.AppendSeparator()
+ add_menu = wx.Menu(title='')
+ self._init_coll_AddMenu_Items(add_menu)
+ parent.AppendMenu(wx.ID_ADD, _(u"&Add Element"), add_menu)
+ AppendMenu(parent, help='', id=wx.ID_SELECTALL,
+ kind=wx.ITEM_NORMAL, text=_(u'Select All') + '\tCTRL+A')
+ AppendMenu(parent, help='', id=wx.ID_DELETE,
+ kind=wx.ITEM_NORMAL, text=_(u'&Delete'))
+ self.Bind(wx.EVT_MENU, self.OnUndoMenu, id=wx.ID_UNDO)
+ self.Bind(wx.EVT_MENU, self.OnRedoMenu, id=wx.ID_REDO)
+ #self.Bind(wx.EVT_MENU, self.OnEnableUndoRedoMenu, id=ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO)
+ self.Bind(wx.EVT_MENU, self.OnCutMenu, id=wx.ID_CUT)
+ 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,
+ id=ID_PLCOPENEDITOREDITMENUFINDNEXT)
+ self.Bind(wx.EVT_MENU, self.OnFindPreviousMenu,
+ id=ID_PLCOPENEDITOREDITMENUFINDPREVIOUS)
+ self.Bind(wx.EVT_MENU, self.OnSearchInProjectMenu,
+ id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT)
+ self.Bind(wx.EVT_MENU, self.OnSearchInProjectMenu,
+ id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT)
+ self.Bind(wx.EVT_MENU, self.OnAddDataTypeMenu,
+ id=ID_PLCOPENEDITOREDITMENUADDDATATYPE)
+ self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction("function"),
+ id=ID_PLCOPENEDITOREDITMENUADDFUNCTION)
+ self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction("functionBlock"),
+ id=ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK)
+ self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction("program"),
+ id=ID_PLCOPENEDITOREDITMENUADDPROGRAM)
+ 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,
+ (wx.ID_CUT, "cut", _(u'Cut'), None),
+ (wx.ID_COPY, "copy", _(u'Copy'), None),
+ (wx.ID_PASTE, "paste", _(u'Paste'), None),
+ None,
+ (ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, "find", _(u'Search in Project'), None)])
+
+ def _init_coll_DisplayMenu_Items(self, parent):
+ AppendMenu(parent, help='', id=wx.ID_REFRESH,
+ kind=wx.ITEM_NORMAL, text=_(u'Refresh') + '\tCTRL+R')
+ if self.EnableDebug:
+ AppendMenu(parent, help='', id=wx.ID_CLEAR,
+ kind=wx.ITEM_NORMAL, text=_(u'Clear Errors') + '\tCTRL+K')
+ parent.AppendSeparator()
+ zoommenu = wx.Menu(title='')
+ parent.AppendMenu(wx.ID_ZOOM_FIT, _("Zoom"), zoommenu)
+ for idx, value in enumerate(ZOOM_FACTORS):
+ new_id = wx.NewId()
+ 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
+
+ def _init_utils(self):
+ self.MenuBar = wx.MenuBar()
+
+ self.FileMenu = wx.Menu(title='')
+ 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)
+ self._init_coll_DisplayMenu_Items(self.DisplayMenu)
+ self._init_coll_HelpMenu_Items(self.HelpMenu)
+
+ def _init_ctrls(self, prnt):
+ wx.Frame.__init__(self, id=ID_PLCOPENEDITOR, name='IDEFrame',
+ parent=prnt, pos=wx.DefaultPosition, size=wx.Size(1000, 600),
+ style=wx.DEFAULT_FRAME_STYLE)
+ self.SetClientSize(wx.Size(1000, 600))
+ self.Bind(wx.EVT_ACTIVATE, self.OnActivated)
+ self.Bind(wx.EVT_SIZE, self.OnResize)
+
+ 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.OnAllowNotebookDnD)
+ 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.OnAllowNotebookDnD)
+ 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.OnAllowNotebookDnD)
+ 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,
+ style=wx.aui.AUI_NB_DEFAULT_STYLE|wx.aui.AUI_NB_WINDOWLIST_BUTTON)
+ self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGING,
+ self.OnPouSelectedChanging)
+ self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED,
+ self.OnPouSelectedChanged)
+ self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE,
+ self.OnPageClose)
+ self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_END_DRAG,
+ self.OnPageDragged)
+ 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,
+ pos=wx.Point(0, 0), size=wx.Size(0, 0),
+ style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_EDIT_LABELS)
+ self.ProjectTree.SetBackgroundBitmap(GetBitmap("custom_tree_background"),
+ wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM)
+ add_menu = wx.Menu()
+ self._init_coll_AddMenu_Items(add_menu)
+ self.ProjectTree.SetAddMenu(add_menu)
+ if wx.Platform == '__WXMSW__':
+ self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnProjectTreeRightUp,
+ id=ID_PLCOPENEDITORPROJECTTREE)
+ self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnProjectTreeItemSelected,
+ id=ID_PLCOPENEDITORPROJECTTREE)
+ else:
+ self.ProjectTree.Bind(wx.EVT_RIGHT_UP, self.OnProjectTreeRightUp)
+ self.ProjectTree.Bind(wx.EVT_LEFT_UP, self.OnProjectTreeLeftUp)
+ self.Bind(wx.EVT_TREE_SEL_CHANGING, self.OnProjectTreeItemChanging,
+ id=ID_PLCOPENEDITORPROJECTTREE)
+ self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnProjectTreeBeginDrag,
+ id=ID_PLCOPENEDITORPROJECTTREE)
+ self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnProjectTreeItemBeginEdit,
+ id=ID_PLCOPENEDITORPROJECTTREE)
+ self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnProjectTreeItemEndEdit,
+ id=ID_PLCOPENEDITORPROJECTTREE)
+ self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnProjectTreeItemActivated,
+ id=ID_PLCOPENEDITORPROJECTTREE)
+
+ #-----------------------------------------------------------------------
+ # 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))
+ MenuToolBar.Realize()
+ self.Panes["MenuToolBar"] = MenuToolBar
+ self.AUIManager.AddPane(MenuToolBar, wx.aui.AuiPaneInfo().
+ 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,
+ GetBitmap("select"), wx.NullBitmap, _("Select an object"))
+ EditorToolBar.Realize()
+ self.Panes["EditorToolBar"] = EditorToolBar
+ self.AUIManager.AddPane(EditorToolBar, wx.aui.AuiPaneInfo().
+ Name("EditorToolBar").Caption(_("Editor ToolBar")).
+ ToolbarPane().Top().Position(1).
+ LeftDockable(False).RightDockable(False))
+
+ 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.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).
+ # @param fileOpen The filepath to open if no controler defined (default: None).
+ # @param debug The filepath to open if no controler defined (default: False).
+ def __init__(self, parent, enable_debug = False):
+ 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
+ ("PROJECT", ITEM_PROJECT),
+ #("POU", ITEM_POU),
+ #("VARIABLE", ITEM_VARIABLE),
+ ("TRANSITION", ITEM_TRANSITION),
+ ("ACTION", ITEM_ACTION),
+ ("CONFIGURATION", ITEM_CONFIGURATION),
+ ("RESOURCE", ITEM_RESOURCE),
+ ("DATATYPE", ITEM_DATATYPE),
+ # uneditables
+ ("DATATYPES", ITEM_DATATYPES),
+ ("FUNCTION", ITEM_FUNCTION),
+ ("FUNCTIONBLOCK", ITEM_FUNCTIONBLOCK),
+ ("PROGRAM", ITEM_PROGRAM),
+ ("VAR_LOCAL", ITEM_VAR_LOCAL),
+ ("VAR_LOCAL", ITEM_VAR_GLOBAL),
+ ("VAR_LOCAL", ITEM_VAR_EXTERNAL),
+ ("VAR_LOCAL", ITEM_VAR_TEMP),
+ ("VAR_INPUT", ITEM_VAR_INPUT),
+ ("VAR_OUTPUT", ITEM_VAR_OUTPUT),
+ ("VAR_INOUT", ITEM_VAR_INOUT),
+ ("TRANSITIONS", ITEM_TRANSITIONS),
+ ("ACTIONS", ITEM_ACTIONS),
+ ("CONFIGURATIONS", ITEM_CONFIGURATIONS),
+ ("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
+ self.SearchParams = None
+ self.Highlights = {}
+ self.DrawingMode = FREEDRAWING_MODE
+ #self.DrawingMode = DRIVENDRAWING_MODE
+ self.AuiTabCtrl = []
+ self.DefaultPerspective = None
+
+ # Initialize Printing configuring elements
+ self.PrintData = wx.PrintData()
+ self.PrintData.SetPaperId(wx.PAPER_A4)
+ self.PrintData.SetPrintMode(wx.PRINT_MODE_PRINTER)
+ self.PageSetupData = wx.PageSetupDialogData(self.PrintData)
+ self.PageSetupData.SetMarginTopLeft(wx.Point(10, 15))
+ self.PageSetupData.SetMarginBottomRight(wx.Point(10, 20))
+
+ self.SetRefreshFunctions()
+
+ def __del__(self):
+ self.FindDialog.Destroy()
+
+ def ResetStarting(self):
+ self.Starting = False
+
+ 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)
+ event.Skip()
+
+#-------------------------------------------------------------------------------
+# Saving and restoring frame organization functions
+#-------------------------------------------------------------------------------
+
+ def OnResize(self, event):
+ if self.Starting:
+ self.RestoreLastLayout()
+ if wx.Platform == '__WXMSW__':
+ wx.CallAfter(self.ResetStarting)
+ else:
+ self.ResetStarting()
+ wx.CallAfter(self.RefreshEditor)
+ event.Skip()
+
+ def GetProjectConfiguration(self):
+ projects = {}
+ try:
+ if self.Config.HasEntry("projects"):
+ projects = cPickle.loads(str(self.Config.Read("projects")))
+ except:
+ pass
+
+ return projects.get(
+ EncodeFileSystemPath(os.path.realpath(self.Controler.GetFilePath())), {})
+
+ def SavePageState(self, page):
+ state = page.GetState()
+ if state is not None:
+ if self.Config.HasEntry("projects"):
+ projects = cPickle.loads(str(self.Config.Read("projects")))
+ else:
+ projects = {}
+
+ project_infos = projects.setdefault(
+ EncodeFileSystemPath(os.path.realpath(self.Controler.GetFilePath())), {})
+ editors_state = project_infos.setdefault("editors_state", {})
+
+ if page.IsDebugging():
+ editors_state[page.GetInstancePath()] = state
+ else:
+ editors_state[page.GetTagName()] = state
+
+ self.Config.Write("projects", cPickle.dumps(projects))
+ self.Config.Flush()
+
+ def GetTabInfos(self, tab):
+ if isinstance(tab, EditorPanel):
+ if tab.IsDebugging():
+ return ("debug", tab.GetInstancePath())
+ else:
+ return ("editor", tab.GetTagName())
+ else:
+ for page_name, (page_ref, page_title) in self.MainTabs.iteritems():
+ if page_ref == tab:
+ return ("main", page_name)
+ return None
+
+ def SaveTabLayout(self, notebook):
+ tabs = []
+ for child in notebook.GetChildren():
+ if isinstance(child, wx.aui.AuiTabCtrl):
+ if child.GetPageCount() > 0:
+ pos = child.GetPosition()
+ tab = {"pos": (pos.x, pos.y), "pages": []}
+ tab_size = child.GetSize()
+ for page_idx in xrange(child.GetPageCount()):
+ page = child.GetWindowFromIdx(page_idx)
+ if not tab.has_key("size"):
+ tab["size"] = (tab_size[0], tab_size[1] + page.GetSize()[1])
+ tab_infos = self.GetTabInfos(page)
+ if tab_infos is not None:
+ tab["pages"].append((tab_infos, page_idx == child.GetActivePage()))
+ tabs.append(tab)
+ 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])
+ if infos is not None:
+ page_ref, page_title = infos
+ notebook.AddPage(page_ref, page_title)
+ return notebook.GetPageIndex(page_ref)
+ elif page_infos[0] == "editor":
+ tagname = page_infos[1]
+ page_ref = self.EditProjectElement(self.Controler.GetElementType(tagname), tagname)
+ if page_ref is not None:
+ page_ref.RefreshView()
+ return notebook.GetPageIndex(page_ref)
+ elif page_infos[0] == "debug":
+ instance_path = page_infos[1]
+ instance_infos = self.Controler.GetInstanceInfos(instance_path, self.EnableDebug)
+ 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:
+ selected = first_index
+ if mode == "others":
+ add_tabs = tabs["pages"][1:]
+ else:
+ add_tabs = tabs["pages"]
+ for page_infos, page_selected in add_tabs:
+ page_idx = self.LoadTab(notebook, page_infos)
+ if page_selected:
+ 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")))
+
+ self.Starting = True
+ if frame_size is None:
+ self.Maximize()
+ else:
+ self.SetClientSize(frame_size)
+
+ def RestoreLastLayout(self):
+ notebooks = {}
+ for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"),
+ (self.BottomNoteBook, "bottomnotebook"),
+ (self.RightNoteBook, "rightnotebook")]:
+ notebooks[entry_name] = self.SaveTabLayout(notebook)
+ self.DefaultPerspective = {
+ "perspective": self.AUIManager.SavePerspective(),
+ "notebooks": notebooks,
+ }
+
+ try:
+ if self.Config.HasEntry("perspective"):
+ self.AUIManager.LoadPerspective(unicode(self.Config.Read("perspective")))
+
+ if self.Config.HasEntry("notebooks"):
+ notebooks = cPickle.loads(str(self.Config.Read("notebooks")))
+
+ for notebook in [self.LeftNoteBook, self.BottomNoteBook, self.RightNoteBook]:
+ for idx in xrange(notebook.GetPageCount()):
+ notebook.RemovePage(0)
+
+ for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"),
+ (self.BottomNoteBook, "bottomnotebook"),
+ (self.RightNoteBook, "rightnotebook")]:
+ self.LoadTabLayout(notebook, notebooks.get(entry_name))
+ except:
+ self.ResetPerspective()
+
+ self.LoadProjectLayout()
+
+ self._Refresh(EDITORTOOLBAR)
+
+ def SaveLastState(self):
+ if not self.IsMaximized():
+ self.Config.Write("framesize", cPickle.dumps(self.GetClientSize()))
+ elif self.Config.HasEntry("framesize"):
+ self.Config.DeleteEntry("framesize")
+
+ notebooks = {}
+ for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"),
+ (self.BottomNoteBook, "bottomnotebook"),
+ (self.RightNoteBook, "rightnotebook")]:
+ notebooks[entry_name] = self.SaveTabLayout(notebook)
+ self.Config.Write("notebooks", cPickle.dumps(notebooks))
+
+ pane = self.AUIManager.GetPane(self.TabsOpened)
+ if pane.IsMaximized():
+ self.AUIManager.RestorePane(pane)
+ self.Config.Write("perspective", self.AUIManager.SavePerspective())
+
+ self.SaveProjectLayout()
+
+ for i in xrange(self.TabsOpened.GetPageCount()):
+ self.SavePageState(self.TabsOpened.GetPage(i))
+
+ self.Config.Flush()
+
+ def SaveProjectLayout(self):
+ if self.Controler is not None:
+ tabs = []
+
+ projects = {}
+ try:
+ if self.Config.HasEntry("projects"):
+ projects = cPickle.loads(str(self.Config.Read("projects")))
+ except:
+ pass
+
+ project_infos = projects.setdefault(
+ EncodeFileSystemPath(os.path.realpath(self.Controler.GetFilePath())), {})
+ project_infos["tabs"] = self.SaveTabLayout(self.TabsOpened)
+ if self.EnableDebug:
+ project_infos["debug_vars"] = self.DebugVariablePanel.GetDebugVariables()
+
+ self.Config.Write("projects", cPickle.dumps(projects))
+ self.Config.Flush()
+
+ def LoadProjectLayout(self):
+ if self.Controler is not None:
+ project = self.GetProjectConfiguration()
+
+ try:
+ if project.has_key("tabs"):
+ self.LoadTabLayout(self.TabsOpened, project["tabs"])
+ except:
+ self.DeleteAllPages()
+
+ if self.EnableDebug:
+ try:
+ for variable in project.get("debug_vars", []):
+ self.DebugVariablePanel.InsertValue(variable, force=True)
+ except:
+ self.DebugVariablePanel.ResetGrid()
+
+#-------------------------------------------------------------------------------
+# General Functions
+#-------------------------------------------------------------------------------
+
+ def SetRefreshFunctions(self):
+ self.RefreshFunctions = {
+ TITLE : self.RefreshTitle,
+ EDITORTOOLBAR : self.RefreshEditorToolBar,
+ FILEMENU : self.RefreshFileMenu,
+ EDITMENU : self.RefreshEditMenu,
+ DISPLAYMENU : self.RefreshDisplayMenu,
+ PROJECTTREE : self.RefreshProjectTree,
+ POUINSTANCEVARIABLESPANEL : self.RefreshPouInstanceVariablesPanel,
+ LIBRARYTREE : self.RefreshLibraryPanel,
+ SCALING : self.RefreshScaling,
+ PAGETITLES: self.RefreshPageTitles}
+
+ ## Call PLCOpenEditor refresh functions.
+ # @param elements List of elements to refresh.
+ def _Refresh(self, *elements):
+ try:
+ for element in elements:
+ self.RefreshFunctions[element]()
+ except wx.PyDeadObjectError:
+ # ignore exceptions caused by refresh while quitting
+ pass
+
+ ## Callback function when AUINotebook Page closed with CloseButton
+ # @param event AUINotebook Event.
+ def OnPageClose(self, event):
+ selected = self.TabsOpened.GetSelection()
+ if selected > -1:
+ window = self.TabsOpened.GetPage(selected)
+
+ if window.CheckSaveBeforeClosing():
+ self.SavePageState(window)
+
+ # Refresh all window elements that have changed
+ wx.CallAfter(self._Refresh, TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
+ wx.CallAfter(self.RefreshTabCtrlEvent)
+ wx.CallAfter(self.CloseFindInPouDialog)
+ event.Skip()
+ else:
+ event.Veto()
+
+
+ def GetCopyBuffer(self):
+ data = None
+ if wx.TheClipboard.Open():
+ dataobj = wx.TextDataObject()
+ if wx.TheClipboard.GetData(dataobj):
+ data = dataobj.GetText()
+ wx.TheClipboard.Close()
+ return data
+
+ def SetCopyBuffer(self, text):
+ if wx.TheClipboard.Open():
+ data = wx.TextDataObject()
+ data.SetText(text)
+ wx.TheClipboard.SetData(data)
+ wx.TheClipboard.Flush()
+ wx.TheClipboard.Close()
+ self.RefreshEditMenu()
+
+ def GetDrawingMode(self):
+ return self.DrawingMode
+
+ def RefreshScaling(self):
+ for i in xrange(self.TabsOpened.GetPageCount()):
+ editor = self.TabsOpened.GetPage(i)
+ editor.RefreshScaling()
+
+ def EditProjectSettings(self):
+ old_values = self.Controler.GetProjectProperties()
+ dialog = ProjectDialog(self)
+ dialog.SetValues(old_values)
+ if dialog.ShowModal() == wx.ID_OK:
+ new_values = dialog.GetValues()
+ new_values["creationDateTime"] = old_values["creationDateTime"]
+ if new_values != old_values:
+ self.Controler.SetProjectProperties(None, new_values)
+ 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.
+ # @param text title for the tab ctrl.
+ 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.
+ # @param text title for the tab ctrl.
+ def DeletePage(self, window):
+ for idx in xrange(self.TabsOpened.GetPageCount()):
+ if self.TabsOpened.GetPage(idx) == window:
+ self.TabsOpened.DeletePage(idx)
+ self.RefreshTabCtrlEvent()
+ 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
+ # wx.Notebook and wx.aui.AUINotebook.
+ # @param idx Tab index.
+ # @param bitmap wx.Bitmap to define on tab.
+ # @return True if operation succeeded
+ def SetPageBitmap(self, idx, bitmap):
+ return self.TabsOpened.SetPageBitmap(idx, bitmap)
+
+#-------------------------------------------------------------------------------
+# Dialog Message Functions
+#-------------------------------------------------------------------------------
+
+ ## Function displaying an Error dialog in PLCOpenEditor.
+ # @param message The message to display.
+ def ShowErrorMessage(self, message):
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog.ShowModal()
+ dialog.Destroy()
+
+ ## Function displaying an Error dialog in PLCOpenEditor.
+ # @return False if closing cancelled.
+ def CheckSaveBeforeClosing(self, title=_("Close Project")):
+ if not self.Controler.ProjectIsSaved():
+ dialog = wx.MessageDialog(self, _("There are changes, do you want to save?"), title, wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION)
+ answer = dialog.ShowModal()
+ dialog.Destroy()
+ if answer == wx.ID_YES:
+ 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
+
+#-------------------------------------------------------------------------------
+# File Menu Functions
+#-------------------------------------------------------------------------------
+
+ def RefreshFileMenu(self):
+ pass
+
+ def ResetView(self):
+ self.DeleteAllPages()
+ self.ProjectTree.DeleteAllItems()
+ self.ProjectTree.Enable(False)
+ self.PouInstanceVariablesPanel.ResetView()
+ self.LibraryPanel.ResetTree()
+ self.LibraryPanel.SetController(None)
+ if self.EnableDebug:
+ self.DebugVariablePanel.ResetGrid()
+ self.Controler = None
+
+ def OnCloseTabMenu(self, event):
+ selected = self.TabsOpened.GetSelection()
+ if selected >= 0:
+ self.TabsOpened.DeletePage(selected)
+ if self.TabsOpened.GetPageCount() > 0:
+ new_index = min(selected, self.TabsOpened.GetPageCount() - 1)
+ self.TabsOpened.SetSelection(new_index)
+ # Refresh all window elements that have changed
+ self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
+ self.RefreshTabCtrlEvent()
+
+ def OnPageSetupMenu(self, event):
+ dialog = wx.PageSetupDialog(self, self.PageSetupData)
+ if dialog.ShowModal() == wx.ID_OK:
+ self.PageSetupData = wx.PageSetupDialogData(dialog.GetPageSetupData())
+ self.PrintData = wx.PrintData(self.PageSetupData.GetPrintData())
+ dialog.Destroy()
+
+ def OnPreviewMenu(self, event):
+ selected = self.TabsOpened.GetSelection()
+ if selected != -1:
+ window = self.TabsOpened.GetPage(selected)
+ data = wx.PrintDialogData(self.PrintData)
+ properties = self.Controler.GetProjectProperties(window.IsDebugging())
+ page_size = map(int, properties["pageSize"])
+ margins = (self.PageSetupData.GetMarginTopLeft(), self.PageSetupData.GetMarginBottomRight())
+ printout = GraphicPrintout(window, page_size, margins, True)
+ printout2 = GraphicPrintout(window, page_size, margins, True)
+ preview = wx.PrintPreview(printout, printout2, data)
+
+ if preview.Ok():
+ 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()
+ if selected != -1:
+ window = self.TabsOpened.GetPage(selected)
+ dialog_data = wx.PrintDialogData(self.PrintData)
+ dialog_data.SetToPage(1)
+ properties = self.Controler.GetProjectProperties(window.IsDebugging())
+ page_size = map(int, properties["pageSize"])
+ 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()
+
+ def OnPropertiesMenu(self, event):
+ self.EditProjectSettings()
+
+ def OnQuitMenu(self, event):
+ self.Close()
+
+#-------------------------------------------------------------------------------
+# Edit Menu Functions
+#-------------------------------------------------------------------------------
+
+ def RefreshEditMenu(self):
+ MenuToolBar = self.Panes["MenuToolBar"]
+ if self.Controler is not None:
+ selected = self.TabsOpened.GetSelection()
+ if selected > -1:
+ window = self.TabsOpened.GetPage(selected)
+ undo, redo = window.GetBufferState()
+ else:
+ undo, redo = self.Controler.GetBufferState()
+ self.EditMenu.Enable(wx.ID_UNDO, undo)
+ MenuToolBar.EnableTool(wx.ID_UNDO, undo)
+ 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.Controler.IsProjectBufferEnabled())
+ self.EditMenu.Enable(wx.ID_FIND, selected > -1)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDNEXT,
+ selected > -1 and self.SearchParams is not None)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDPREVIOUS,
+ selected > -1 and self.SearchParams is not None)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, True)
+ MenuToolBar.EnableTool(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, True)
+ self.EditMenu.Enable(wx.ID_ADD, True)
+ self.EditMenu.Enable(wx.ID_DELETE, True)
+ if self.TabsOpened.GetPageCount() > 0:
+ self.EditMenu.Enable(wx.ID_CUT, True)
+ MenuToolBar.EnableTool(wx.ID_CUT, True)
+ self.EditMenu.Enable(wx.ID_COPY, True)
+ MenuToolBar.EnableTool(wx.ID_COPY, True)
+ if self.GetCopyBuffer() is not None:
+ self.EditMenu.Enable(wx.ID_PASTE, True)
+ MenuToolBar.EnableTool(wx.ID_PASTE, True)
+ else:
+ self.EditMenu.Enable(wx.ID_PASTE, False)
+ MenuToolBar.EnableTool(wx.ID_PASTE, False)
+ self.EditMenu.Enable(wx.ID_SELECTALL, True)
+ else:
+ self.EditMenu.Enable(wx.ID_CUT, False)
+ MenuToolBar.EnableTool(wx.ID_CUT, False)
+ self.EditMenu.Enable(wx.ID_COPY, False)
+ MenuToolBar.EnableTool(wx.ID_COPY, False)
+ self.EditMenu.Enable(wx.ID_PASTE, False)
+ MenuToolBar.EnableTool(wx.ID_PASTE, False)
+ self.EditMenu.Enable(wx.ID_SELECTALL, False)
+ else:
+ self.EditMenu.Enable(wx.ID_UNDO, False)
+ MenuToolBar.EnableTool(wx.ID_UNDO, False)
+ self.EditMenu.Enable(wx.ID_REDO, False)
+ MenuToolBar.EnableTool(wx.ID_REDO, False)
+ #self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, False)
+ self.EditMenu.Enable(wx.ID_CUT, False)
+ MenuToolBar.EnableTool(wx.ID_CUT, False)
+ self.EditMenu.Enable(wx.ID_COPY, False)
+ MenuToolBar.EnableTool(wx.ID_COPY, False)
+ self.EditMenu.Enable(wx.ID_PASTE, False)
+ MenuToolBar.EnableTool(wx.ID_PASTE, False)
+ self.EditMenu.Enable(wx.ID_SELECTALL, False)
+ self.EditMenu.Enable(wx.ID_FIND, False)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDNEXT, False)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDPREVIOUS, False)
+ self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, False)
+ 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()
+ for idx in idxs:
+ window = self.TabsOpened.GetPage(idx)
+ if window.HasNoModel():
+ self.TabsOpened.DeletePage(idx)
+ if refresh:
+ self.RefreshEditor()
+
+ def OnUndoMenu(self, event):
+ selected = self.TabsOpened.GetSelection()
+ if selected != -1:
+ window = self.TabsOpened.GetPage(selected)
+ window.Undo()
+ else:
+ self.Controler.LoadPrevious()
+ self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE,
+ SCALING, PAGETITLES)
+
+ def OnRedoMenu(self, event):
+ selected = self.TabsOpened.GetSelection()
+ if selected != -1:
+ window = self.TabsOpened.GetPage(selected)
+ window.Redo()
+ else:
+ self.Controler.LoadNext()
+ self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE,
+ SCALING, PAGETITLES)
+
+ def OnEnableUndoRedoMenu(self, event):
+ self.Controler.EnableProjectBuffer(event.IsChecked())
+ self.RefreshEditMenu()
+
+ OnCutMenu = GetShortcutKeyCallbackFunction("Cut")
+ OnCopyMenu = GetShortcutKeyCallbackFunction("Copy")
+ OnPasteMenu = GetShortcutKeyCallbackFunction("Paste")
+
+ def OnSelectAllMenu(self, event):
+ control = self.FindFocus()
+ if control is not None and control.GetName() == "Viewer":
+ control.Parent.SelectAll()
+ elif isinstance(control, wx.stc.StyledTextCtrl):
+ control.SelectAll()
+ elif isinstance(control, wx.TextCtrl):
+ control.SetSelection(0, control.GetLastPosition())
+ elif isinstance(control, wx.ComboBox):
+ control.SetMark(0, control.GetLastPosition() + 1)
+
+ DeleteFunctions = {
+ ITEM_DATATYPE: GetDeleteElementFunction(PLCControler.ProjectRemoveDataType, check_function=PLCControler.DataTypeIsUsed),
+ ITEM_POU: GetDeleteElementFunction(PLCControler.ProjectRemovePou, check_function=PLCControler.PouIsUsed),
+ ITEM_TRANSITION: GetDeleteElementFunction(PLCControler.ProjectRemovePouTransition, ITEM_POU),
+ ITEM_ACTION: GetDeleteElementFunction(PLCControler.ProjectRemovePouAction, ITEM_POU),
+ ITEM_CONFIGURATION: GetDeleteElementFunction(PLCControler.ProjectRemoveConfiguration),
+ ITEM_RESOURCE: GetDeleteElementFunction(PLCControler.ProjectRemoveConfigurationResource, ITEM_CONFIGURATION)
+ }
+
+ def OnDeleteMenu(self, event):
+ window = self.FindFocus()
+ if window == self.ProjectTree or window is None:
+ selected = self.ProjectTree.GetSelection()
+ if selected.IsOk():
+ function = self.DeleteFunctions.get(self.ProjectTree.GetPyData(selected)["type"], None)
+ if function is not None:
+ function(self, selected)
+ self.CloseTabsWithoutModel()
+ self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE,
+ POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
+ elif isinstance(window, (Viewer, TextViewer)):
+ event = wx.KeyEvent(wx.EVT_CHAR._getEvtType())
+ event.m_keyCode = wx.WXK_DELETE
+ window.ProcessEvent(event)
+
+ 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
+ selected = self.TabsOpened.GetSelection()
+ 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:
+ criteria = dialog.GetCriteria()
+ result = self.Controler.SearchInProject(criteria)
+ self.ClearSearchResults()
+ self.SearchResultPanel.SetSearchResults(criteria, result)
+ self.BottomNoteBook.SetSelection(self.BottomNoteBook.GetPageIndex(self.SearchResultPanel))
+
+#-------------------------------------------------------------------------------
+# Display Menu Functions
+#-------------------------------------------------------------------------------
+
+ def RefreshDisplayMenu(self):
+ if self.Controler is not None:
+ if self.TabsOpened.GetPageCount() > 0:
+ self.DisplayMenu.Enable(wx.ID_REFRESH, True)
+ selected = self.TabsOpened.GetSelection()
+ if selected != -1:
+ window = self.TabsOpened.GetPage(selected)
+ if isinstance(window, Viewer):
+ self.DisplayMenu.Enable(wx.ID_ZOOM_FIT, True)
+ zoommenu = self.DisplayMenu.FindItemById(wx.ID_ZOOM_FIT).GetSubMenu()
+ zoomitem = zoommenu.FindItemByPosition(window.GetScale())
+ zoomitem.Check(True)
+ else:
+ self.DisplayMenu.Enable(wx.ID_ZOOM_FIT, False)
+ else:
+ self.DisplayMenu.Enable(wx.ID_ZOOM_FIT, False)
+ else:
+ self.DisplayMenu.Enable(wx.ID_REFRESH, False)
+ self.DisplayMenu.Enable(wx.ID_ZOOM_FIT, False)
+ if self.EnableDebug:
+ self.DisplayMenu.Enable(wx.ID_CLEAR, True)
+ else:
+ self.DisplayMenu.Enable(wx.ID_REFRESH, False)
+ if self.EnableDebug:
+ self.DisplayMenu.Enable(wx.ID_CLEAR, False)
+ self.DisplayMenu.Enable(wx.ID_ZOOM_FIT, False)
+
+ def OnRefreshMenu(self, event):
+ self.RefreshEditor()
+
+ def OnClearErrorsMenu(self, event):
+ self.ClearErrors()
+
+ def GenerateZoomFunction(self, idx):
+ def ZoomFunction(event):
+ selected = self.TabsOpened.GetSelection()
+ if selected != -1:
+ window = self.TabsOpened.GetPage(selected)
+ window.SetScale(idx)
+ window.RefreshVisibleElements()
+ window.RefreshScrollBars()
+ event.Skip()
+ return ZoomFunction
+
+ def OnResetPerspective(self, event):
+ self.ResetPerspective()
+
+#-------------------------------------------------------------------------------
+# 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():
+ if isinstance(child, wx.aui.AuiTabCtrl):
+ auitabctrl.append(child)
+ if child not in self.AuiTabCtrl:
+ child.Bind(wx.EVT_LEFT_DCLICK, self.GetTabsOpenedDClickFunction(child))
+ self.AuiTabCtrl = auitabctrl
+ if self.TabsOpened.GetPageCount() == 0:
+ pane = self.AUIManager.GetPane(self.TabsOpened)
+ 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):
+ if not self.Starting:
+ selected = self.TabsOpened.GetSelection()
+ if selected >= 0:
+ window = self.TabsOpened.GetPage(selected)
+ if not window.IsDebugging():
+ window.ResetBuffer()
+ event.Skip()
+
+ def OnPouSelectedChanged(self, event):
+ if not self.Starting:
+ selected = self.TabsOpened.GetSelection()
+ if selected >= 0:
+ window = self.TabsOpened.GetPage(selected)
+ tagname = window.GetTagName()
+ if not window.IsDebugging():
+ wx.CallAfter(self.SelectProjectTreeItem, tagname)
+ wx.CallAfter(self.PouInstanceVariablesPanel.SetPouType, tagname)
+ window.RefreshView()
+ self.EnsureTabVisible(self.LibraryPanel)
+ else:
+ instance_path = window.GetInstancePath()
+ if tagname == "":
+ instance_path = instance_path.rsplit(".", 1)[0]
+ tagname = self.Controler.GetPouInstanceTagName(instance_path, self.EnableDebug)
+ self.EnsureTabVisible(self.DebugVariablePanel)
+ 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:
+ window = self.TabsOpened.GetPage(selected)
+ tagname = window.GetTagName()
+ if not window.IsDebugging():
+ self.SelectProjectTreeItem(tagname)
+ self.PouInstanceVariablesPanel.SetPouType(tagname)
+ else:
+ instance_path = window.GetInstancePath()
+ if tagname == "":
+ instance_path = instance_path.rsplit(".", 1)[0]
+ tagname = self.Controler.GetPouInstanceTagName(instance_path, self.EnableDebug)
+ self.PouInstanceVariablesPanel.SetPouType(tagname, instance_path)
+ for child in self.TabsOpened.GetChildren():
+ if isinstance(child, wx.aui.AuiTabCtrl):
+ active_page = child.GetActivePage()
+ if active_page >= 0:
+ 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):
+ return idx
+ return None
+
+ def RefreshPageTitles(self):
+ for idx in xrange(self.TabsOpened.GetPageCount()):
+ window = self.TabsOpened.GetPage(idx)
+ icon = window.GetIcon()
+ if icon is not None:
+ self.SetPageBitmap(idx, icon)
+ self.TabsOpened.SetPageText(idx, window.GetTitle())
+
+ def GetTabsOpenedDClickFunction(self, tabctrl):
+ def OnTabsOpenedDClick(event):
+ pos = event.GetPosition()
+ if tabctrl.TabHitTest(pos.x, pos.y, None):
+ pane = self.AUIManager.GetPane(self.TabsOpened)
+ if pane.IsMaximized():
+ self.AUIManager.RestorePane(pane)
+ else:
+ self.AUIManager.MaximizePane(pane)
+ self.AUIManager.Update()
+ event.Skip()
+ return OnTabsOpenedDClick
+
+#-------------------------------------------------------------------------------
+# Types Tree Management Functions
+#-------------------------------------------------------------------------------
+
+ def RefreshProjectTree(self):
+ infos = self.Controler.GetProjectInfos()
+ root = self.ProjectTree.GetRootItem()
+ if not root.IsOk():
+ root = self.ProjectTree.AddRoot(infos["name"])
+ self.GenerateProjectTreeBranch(root, infos)
+ self.ProjectTree.Expand(root)
+
+ def ResetSelectedItem(self):
+ self.SelectedItem = None
+
+ def GenerateProjectTreeBranch(self, root, infos):
+ to_delete = []
+ item_name = infos["name"]
+ if infos["type"] in ITEMS_UNEDITABLE:
+ if len(infos["values"]) == 1:
+ return self.GenerateProjectTreeBranch(root, infos["values"][0])
+ item_name = _(item_name)
+ self.ProjectTree.SetItemText(root, item_name)
+ self.ProjectTree.SetPyData(root, infos)
+ highlight_colours = self.Highlights.get(infos.get("tagname", None), (wx.WHITE, wx.BLACK))
+ self.ProjectTree.SetItemBackgroundColour(root, highlight_colours[0])
+ self.ProjectTree.SetItemTextColour(root, highlight_colours[1])
+ if infos["type"] == ITEM_POU:
+ self.ProjectTree.SetItemImage(root, self.TreeImageDict[self.Controler.GetPouBodyType(infos["name"])])
+ elif infos.has_key("icon") and infos["icon"] is not None:
+ icon_name = infos["icon"]
+ if not self.TreeImageDict.has_key(icon_name):
+ 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"]])
+
+ if wx.VERSION >= (2, 6, 0):
+ item, root_cookie = self.ProjectTree.GetFirstChild(root)
+ else:
+ item, root_cookie = self.ProjectTree.GetFirstChild(root, 0)
+ for values in infos["values"]:
+ if values["type"] not in ITEMS_UNEDITABLE or len(values["values"]) > 0:
+ if not item.IsOk():
+ item = self.ProjectTree.AppendItem(root, "")
+ if wx.Platform != '__WXMSW__':
+ item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
+ self.GenerateProjectTreeBranch(item, values)
+ item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
+ while item.IsOk():
+ to_delete.append(item)
+ item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
+ for item in to_delete:
+ self.ProjectTree.Delete(item)
+
+ def SelectProjectTreeItem(self, tagname):
+ if self.ProjectTree is not None:
+ root = self.ProjectTree.GetRootItem()
+ if root.IsOk():
+ words = tagname.split("::")
+ if words[0] == "D":
+ return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_DATATYPE)])
+ elif words[0] == "P":
+ return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU)])
+ elif words[0] == "T":
+ return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_TRANSITION)])
+ elif words[0] == "A":
+ return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_ACTION)])
+ elif words[0] == "C":
+ return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION)])
+ elif words[0] == "R":
+ return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION), (words[2], ITEM_RESOURCE)])
+ return False
+
+ def RecursiveProjectTreeItemSelection(self, root, items):
+ found = False
+ if wx.VERSION >= (2, 6, 0):
+ item, root_cookie = self.ProjectTree.GetFirstChild(root)
+ else:
+ item, root_cookie = self.ProjectTree.GetFirstChild(root, 0)
+ while item.IsOk() and not found:
+ item_infos = self.ProjectTree.GetPyData(item)
+ if (item_infos["name"].split(":")[-1].strip(), item_infos["type"]) == items[0]:
+ if len(items) == 1:
+ self.SelectedItem = item
+ wx.CallAfter(self.ProjectTree.SelectItem, item)
+ wx.CallAfter(self.ResetSelectedItem)
+ return True
+ else:
+ found = self.RecursiveProjectTreeItemSelection(item, items[1:])
+ else:
+ found = self.RecursiveProjectTreeItemSelection(item, items)
+ item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
+ return found
+
+ def OnProjectTreeBeginDrag(self, event):
+ if wx.Platform == '__WXMSW__':
+ self.SelectedItem = event.GetItem()
+ if self.SelectedItem is not None and self.ProjectTree.GetPyData(self.SelectedItem)["type"] == ITEM_POU:
+ block_name = self.ProjectTree.GetItemText(self.SelectedItem)
+ block_type = self.Controler.GetPouType(block_name)
+ if block_type != "program":
+ data = wx.TextDataObject(str((block_name, block_type, "")))
+ dragSource = wx.DropSource(self.ProjectTree)
+ dragSource.SetData(data)
+ dragSource.DoDragDrop()
+ self.ResetSelectedItem()
+
+ def OnProjectTreeItemBeginEdit(self, event):
+ selected = event.GetItem()
+ if self.ProjectTree.GetPyData(selected)["type"] in ITEMS_UNEDITABLE:
+ event.Veto()
+ else:
+ event.Skip()
+
+ def OnProjectTreeItemEndEdit(self, event):
+ message = None
+ abort = False
+ new_name = event.GetLabel()
+ if new_name != "":
+ if not TestIdentifier(new_name):
+ message = _("\"%s\" is not a valid identifier!")%new_name
+ elif new_name.upper() in IEC_KEYWORDS:
+ message = _("\"%s\" is a keyword. It can't be used!")%new_name
+ else:
+ item = event.GetItem()
+ old_name = self.ProjectTree.GetItemText(item)
+ item_infos = self.ProjectTree.GetPyData(item)
+ if item_infos["type"] == ITEM_PROJECT:
+ self.Controler.SetProjectProperties(name = new_name)
+ elif item_infos["type"] == ITEM_DATATYPE:
+ if new_name.upper() in [name.upper() for name in self.Controler.GetProjectDataTypeNames() if name != old_name]:
+ message = _("\"%s\" data type already exists!")%new_name
+ abort = True
+ if not abort:
+ self.Controler.ChangeDataTypeName(old_name, new_name)
+ self.RefreshEditorNames(self.Controler.ComputeDataTypeName(old_name),
+ self.Controler.ComputeDataTypeName(new_name))
+ self.RefreshPageTitles()
+ elif item_infos["type"] == ITEM_POU:
+ if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames() if name != old_name]:
+ message = _("\"%s\" pou already exists!")%new_name
+ abort = True
+ elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables()]:
+ messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
+ if messageDialog.ShowModal() == wx.ID_NO:
+ abort = True
+ messageDialog.Destroy()
+ if not abort:
+ self.Controler.ChangePouName(old_name, new_name)
+ self.RefreshEditorNames(self.Controler.ComputePouName(old_name),
+ self.Controler.ComputePouName(new_name))
+ self.RefreshLibraryPanel()
+ self.RefreshPageTitles()
+ elif item_infos["type"] == ITEM_TRANSITION:
+ if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
+ message = _("A POU named \"%s\" already exists!")%new_name
+ elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables(pou_name) if name != old_name]:
+ message = _("A variable with \"%s\" as name already exists in this pou!")%new_name
+ 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.Controler.ComputePouTransitionName(words[1], new_name))
+ self.RefreshPageTitles()
+ elif item_infos["type"] == ITEM_ACTION:
+ if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
+ message = _("A POU named \"%s\" already exists!")%new_name
+ elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables(pou_name) if name != old_name]:
+ message = _("A variable with \"%s\" as name already exists in this pou!")%new_name
+ 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.Controler.ComputePouActionName(words[1], new_name))
+ self.RefreshPageTitles()
+ elif item_infos["type"] == ITEM_CONFIGURATION:
+ if new_name.upper() in [name.upper() for name in self.Controler.GetProjectConfigNames() if name != old_name]:
+ message = _("\"%s\" config already exists!")%new_name
+ abort = True
+ elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
+ messageDialog = wx.MessageDialog(self, _("There is a POU named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
+ if messageDialog.ShowModal() == wx.ID_NO:
+ abort = True
+ messageDialog.Destroy()
+ elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables()]:
+ messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
+ if messageDialog.ShowModal() == wx.ID_NO:
+ abort = True
+ messageDialog.Destroy()
+ if not abort:
+ self.Controler.ChangeConfigurationName(old_name, new_name)
+ self.RefreshEditorNames(self.Controler.ComputeConfigurationName(old_name),
+ self.Controler.ComputeConfigurationName(new_name))
+ self.RefreshPageTitles()
+ elif item_infos["type"] == ITEM_RESOURCE:
+ if new_name.upper() in [name.upper() for name in self.Controler.GetProjectConfigNames()]:
+ message = _("\"%s\" config already exists!")%new_name
+ abort = True
+ elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
+ messageDialog = wx.MessageDialog(self, _("There is a POU named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
+ if messageDialog.ShowModal() == wx.ID_NO:
+ abort = True
+ messageDialog.Destroy()
+ elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables()]:
+ messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
+ if messageDialog.ShowModal() == wx.ID_NO:
+ abort = True
+ messageDialog.Destroy()
+ 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.Controler.ComputeConfigurationResourceName(words[1], new_name))
+ self.RefreshPageTitles()
+ if message or abort:
+ if message:
+ self.ShowErrorMessage(message)
+ item = event.GetItem()
+ wx.CallAfter(self.ProjectTree.EditLabel, item)
+ event.Veto()
+ else:
+ wx.CallAfter(self.RefreshProjectTree)
+ self.RefreshEditor()
+ self._Refresh(TITLE, FILEMENU, EDITMENU)
+ event.Skip()
+
+ def OnProjectTreeItemActivated(self, event):
+ selected = event.GetItem()
+ name = self.ProjectTree.GetItemText(selected)
+ item_infos = self.ProjectTree.GetPyData(selected)
+ if item_infos["type"] == ITEM_PROJECT:
+ self.EditProjectSettings()
+ else:
+ if item_infos["type"] in [ITEM_DATATYPE, ITEM_POU,
+ ITEM_CONFIGURATION, ITEM_RESOURCE,
+ ITEM_TRANSITION, ITEM_ACTION]:
+ self.EditProjectElement(item_infos["type"], item_infos["tagname"])
+ event.Skip()
+
+ def ProjectTreeItemSelect(self, select_item):
+ name = self.ProjectTree.GetItemText(select_item)
+ item_infos = self.ProjectTree.GetPyData(select_item)
+ if item_infos["type"] in [ITEM_DATATYPE, ITEM_POU,
+ ITEM_CONFIGURATION, ITEM_RESOURCE,
+ 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)
+ wx.CallAfter(self.ResetSelectedItem)
+ event.Skip()
+
+ def OnProjectTreeItemSelected(self, event):
+ self.ProjectTreeItemSelect(event.GetItem())
+ 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:
+ old_selected = self.TabsOpened.GetSelection()
+ if old_selected != openedidx:
+ if old_selected >= 0:
+ self.TabsOpened.GetPage(old_selected).ResetBuffer()
+ self.TabsOpened.SetSelection(openedidx)
+ self._Refresh(FILEMENU, EDITMENU, EDITORTOOLBAR, PAGETITLES)
+ elif not onlyopened:
+ new_window = None
+ if element == ITEM_CONFIGURATION:
+ new_window = ConfigurationEditor(self.TabsOpened, tagname, self, self.Controler)
+ new_window.SetIcon(GetBitmap("CONFIGURATION"))
+ self.AddPage(new_window, "")
+ elif element == ITEM_RESOURCE:
+ new_window = ResourceEditor(self.TabsOpened, tagname, self, self.Controler)
+ new_window.SetIcon(GetBitmap("RESOURCE"))
+ self.AddPage(new_window, "")
+ elif element in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]:
+ bodytype = self.Controler.GetEditedElementBodyType(tagname)
+ if bodytype == "FBD":
+ new_window = Viewer(self.TabsOpened, tagname, self, self.Controler)
+ new_window.RefreshScaling(False)
+ elif bodytype == "LD":
+ new_window = LD_Viewer(self.TabsOpened, tagname, self, self.Controler)
+ new_window.RefreshScaling(False)
+ elif bodytype == "SFC":
+ new_window = SFC_Viewer(self.TabsOpened, tagname, self, self.Controler)
+ new_window.RefreshScaling(False)
+ else:
+ new_window = TextViewer(self.TabsOpened, tagname, self, self.Controler)
+ new_window.SetTextSyntax(bodytype)
+ if bodytype == "IL":
+ new_window.SetKeywords(IL_KEYWORDS)
+ else:
+ new_window.SetKeywords(ST_KEYWORDS)
+ if element == ITEM_POU:
+ pou_type = self.Controler.GetEditedElementType(tagname)[1].upper()
+ icon = GetBitmap(pou_type, bodytype)
+ elif element == ITEM_TRANSITION:
+ icon = GetBitmap("TRANSITION", bodytype)
+ elif element == ITEM_ACTION:
+ icon = GetBitmap("ACTION", bodytype)
+ new_window.SetIcon(icon)
+ self.AddPage(new_window, "")
+ elif element == ITEM_DATATYPE:
+ new_window = DataTypeEditor(self.TabsOpened, tagname, self, self.Controler)
+ new_window.SetIcon(GetBitmap("DATATYPE"))
+ self.AddPage(new_window, "")
+ elif isinstance(element, EditorPanel):
+ new_window = element
+ self.AddPage(element, "")
+ if new_window is not None:
+ project_infos = self.GetProjectConfiguration()
+ if project_infos.has_key("editors_state"):
+ state = project_infos["editors_state"].get(tagname)
+ if state is not None:
+ wx.CallAfter(new_window.SetState, state)
+
+ openedidx = self.IsOpened(tagname)
+ old_selected = self.TabsOpened.GetSelection()
+ if old_selected != openedidx:
+ if old_selected >= 0:
+ self.TabsOpened.GetPage(old_selected).ResetBuffer()
+ for i in xrange(self.TabsOpened.GetPageCount()):
+ window = self.TabsOpened.GetPage(i)
+ if window == new_window:
+ self.TabsOpened.SetSelection(i)
+ window.SetFocus()
+ self.RefreshPageTitles()
+ return new_window
+
+ def OnProjectTreeRightUp(self, event):
+ if wx.Platform == '__WXMSW__':
+ item = event.GetItem()
+ else:
+ item, flags = self.ProjectTree.HitTest(wx.Point(event.GetX(), event.GetY()))
+ 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"))
+ self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction({"Functions" : "function", "Function Blocks" : "functionBlock", "Programs" : "program"}[name]), id=new_id)
+
+ new_id = wx.NewId()
+ AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Paste POU"))
+ self.Bind(wx.EVT_MENU, self.OnPastePou, id=new_id)
+ if self.GetCopyBuffer() is None:
+ menu.Enable(new_id, False)
+
+ elif name == "Configurations":
+ menu = wx.Menu(title='')
+ 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()
+ AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Transition"))
+ parent = self.ProjectTree.GetItemParent(item)["type"]
+ parent_type = self.ProjectTree.GetPyData(parent)
+ while parent_type != ITEM_POU:
+ 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()
+ AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Action"))
+ parent = self.ProjectTree.GetItemParent(item)
+ parent_type = self.ProjectTree.GetPyData(parent)["type"]
+ while parent_type != ITEM_POU:
+ 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()
+ AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Resource"))
+ parent = self.ProjectTree.GetItemParent(item)
+ parent_type = self.ProjectTree.GetPyData(parent)["type"]
+ while parent_type not in [ITEM_CONFIGURATION, ITEM_PROJECT]:
+ parent = self.ProjectTree.GetItemParent(parent)
+ parent_type = self.ProjectTree.GetPyData(parent)["type"]
+ if parent_type == ITEM_PROJECT:
+ parent_name = None
+ else:
+ parent_name = self.ProjectTree.GetItemText(parent)
+ self.Bind(wx.EVT_MENU, self.GenerateAddResourceFunction(parent_name), id=new_id)
+
+ else:
+ if item_infos["type"] == ITEM_POU:
+ menu = wx.Menu(title='')
+ if self.Controler.GetPouBodyType(name) == "SFC":
+ new_id = wx.NewId()
+ AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Transition"))
+ self.Bind(wx.EVT_MENU, self.GenerateAddTransitionFunction(name), id=new_id)
+ new_id = wx.NewId()
+ 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='')
+ if pou_type == "function":
+ new_id = wx.NewId()
+ AppendMenu(change_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Function Block"))
+ self.Bind(wx.EVT_MENU, self.GenerateChangePouTypeFunction(name, "functionBlock"), id=new_id)
+ new_id = wx.NewId()
+ AppendMenu(change_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Program"))
+ self.Bind(wx.EVT_MENU, self.GenerateChangePouTypeFunction(name, "program"), id=new_id)
+ menu.AppendMenu(wx.NewId(), _("Change POU Type To"), change_menu)
+ 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()
+
+ event.Skip()
+
+
+#-------------------------------------------------------------------------------
+# Instances Tree Management Functions
+#-------------------------------------------------------------------------------
+
+ def GetTreeImage(self, var_class):
+ return self.TreeImageDict[var_class]
+
+ def RefreshPouInstanceVariablesPanel(self):
+ self.PouInstanceVariablesPanel.RefreshView()
+
+ def OpenDebugViewer(self, instance_category, instance_path, instance_type):
+ openedidx = self.IsOpened(instance_path)
+ if openedidx is not None:
+ old_selected = self.TabsOpened.GetSelection()
+ if old_selected != openedidx:
+ if old_selected >= 0:
+ self.TabsOpened.GetPage(old_selected).ResetBuffer()
+ self.TabsOpened.SetSelection(openedidx)
+
+ elif instance_category in ITEMS_VARIABLE:
+ if self.Controler.IsOfType(instance_type, "ANY_NUM", True) or\
+ self.Controler.IsOfType(instance_type, "ANY_BIT", True):
+
+ return self.OpenGraphicViewer(instance_path)
+
+ else:
+ bodytype = self.Controler.GetEditedElementBodyType(instance_type, True)
+ new_window = None
+ if bodytype == "FBD":
+ new_window = Viewer(self.TabsOpened, instance_type, self, self.Controler, True, instance_path)
+ new_window.RefreshScaling(False)
+ elif bodytype == "LD":
+ new_window = LD_Viewer(self.TabsOpened, instance_type, self, self.Controler, True, instance_path)
+ new_window.RefreshScaling(False)
+ elif bodytype == "SFC":
+ new_window = SFC_Viewer(self.TabsOpened, instance_type, self, self.Controler, True, instance_path)
+ new_window.RefreshScaling(False)
+ else:
+ new_window = TextViewer(self.TabsOpened, instance_type, self, self.Controler, True, instance_path)
+ new_window.SetTextSyntax(bodytype)
+ if bodytype == "IL":
+ new_window.SetKeywords(IL_KEYWORDS)
+ else:
+ new_window.SetKeywords(ST_KEYWORDS)
+ if new_window is not None:
+ project_infos = self.GetProjectConfiguration()
+ if project_infos.has_key("editors_state"):
+ state = project_infos["editors_state"].get(instance_path)
+ if state is not None:
+ wx.CallAfter(new_window.SetState, state)
+
+ if instance_category in [ITEM_FUNCTIONBLOCK, ITEM_PROGRAM]:
+ pou_type = self.Controler.GetEditedElementType(instance_type, True)[1].upper()
+ icon = GetBitmap(pou_type, bodytype)
+ elif instance_category == ITEM_TRANSITION:
+ icon = GetBitmap("TRANSITION", bodytype)
+ elif instance_category == ITEM_ACTION:
+ icon = GetBitmap("ACTION", bodytype)
+ new_window.SetIcon(icon)
+ self.AddPage(new_window, "")
+ new_window.RefreshView()
+ new_window.SetFocus()
+ self.RefreshPageTitles()
+ return new_window
+
+ return None
+
+ def OpenGraphicViewer(self, var_path):
+ new_window = GraphicViewer(self.TabsOpened, self, self.Controler, var_path)
+ new_window.SetIcon(GetBitmap("GRAPH"))
+ self.AddPage(new_window, "")
+ new_window.RefreshView()
+ new_window.SetFocus()
+ self.RefreshPageTitles()
+ return new_window
+
+ def ResetGraphicViewers(self):
+ for i in xrange(self.TabsOpened.GetPageCount()):
+ editor = self.TabsOpened.GetPage(i)
+ if isinstance(editor, GraphicViewer):
+ editor.ResetView()
+
+ def CloseObsoleteDebugTabs(self):
+ if self.EnableDebug:
+ idxs = range(self.TabsOpened.GetPageCount())
+ idxs.reverse()
+ for idx in idxs:
+ editor = self.TabsOpened.GetPage(idx)
+ if editor.IsDebugging():
+ instance_infos = self.Controler.GetInstanceInfos(editor.GetInstancePath(), self.EnableDebug)
+ if instance_infos is None:
+ self.TabsOpened.DeletePage(idx)
+ elif isinstance(editor, GraphicViewer):
+ editor.ResetView(True)
+ else:
+ editor.RefreshView()
+ self.DebugVariablePanel.UnregisterObsoleteData()
+
+ def AddDebugVariable(self, iec_path, force=False):
+ if self.EnableDebug:
+ self.DebugVariablePanel.InsertValue(iec_path, force=force)
+ self.EnsureTabVisible(self.DebugVariablePanel)
+
+#-------------------------------------------------------------------------------
+# Library Panel Management Function
+#-------------------------------------------------------------------------------
+
+ def RefreshLibraryPanel(self):
+ self.LibraryPanel.RefreshTree()
+
+#-------------------------------------------------------------------------------
+# ToolBars Management Functions
+#-------------------------------------------------------------------------------
+
+ def AddToMenuToolBar(self, items):
+ MenuToolBar = self.Panes["MenuToolBar"]
+ if MenuToolBar.GetToolsCount() > 0:
+ MenuToolBar.AddSeparator()
+ for toolbar_item in items:
+ if toolbar_item is None:
+ MenuToolBar.AddSeparator()
+ else:
+ id, bitmap, help, callback = toolbar_item
+ MenuToolBar.AddSimpleTool(id=id, shortHelpString=help, bitmap=GetBitmap(bitmap))
+ if callback is not None:
+ self.Bind(wx.EVT_TOOL, callback, id=id)
+ MenuToolBar.Realize()
+ self.AUIManager.GetPane("MenuToolBar").BestSize(MenuToolBar.GetBestSize())
+
+ 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)
+
+ if EditorToolBar:
+ EditorToolBar.DeleteTool(item)
+
+ if EditorToolBar:
+ EditorToolBar.Realize()
+ self.AUIManager.GetPane("EditorToolBar").BestSize(EditorToolBar.GetBestSize())
+ self.AUIManager.GetPane("EditorToolBar").Hide()
+ self.AUIManager.Update()
+
+ def RefreshEditorToolBar(self):
+ selected = self.TabsOpened.GetSelection()
+ menu = None
+ if selected != -1:
+ window = self.TabsOpened.GetPage(selected)
+ if isinstance(window, (Viewer, TextViewer, GraphicViewer)):
+ if not window.IsDebugging():
+ menu = self.Controler.GetEditedElementBodyType(window.GetTagName())
+ else:
+ menu = "debug"
+ if menu is not None and menu != self.CurrentMenu:
+ self.ResetEditorToolBar()
+ self.CurrentMenu = menu
+ self.CurrentEditorToolBar = []
+ EditorToolBar = self.Panes["EditorToolBar"]
+ if EditorToolBar:
+ for radio, modes, id, method, picture, help in EditorToolBarItems[menu]:
+ if modes & self.DrawingMode:
+ if radio or self.DrawingMode == FREEDRAWING_MODE:
+ EditorToolBar.AddRadioTool(id, GetBitmap(picture), wx.NullBitmap, help)
+ else:
+ EditorToolBar.AddSimpleTool(id, GetBitmap(picture), help)
+ self.Bind(wx.EVT_MENU, getattr(self, method), id=id)
+ self.CurrentEditorToolBar.append(id)
+ EditorToolBar.Realize()
+ self.AUIManager.GetPane("EditorToolBar").BestSize(EditorToolBar.GetBestSize())
+ self.AUIManager.GetPane("EditorToolBar").Show()
+ self.AUIManager.Update()
+ elif menu is None:
+ self.ResetEditorToolBar()
+ self.CurrentMenu = menu
+ self.ResetCurrentMode()
+
+
+#-------------------------------------------------------------------------------
+# EditorToolBar Items Functions
+#-------------------------------------------------------------------------------
+
+ def ResetCurrentMode(self):
+ selected = self.TabsOpened.GetSelection()
+ if selected != -1:
+ window = self.TabsOpened.GetPage(selected)
+ window.SetMode(MODE_SELECTION)
+ EditorToolBar = self.Panes["EditorToolBar"]
+ 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)
+
+ def OnSelectionTool(self, event):
+ 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)
+ selected = self.TabsOpened.GetSelection()
+ if selected != -1:
+ if self.DrawingMode == FREEDRAWING_MODE:
+ self.TabsOpened.GetPage(selected).SetMode(MODE_CONTACT)
+ else:
+ self.TabsOpened.GetPage(selected).AddLadderContact()
+
+ 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)
+ selected = self.TabsOpened.GetSelection()
+ if selected != -1:
+ if self.GetDrawingMode() == FREEDRAWING_MODE:
+ 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)
+ selected = self.TabsOpened.GetSelection()
+ if selected != -1:
+ if self.GetDrawingMode() == FREEDRAWING_MODE:
+ 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)
+ selected = self.TabsOpened.GetSelection()
+ if selected != -1:
+ if self.GetDrawingMode() == FREEDRAWING_MODE:
+ 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)
+ selected = self.TabsOpened.GetSelection()
+ if selected != -1:
+ if self.GetDrawingMode() == FREEDRAWING_MODE:
+ self.TabsOpened.GetPage(selected).SetMode(MODE_JUMP)
+ else:
+ self.TabsOpened.GetPage(selected).AddJump()
+
+
+#-------------------------------------------------------------------------------
+# Add Project Elements Functions
+#-------------------------------------------------------------------------------
+
+ def OnAddDataTypeMenu(self, event):
+ tagname = self.Controler.ProjectAddDataType()
+ 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)
+ dialog.SetPouNames(self.Controler.GetProjectPouNames())
+ dialog.SetPouElementNames(self.Controler.GetProjectPouVariables())
+ dialog.SetValues({"pouName": self.Controler.GenerateNewName(None, None, "%s%%d" % pou_type)})
+ if dialog.ShowModal() == wx.ID_OK:
+ values = dialog.GetValues()
+ tagname = self.Controler.ProjectAddPou(values["pouName"], values["pouType"], values["language"])
+ if tagname is not None:
+ self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, LIBRARYTREE)
+ self.EditProjectElement(ITEM_POU, tagname)
+ dialog.Destroy()
+ return OnAddPouMenu
+
+ def GenerateAddTransitionFunction(self, pou_name):
+ def OnAddTransitionMenu(event):
+ dialog = PouTransitionDialog(self)
+ dialog.SetPouNames(self.Controler.GetProjectPouNames())
+ dialog.SetPouElementNames(self.Controler.GetProjectPouVariables(pou_name))
+ dialog.SetValues({"transitionName": self.Controler.GenerateNewName(None, None, "transition%d")})
+ if dialog.ShowModal() == wx.ID_OK:
+ values = dialog.GetValues()
+ tagname = self.Controler.ProjectAddPouTransition(pou_name, values["transitionName"], values["language"])
+ if tagname is not None:
+ self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE)
+ self.EditProjectElement(ITEM_TRANSITION, tagname)
+ dialog.Destroy()
+ return OnAddTransitionMenu
+
+ def GenerateAddActionFunction(self, pou_name):
+ def OnAddActionMenu(event):
+ dialog = PouActionDialog(self)
+ dialog.SetPouNames(self.Controler.GetProjectPouNames())
+ dialog.SetPouElementNames(self.Controler.GetProjectPouVariables(pou_name))
+ dialog.SetValues({"actionName": self.Controler.GenerateNewName(None, None, "action%d")})
+ if dialog.ShowModal() == wx.ID_OK:
+ values = dialog.GetValues()
+ tagname = self.Controler.ProjectAddPouAction(pou_name, values["actionName"], values["language"])
+ if tagname is not None:
+ self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE)
+ self.EditProjectElement(ITEM_ACTION, tagname)
+ dialog.Destroy()
+ return OnAddActionMenu
+
+ def OnAddConfigurationMenu(self, event):
+ tagname = self.Controler.ProjectAddConfiguration()
+ if tagname is not None:
+ self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL)
+ self.EditProjectElement(ITEM_CONFIGURATION, tagname)
+ dialog.Destroy()
+
+ def GenerateAddResourceFunction(self, config_name):
+ def OnAddResourceMenu(event):
+ tagname = self.Controler.ProjectAddConfigurationResource(config_name)
+ if tagname is not None:
+ self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL)
+ self.EditProjectElement(ITEM_RESOURCE, tagname)
+ return OnAddResourceMenu
+
+ def GenerateChangePouTypeFunction(self, name, new_type):
+ def OnChangePouTypeMenu(event):
+ selected = self.ProjectTree.GetSelection()
+ if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU:
+ self.Controler.ProjectChangePouType(name, new_type)
+ self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, LIBRARYTREE)
+ return OnChangePouTypeMenu
+
+ 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)
+ self._Refresh(EDITMENU)
+
+ def OnPastePou(self, event):
+ selected = self.ProjectTree.GetSelection()
+
+ 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)
+
+ if not isinstance(result, TupleType):
+ message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ else:
+ self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, LIBRARYTREE)
+ self.EditProjectElement(ITEM_POU, result[0])
+
+#-------------------------------------------------------------------------------
+# Remove Project Elements Functions
+#-------------------------------------------------------------------------------
+
+ def OnRemoveDataTypeMenu(self, event):
+ selected = self.ProjectTree.GetSelection()
+ if self.ProjectTree.GetPyData(selected)["type"] == ITEM_DATATYPE:
+ name = self.ProjectTree.GetItemText(selected)
+ if not self.Controler.DataTypeIsUsed(name):
+ self.Controler.ProjectRemoveDataType(name)
+ tagname = self.Controler.ComputeDataTypeName(name)
+ idx = self.IsOpened(tagname)
+ if idx is not None:
+ self.TabsOpened.DeletePage(idx)
+ self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE)
+ else:
+ self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!"))
+
+ def OnRenamePouMenu(self, event):
+ selected = self.ProjectTree.GetSelection()
+ if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU:
+ wx.CallAfter(self.ProjectTree.EditLabel, selected)
+
+ def OnRemovePouMenu(self, event):
+ selected = self.ProjectTree.GetSelection()
+ if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU:
+ name = self.ProjectTree.GetItemText(selected)
+ if not self.Controler.PouIsUsed(name):
+ self.Controler.ProjectRemovePou(name)
+ tagname = self.Controler.ComputePouName(name)
+ idx = self.IsOpened(tagname)
+ if idx is not None:
+ self.TabsOpened.DeletePage(idx)
+ self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
+ else:
+ self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!"))
+
+ def OnRemoveTransitionMenu(self, event):
+ selected = self.ProjectTree.GetSelection()
+ item_infos = self.ProjectTree.GetPyData(selected)
+ if item_infos["type"] == ITEM_TRANSITION:
+ transition = self.ProjectTree.GetItemText(selected)
+ pou_name = item_infos["tagname"].split("::")[1]
+ self.Controler.ProjectRemovePouTransition(pou_name, transition)
+ tagname = self.Controler.ComputePouTransitionName(pou_name, transition)
+ idx = self.IsOpened(tagname)
+ if idx is not None:
+ self.TabsOpened.DeletePage(idx)
+ self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE)
+
+ def OnRemoveActionMenu(self, event):
+ selected = self.ProjectTree.GetSelection()
+ item_infos = self.ProjectTree.GetPyData(selected)
+ if item_infos["type"] == ITEM_ACTION:
+ action = self.ProjectTree.GetItemText(selected)
+ pou_name = item_infos["tagname"].split("::")[1]
+ self.Controler.ProjectRemovePouAction(pou_name, action)
+ tagname = self.Controler.ComputePouActionName(pou_name, action)
+ idx = self.IsOpened(tagname)
+ if idx is not None:
+ self.TabsOpened.DeletePage(idx)
+ self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE)
+
+ def OnRemoveConfigurationMenu(self, event):
+ selected = self.ProjectTree.GetSelection()
+ if self.ProjectTree.GetPyData(selected)["type"] == ITEM_CONFIGURATION:
+ name = self.ProjectTree.GetItemText(selected)
+ self.Controler.ProjectRemoveConfiguration(name)
+ tagname = self.Controler.ComputeConfigurationName(name)
+ idx = self.IsOpened(tagname)
+ if idx is not None:
+ self.TabsOpened.DeletePage(idx)
+ self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL)
+
+ def OnRemoveResourceMenu(self, event):
+ selected = self.ProjectTree.GetSelection()
+ item_infos = self.ProjectTree.GetPyData(selected)
+ if item_infos["type"] == ITEM_RESOURCE:
+ resource = self.ProjectTree.GetItemText(selected)
+ config_name = item_infos["tagname"].split("::")[1]
+ self.Controler.ProjectRemoveConfigurationResource(config_name, resource)
+ tagname = self.Controler.ComputeConfigurationResourceName(config_name, selected)
+ idx = self.IsOpened(tagname)
+ if idx is not None:
+ self.TabsOpened.DeletePage(idx)
+ self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL)
+
+#-------------------------------------------------------------------------------
+# Highlights showing functions
+#-------------------------------------------------------------------------------
+
+ def ShowHighlight(self, infos, start, end, highlight_type):
+ self.SelectProjectTreeItem(infos[0])
+ if infos[1] == "name":
+ self.Highlights[infos[0]] = highlight_type
+ self.RefreshProjectTree()
+ self.ProjectTree.Unselect()
+ else:
+ self.EditProjectElement(self.Controler.GetElementType(infos[0]), infos[0])
+ selected = self.TabsOpened.GetSelection()
+ if selected != -1:
+ viewer = self.TabsOpened.GetPage(selected)
+ viewer.AddHighlight(infos[1:], start, end, highlight_type)
+
+ def ShowError(self, infos, start, end):
+ self.ShowHighlight(infos, start, end, ERROR_HIGHLIGHT)
+
+ def ShowSearchResult(self, infos, start, end):
+ self.ShowHighlight(infos, start, end, SEARCH_RESULT_HIGHLIGHT)
+
+ def ClearHighlights(self, highlight_type=None):
+ if highlight_type is None:
+ self.Highlights = {}
+ else:
+ self.Highlights = dict([(name, highlight) for name, highlight in self.Highlights.iteritems() if highlight != highlight_type])
+ self.RefreshProjectTree()
+ for i in xrange(self.TabsOpened.GetPageCount()):
+ viewer = self.TabsOpened.GetPage(i)
+ viewer.ClearHighlights(highlight_type)
+
+ def ClearErrors(self):
+ self.ClearHighlights(ERROR_HIGHLIGHT)
+
+ def ClearSearchResults(self):
+ self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT)