# HG changeset patch # User laurent # Date 1320785962 -3600 # Node ID 9aa96a36cf33299ef852c045d3d33b908badfe32 # Parent bd8c7a033b17fb63b6e3b06c2fca7ed0582a2d68 Moving variable panel from bottom notebook panel to POU editor panel diff -r bd8c7a033b17 -r 9aa96a36cf33 DataTypeEditor.py --- a/DataTypeEditor.py Mon Nov 07 10:55:17 2011 +0100 +++ b/DataTypeEditor.py Tue Nov 08 21:59:22 2011 +0100 @@ -27,7 +27,7 @@ from plcopen.structures import IEC_KEYWORDS, TestIdentifier from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD -from controls import CustomEditableListBox, CustomGrid +from controls import CustomEditableListBox, CustomGrid, EditorPanel import re @@ -231,7 +231,7 @@ # Datatype Editor class #------------------------------------------------------------------------------- -[ID_DATATYPEEDITOR, ID_DATATYPEEDITORSTATICBOX, +[ID_DATATYPEEDITOR, ID_DATATYPEEDITORPANEL, ID_DATATYPEEDITORSTATICBOX, ID_DATATYPEEDITORDERIVATIONTYPE, ID_DATATYPEEDITORDIRECTLYPANEL, ID_DATATYPEEDITORSUBRANGEPANEL, ID_DATATYPEEDITORDIRECTLYBASETYPE, ID_DATATYPEEDITORSUBRANGEBASETYPE, ID_DATATYPEEDITORSUBRANGEMINIMUM, @@ -249,14 +249,16 @@ ID_DATATYPEEDITORSTATICTEXT7, ID_DATATYPEEDITORSTATICTEXT8, ID_DATATYPEEDITORSTATICTEXT9, ID_DATATYPEEDITORSTATICTEXT10, ID_DATATYPEEDITORSTATICTEXT11, -] = [wx.NewId() for _init_ctrls in range(35)] +] = [wx.NewId() for _init_ctrls in range(36)] def GetDatatypeTypes(): _ = lambda x : x return [_("Directly"), _("Subrange"), _("Enumerated"), _("Array"), _("Structure")] DATATYPE_TYPES_DICT = dict([(_(datatype), datatype) for datatype in GetDatatypeTypes()]) -class DataTypeEditor(wx.Panel): +class DataTypeEditor(EditorPanel): + + ID = ID_DATATYPEEDITOR def _init_coll_MainSizer_Items(self, parent): parent.AddSizer(self.TopSizer, 0, border=5, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) @@ -322,20 +324,24 @@ parent.AddWindow(self.ArrayInitialValue, 1, border=5, flag=wx.ALL) def _init_coll_StructurePanelSizer_Items(self, parent): - parent.AddWindow(self.staticText11, 0, border=5, flag=wx.ALL) + parent.AddSizer(self.StructurePanelButtonSizer, 0, border=5, flag=wx.ALL|wx.GROW) parent.AddWindow(self.StructureElementsGrid, 0, border=0, flag=wx.GROW) - parent.AddSizer(self.StructurePanelButtonSizer, 0, border=0, flag=wx.ALIGN_RIGHT) def _init_coll_StructurePanelSizer_Growables(self, parent): parent.AddGrowableCol(0) parent.AddGrowableRow(1) - + def _init_coll_StructurePanelButtonSizer_Items(self, parent): - parent.AddWindow(self.StructureAddButton, 0, border=5, flag=wx.ALL) - parent.AddWindow(self.StructureDeleteButton, 0, border=5, flag=wx.ALL) - parent.AddWindow(self.StructureUpButton, 0, border=5, flag=wx.ALL) - parent.AddWindow(self.StructureDownButton, 0, border=5, flag=wx.ALL) - + parent.AddWindow(self.staticText11, 0, border=0, flag=wx.ALIGN_BOTTOM) + parent.AddWindow(self.StructureAddButton, 0, border=0, flag=0) + parent.AddWindow(self.StructureDeleteButton, 0, border=0, flag=0) + parent.AddWindow(self.StructureUpButton, 0, border=0, flag=0) + parent.AddWindow(self.StructureDownButton, 0, border=0, flag=0) + + def _init_coll_StructurePanelButtonSizer_Growables(self, parent): + parent.AddGrowableCol(0) + parent.AddGrowableRow(0) + def _init_sizers(self): self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) self.TopSizer = wx.BoxSizer(wx.HORIZONTAL) @@ -347,8 +353,9 @@ self.ArrayPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=0) self.ArrayPanelLeftSizer = wx.BoxSizer(wx.HORIZONTAL) self.ArrayPanelRightSizer = wx.BoxSizer(wx.HORIZONTAL) - self.StructurePanelSizer = wx.FlexGridSizer(cols=1, hgap=5, rows=3, vgap=0) - self.StructurePanelButtonSizer = wx.BoxSizer(wx.HORIZONTAL) + self.StructurePanelSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) + self.StructurePanelButtonSizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) + self._init_coll_MainSizer_Items(self.MainSizer) self._init_coll_MainSizer_Growables(self.MainSizer) self._init_coll_TopSizer_Items(self.TopSizer) @@ -364,35 +371,36 @@ self._init_coll_StructurePanelSizer_Items(self.StructurePanelSizer) self._init_coll_StructurePanelSizer_Growables(self.StructurePanelSizer) self._init_coll_StructurePanelButtonSizer_Items(self.StructurePanelButtonSizer) - - self.SetSizer(self.MainSizer) + self._init_coll_StructurePanelButtonSizer_Growables(self.StructurePanelButtonSizer) + + self.Editor.SetSizer(self.MainSizer) self.DirectlyPanel.SetSizer(self.DirectlyPanelSizer) self.SubrangePanel.SetSizer(self.SubrangePanelSizer) self.EnumeratedPanel.SetSizer(self.EnumeratedPanelSizer) self.ArrayPanel.SetSizer(self.ArrayPanelSizer) self.StructurePanel.SetSizer(self.StructurePanelSizer) - def _init_ctrls(self, prnt): - wx.Panel.__init__(self, id=ID_DATATYPEEDITOR, name='', parent=prnt, + def _init_Editor(self, prnt): + self.Editor = wx.Panel(id=ID_DATATYPEEDITORPANEL, name='', parent=prnt, size=wx.Size(0, 0), style=wx.SUNKEN_BORDER) self.staticbox = wx.StaticBox(id=ID_DATATYPEEDITORSTATICBOX, - label=_('Type infos:'), name='staticBox1', parent=self, + label=_('Type infos:'), name='staticBox1', parent=self.Editor, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.staticText1 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT1, - label=_('Derivation Type:'), name='staticText1', parent=self, + label=_('Derivation Type:'), name='staticText1', parent=self.Editor, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.DerivationType = wx.ComboBox(id=ID_DATATYPEEDITORDERIVATIONTYPE, - name='DerivationType', parent=self, pos=wx.Point(0, 0), + name='DerivationType', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(200, 28), style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnDerivationTypeChanged, id=ID_DATATYPEEDITORDERIVATIONTYPE) # Panel for Directly derived data types self.DirectlyPanel = wx.Panel(id=ID_DATATYPEEDITORDIRECTLYPANEL, - name='DirectlyPanel', parent=self, pos=wx.Point(0, 0), + name='DirectlyPanel', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText2 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT2, @@ -417,7 +425,7 @@ # Panel for Subrange data types self.SubrangePanel = wx.Panel(id=ID_DATATYPEEDITORSUBRANGEPANEL, - name='SubrangePanel', parent=self, pos=wx.Point(0, 0), + name='SubrangePanel', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText4 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT4, @@ -460,7 +468,7 @@ # Panel for Enumerated data types self.EnumeratedPanel = wx.Panel(id=ID_DATATYPEEDITORENUMERATEDPANEL, - name='EnumeratedPanel', parent=self, pos=wx.Point(0, 0), + name='EnumeratedPanel', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.EnumeratedValues = CustomEditableListBox(id=ID_DATATYPEEDITORENUMERATEDVALUES, @@ -481,7 +489,7 @@ # Panel for Array data types self.ArrayPanel = wx.Panel(id=ID_DATATYPEEDITORARRAYPANEL, - name='ArrayPanel', parent=self, pos=wx.Point(0, 0), + name='ArrayPanel', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText9 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT9, @@ -512,7 +520,7 @@ # Panel for Structure data types self.StructurePanel = wx.Panel(id=ID_DATATYPEEDITORSTRUCTUREPANEL, - name='StructurePanel', parent=self, pos=wx.Point(0, 0), + name='StructurePanel', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText11 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT11, @@ -554,7 +562,7 @@ self._init_sizers() def __init__(self, parent, tagname, window, controler): - self._init_ctrls(parent) + EditorPanel.__init__(self, parent, tagname, window, controler) self.StructureElementDefaultValue = {"Name" : "", "Type" : "INT", "Initial Value" : ""} self.StructureElementsTable = ElementsTable(self, [], GetElementsTableColnames()) @@ -607,10 +615,6 @@ self.Highlights = [] self.Initializing = False - self.ParentWindow = window - self.Controler = controler - self.TagName = tagname - self.HighlightControls = { ("Directly", "base"): self.DirectlyBaseType, ("Directly", "initial"): self.DirectlyInitialValue, @@ -631,24 +635,22 @@ def __del__(self): self.RefreshHighlightsTimer.Stop() - def SetTagName(self, tagname): - self.TagName = tagname - - def GetTagName(self): - return self.TagName - - def IsViewing(self, tagname): - return self.TagName == tagname - - def IsDebugging(self): - return False - - def SetMode(self, mode): - pass - - def ResetBuffer(self): - pass - + def GetBufferState(self): + return self.Controler.GetBufferState() + + def Undo(self): + self.Controler.LoadPrevious() + self.ParentWindow.CloseTabsWithoutModel() + self.ParentWindow.RefreshEditor() + + def Redo(self): + self.Controler.LoadNext() + self.ParentWindow.CloseTabsWithoutModel() + self.ParentWindow.RefreshEditor() + + def HasNoModel(self): + return self.Controler.GetEditedElement(self.TagName) is None + def RefreshView(self): self.Initializing = True self.DirectlyBaseType.Clear() @@ -695,10 +697,7 @@ self.StructureElementsTable.ResetView(self.StructureElementsGrid) self.StructureElementsGrid.RefreshButtons() self.Initializing = False - - def RefreshScaling(self, refresh=True): - pass - + def OnDerivationTypeChanged(self, event): self.RefreshDisplayedInfos() self.RefreshTypeInfos() diff -r bd8c7a033b17 -r 9aa96a36cf33 GraphicViewer.py --- a/GraphicViewer.py Mon Nov 07 10:55:17 2011 +0100 +++ b/GraphicViewer.py Tue Nov 08 21:59:22 2011 +0100 @@ -25,7 +25,7 @@ import wx import wx.lib.plot as plot from graphics.GraphicCommons import DebugViewer - +from controls import EditorPanel colours = ['blue', 'red', 'green', 'yellow', 'orange', 'purple', 'brown', 'cyan', 'pink', 'grey'] @@ -45,7 +45,7 @@ ID_GRAPHICVIEWERSTATICTEXT1, ID_GRAPHICVIEWERSTATICTEXT2, ] = [wx.NewId() for _init_ctrls in range(8)] -class GraphicViewer(wx.Panel, DebugViewer): +class GraphicViewer(EditorPanel, DebugViewer): def _init_coll_MainGridSizer_Items(self, parent): # generated method, don't edit @@ -81,14 +81,14 @@ self._init_coll_RangeSizer_Items(self.RangeSizer) self._init_coll_RangeSizer_Growables(self.RangeSizer) - self.SetSizer(self.MainGridSizer) - - def _init_ctrls(self, prnt): - wx.Panel.__init__(self, prnt, ID_GRAPHICVIEWER, wx.DefaultPosition, + self.Editor.SetSizer(self.MainGridSizer) + + def _init_Editor(self, prnt): + self.Editor = wx.Panel(prnt, ID_GRAPHICVIEWER, wx.DefaultPosition, wx.DefaultSize, 0) self.Canvas = plot.PlotCanvas(id=ID_GRAPHICVIEWERCANVAS, - name='Canvas', parent=self, pos=wx.Point(0, 0), + name='Canvas', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=0) def _axisInterval(spec, lower, upper): if spec == 'border': @@ -103,22 +103,22 @@ self.Canvas.SetYSpec('border') self.staticbox1 = wx.StaticText(id=ID_GRAPHICVIEWERSTATICTEXT1, - label=_('Range:'), name='staticText1', parent=self, + label=_('Range:'), name='staticText1', parent=self.Editor, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.CanvasRange = wx.ComboBox(id=ID_GRAPHICVIEWERCANVASRANGE, - name='CanvasRange', parent=self, pos=wx.Point(0, 0), + name='CanvasRange', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(100, 28), choices=RANGE_VALUES, style=0) self.CanvasRange.SetStringSelection("25") self.Bind(wx.EVT_COMBOBOX, self.OnRangeChanged, id=ID_GRAPHICVIEWERCANVASRANGE) self.Bind(wx.EVT_TEXT_ENTER, self.OnRangeChanged, id=ID_GRAPHICVIEWERCANVASRANGE) self.staticText2 = wx.StaticText(id=ID_GRAPHICVIEWERSTATICTEXT2, - label=_('Position:'), name='staticText2', parent=self, + label=_('Position:'), name='staticText2', parent=self.Editor, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.CanvasPosition = wx.ScrollBar(id=ID_GRAPHICVIEWERCANVASPOSITION, - name='Position', parent=self, pos=wx.Point(0, 0), + name='Position', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(0, 16), style=wx.SB_HORIZONTAL) self.CanvasPosition.SetScrollbar(0, 10, 100, 10) self.CanvasPosition.Bind(wx.EVT_SCROLL_THUMBTRACK, self.OnPositionChanging, @@ -133,22 +133,21 @@ id = ID_GRAPHICVIEWERCANVASPOSITION) self.ResetButton = wx.Button(id=ID_GRAPHICVIEWERRESETBUTTON, label='Reset', - name='ResetButton', parent=self, pos=wx.Point(0, 0), + name='ResetButton', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(72, 24), style=0) self.Bind(wx.EVT_BUTTON, self.OnResetButton, id=ID_GRAPHICVIEWERRESETBUTTON) self.CurrentButton = wx.Button(id=ID_GRAPHICVIEWERCURRENTBUTTON, label='Current', - name='CurrentButton', parent=self, pos=wx.Point(0, 0), + name='CurrentButton', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(72, 24), style=0) self.Bind(wx.EVT_BUTTON, self.OnCurrentButton, id=ID_GRAPHICVIEWERCURRENTBUTTON) self._init_sizers() def __init__(self, parent, window, producer, instancepath = ""): - self._init_ctrls(parent) + EditorPanel.__init__(self, parent, "", window, None) DebugViewer.__init__(self, producer, True, False) - self.ParentWindow = window self.InstancePath = instancepath self.Datas = [] @@ -161,6 +160,11 @@ DebugViewer.__del__(self) self.RemoveDataConsumer(self) + def GetTitle(self): + if len(self.InstancePath) > 15: + return "..." + self.InstancePath[-12:] + return self.InstancePath + def ResetView(self): self.Datas = [] self.CurrentValue = 0 @@ -192,30 +196,12 @@ self.RefreshScrollBar() self.Thaw() - def SetMode(self, mode): - pass - - def GetTagName(self): - return "" - def GetInstancePath(self): return self.InstancePath def IsViewing(self, tagname): return self.InstancePath == tagname - def ResetBuffer(self): - pass - - def RefreshScaling(self, refresh=True): - pass - - def SelectAll(self): - pass - - def ClearErrors(self): - pass - def NewValue(self, tick, value, forced=False): self.Datas.append((float(tick), {True:1., False:0.}.get(value, float(value)))) if self.CurrentValue + self.CurrentRange == len(self.Datas) - 1: diff -r bd8c7a033b17 -r 9aa96a36cf33 LDViewer.py --- a/LDViewer.py Mon Nov 07 10:55:17 2011 +0100 +++ b/LDViewer.py Tue Nov 08 21:59:22 2011 +0100 @@ -182,8 +182,8 @@ self.RungComments = [] Viewer.ResetView(self) - def RefreshView(self, selection=None): - Viewer.RefreshView(self, selection) + def RefreshView(self, variablepanel=True, selection=None): + Viewer.RefreshView(self, variablepanel, selection) wx.CallAfter(self.Refresh) for i, rung in enumerate(self.Rungs): bbox = rung.GetBoundingBox() diff -r bd8c7a033b17 -r 9aa96a36cf33 PLCOpenEditor.py --- a/PLCOpenEditor.py Mon Nov 07 10:55:17 2011 +0100 +++ b/PLCOpenEditor.py Tue Nov 08 21:59:22 2011 +0100 @@ -113,7 +113,7 @@ from RessourceEditor import * from DataTypeEditor import * from PLCControler import * -from VariablePanel import VariablePanel +from controls.VariablePanel import VariablePanel from SearchResultPanel import SearchResultPanel from controls import CustomGrid @@ -267,14 +267,14 @@ parent.Append(helpString=help, id=id, kind=kind, item=text) [TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, TYPESTREE, - INSTANCESTREE, LIBRARYTREE, SCALING -] = range(9) + INSTANCESTREE, LIBRARYTREE, SCALING, PAGETITLES +] = range(10) def GetShortcutKeyCallbackFunction(viewer_function): def ShortcutKeyFunction(self, event): control = self.FindFocus() - if isinstance(control, (Viewer, TextViewer)): - getattr(control, viewer_function)() + if control.GetName() in ["Viewer", "TextViewer"]: + getattr(control.Parent, viewer_function)() elif isinstance(control, wx.TextCtrl): control.ProcessEvent(event) return ShortcutKeyFunction @@ -608,9 +608,6 @@ self.Bind(wx.EVT_TOOL, self.OnSelectionTool, id=ID_PLCOPENEDITORTOOLBARSELECTION) - self.VariablePanelIndexer = VariablePanelIndexer(self.BottomNoteBook, self) - self.BottomNoteBook.AddPage(self.VariablePanelIndexer, _("Variables")) - self.SearchResultPanel = SearchResultPanel(self.BottomNoteBook, self) self.BottomNoteBook.AddPage(self.SearchResultPanel, _("Search")) @@ -754,7 +751,8 @@ TYPESTREE : self.RefreshTypesTree, INSTANCESTREE : self.RefreshInstancesTree, LIBRARYTREE : self.RefreshLibraryTree, - SCALING : self.RefreshScaling} + SCALING : self.RefreshScaling, + PAGETITLES: self.RefreshPageTitles} ## Call PLCOpenEditor refresh functions. # @param elements List of elements to refresh. @@ -765,14 +763,6 @@ ## Callback function when AUINotebook Page closed with CloseButton # @param event AUINotebook Event. def OnPageClose(self, event): - # Get Selected Tab - selected = event.GetSelection() - if selected >= 0: - # Remove corresponding VariablePanel - window = self.TabsOpened.GetPage(selected) - if not window.IsDebugging(): - self.VariablePanelIndexer.RemoveVariablePanel(window.GetTagName()) - wx.CallAfter(self.RefreshTabCtrlEvent) event.Skip() @@ -925,7 +915,6 @@ def ResetView(self): self.DeleteAllPages() - self.VariablePanelIndexer.RemoveAllPanels() self.TypesTree.DeleteAllItems() self.InstancesTree.DeleteAllItems() self.LibraryTree.DeleteAllItems() @@ -934,16 +923,10 @@ def OnCloseTabMenu(self, event): selected = self.TabsOpened.GetSelection() if selected >= 0: - window = self.TabsOpened.GetPage(selected) - if not window.IsDebugging(): - self.VariablePanelIndexer.RemoveVariablePanel(window.GetTagName()) self.TabsOpened.DeletePage(selected) if self.TabsOpened.GetPageCount() > 0: new_index = min(selected, self.TabsOpened.GetPageCount() - 1) self.TabsOpened.SetSelection(new_index) - window = self.TabsOpened.GetPage(new_index) - if not window.IsDebugging(): - self.VariablePanelIndexer.ChangeVariablePanel(window.GetTagName()) # Refresh all window elements that have changed self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) self.RefreshTabCtrlEvent() @@ -1006,7 +989,12 @@ def RefreshEditMenu(self): if self.Controler is not None: - undo, redo = self.Controler.GetBufferState() + selected = self.TabsOpened.GetSelection() + if selected > -1: + window = self.TabsOpened.GetPage(selected) + undo, redo = window.GetBufferState() + else: + undo, redo = False, False self.EditMenu.Enable(wx.ID_UNDO, undo) self.EditMenu.Enable(wx.ID_REDO, redo) #self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, True) @@ -1045,25 +1033,24 @@ idxs.reverse() for idx in idxs: window = self.TabsOpened.GetPage(idx) - if not window.IsDebugging(): - tagname = window.GetTagName() - if self.Controler.GetEditedElement(tagname) is None: - self.VariablePanelIndexer.RemoveVariablePanel(tagname) - self.TabsOpened.DeletePage(idx) + if window.HasNoModel(): + self.TabsOpened.DeletePage(idx) def OnUndoMenu(self, event): - self.Controler.LoadPrevious() - self.CloseTabsWithoutModel() - self.RefreshEditor() - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE, - SCALING) + selected = self.TabsOpened.GetSelection() + if selected != -1: + window = self.TabsOpened.GetPage(selected) + window.Undo() + self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE, + SCALING, PAGETITLES) def OnRedoMenu(self, event): - self.Controler.LoadNext() - self.CloseTabsWithoutModel() - self.RefreshEditor() - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE, - SCALING) + selected = self.TabsOpened.GetSelection() + if selected != -1: + window = self.TabsOpened.GetPage(selected) + window.Redo() + self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE, + SCALING, PAGETITLES) def OnEnableUndoRedoMenu(self, event): self.Controler.EnableProjectBuffer(event.IsChecked()) @@ -1075,8 +1062,8 @@ def OnSelectAllMenu(self, event): control = self.FindFocus() - if isinstance(control, (Viewer, TextViewer)): - control.SelectAll() + if control.GetName() in ["Viewer", "TextViewer"]: + control.Parent.SelectAll() elif isinstance(control, wx.TextCtrl): control.SetSelection(0, control.GetLastPosition()) elif isinstance(control, wx.ComboBox): @@ -1203,38 +1190,28 @@ else: wx.CallAfter(self.SelectInstancesTreeItem, self.InstancesTree.GetRootItem(), window.GetInstancePath()) window.RefreshView() - if not window.IsDebugging(): - self.VariablePanelIndexer.ChangeVariablePanel(window.GetTagName()) self._Refresh(FILEMENU, EDITMENU, DISPLAYMENU, TOOLBAR) event.Skip() - def RefreshEditor(self, variablepanel = True): + def RefreshEditor(self): selected = self.TabsOpened.GetSelection() if USE_AUI: for child in self.TabsOpened.GetChildren(): if isinstance(child, wx.aui.AuiTabCtrl): active_page = child.GetActivePage() if active_page >= 0: - window = child.GetWindowFromIdx(child.GetActivePage()) + window = child.GetWindowFromIdx(active_page) window.RefreshView() - if not window.IsDebugging() and self.TabsOpened.GetPageIndex(window) == selected and variablepanel: - self.RefreshVariablePanel(window.GetTagName()) elif selected >= 0: window = self.TabsOpened.GetPage(idx) window.RefreshView() - if not window.IsDebugging() and variablepanel: - self.RefreshVariablePanel(window.GetTagName()) - - def RefreshVariablePanel(self, tagname): - self.VariablePanelIndexer.RefreshVariablePanel(tagname) - + 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) - self.VariablePanelIndexer.UpdateVariablePanelTagName(old_tagname, new_tagname) - + def IsOpened(self, tagname): for idx in xrange(self.TabsOpened.GetPageCount()): if self.TabsOpened.GetPage(idx).IsViewing(tagname): @@ -1244,31 +1221,10 @@ def RefreshPageTitles(self): for idx in xrange(self.TabsOpened.GetPageCount()): window = self.TabsOpened.GetPage(idx) - debug = window.IsDebugging() - words = window.GetTagName().split("::") - if words[0] == "P": - pou_type = self.Controler.GetEditedElementType(window.GetTagName(), debug)[1].upper() - pou_body_type = self.Controler.GetEditedElementBodyType(window.GetTagName(), debug) - self.SetPageBitmap(idx, self.GenerateBitmap(pou_type, pou_body_type)) - elif words[0] == "T": - pou_body_type = self.Controler.GetEditedElementBodyType(window.GetTagName(), debug) - self.SetPageBitmap(idx, self.GenerateBitmap("TRANSITION", pou_body_type)) - elif words[0] == "A": - pou_body_type = self.Controler.GetEditedElementBodyType(window.GetTagName(), debug) - self.SetPageBitmap(idx, self.GenerateBitmap("ACTION", pou_body_type)) - elif words[0] == "C": - self.SetPageBitmap(idx, self.GenerateBitmap("CONFIGURATION")) - elif words[0] == "R": - self.SetPageBitmap(idx, self.GenerateBitmap("RESOURCE")) - elif words[0] == "D": - self.SetPageBitmap(idx, self.GenerateBitmap("DATATYPE")) - if debug: - text = window.GetInstancePath() - if len(text) > 15: - text = "..." + text[-12:] - self.TabsOpened.SetPageText(idx, text) - else: - self.TabsOpened.SetPageText(idx, "-".join(words[1:])) + 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): @@ -1563,7 +1519,7 @@ else: event.Skip() - def EditProjectElement(self, elementtype, tagname, onlyopened = False): + def EditProjectElement(self, element, tagname, onlyopened = False): openedidx = self.IsOpened(tagname) if openedidx is not None: old_selected = self.TabsOpened.GetSelection() @@ -1571,19 +1527,18 @@ if old_selected >= 0: self.TabsOpened.GetPage(old_selected).ResetBuffer() self.TabsOpened.SetSelection(openedidx) - self.VariablePanelIndexer.ChangeVariablePanel(tagname) - self.RefreshPageTitles() - self._Refresh(FILEMENU, EDITMENU, TOOLBAR) + self._Refresh(FILEMENU, EDITMENU, TOOLBAR, PAGETITLES) elif not onlyopened: - if elementtype == ITEM_CONFIGURATION: + new_window = None + if element == ITEM_CONFIGURATION: new_window = ConfigurationEditor(self.TabsOpened, tagname, self, self.Controler) + new_window.SetIcon(self.GenerateBitmap("CONFIGURATION")) self.AddPage(new_window, "") - self.VariablePanelIndexer.AddVariablePanel(tagname, "config") - elif elementtype == ITEM_RESOURCE: + elif element == ITEM_RESOURCE: new_window = ResourceEditor(self.TabsOpened, tagname, self, self.Controler) + new_window.SetIcon(self.GenerateBitmap("RESOURCE")) self.AddPage(new_window, "") - self.VariablePanelIndexer.AddVariablePanel(tagname, "resource") - elif elementtype in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]: + 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) @@ -1601,24 +1556,35 @@ new_window.SetKeywords(IL_KEYWORDS) else: new_window.SetKeywords(ST_KEYWORDS) + if element == ITEM_POU: + pou_type = self.Controler.GetEditedElementType(tagname)[1].upper() + icon = self.GenerateBitmap(pou_type, bodytype) + elif element == ITEM_TRANSITION: + icon = self.GenerateBitmap("TRANSITION", bodytype) + elif element == ITEM_ACTION: + icon = self.GenerateBitmap("ACTION", bodytype) + new_window.SetIcon(icon) self.AddPage(new_window, "") words = tagname.split("::") - self.VariablePanelIndexer.AddVariablePanel(tagname, self.Controler.GetPouType(words[1])) - elif elementtype == ITEM_DATATYPE: + elif element == ITEM_DATATYPE: new_window = DataTypeEditor(self.TabsOpened, tagname, self, self.Controler) + new_window.SetIcon(self.GenerateBitmap("DATATYPE")) self.AddPage(new_window, "") - self.VariablePanelIndexer.ChangeVariablePanel(tagname) - 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.GetTagName() == tagname: - self.TabsOpened.SetSelection(i) - window.SetFocus() - self.RefreshPageTitles() + elif isinstance(element, EditorPanel): + new_window = element + self.AddPage(element, "") + if new_window is not None: + 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() def OnTypesTreeRightUp(self, event): if wx.Platform == '__WXMSW__': @@ -1836,6 +1802,14 @@ new_window.SetKeywords(IL_KEYWORDS) else: new_window.SetKeywords(ST_KEYWORDS) + if selected_infos[0] in [ITEM_FUNCTIONBLOCK, ITEM_PROGRAM]: + pou_type = self.Controler.GetEditedElementType(selected_infos[1], True)[1].upper() + icon = self.GenerateBitmap(pou_type, bodytype) + elif selected_infos[0] == ITEM_TRANSITION: + icon = self.GenerateBitmap("TRANSITION", bodytype) + elif selected_infos[0] == ITEM_ACTION: + icon = self.GenerateBitmap("ACTION", bodytype) + new_window.SetIcon(icon) self.AddPage(new_window, "") new_window.SetFocus() self.RefreshPageTitles() @@ -2359,7 +2333,6 @@ tagname = self.Controler.ComputePouName(name) idx = self.IsOpened(tagname) if idx is not None: - self.VariablePanelIndexer.RemoveVariablePanel(tagname) self.TabsOpened.DeletePage(idx) self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE) else: @@ -2379,7 +2352,6 @@ tagname = self.Controler.ComputePouTransitionName(pou_name, transition) idx = self.IsOpened(tagname) if idx is not None: - self.VariablePanelIndexer.RemoveVariablePanel(tagname) self.TabsOpened.DeletePage(idx) self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE) @@ -2397,7 +2369,6 @@ tagname = self.Controler.ComputePouActionName(pou_name, action) idx = self.IsOpened(tagname) if idx is not None: - self.VariablePanelIndexer.RemoveVariablePanel(tagname) self.TabsOpened.DeletePage(idx) self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE) @@ -2409,7 +2380,6 @@ tagname = self.Controler.ComputeConfigurationName(name) idx = self.IsOpened(tagname) if idx is not None: - self.VariablePanelIndexer.RemoveVariablePanel(tagname) self.TabsOpened.DeletePage(idx) self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE) @@ -2427,7 +2397,6 @@ tagname = self.Controler.ComputeConfigurationResourceName(config_name, selected) idx = self.IsOpened(tagname) if idx is not None: - self.VariablePanelIndexer.RemoveVariablePanel(tagname) self.TabsOpened.DeletePage(idx) self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE) @@ -2453,13 +2422,10 @@ self.TypesTree.Unselect() else: self.EditProjectElement(self.Controler.GetElementType(infos[0]), infos[0]) - if infos[1] in plcopen.searchResultVarTypes.values() + ["var_local"]: - self.VariablePanelIndexer.AddVariableHighlight(infos, highlight_type) - else: - selected = self.TabsOpened.GetSelection() - if selected != -1: - viewer = self.TabsOpened.GetPage(selected) - viewer.AddHighlight(infos[1:], start, end, highlight_type) + 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) @@ -2473,7 +2439,6 @@ else: self.Highlights = dict([(name, highlight) for name, highlight in self.Highlights.iteritems() if highlight != highlight_type]) self.RefreshTypesTree() - self.VariablePanelIndexer.ClearHighlights(highlight_type) for i in xrange(self.TabsOpened.GetPageCount()): viewer = self.TabsOpened.GetPage(i) viewer.ClearHighlights(highlight_type) @@ -2721,9 +2686,8 @@ if not result: self.SaveProjectAs() else: - self.RefreshTitle() - self.RefreshFileMenu() - + self._Refresh(TITLE, FILEMENU, PAGETITLES) + def SaveProjectAs(self): filepath = self.Controler.GetFilePath() if filepath != "": @@ -2739,8 +2703,7 @@ self.ShowErrorMessage(_("Can't save project to file %s!")%filepath) else: self.ShowErrorMessage(_("\"%s\" is not a valid folder!")%os.path.dirname(filepath)) - self.RefreshTitle() - self.RefreshFileMenu() + self._Refresh(TITLE, FILEMENU, PAGETITLES) dialog.Destroy() #------------------------------------------------------------------------------- @@ -3846,106 +3809,6 @@ return self.GetSizer().GetItem(1).GetWindow().GetValue() #------------------------------------------------------------------------------- -# Variables Editor Panel -#------------------------------------------------------------------------------- - -def PouTagname(tagname): - words = tagname.split("::") - if words[0] in ["T", "A"]: - return "P::%s" % words[1] - return tagname - -class VariablePanelIndexer(wx.Panel): - - def _init_sizers(self): - self.MainSizer = wx.BoxSizer(wx.HORIZONTAL) - - self.SetSizer(self.MainSizer) - - def _init_ctrls(self, prnt): - wx.Panel.__init__(self, id=wx.NewId(), - name='VariablePanelIndexer', parent=prnt, pos=wx.Point(0, 0), - size=wx.Size(0, 300), style=wx.TAB_TRAVERSAL) - - self._init_sizers() - - def __init__(self, parent, window): - self._init_ctrls(parent) - - self.ParentWindow = window - - self.VariablePanelList = {} - self.CurrentPanel = None - - def AddVariablePanel(self, tagname, element_type): - tagname = PouTagname(tagname) - panel, users = self.VariablePanelList.get(tagname, (None, 0)) - if panel is None: - panel = VariablePanel(self, self.ParentWindow, self.ParentWindow.Controler, element_type) - panel.SetTagName(tagname) - panel.Hide() - panel.RefreshView() - self.MainSizer.AddWindow(panel, 1, border=0, flag=wx.GROW) - self.VariablePanelList[tagname] = (panel, users + 1) - - def RemoveVariablePanel(self, tagname): - tagname = PouTagname(tagname) - panel, users = self.VariablePanelList.pop(tagname, (None, 0)) - if panel is not None: - if users > 1: - self.VariablePanelList[tagname] = (panel, users - 1) - else: - self.MainSizer.Remove(panel) - panel.Destroy() - if self.CurrentPanel == tagname: - self.CurrentPanel = None - - def RemoveAllPanels(self): - for panel, users in self.VariablePanelList.itervalues(): - self.MainSizer.Remove(panel) - panel.Destroy() - self.VariablePanelList = {} - self.CurrentPanel = None - - def UpdateVariablePanelTagName(self, old_tagname, new_tagname): - old_tagname = PouTagname(old_tagname) - new_tagname = PouTagname(new_tagname) - if old_tagname in self.VariablePanelList and old_tagname != new_tagname: - self.VariablePanelList[new_tagname] = self.VariablePanelList.pop(old_tagname) - if self.CurrentPanel == old_tagname: - self.CurrentPanel = new_tagname - - def ChangeVariablePanel(self, tagname): - tagname = PouTagname(tagname) - panel, users = self.VariablePanelList.get(tagname, (None, 0)) - if panel is None: - if self.CurrentPanel is not None: - self.VariablePanelList[self.CurrentPanel][0].Hide() - self.CurrentPanel = None - self.MainSizer.Layout() - elif tagname != self.CurrentPanel: - if self.CurrentPanel is not None: - self.VariablePanelList[self.CurrentPanel][0].Hide() - self.CurrentPanel = tagname - panel.RefreshView() - panel.Show() - self.MainSizer.Layout() - - def RefreshVariablePanel(self, tagname): - panel, users = self.VariablePanelList.get(PouTagname(tagname), (None, 0)) - if panel is not None: - panel.RefreshView() - - def AddVariableHighlight(self, infos, highlight_type): - self.ChangeVariablePanel(infos[0]) - if self.CurrentPanel is not None: - self.VariablePanelList[self.CurrentPanel][0].AddVariableHighlight(infos[2:], highlight_type) - - def ClearHighlights(self, highlight_type=None): - for panel, users in self.VariablePanelList.values(): - panel.ClearHighlights(highlight_type) - -#------------------------------------------------------------------------------- # Debug Variables Panel #------------------------------------------------------------------------------- diff -r bd8c7a033b17 -r 9aa96a36cf33 RessourceEditor.py --- a/RessourceEditor.py Mon Nov 07 10:55:17 2011 +0100 +++ b/RessourceEditor.py Tue Nov 08 21:59:22 2011 +0100 @@ -25,8 +25,8 @@ import wx import wx.grid -from dialogs import DurationEditorDialog -from controls import CustomGrid +from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD +from controls import CustomGrid, EditorPanel, DurationCellEditor #------------------------------------------------------------------------------- # Configuration Editor class @@ -35,45 +35,27 @@ [ID_CONFIGURATIONEDITOR, ] = [wx.NewId() for _init_ctrls in range(1)] -class ConfigurationEditor(wx.Panel): - - def _init_ctrls(self, prnt): - wx.Panel.__init__(self, id=ID_CONFIGURATIONEDITOR, name='', parent=prnt, - size=wx.Size(0, 0), style=wx.SUNKEN_BORDER) - - def __init__(self, parent, tagname, window, controler): - self._init_ctrls(parent) - - self.ParentWindow = window - self.Controler = controler - self.TagName = tagname - - def SetTagName(self, tagname): - self.TagName = tagname - - def GetTagName(self): - return self.TagName - - def IsViewing(self, tagname): - return self.TagName == tagname - - def IsDebugging(self): - return False - - def SetMode(self, mode): - pass - - def ResetBuffer(self): - pass - - def RefreshView(self): - pass - - def RefreshScaling(self, refresh=True): - pass - - def ClearHighlights(self, highlight_type=None): - pass +class ConfigurationEditor(EditorPanel): + + ID = ID_CONFIGURATIONEDITOR + VARIABLE_PANEL_TYPE = "config" + + def GetBufferState(self): + return self.Controler.GetBufferState() + + def Undo(self): + self.Controler.LoadPrevious() + self.ParentWindow.CloseTabsWithoutModel() + self.ParentWindow.RefreshEditor() + + def Redo(self): + self.Controler.LoadNext() + self.ParentWindow.CloseTabsWithoutModel() + self.ParentWindow.RefreshEditor() + + def HasNoModel(self): + return self.Controler.GetEditedElement(self.TagName) is None + #------------------------------------------------------------------------------- # Resource Editor class @@ -306,23 +288,19 @@ if len(col_highlights) == 0: row_highlights.pop(col) -[ID_RESOURCEEDITOR, ID_RESOURCEEDITORSTATICTEXT1, +[ID_RESOURCEEDITOR, ID_RESOURCEEDITORPANEL, ID_RESOURCEEDITORSTATICTEXT1, ID_RESOURCEEDITORSTATICTEXT2, ID_RESOURCEEDITORINSTANCESGRID, ID_RESOURCEEDITORTASKSGRID, ID_RESOURCEEDITORADDINSTANCEBUTTON, ID_RESOURCEEDITORDELETEINSTANCEBUTTON, ID_RESOURCEEDITORUPINSTANCEBUTTON, ID_RESOURCEEDITORDOWNINSTANCEBUTTON, ID_RESOURCEEDITORADDTASKBUTTON, ID_RESOURCEEDITORDELETETASKBUTTON, ID_RESOURCEEDITORUPTASKBUTTON, ID_RESOURCEEDITORDOWNTASKBUTTON, -] = [wx.NewId() for _init_ctrls in range(13)] - -class ResourceEditor(wx.Panel): - - 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) +] = [wx.NewId() for _init_ctrls in range(14)] + +class ResourceEditor(EditorPanel): + + ID = ID_RESOURCEEDITOR + VARIABLE_PANEL_TYPE = "resource" def _init_coll_InstancesSizer_Growables(self, parent): parent.AddGrowableCol(0) @@ -389,18 +367,18 @@ self._init_coll_TasksButtonsSizer_Growables(self.TasksButtonsSizer) self._init_coll_TasksButtonsSizer_Items(self.TasksButtonsSizer) - self.SetSizer(self.MainGridSizer) - - def _init_ctrls(self, prnt): - wx.Panel.__init__(self, id=ID_RESOURCEEDITOR, name='', parent=prnt, + self.Editor.SetSizer(self.MainGridSizer) + + def _init_Editor(self, prnt): + self.Editor = wx.Panel(id=ID_RESOURCEEDITORPANEL, name='ResourceEditor', parent=prnt, size=wx.Size(0, 0), style=wx.SUNKEN_BORDER) self.staticText1 = wx.StaticText(id=ID_RESOURCEEDITORSTATICTEXT1, - label=_(u'Tasks:'), name='staticText2', parent=self, pos=wx.Point(0, + label=_(u'Tasks:'), name='staticText2', parent=self.Editor, pos=wx.Point(0, 0), size=wx.DefaultSize, style=wx.ALIGN_CENTER) self.TasksGrid = CustomGrid(id=ID_RESOURCEEDITORTASKSGRID, - name='TasksGrid', parent=self, pos=wx.Point(0, 0), + name='TasksGrid', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(-1, -1), style=wx.VSCROLL) self.TasksGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False, 'Sans')) @@ -412,27 +390,27 @@ wx.grid.EVT_GRID_CELL_CHANGE(self.TasksGrid, self.OnTasksGridCellChange) self.AddTaskButton = wx.Button(id=ID_RESOURCEEDITORADDTASKBUTTON, label=_('Add Task'), - name='AddTaskButton', parent=self, pos=wx.Point(0, 0), + name='AddTaskButton', parent=self.Editor, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.DeleteTaskButton = wx.Button(id=ID_RESOURCEEDITORDELETETASKBUTTON, label=_('Delete Task'), - name='DeleteTaskButton', parent=self, pos=wx.Point(0, 0), + name='DeleteTaskButton', parent=self.Editor, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.UpTaskButton = wx.Button(id=ID_RESOURCEEDITORUPTASKBUTTON, label='^', - name='UpTaskButton', parent=self, pos=wx.Point(0, 0), + name='UpTaskButton', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(32, 32), style=0) self.DownTaskButton = wx.Button(id=ID_RESOURCEEDITORDOWNTASKBUTTON, label='v', - name='DownTaskButton', parent=self, pos=wx.Point(0, 0), + name='DownTaskButton', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(32, 32), style=0) self.staticText2 = wx.StaticText(id=ID_RESOURCEEDITORSTATICTEXT2, - label=_(u'Instances:'), name='staticText1', parent=self, + label=_(u'Instances:'), name='staticText1', parent=self.Editor, pos=wx.Point(0, 0), size=wx.DefaultSize, style=wx.ALIGN_CENTER) self.InstancesGrid = CustomGrid(id=ID_RESOURCEEDITORINSTANCESGRID, - name='InstancesGrid', parent=self, pos=wx.Point(0, 0), + name='InstancesGrid', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(-1, -1), style=wx.VSCROLL) self.InstancesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False, 'Sans')) @@ -444,29 +422,25 @@ wx.grid.EVT_GRID_CELL_CHANGE(self.InstancesGrid, self.OnInstancesGridCellChange) self.AddInstanceButton = wx.Button(id=ID_RESOURCEEDITORADDINSTANCEBUTTON, label=_('Add Instance'), - name='AddInstanceButton', parent=self, pos=wx.Point(0, 0), + name='AddInstanceButton', parent=self.Editor, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.DeleteInstanceButton = wx.Button(id=ID_RESOURCEEDITORDELETEINSTANCEBUTTON, label=_('Delete Instance'), - name='DeleteInstanceButton', parent=self, pos=wx.Point(0, 0), + name='DeleteInstanceButton', parent=self.Editor, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.UpInstanceButton = wx.Button(id=ID_RESOURCEEDITORUPINSTANCEBUTTON, label='^', - name='UpInstanceButton', parent=self, pos=wx.Point(0, 0), + name='UpInstanceButton', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(32, 32), style=0) self.DownInstanceButton = wx.Button(id=ID_RESOURCEEDITORDOWNINSTANCEBUTTON, label='v', - name='DownInstanceButton', parent=self, pos=wx.Point(0, 0), + name='DownInstanceButton', parent=self.Editor, pos=wx.Point(0, 0), size=wx.Size(32, 32), style=0) self._init_sizers() def __init__(self, parent, tagname, window, controler): - self._init_ctrls(parent) - - self.ParentWindow = window - self.Controler = controler - self.TagName = tagname + EditorPanel.__init__(self, parent, tagname, window, controler) self.RefreshHighlightsTimer = wx.Timer(self, -1) self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) @@ -559,21 +533,6 @@ def __del__(self): self.RefreshHighlightsTimer.Stop() - def SetTagName(self, tagname): - self.TagName = tagname - - def GetTagName(self): - return self.TagName - - def IsViewing(self, tagname): - return self.TagName == tagname - - def IsDebugging(self): - return False - - def SetMode(self, mode): - pass - def RefreshTypeList(self): self.TypeList = "" blocktypes = self.Controler.GetBlockResource() @@ -594,9 +553,6 @@ self.Controler.SetEditedResourceInfos(self.TagName, self.TasksTable.GetData(), self.InstancesTable.GetData()) self.RefreshBuffer() - def ResetBuffer(self): - pass - # Buffer the last model state def RefreshBuffer(self): self.Controler.BufferProject() @@ -604,7 +560,25 @@ self.ParentWindow.RefreshFileMenu() self.ParentWindow.RefreshEditMenu() - def RefreshView(self): + def GetBufferState(self): + return self.Controler.GetBufferState() + + def Undo(self): + self.Controler.LoadPrevious() + self.ParentWindow.CloseTabsWithoutModel() + self.ParentWindow.RefreshEditor() + + def Redo(self): + self.Controler.LoadNext() + self.ParentWindow.CloseTabsWithoutModel() + self.ParentWindow.RefreshEditor() + + def HasNoModel(self): + return self.Controler.GetEditedElement(self.TagName) is None + + def RefreshView(self, variablepanel=True): + EditorPanel.RefreshView(self, variablepanel) + tasks, instances = self.Controler.GetEditedResourceInfos(self.TagName) self.TasksTable.SetData(tasks) self.InstancesTable.SetData(instances) @@ -616,9 +590,6 @@ self.TasksGrid.RefreshButtons() self.InstancesGrid.RefreshButtons() - def RefreshScaling(self, refresh=True): - pass - def OnTasksGridCellChange(self, event): row, col = event.GetRow(), event.GetCol() if self.TasksTable.GetColLabelValue(event.GetCol()) == "Name": @@ -659,127 +630,12 @@ self.TasksTable.AddHighlight(infos[1:], highlight_type) elif infos[0] == "instance": self.InstancesTable.AddHighlight(infos[1:], highlight_type) + self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) def ClearHighlights(self, highlight_type=None): + EditorPanel.ClearHighlights(self, highlight_type) + self.TasksTable.ClearHighlights(highlight_type) self.InstancesTable.ClearHighlights(highlight_type) self.TasksTable.ResetView(self.TasksGrid) self.InstancesTable.ResetView(self.InstancesGrid) - -class DurationCellControl(wx.PyControl): - - def _init_coll_MainSizer_Items(self, parent): - parent.AddWindow(self.Duration, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.EditButton, 0, border=0, flag=wx.GROW) - - def _init_coll_MainSizer_Growables(self, parent): - parent.AddGrowableCol(0) - parent.AddGrowableRow(0) - - def _init_sizers(self): - self.MainSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) - - self._init_coll_MainSizer_Items(self.MainSizer) - self._init_coll_MainSizer_Growables(self.MainSizer) - - self.SetSizer(self.MainSizer) - - def _init_ctrls(self, prnt): - wx.Control.__init__(self, id=-1, - name='DurationCellControl', parent=prnt, - size=wx.DefaultSize, style=0) - - # create location text control - self.Duration = wx.TextCtrl(id=-1, name='Duration', parent=self, - pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TE_PROCESS_ENTER) - self.Duration.Bind(wx.EVT_KEY_DOWN, self.OnDurationChar) - - # create browse button - self.EditButton = wx.Button(id=-1, label='...', - name='EditButton', parent=self, pos=wx.Point(0, 0), - size=wx.Size(30, 0), style=0) - self.EditButton.Bind(wx.EVT_BUTTON, self.OnEditButtonClick) - - self.Bind(wx.EVT_SIZE, self.OnSize) - - self._init_sizers() - - ''' - Custom cell editor control with a text box and a button that launches - the DurationEditorDialog. - ''' - def __init__(self, parent): - self._init_ctrls(parent) - - def SetValue(self, value): - self.Duration.SetValue(value) - - def GetValue(self): - return self.Duration.GetValue() - - def OnSize(self, event): - self.Layout() - - def OnEditButtonClick(self, event): - # pop up the Duration Editor dialog - dialog = DurationEditorDialog(self) - dialog.SetDuration(self.Duration.GetValue()) - if dialog.ShowModal() == wx.ID_OK: - # set the duration - self.Duration.SetValue(dialog.GetDuration()) - - dialog.Destroy() - - self.Duration.SetFocus() - - def OnDurationChar(self, event): - keycode = event.GetKeyCode() - if keycode == wx.WXK_RETURN or keycode == wx.WXK_TAB: - self.Parent.Parent.ProcessEvent(event) - self.Parent.Parent.SetFocus() - else: - event.Skip() - - def SetInsertionPoint(self, i): - self.Duration.SetInsertionPoint(i) - - def SetFocus(self): - self.Duration.SetFocus() - -class DurationCellEditor(wx.grid.PyGridCellEditor): - ''' - Grid cell editor that uses DurationCellControl to display an edit button. - ''' - def __init__(self, table): - wx.grid.PyGridCellEditor.__init__(self) - self.Table = table - - def __del__(self): - self.CellControl = None - - def Create(self, parent, id, evt_handler): - self.CellControl = DurationCellControl(parent) - self.SetControl(self.CellControl) - if evt_handler: - self.CellControl.PushEventHandler(evt_handler) - - def BeginEdit(self, row, col, grid): - self.CellControl.SetValue(self.Table.GetValueByName(row, 'Interval')) - self.CellControl.SetFocus() - - def EndEdit(self, row, col, grid): - duration = self.CellControl.GetValue() - old_duration = self.Table.GetValueByName(row, 'Interval') - if duration != old_duration: - self.Table.SetValueByName(row, 'Interval', duration) - return True - return False - - def SetSize(self, rect): - self.CellControl.SetDimensions(rect.x + 1, rect.y, - rect.width, rect.height, - wx.SIZE_ALLOW_MINUS_ONE) - - def Clone(self): - return DurationCellEditor(self.Table) - diff -r bd8c7a033b17 -r 9aa96a36cf33 TextViewer.py --- a/TextViewer.py Mon Nov 07 10:55:17 2011 +0100 +++ b/TextViewer.py Tue Nov 08 21:59:22 2011 +0100 @@ -29,7 +29,8 @@ import re from graphics.GraphicCommons import ERROR_HIGHLIGHT, SEARCH_RESULT_HIGHLIGHT, REFRESH_HIGHLIGHT_PERIOD -from plcopen.structures import ST_BLOCK_START_KEYWORDS, ST_BLOCK_END_KEYWORDS +from plcopen.structures import ST_BLOCK_START_KEYWORDS, ST_BLOCK_END_KEYWORDS, IEC_BLOCK_START_KEYWORDS, IEC_BLOCK_END_KEYWORDS +from controls import EditorPanel #------------------------------------------------------------------------------- # Textual programs Viewer class @@ -48,8 +49,8 @@ STC_PLC_ERROR, STC_PLC_SEARCH_RESULT] = range(10) [SPACE, WORD, NUMBER, STRING, WSTRING, COMMENT] = range(6) -[ID_TEXTVIEWER, -] = [wx.NewId() for _init_ctrls in range(1)] +[ID_TEXTVIEWER, ID_TEXTVIEWERTEXTCTRL, +] = [wx.NewId() for _init_ctrls in range(2)] if wx.Platform == '__WXMSW__': faces = { 'times': 'Times New Roman', @@ -102,7 +103,9 @@ def LineStartswith(line, symbols): return reduce(lambda x, y: x or y, map(lambda x: line.startswith(x), symbols), False) -class TextViewer(wx.stc.StyledTextCtrl): +class TextViewer(EditorPanel): + + ID = ID_TEXTVIEWER if wx.VERSION < (2, 6, 0): def Bind(self, event, function, id = None): @@ -111,58 +114,77 @@ else: event(self, function) + def _init_Editor(self, prnt): + self.Editor = wx.stc.StyledTextCtrl(id=ID_TEXTVIEWERTEXTCTRL, + parent=prnt, name="TextViewer", size=wx.Size(0, 0), style=0) + + self.Editor.CmdKeyAssign(ord('+'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMIN) + self.Editor.CmdKeyAssign(ord('-'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMOUT) + + self.Editor.SetViewWhiteSpace(False) + + self.Editor.SetLexer(wx.stc.STC_LEX_CONTAINER) + + # Global default styles for all languages + self.Editor.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) + self.Editor.StyleClearAll() # Reset all to be like the default + + self.Editor.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,size:%(size)d" % faces) + self.Editor.SetSelBackground(1, "#E0E0E0") + + # Highlighting styles + self.Editor.StyleSetSpec(STC_PLC_WORD, "fore:#00007F,bold,size:%(size)d" % faces) + self.Editor.StyleSetSpec(STC_PLC_VARIABLE, "fore:#7F0000,size:%(size)d" % faces) + self.Editor.StyleSetSpec(STC_PLC_PARAMETER, "fore:#7F007F,size:%(size)d" % faces) + self.Editor.StyleSetSpec(STC_PLC_FUNCTION, "fore:#7F7F00,size:%(size)d" % faces) + self.Editor.StyleSetSpec(STC_PLC_COMMENT, "fore:#7F7F7F,size:%(size)d" % faces) + self.Editor.StyleSetSpec(STC_PLC_NUMBER, "fore:#007F7F,size:%(size)d" % faces) + self.Editor.StyleSetSpec(STC_PLC_STRING, "fore:#007F00,size:%(size)d" % faces) + self.Editor.StyleSetSpec(STC_PLC_JUMP, "fore:#FF7FFF,size:%(size)d" % faces) + self.Editor.StyleSetSpec(STC_PLC_ERROR, "fore:#FF0000,back:#FFFF00,size:%(size)d" % faces) + self.Editor.StyleSetSpec(STC_PLC_SEARCH_RESULT, "fore:#FFFFFF,back:#FFA500,size:%(size)d" % faces) + + # Indicators styles + self.Editor.IndicatorSetStyle(0, wx.stc.STC_INDIC_SQUIGGLE) + if self.ParentWindow is not None and self.Controler is not None: + self.Editor.IndicatorSetForeground(0, wx.RED) + else: + self.Editor.IndicatorSetForeground(0, wx.WHITE) + + # Line numbers in the margin + self.Editor.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) + self.Editor.SetMarginWidth(1, 50) + + # Folding + self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPEN, wx.stc.STC_MARK_BOXMINUS, "white", "#808080") + self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDER, wx.stc.STC_MARK_BOXPLUS, "white", "#808080") + self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERSUB, wx.stc.STC_MARK_VLINE, "white", "#808080") + self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERTAIL, wx.stc.STC_MARK_LCORNER, "white", "#808080") + self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEREND, wx.stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") + self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPENMID, wx.stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") + self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERMIDTAIL, wx.stc.STC_MARK_TCORNER, "white", "#808080") + + # Indentation size + self.Editor.SetTabWidth(2) + self.Editor.SetUseTabs(0) + + self.Editor.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT| + wx.stc.STC_MOD_BEFOREDELETE| + wx.stc.STC_PERFORMED_USER) + + self.Bind(wx.stc.EVT_STC_STYLENEEDED, self.OnStyleNeeded, id=ID_TEXTVIEWERTEXTCTRL) + self.Editor.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnMarginClick) + self.Editor.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) + if self.Controler is not None: + self.Editor.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) + self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_TEXTVIEWERTEXTCTRL) + self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_TEXTVIEWERTEXTCTRL) + def __init__(self, parent, tagname, window, controler, debug = False, instancepath = ""): - wx.stc.StyledTextCtrl.__init__(self, parent, ID_TEXTVIEWER, size=wx.Size(0, 0), style=0) - - self.CmdKeyAssign(ord('+'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMIN) - self.CmdKeyAssign(ord('-'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMOUT) - - self.SetViewWhiteSpace(False) - - self.SetLexer(wx.stc.STC_LEX_CONTAINER) - - # Global default styles for all languages - self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) - self.StyleClearAll() # Reset all to be like the default - - self.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,size:%(size)d" % faces) - self.SetSelBackground(1, "#E0E0E0") - - # Highlighting styles - self.StyleSetSpec(STC_PLC_WORD, "fore:#00007F,bold,size:%(size)d" % faces) - self.StyleSetSpec(STC_PLC_VARIABLE, "fore:#7F0000,size:%(size)d" % faces) - self.StyleSetSpec(STC_PLC_PARAMETER, "fore:#7F007F,size:%(size)d" % faces) - self.StyleSetSpec(STC_PLC_FUNCTION, "fore:#7F7F00,size:%(size)d" % faces) - self.StyleSetSpec(STC_PLC_COMMENT, "fore:#7F7F7F,size:%(size)d" % faces) - self.StyleSetSpec(STC_PLC_NUMBER, "fore:#007F7F,size:%(size)d" % faces) - self.StyleSetSpec(STC_PLC_STRING, "fore:#007F00,size:%(size)d" % faces) - self.StyleSetSpec(STC_PLC_JUMP, "fore:#FF7FFF,size:%(size)d" % faces) - self.StyleSetSpec(STC_PLC_ERROR, "fore:#FF0000,back:#FFFF00,size:%(size)d" % faces) - self.StyleSetSpec(STC_PLC_SEARCH_RESULT, "fore:#FFFFFF,back:#FFA500,size:%(size)d" % faces) - - # Indicators styles - self.IndicatorSetStyle(0, wx.stc.STC_INDIC_SQUIGGLE) - if window and controler: - self.IndicatorSetForeground(0, wx.RED) - else: - self.IndicatorSetForeground(0, wx.WHITE) - - # Line numbers in the margin - self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) - self.SetMarginWidth(1, 50) - - # Folding - self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPEN, wx.stc.STC_MARK_BOXMINUS, "white", "#808080") - self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDER, wx.stc.STC_MARK_BOXPLUS, "white", "#808080") - self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERSUB, wx.stc.STC_MARK_VLINE, "white", "#808080") - self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERTAIL, wx.stc.STC_MARK_LCORNER, "white", "#808080") - self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEREND, wx.stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") - self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPENMID, wx.stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") - self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERMIDTAIL, wx.stc.STC_MARK_TCORNER, "white", "#808080") - - # Indentation size - self.SetTabWidth(2) - self.SetUseTabs(0) + if tagname != "" and controler is not None: + self.VARIABLE_PANEL_TYPE = controler.GetPouType(tagname.split("::")[1]) + + EditorPanel.__init__(self, parent, tagname, window, controler) self.Keywords = [] self.Variables = {} @@ -171,47 +193,32 @@ self.Jumps = [] self.EnumeratedValues = [] self.DisableEvents = True - self.TextSyntax = "ST" + self.TextSyntax = None self.CurrentAction = None - self.TagName = tagname self.Highlights = [] self.Debug = debug self.InstancePath = instancepath self.ContextStack = [] self.CallStack = [] - self.ParentWindow = window - self.Controler = controler - self.RefreshHighlightsTimer = wx.Timer(self, -1) self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) - - self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT| - wx.stc.STC_MOD_BEFOREDELETE| - wx.stc.STC_PERFORMED_USER) - - self.Bind(wx.stc.EVT_STC_STYLENEEDED, self.OnStyleNeeded, id=ID_TEXTVIEWER) - self.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnMarginClick) - if controler: - self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) - self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_TEXTVIEWER) - self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) - self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_TEXTVIEWER) def __del__(self): self.RefreshHighlightsTimer.Stop() - def SetTagName(self, tagname): - self.TagName = tagname - - def GetTagName(self): - return self.TagName + def GetTitle(self): + if self.Debug or self.TagName == "": + if len(self.InstancePath) > 15: + return "..." + self.InstancePath[-12:] + return self.InstancePath + return EditorPanel.GetTitle(self) def GetInstancePath(self): return self.InstancePath def IsViewing(self, tagname): - if self.Debug: + if self.Debug or self.TagName == "": return self.InstancePath == tagname else: return self.TagName == tagname @@ -219,8 +226,26 @@ def IsDebugging(self): return self.Debug - def SetMode(self, mode): - pass + def GetText(self): + return self.Editor.GetText() + + def SetText(self, text): + self.Editor.SetText(text) + + def SelectAll(self): + self.Editor.SelectAll() + + def Colourise(self, start, end): + self.Editor.Colourise(start, end) + + def StartStyling(self, pos, mask): + self.Editor.StartStyling(pos, mask) + + def SetStyling(self, length, style): + self.Editor.SetStyling(length, style) + + def GetCurrentPos(self): + return self.Editor.GetCurrentPos() def OnModification(self, event): if not self.DisableEvents: @@ -272,7 +297,7 @@ message = _("\"%s\" element for this pou already exists!")%blockname else: self.Controler.AddEditedElementPouVar(self.TagName, values[0], blockname) - self.ParentWindow.RefreshVariablePanel(self.TagName) + self.RefreshVariablePanel() self.RefreshVariableTree() blockinfo = self.Controler.GetBlockType(values[0], blockinputs, self.Debug) hint = ',\n '.join( @@ -293,7 +318,7 @@ else: var_type = LOCATIONDATATYPES.get(values[0][2], ["BOOL"])[0] self.Controler.AddEditedElementPouVar(self.TagName, var_type, var_name, values[0], values[4]) - self.ParentWindow.RefreshVariablePanel(self.TagName) + self.RefreshVariablePanel() self.RefreshVariableTree() event.SetDragText(var_name) else: @@ -313,11 +338,20 @@ def SetTextSyntax(self, syntax): self.TextSyntax = syntax - if syntax == "ST": - self.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL) - self.SetMarginMask(2, wx.stc.STC_MASK_FOLDERS) - self.SetMarginSensitive(2, 1) - self.SetMarginWidth(2, 12) + if syntax in ["ST", "ALL"]: + self.Editor.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL) + self.Editor.SetMarginMask(2, wx.stc.STC_MASK_FOLDERS) + self.Editor.SetMarginSensitive(2, 1) + self.Editor.SetMarginWidth(2, 12) + if syntax == "ST": + self.BlockStartKeywords = ST_BLOCK_START_KEYWORDS + self.BlockEndKeywords = ST_BLOCK_START_KEYWORDS + else: + self.BlockStartKeywords = IEC_BLOCK_START_KEYWORDS + self.BlockEndKeywords = IEC_BLOCK_START_KEYWORDS + else: + self.BlockStartKeywords = [] + self.BlockEndKeywords = [] def SetKeywords(self, keywords): self.Keywords = [keyword.upper() for keyword in keywords] @@ -348,43 +382,69 @@ self.Controler.EndBuffering() self.CurrentAction = None - def RefreshView(self): - self.ResetBuffer() - self.DisableEvents = True - old_cursor_pos = self.GetCurrentPos() - old_text = self.GetText() - new_text = self.Controler.GetEditedElementText(self.TagName, self.Debug) - self.SetText(new_text) - new_cursor_pos = GetCursorPos(old_text, new_text) - if new_cursor_pos != None: - self.GotoPos(new_cursor_pos) - else: - self.GotoPos(old_cursor_pos) - self.ScrollToColumn(0) - self.RefreshJumpList() - self.EmptyUndoBuffer() - self.DisableEvents = False - - self.RefreshVariableTree() - - self.TypeNames = [typename.upper() for typename in self.Controler.GetDataTypes(self.TagName, True, self.Debug)] - self.EnumeratedValues = [value.upper() for value in self.Controler.GetEnumeratedDataValues()] - - self.Functions = {} - for category in self.Controler.GetBlockTypes(self.TagName, self.Debug): - for blocktype in category["list"]: - blockname = blocktype["name"].upper() - if blocktype["type"] == "function" and blockname not in self.Keywords and blockname not in self.Variables.keys(): - interface = dict([(name, {}) for name, type, modifier in blocktype["inputs"] + blocktype["outputs"] if name != '']) - for param in ["EN", "ENO"]: - if not interface.has_key(param): - interface[param] = {} - if self.Functions.has_key(blockname): - self.Functions[blockname]["interface"].update(interface) - self.Functions[blockname]["extensible"] |= blocktype["extensible"] - else: - self.Functions[blockname] = {"interface": interface, - "extensible": blocktype["extensible"]} + def GetBufferState(self): + if not self.Debug and self.TextSyntax != "ALL": + return self.Controler.GetBufferState() + return False, False + + def Undo(self): + if not self.Debug and self.TextSyntax != "ALL": + self.Controler.LoadPrevious() + self.ParentWindow.CloseTabsWithoutModel() + self.ParentWindow.RefreshEditor() + + def Redo(self): + if not self.Debug and self.TextSyntax != "ALL": + self.Controler.LoadNext() + self.ParentWindow.CloseTabsWithoutModel() + self.ParentWindow.RefreshEditor() + + def HasNoModel(self): + if not self.Debug and self.TextSyntax != "ALL": + return self.Controler.GetEditedElement(self.TagName) is None + return False + + def RefreshView(self, variablepanel=True): + EditorPanel.RefreshView(self, variablepanel) + + if self.Controler is not None: + self.ResetBuffer() + self.DisableEvents = True + old_cursor_pos = self.GetCurrentPos() + old_text = self.GetText() + new_text = self.Controler.GetEditedElementText(self.TagName, self.Debug) + self.SetText(new_text) + new_cursor_pos = GetCursorPos(old_text, new_text) + if new_cursor_pos != None: + self.Editor.GotoPos(new_cursor_pos) + else: + self.Editor.GotoPos(old_cursor_pos) + self.Editor.ScrollToColumn(0) + self.RefreshJumpList() + self.Editor.EmptyUndoBuffer() + self.DisableEvents = False + + self.RefreshVariableTree() + + self.TypeNames = [typename.upper() for typename in self.Controler.GetDataTypes(self.TagName, True, self.Debug)] + self.EnumeratedValues = [value.upper() for value in self.Controler.GetEnumeratedDataValues()] + + self.Functions = {} + for category in self.Controler.GetBlockTypes(self.TagName, self.Debug): + for blocktype in category["list"]: + blockname = blocktype["name"].upper() + if blocktype["type"] == "function" and blockname not in self.Keywords and blockname not in self.Variables.keys(): + interface = dict([(name, {}) for name, type, modifier in blocktype["inputs"] + blocktype["outputs"] if name != '']) + for param in ["EN", "ENO"]: + if not interface.has_key(param): + interface[param] = {} + if self.Functions.has_key(blockname): + self.Functions[blockname]["interface"].update(interface) + self.Functions[blockname]["extensible"] |= blocktype["extensible"] + else: + self.Functions[blockname] = {"interface": interface, + "extensible": blocktype["extensible"]} + self.Colourise(0, -1) def RefreshVariableTree(self): @@ -404,9 +464,6 @@ tree[var_name.upper()] = self.GenerateVariableTree(var_tree) return tree - def RefreshScaling(self, refresh=True): - pass - def IsValidVariable(self, name, context): return context is not None and context.get(name, None) is not None @@ -417,33 +474,33 @@ return False def RefreshLineFolding(self, line_number): - if self.TextSyntax == "ST": - level = wx.stc.STC_FOLDLEVELBASE + self.GetLineIndentation(line_number) - line = self.GetLine(line_number).strip() + if self.TextSyntax in ["ST", "ALL"]: + level = wx.stc.STC_FOLDLEVELBASE + self.Editor.GetLineIndentation(line_number) + line = self.Editor.GetLine(line_number).strip() if line == "": if line_number > 0: - if LineStartswith(self.GetLine(line_number - 1).strip(), ST_BLOCK_END_KEYWORDS): - level = self.GetFoldLevel(self.GetFoldParent(line_number - 1)) & wx.stc.STC_FOLDLEVELNUMBERMASK + if LineStartswith(self.Editor.GetLine(line_number - 1).strip(), self.BlockEndKeywords): + level = self.Editor.GetFoldLevel(self.Editor.GetFoldParent(line_number - 1)) & wx.stc.STC_FOLDLEVELNUMBERMASK else: - level = self.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK + level = self.Editor.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK if level != wx.stc.STC_FOLDLEVELBASE: level |= wx.stc.STC_FOLDLEVELWHITEFLAG - elif LineStartswith(line, ST_BLOCK_START_KEYWORDS): + elif LineStartswith(line, self.BlockStartKeywords): level |= wx.stc.STC_FOLDLEVELHEADERFLAG - elif LineStartswith(line, ST_BLOCK_END_KEYWORDS): - if LineStartswith(self.GetLine(line_number - 1).strip(), ST_BLOCK_END_KEYWORDS): - level = self.GetFoldLevel(self.GetFoldParent(line_number - 1)) & wx.stc.STC_FOLDLEVELNUMBERMASK + elif LineStartswith(line, self.BlockEndKeywords): + if LineStartswith(self.Editor.GetLine(line_number - 1).strip(), self.BlockEndKeywords): + level = self.Editor.GetFoldLevel(self.Editor.GetFoldParent(line_number - 1)) & wx.stc.STC_FOLDLEVELNUMBERMASK else: - level = self.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK - self.SetFoldLevel(line_number, level) + level = self.Editor.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK + self.Editor.SetFoldLevel(line_number, level) def OnStyleNeeded(self, event): self.TextChanged = True - line_number = self.LineFromPosition(self.GetEndStyled()) + line_number = self.Editor.LineFromPosition(self.Editor.GetEndStyled()) if line_number == 0: start_pos = last_styled_pos = 0 else: - start_pos = last_styled_pos = self.GetLineEndPosition(line_number - 1) + 1 + start_pos = last_styled_pos = self.Editor.GetLineEndPosition(line_number - 1) + 1 self.RefreshLineFolding(line_number) end_pos = event.GetPosition() self.StartStyling(start_pos, 0xff) @@ -456,7 +513,7 @@ line = "" word = "" while current_pos < end_pos: - char = chr(self.GetCharAt(current_pos)).upper() + char = chr(self.Editor.GetCharAt(current_pos)).upper() line += char if char == NEWLINE: self.ContextStack = [] @@ -629,21 +686,27 @@ def OnMarginClick(self, event): if event.GetMargin() == 2: - self.ToggleFold(self.LineFromPosition(event.GetPosition())) + line = self.Editor.LineFromPosition(event.GetPosition()) + if self.Editor.GetFoldLevel(line) & wx.stc.STC_FOLDLEVELHEADERFLAG: + self.Editor.ToggleFold(line) event.Skip() def Cut(self): self.ResetBuffer() - self.CmdKeyExecute(wx.stc.STC_CMD_CUT) + self.DisableEvents = True + self.Editor.CmdKeyExecute(wx.stc.STC_CMD_CUT) + self.DisableEvents = False self.RefreshModel() self.RefreshBuffer() def Copy(self): - self.CmdKeyExecute(wx.stc.STC_CMD_COPY) + self.Editor.CmdKeyExecute(wx.stc.STC_CMD_COPY) def Paste(self): self.ResetBuffer() - self.CmdKeyExecute(wx.stc.STC_CMD_PASTE) + self.DisableEvents = True + self.Editor.CmdKeyExecute(wx.stc.STC_CMD_PASTE) + self.DisableEvents = False self.RefreshModel() self.RefreshBuffer() @@ -652,67 +715,67 @@ self.Controler.SetEditedElementText(self.TagName, self.GetText()) def OnKeyDown(self, event): - if self.CallTipActive(): - self.CallTipCancel() - key = event.GetKeyCode() - key_handled = False - - # Code completion - if key == wx.WXK_SPACE and event.ControlDown(): - - line = self.GetCurrentLine() + if self.Controler is not None: + + if self.Editor.CallTipActive(): + self.Editor.CallTipCancel() + key = event.GetKeyCode() + key_handled = False + + line = self.Editor.GetCurrentLine() if line == 0: start_pos = 0 else: - start_pos = self.GetLineEndPosition(line - 1) + 1 + start_pos = self.Editor.GetLineEndPosition(line - 1) + 1 end_pos = self.GetCurrentPos() - - lineText = self.GetTextRange(start_pos, end_pos).replace("\t", " ") - words = lineText.split(" ") - words = [word for i, word in enumerate(words) if word != '' or i == len(words) - 1] - - kw = [] + lineText = self.Editor.GetTextRange(start_pos, end_pos).replace("\t", " ") - if self.TextSyntax == "IL": - if len(words) == 1: - kw = self.Keywords - elif len(words) == 2: - if words[0].upper() in ["CAL", "CALC", "CALNC"]: - kw = self.Functions - elif words[0].upper() in ["JMP", "JMPC", "JMPNC"]: - kw = self.Jumps - else: - kw = self.Variables.keys() - else: - kw = self.Keywords + self.Variables.keys() + self.Functions - if len(kw) > 0: - if len(words[-1]) > 0: - kw = [keyword for keyword in kw if keyword.startswith(words[-1])] - kw.sort() - self.AutoCompSetIgnoreCase(True) - self.AutoCompShow(len(words[-1]), " ".join(kw)) - key_handled = True - elif key == wx.WXK_RETURN or key == wx.WXK_NUMPAD_ENTER: - if self.TextSyntax == "ST": - line = self.GetCurrentLine() - indent = self.GetLineIndentation(line) - if LineStartswith(self.GetLine(line).strip(), ST_BLOCK_START_KEYWORDS): - indent += 2 - self.AddText("\n" + " " * indent) + # Code completion + if key == wx.WXK_SPACE and event.ControlDown(): + + words = lineText.split(" ") + words = [word for i, word in enumerate(words) if word != '' or i == len(words) - 1] + + kw = [] + + if self.TextSyntax == "IL": + if len(words) == 1: + kw = self.Keywords + elif len(words) == 2: + if words[0].upper() in ["CAL", "CALC", "CALNC"]: + kw = self.Functions + elif words[0].upper() in ["JMP", "JMPC", "JMPNC"]: + kw = self.Jumps + else: + kw = self.Variables.keys() + else: + kw = self.Keywords + self.Variables.keys() + self.Functions + if len(kw) > 0: + if len(words[-1]) > 0: + kw = [keyword for keyword in kw if keyword.startswith(words[-1])] + kw.sort() + self.Editor.AutoCompSetIgnoreCase(True) + self.Editor.AutoCompShow(len(words[-1]), " ".join(kw)) key_handled = True - elif key == wx.WXK_BACK: - if self.TextSyntax == "ST": - line = self.GetCurrentLine() - indent = self.GetLineIndentation(line) - if self.GetLine(line).strip() == "" and indent > 0: - self.DelLineLeft() - self.AddText(" " * max(0, indent - 2)) + elif key == wx.WXK_RETURN or key == wx.WXK_NUMPAD_ENTER: + if self.TextSyntax in ["ST", "ALL"]: + indent = self.Editor.GetLineIndentation(line) + if LineStartswith(lineText.strip(), self.BlockStartKeywords): + indent += 2 + self.Editor.AddText("\n" + " " * indent) key_handled = True - if not key_handled: - event.Skip() + elif key == wx.WXK_BACK: + if self.TextSyntax in ["ST", "ALL"]: + indent = self.Editor.GetLineIndentation(line) + if lineText.strip() == "" and indent > 0: + self.Editor.DelLineLeft() + self.Editor.AddText(" " * max(0, indent - 2)) + key_handled = True + if not key_handled: + event.Skip() def OnKillFocus(self, event): - self.AutoCompCancel() + self.Editor.AutoCompCancel() event.Skip() #------------------------------------------------------------------------------- diff -r bd8c7a033b17 -r 9aa96a36cf33 VariablePanel.py --- a/VariablePanel.py Mon Nov 07 10:55:17 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1242 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor -#based on the plcopen standard. -# -#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD -# -#See COPYING file for copyrights details. -# -#This library is free software; you can redistribute it and/or -#modify it under the terms of the GNU General Public -#License as published by the Free Software Foundation; either -#version 2.1 of the License, or (at your option) any later version. -# -#This library is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -#General Public License for more details. -# -#You should have received a copy of the GNU General Public -#License along with this library; if not, write to the Free Software -#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import wx, wx.grid - -from types import TupleType, StringType, UnicodeType - -from plcopen.structures import LOCATIONDATATYPES, TestIdentifier, IEC_KEYWORDS -from PLCControler import LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY -from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD -from dialogs import ArrayTypeDialog -from controls import CustomGrid - -CWD = os.path.split(os.path.realpath(__file__))[0] - -# 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, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, TYPESTREE, - INSTANCESTREE, LIBRARYTREE, SCALING -] = range(9) - -#------------------------------------------------------------------------------- -# Variables Editor Panel -#------------------------------------------------------------------------------- - -def GetVariableTableColnames(location): - _ = lambda x : x - if location: - return ["#", _("Name"), _("Class"), _("Type"), _("Location"), _("Initial Value"), _("Option"), _("Documentation")] - return ["#", _("Name"), _("Class"), _("Type"), _("Initial Value"), _("Option"), _("Documentation")] - -def GetOptions(constant=True, retain=True, non_retain=True): - _ = lambda x : x - options = [""] - if constant: - options.append(_("Constant")) - if retain: - options.append(_("Retain")) - if non_retain: - options.append(_("Non-Retain")) - return options -OPTIONS_DICT = dict([(_(option), option) for option in GetOptions()]) - -def GetFilterChoiceTransfer(): - _ = lambda x : x - return {_("All"): _("All"), _("Interface"): _("Interface"), - _(" Input"): _("Input"), _(" Output"): _("Output"), _(" InOut"): _("InOut"), - _(" External"): _("External"), _("Variables"): _("Variables"), _(" Local"): _("Local"), - _(" Temp"): _("Temp"), _("Global"): _("Global")}#, _("Access") : _("Access")} -VARIABLE_CHOICES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().iterkeys()]) -VARIABLE_CLASSES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().itervalues()]) - -CheckOptionForClass = {"Local": lambda x: x, - "Temp": lambda x: "", - "Input": lambda x: {"Retain": "Retain", "Non-Retain": "Non-Retain"}.get(x, ""), - "InOut": lambda x: "", - "Output": lambda x: {"Retain": "Retain", "Non-Retain": "Non-Retain"}.get(x, ""), - "Global": lambda x: {"Constant": "Constant", "Retain": "Retain"}.get(x, ""), - "External": lambda x: {"Constant": "Constant"}.get(x, "") - } - -class VariableTable(wx.grid.PyGridTableBase): - - """ - A custom wx.grid.Grid Table using user supplied data - """ - def __init__(self, parent, data, colnames): - # The base class must be initialized *first* - wx.grid.PyGridTableBase.__init__(self) - self.data = data - self.old_value = None - self.colnames = colnames - self.Highlights = {} - self.Parent = parent - # XXX - # we need to store the row length and collength to - # see if the table has changed size - self._rows = self.GetNumberRows() - self._cols = self.GetNumberCols() - - def GetNumberCols(self): - return len(self.colnames) - - def GetNumberRows(self): - return len(self.data) - - def GetColLabelValue(self, col, translate=True): - if col < len(self.colnames): - if translate: - return _(self.colnames[col]) - return self.colnames[col] - - def GetRowLabelValues(self, row, translate=True): - return row - - def GetValue(self, row, col): - if row < self.GetNumberRows(): - if col == 0: - return self.data[row]["Number"] - colname = self.GetColLabelValue(col, False) - value = self.data[row].get(colname, "") - if colname == "Type" and isinstance(value, TupleType): - if value[0] == "array": - return "ARRAY [%s] OF %s" % (",".join(map(lambda x : "..".join(x), value[2])), value[1]) - if not isinstance(value, (StringType, UnicodeType)): - value = str(value) - if colname in ["Class", "Option"]: - return _(value) - return value - - def SetValue(self, row, col, value): - if col < len(self.colnames): - colname = self.GetColLabelValue(col, False) - if colname == "Name": - self.old_value = self.data[row][colname] - elif colname == "Class": - value = VARIABLE_CLASSES_DICT[value] - self.SetValueByName(row, "Option", CheckOptionForClass[value](self.GetValueByName(row, "Option"))) - if value == "External": - self.SetValueByName(row, "Initial Value", "") - elif colname == "Option": - value = OPTIONS_DICT[value] - self.data[row][colname] = value - - def GetValueByName(self, row, colname): - if row < self.GetNumberRows(): - return self.data[row].get(colname) - - def SetValueByName(self, row, colname, value): - if row < self.GetNumberRows(): - self.data[row][colname] = value - - def GetOldValue(self): - return self.old_value - - def ResetView(self, grid): - """ - (wx.grid.Grid) -> Reset the grid view. Call this to - update the grid if rows and columns have been added or deleted - """ - grid.BeginBatch() - for current, new, delmsg, addmsg in [ - (self._rows, self.GetNumberRows(), wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED), - (self._cols, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED), - ]: - if new < current: - msg = wx.grid.GridTableMessage(self,delmsg,new,current-new) - grid.ProcessTableMessage(msg) - elif new > current: - msg = wx.grid.GridTableMessage(self,addmsg,new-current) - grid.ProcessTableMessage(msg) - self.UpdateValues(grid) - grid.EndBatch() - - self._rows = self.GetNumberRows() - self._cols = self.GetNumberCols() - # update the column rendering scheme - self._updateColAttrs(grid) - - # update the scrollbars and the displayed part of the grid - grid.AdjustScrollbars() - grid.ForceRefresh() - - def UpdateValues(self, grid): - """Update all displayed values""" - # This sends an event to the grid table to update all of the values - msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES) - grid.ProcessTableMessage(msg) - - def _updateColAttrs(self, grid): - """ - wx.grid.Grid -> update the column attributes to add the - appropriate renderer given the column name. - - Otherwise default to the default renderer. - """ - for row in range(self.GetNumberRows()): - var_class = self.GetValueByName(row, "Class") - var_type = self.GetValueByName(row, "Type") - row_highlights = self.Highlights.get(row, {}) - for col in range(self.GetNumberCols()): - editor = None - renderer = None - colname = self.GetColLabelValue(col, False) - if colname == "Option": - options = GetOptions(constant = var_class in ["Local", "External", "Global"], - retain = self.Parent.ElementType != "function" and var_class in ["Local", "Input", "Output", "Global"], - non_retain = self.Parent.ElementType != "function" and var_class in ["Local", "Input", "Output"]) - if len(options) > 1: - editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters(",".join(map(_, options))) - else: - grid.SetReadOnly(row, col, True) - elif col != 0 and self.GetValueByName(row, "Edit"): - grid.SetReadOnly(row, col, False) - if colname == "Name": - if self.Parent.PouIsUsed and var_class in ["Input", "Output", "InOut"]: - grid.SetReadOnly(row, col, True) - else: - editor = wx.grid.GridCellTextEditor() - renderer = wx.grid.GridCellStringRenderer() - elif colname == "Initial Value": - if var_class != "External": - if self.Parent.Controler.IsEnumeratedType(var_type): - editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters(",".join(self.Parent.Controler.GetEnumeratedDataValues(var_type))) - else: - editor = wx.grid.GridCellTextEditor() - renderer = wx.grid.GridCellStringRenderer() - else: - grid.SetReadOnly(row, col, True) - elif colname == "Location": - if var_class in ["Local", "Global"] and self.Parent.Controler.IsLocatableType(var_type): - editor = LocationCellEditor(self, self.Parent.Controler) - renderer = wx.grid.GridCellStringRenderer() - else: - grid.SetReadOnly(row, col, True) - elif colname == "Class": - if len(self.Parent.ClassList) == 1 or self.Parent.PouIsUsed and var_class in ["Input", "Output", "InOut"]: - grid.SetReadOnly(row, col, True) - else: - editor = wx.grid.GridCellChoiceEditor() - excluded = [] - if self.Parent.PouIsUsed: - excluded.extend(["Input","Output","InOut"]) - if self.Parent.IsFunctionBlockType(var_type): - excluded.extend(["Local","Temp"]) - editor.SetParameters(",".join([_(choice) for choice in self.Parent.ClassList if choice not in excluded])) - elif colname != "Documentation": - grid.SetReadOnly(row, col, True) - - grid.SetCellEditor(row, col, editor) - grid.SetCellRenderer(row, col, renderer) - - highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1] - grid.SetCellBackgroundColour(row, col, highlight_colours[0]) - grid.SetCellTextColour(row, col, highlight_colours[1]) - if wx.Platform == '__WXMSW__': - grid.SetRowMinimalHeight(row, 20) - else: - grid.SetRowMinimalHeight(row, 28) - grid.AutoSizeRow(row, False) - - def SetData(self, data): - self.data = data - - def GetData(self): - return self.data - - def GetCurrentIndex(self): - return self.CurrentIndex - - def SetCurrentIndex(self, index): - self.CurrentIndex = index - - def AppendRow(self, row_content): - self.data.append(row_content) - - def RemoveRow(self, row_index): - self.data.pop(row_index) - - def GetRow(self, row_index): - return self.data[row_index] - - def Empty(self): - self.data = [] - self.editors = [] - - def AddHighlight(self, infos, highlight_type): - row_highlights = self.Highlights.setdefault(infos[0], {}) - col_highlights = row_highlights.setdefault(infos[1], []) - col_highlights.append(highlight_type) - - def ClearHighlights(self, highlight_type=None): - if highlight_type is None: - self.Highlights = {} - else: - for row, row_highlights in self.Highlights.iteritems(): - row_items = row_highlights.items() - for col, col_highlights in row_items: - if highlight_type in col_highlights: - col_highlights.remove(highlight_type) - if len(col_highlights) == 0: - row_highlights.pop(col) - - -class VariableDropTarget(wx.TextDropTarget): - ''' - This allows dragging a variable location from somewhere to the Location - column of a variable row. - - The drag source should be a TextDataObject containing a Python tuple like: - ('%ID0.0.0', 'location', 'REAL') - - c_ext/CFileEditor.py has an example of this (you can drag a C extension - variable to the Location column of the variable panel). - ''' - def __init__(self, parent): - wx.TextDropTarget.__init__(self) - self.ParentWindow = parent - - def OnDropText(self, x, y, data): - x, y = self.ParentWindow.VariablesGrid.CalcUnscrolledPosition(x, y) - col = self.ParentWindow.VariablesGrid.XToCol(x) - row = self.ParentWindow.VariablesGrid.YToRow(y - self.ParentWindow.VariablesGrid.GetColLabelSize()) - if col != wx.NOT_FOUND and row != wx.NOT_FOUND: - if self.ParentWindow.Table.GetColLabelValue(col, False) != "Location": - return - message = None - if not self.ParentWindow.Table.GetValueByName(row, "Edit"): - message = _("Can't give a location to a function block instance") - elif self.ParentWindow.Table.GetValueByName(row, "Class") not in ["Local", "Global"]: - message = _("Can only give a location to local or global variables") - else: - try: - values = eval(data) - except: - message = _("Invalid value \"%s\" for location")%data - values = None - if not isinstance(values, TupleType): - message = _("Invalid value \"%s\" for location")%data - values = None - if values is not None and values[1] == "location": - location = values[0] - variable_type = self.ParentWindow.Table.GetValueByName(row, "Type") - base_type = self.ParentWindow.Controler.GetBaseType(variable_type) - message = None - if location.startswith("%"): - if base_type != values[2]: - message = _("Incompatible data types between \"%s\" and \"%s\"")%(values[2], variable_type) - else: - self.ParentWindow.Table.SetValue(row, col, location) - self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid) - self.ParentWindow.SaveValues() - else: - if location[0].isdigit() and base_type != "BOOL": - message = _("Incompatible size of data between \"%s\" and \"BOOL\"")%location - elif location[0] not in LOCATIONDATATYPES: - message = _("Unrecognized data size \"%s\"")%location[0] - elif base_type not in LOCATIONDATATYPES[location[0]]: - message = _("Incompatible size of data between \"%s\" and \"%s\"")%(location, variable_type) - else: - dialog = wx.SingleChoiceDialog(self.ParentWindow, _("Select a variable class:"), _("Variable class"), ["Input", "Output", "Memory"], wx.OK|wx.CANCEL) - if dialog.ShowModal() == wx.ID_OK: - selected = dialog.GetSelection() - if selected == 0: - location = "%I" + location - elif selected == 1: - location = "%Q" + location - else: - location = "%M" + location - self.ParentWindow.Table.SetValue(row, col, location) - self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid) - self.ParentWindow.SaveValues() - dialog.Destroy() - if message is not None: - wx.CallAfter(self.ShowMessage, message) - - def ShowMessage(self, message): - message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() - -[ID_VARIABLEEDITORPANEL, ID_VARIABLEEDITORPANELVARIABLESGRID, - ID_VARIABLEEDITORCONTROLPANEL, ID_VARIABLEEDITORPANELRETURNTYPE, - ID_VARIABLEEDITORPANELCLASSFILTER, ID_VARIABLEEDITORPANELADDBUTTON, - ID_VARIABLEEDITORPANELDELETEBUTTON, ID_VARIABLEEDITORPANELUPBUTTON, - ID_VARIABLEEDITORPANELDOWNBUTTON, ID_VARIABLEEDITORPANELSTATICTEXT1, - ID_VARIABLEEDITORPANELSTATICTEXT2, ID_VARIABLEEDITORPANELSTATICTEXT3, -] = [wx.NewId() for _init_ctrls in range(12)] - -class VariablePanel(wx.Panel): - - 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_MainSizer_Items(self, parent): - parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.ControlPanel, 0, border=5, flag=wx.GROW|wx.ALL) - - def _init_coll_MainSizer_Growables(self, parent): - parent.AddGrowableCol(0) - parent.AddGrowableRow(0) - - def _init_coll_ControlPanelSizer_Items(self, parent): - parent.AddSizer(self.ChoicePanelSizer, 0, border=0, flag=wx.GROW) - parent.AddSizer(self.ButtonPanelSizer, 0, border=0, flag=wx.ALIGN_CENTER) - - def _init_coll_ControlPanelSizer_Growables(self, parent): - parent.AddGrowableCol(0) - parent.AddGrowableRow(0) - parent.AddGrowableRow(1) - - def _init_coll_ChoicePanelSizer_Items(self, parent): - parent.AddWindow(self.staticText1, 0, border=0, flag=wx.ALIGN_BOTTOM) - parent.AddWindow(self.ReturnType, 0, border=0, flag=0) - parent.AddWindow(self.staticText2, 0, border=0, flag=wx.ALIGN_BOTTOM) - parent.AddWindow(self.ClassFilter, 0, border=0, flag=0) - - def _init_coll_ButtonPanelSizer_Items(self, parent): - parent.AddWindow(self.UpButton, 0, border=0, flag=0) - parent.AddWindow(self.AddButton, 0, border=0, flag=0) - parent.AddWindow(self.DownButton, 0, border=0, flag=0) - parent.AddWindow(self.DeleteButton, 0, border=0, flag=0) - - def _init_coll_ButtonPanelSizer_Growables(self, parent): - parent.AddGrowableCol(0) - parent.AddGrowableCol(1) - parent.AddGrowableCol(2) - parent.AddGrowableCol(3) - parent.AddGrowableRow(0) - - def _init_sizers(self): - self.MainSizer = wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=0) - self.ControlPanelSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) - self.ChoicePanelSizer = wx.GridSizer(cols=1, hgap=5, rows=4, vgap=5) - self.ButtonPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5) - - self._init_coll_MainSizer_Items(self.MainSizer) - self._init_coll_MainSizer_Growables(self.MainSizer) - self._init_coll_ControlPanelSizer_Items(self.ControlPanelSizer) - self._init_coll_ControlPanelSizer_Growables(self.ControlPanelSizer) - self._init_coll_ChoicePanelSizer_Items(self.ChoicePanelSizer) - self._init_coll_ButtonPanelSizer_Items(self.ButtonPanelSizer) - self._init_coll_ButtonPanelSizer_Growables(self.ButtonPanelSizer) - - self.SetSizer(self.MainSizer) - self.ControlPanel.SetSizer(self.ControlPanelSizer) - - def _init_ctrls(self, prnt): - wx.Panel.__init__(self, id=ID_VARIABLEEDITORPANEL, - name='VariableEditorPanel', parent=prnt, pos=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) - - self.VariablesGrid = CustomGrid(id=ID_VARIABLEEDITORPANELVARIABLESGRID, - name='VariablesGrid', parent=self, pos=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.VSCROLL) - self.VariablesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False, - 'Sans')) - self.VariablesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL, - False, 'Sans')) - self.VariablesGrid.SetSelectionBackground(wx.WHITE) - self.VariablesGrid.SetSelectionForeground(wx.BLACK) - if wx.VERSION >= (2, 6, 0): - self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange) - self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) - self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) - else: - wx.grid.EVT_GRID_CELL_CHANGE(self.VariablesGrid, self.OnVariablesGridCellChange) - wx.grid.EVT_GRID_CELL_LEFT_CLICK(self.VariablesGrid, self.OnVariablesGridCellLeftClick) - wx.grid.EVT_GRID_EDITOR_SHOWN(self.VariablesGrid, self.OnVariablesGridEditorShown) - - self.ControlPanel = wx.ScrolledWindow(id=ID_VARIABLEEDITORCONTROLPANEL, - name='ControlPanel', parent=self, pos=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) - self.ControlPanel.SetScrollRate(0, 10) - - self.staticText1 = wx.StaticText(id=ID_VARIABLEEDITORPANELSTATICTEXT1, - label=_('Return Type:'), name='staticText1', parent=self.ControlPanel, - pos=wx.Point(0, 0), size=wx.Size(145, 17), style=0) - - self.ReturnType = wx.ComboBox(id=ID_VARIABLEEDITORPANELRETURNTYPE, - name='ReturnType', parent=self.ControlPanel, pos=wx.Point(0, 0), - size=wx.Size(145, 28), style=wx.CB_READONLY) - self.Bind(wx.EVT_COMBOBOX, self.OnReturnTypeChanged, id=ID_VARIABLEEDITORPANELRETURNTYPE) - - self.staticText2 = wx.StaticText(id=ID_VARIABLEEDITORPANELSTATICTEXT2, - label=_('Class Filter:'), name='staticText2', parent=self.ControlPanel, - pos=wx.Point(0, 0), size=wx.Size(145, 17), style=0) - - self.ClassFilter = wx.ComboBox(id=ID_VARIABLEEDITORPANELCLASSFILTER, - name='ClassFilter', parent=self.ControlPanel, pos=wx.Point(0, 0), - size=wx.Size(145, 28), style=wx.CB_READONLY) - self.Bind(wx.EVT_COMBOBOX, self.OnClassFilter, id=ID_VARIABLEEDITORPANELCLASSFILTER) - - self.AddButton = wx.Button(id=ID_VARIABLEEDITORPANELADDBUTTON, label=_('Add'), - name='AddButton', parent=self.ControlPanel, pos=wx.Point(0, 0), - size=wx.DefaultSize, style=0) - - self.DeleteButton = wx.Button(id=ID_VARIABLEEDITORPANELDELETEBUTTON, label=_('Delete'), - name='DeleteButton', parent=self.ControlPanel, pos=wx.Point(0, 0), - size=wx.DefaultSize, style=0) - - self.UpButton = wx.Button(id=ID_VARIABLEEDITORPANELUPBUTTON, label='^', - name='UpButton', parent=self.ControlPanel, pos=wx.Point(0, 0), - size=wx.Size(32, 32), style=0) - - self.DownButton = wx.Button(id=ID_VARIABLEEDITORPANELDOWNBUTTON, label='v', - name='DownButton', parent=self.ControlPanel, pos=wx.Point(0, 0), - size=wx.Size(32, 32), style=0) - - self._init_sizers() - - def __init__(self, parent, window, controler, element_type): - self._init_ctrls(parent) - self.ParentWindow = window - self.Controler = controler - self.ElementType = element_type - - self.RefreshHighlightsTimer = wx.Timer(self, -1) - self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) - - self.Filter = "All" - self.FilterChoices = [] - self.FilterChoiceTransfer = GetFilterChoiceTransfer() - - self.DefaultValue = { "Name" : "", "Class" : "", "Type" : "INT", "Location" : "", - "Initial Value" : "", "Option" : "", - "Documentation" : "", "Edit" : True - } - - if element_type in ["config", "resource"]: - self.DefaultTypes = {"All" : "Global"} - else: - self.DefaultTypes = {"All" : "Local", "Interface" : "Input", "Variables" : "Local"} - - if element_type in ["config", "resource"] \ - or element_type in ["program", "transition", "action"]: - # this is an element that can have located variables - self.Table = VariableTable(self, [], GetVariableTableColnames(True)) - - if element_type in ["config", "resource"]: - self.FilterChoices = ["All", "Global"]#,"Access"] - else: - self.FilterChoices = ["All", - "Interface", " Input", " Output", " InOut", " External", - "Variables", " Local", " Temp"]#,"Access"] - - # these condense the ColAlignements list - l = wx.ALIGN_LEFT - c = wx.ALIGN_CENTER - - # Num Name Class Type Loc Init Option Doc - self.ColSizes = [40, 80, 70, 80, 80, 80, 100, 80] - self.ColAlignements = [c, l, l, l, l, l, l, l] - - else: - # this is an element that cannot have located variables - self.Table = VariableTable(self, [], GetVariableTableColnames(False)) - - if element_type == "function": - self.FilterChoices = ["All", - "Interface", " Input", " Output", " InOut", - "Variables", " Local"] - else: - self.FilterChoices = ["All", - "Interface", " Input", " Output", " InOut", " External", - "Variables", " Local", " Temp"] - - # these condense the ColAlignements list - l = wx.ALIGN_LEFT - c = wx.ALIGN_CENTER - - # Num Name Class Type Init Option Doc - self.ColSizes = [40, 80, 70, 80, 80, 100, 160] - self.ColAlignements = [c, l, l, l, l, l, l] - - for choice in self.FilterChoices: - self.ClassFilter.Append(_(choice)) - - reverse_transfer = {} - for filter, choice in self.FilterChoiceTransfer.items(): - reverse_transfer[choice] = filter - self.ClassFilter.SetStringSelection(_(reverse_transfer[self.Filter])) - self.RefreshTypeList() - - self.VariablesGrid.SetTable(self.Table) - self.VariablesGrid.SetButtons({"Add": self.AddButton, - "Delete": self.DeleteButton, - "Up": self.UpButton, - "Down": self.DownButton}) - - def _AddVariable(new_row): - if not self.PouIsUsed or self.Filter not in ["Interface", "Input", "Output", "InOut"]: - row_content = self.DefaultValue.copy() - if self.Filter in self.DefaultTypes: - row_content["Class"] = self.DefaultTypes[self.Filter] - else: - row_content["Class"] = self.Filter - if self.Filter == "All" and len(self.Values) > 0: - self.Values.insert(new_row, row_content) - else: - self.Values.append(row_content) - new_row = self.Table.GetNumberRows() - self.SaveValues() - self.RefreshValues() - return new_row - return self.VariablesGrid.GetGridCursorRow() - setattr(self.VariablesGrid, "_AddRow", _AddVariable) - - def _DeleteVariable(row): - if (self.Table.GetValueByName(row, "Edit") and - (not self.PouIsUsed or self.Table.GetValueByName(row, "Class") not in ["Input", "Output", "InOut"])): - self.Values.remove(self.Table.GetRow(row)) - self.SaveValues() - self.RefreshValues() - setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) - - def _MoveVariable(row, move): - if (self.Filter == "All" and - (not self.PouIsUsed or self.Table.GetValueByName(row, "Class") not in ["Input", "Output", "InOut"])): - new_row = max(0, min(row + move, len(self.Values) - 1)) - if new_row != row: - self.Values.insert(new_row, self.Values.pop(row)) - self.SaveValues() - self.RefreshValues() - return new_row - return row - setattr(self.VariablesGrid, "_MoveRow", _MoveVariable) - - def _RefreshButtons(): - table_length = len(self.Table.data) - row_class = None - row_edit = True - row = 0 - if table_length > 0: - row = self.VariablesGrid.GetGridCursorRow() - row_edit = self.Table.GetValueByName(row, "Edit") - if self.PouIsUsed: - row_class = self.Table.GetValueByName(row, "Class") - self.AddButton.Enable(not self.PouIsUsed or self.Filter not in ["Interface", "Input", "Output", "InOut"]) - self.DeleteButton.Enable(table_length > 0 and row_edit and row_class not in ["Input", "Output", "InOut"]) - self.UpButton.Enable(table_length > 0 and row > 0 and self.Filter == "All" and row_class not in ["Input", "Output", "InOut"]) - self.DownButton.Enable(table_length > 0 and row < table_length - 1 and self.Filter == "All" and row_class not in ["Input", "Output", "InOut"]) - setattr(self.VariablesGrid, "RefreshButtons", _RefreshButtons) - - self.VariablesGrid.SetRowLabelSize(0) - for col in range(self.Table.GetNumberCols()): - attr = wx.grid.GridCellAttr() - attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE) - self.VariablesGrid.SetColAttr(col, attr) - self.VariablesGrid.SetColMinimalWidth(col, self.ColSizes[col]) - self.VariablesGrid.AutoSizeColumn(col, False) - - def __del__(self): - self.RefreshHighlightsTimer.Stop() - - def SetTagName(self, tagname): - self.TagName = tagname - - def IsFunctionBlockType(self, name): - bodytype = self.Controler.GetEditedElementBodyType(self.TagName) - pouname, poutype = self.Controler.GetEditedElementType(self.TagName) - if poutype != "function" and bodytype in ["ST", "IL"]: - return False - else: - return name in self.Controler.GetFunctionBlockTypes(self.TagName) - - def RefreshView(self): - self.PouNames = self.Controler.GetProjectPouNames() - - words = self.TagName.split("::") - if self.ElementType == "config": - self.PouIsUsed = False - returnType = None - self.Values = self.Controler.GetConfigurationGlobalVars(words[1]) - elif self.ElementType == "resource": - self.PouIsUsed = False - returnType = None - self.Values = self.Controler.GetConfigurationResourceGlobalVars(words[1], words[2]) - else: - if self.ElementType == "function": - self.ReturnType.Clear() - for base_type in self.Controler.GetDataTypes(self.TagName, True): - self.ReturnType.Append(base_type) - returnType = self.Controler.GetEditedElementInterfaceReturnType(self.TagName) - else: - returnType = None - self.PouIsUsed = self.Controler.PouIsUsed(words[1]) - self.Values = self.Controler.GetEditedElementInterfaceVars(self.TagName) - - if returnType is not None: - self.ReturnType.SetStringSelection(returnType) - self.ReturnType.Enable(True) - self.staticText1.Show() - self.ReturnType.Show() - else: - self.ReturnType.Enable(False) - self.staticText1.Hide() - self.ReturnType.Hide() - - self.RefreshValues() - self.VariablesGrid.RefreshButtons() - - def OnReturnTypeChanged(self, event): - words = self.TagName.split("::") - self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection()) - self.Controler.BufferProject() - self.ParentWindow.RefreshEditor(variablepanel = False) - self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) - event.Skip() - - def OnClassFilter(self, event): - self.Filter = self.FilterChoiceTransfer[VARIABLE_CHOICES_DICT[self.ClassFilter.GetStringSelection()]] - self.RefreshTypeList() - self.RefreshValues() - self.VariablesGrid.RefreshButtons() - event.Skip() - - def RefreshTypeList(self): - if self.Filter == "All": - self.ClassList = [self.FilterChoiceTransfer[choice] for choice in self.FilterChoices if self.FilterChoiceTransfer[choice] not in ["All","Interface","Variables"]] - elif self.Filter == "Interface": - self.ClassList = ["Input","Output","InOut","External"] - elif self.Filter == "Variables": - self.ClassList = ["Local","Temp"] - else: - self.ClassList = [self.Filter] - - def OnVariablesGridCellChange(self, event): - row, col = event.GetRow(), event.GetCol() - colname = self.Table.GetColLabelValue(col, False) - value = self.Table.GetValue(row, col) - - if colname == "Name" and value != "": - if not TestIdentifier(value): - message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%value, _("Error"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() - event.Veto() - elif value.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%value, _("Error"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() - event.Veto() - elif value.upper() in self.PouNames: - message = wx.MessageDialog(self, _("A POU named \"%s\" already exists!")%value, _("Error"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() - event.Veto() - elif value.upper() in [var["Name"].upper() for var in self.Values if var != self.Table.data[row]]: - message = wx.MessageDialog(self, _("A variable with \"%s\" as name already exists in this pou!")%value, _("Error"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() - event.Veto() - else: - self.SaveValues(False) - old_value = self.Table.GetOldValue() - if old_value != "": - self.Controler.UpdateEditedElementUsedVariable(self.TagName, old_value, value) - self.Controler.BufferProject() - self.ParentWindow.RefreshEditor(variablepanel = False) - self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) - event.Skip() - else: - self.SaveValues() - if colname == "Class": - self.ParentWindow.RefreshEditor(variablepanel = False) - event.Skip() - - def OnVariablesGridEditorShown(self, event): - row, col = event.GetRow(), event.GetCol() - - label_value = self.Table.GetColLabelValue(col) - if label_value == "Type": - type_menu = wx.Menu(title='') # the root menu - - # build a submenu containing standard IEC types - base_menu = wx.Menu(title='') - for base_type in self.Controler.GetBaseTypes(): - new_id = wx.NewId() - AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type) - self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), id=new_id) - - type_menu.AppendMenu(wx.NewId(), _("Base Types"), base_menu) - - # build a submenu containing user-defined types - datatype_menu = wx.Menu(title='') - - # TODO : remove complextypes argument when matiec can manage complex types in pou interface - datatypes = self.Controler.GetDataTypes(basetypes = False) - for datatype in datatypes: - new_id = wx.NewId() - AppendMenu(datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype) - self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id) - - type_menu.AppendMenu(wx.NewId(), _("User Data Types"), datatype_menu) - - # build a submenu containing function block types - bodytype = self.Controler.GetEditedElementBodyType(self.TagName) - pouname, poutype = self.Controler.GetEditedElementType(self.TagName) - classtype = self.Table.GetValueByName(row, "Class") - - new_id = wx.NewId() - AppendMenu(type_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Array")) - self.Bind(wx.EVT_MENU, self.VariableArrayTypeFunction, id=new_id) - - if classtype in ["Input", "Output", "InOut", "External", "Global"] or \ - poutype != "function" and bodytype in ["ST", "IL"]: - functionblock_menu = wx.Menu(title='') - fbtypes = self.Controler.GetFunctionBlockTypes(self.TagName) - for functionblock_type in fbtypes: - new_id = wx.NewId() - AppendMenu(functionblock_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=functionblock_type) - self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(functionblock_type), id=new_id) - - type_menu.AppendMenu(wx.NewId(), _("Function Block Types"), functionblock_menu) - - rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col)) - corner_x = rect.x + rect.width - corner_y = rect.y + self.VariablesGrid.GetColLabelSize() - - # pop up this new menu - self.VariablesGrid.PopupMenuXY(type_menu, corner_x, corner_y) - event.Veto() - else: - event.Skip() - - def GetVariableTypeFunction(self, base_type): - def VariableTypeFunction(event): - row = self.VariablesGrid.GetGridCursorRow() - self.Table.SetValueByName(row, "Type", base_type) - self.Table.ResetView(self.VariablesGrid) - self.SaveValues(False) - self.ParentWindow.RefreshEditor(variablepanel = False) - self.Controler.BufferProject() - self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) - return VariableTypeFunction - - def VariableArrayTypeFunction(self, event): - row = self.VariablesGrid.GetGridCursorRow() - dialog = ArrayTypeDialog(self, - self.Controler.GetDataTypes(self.TagName), - self.Table.GetValueByName(row, "Type")) - if dialog.ShowModal() == wx.ID_OK: - self.Table.SetValueByName(row, "Type", dialog.GetValue()) - self.Table.ResetView(self.VariablesGrid) - self.SaveValues(False) - self.ParentWindow.RefreshEditor(variablepanel = False) - self.Controler.BufferProject() - self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) - dialog.Destroy() - - def OnVariablesGridCellLeftClick(self, event): - row = event.GetRow() - if event.GetCol() == 0 and self.Table.GetValueByName(row, "Edit"): - row = event.GetRow() - var_name = self.Table.GetValueByName(row, "Name") - var_class = self.Table.GetValueByName(row, "Class") - var_type = self.Table.GetValueByName(row, "Type") - data = wx.TextDataObject(str((var_name, var_class, var_type, self.TagName))) - dragSource = wx.DropSource(self.VariablesGrid) - dragSource.SetData(data) - dragSource.DoDragDrop() - event.Skip() - - def RefreshValues(self): - data = [] - for num, variable in enumerate(self.Values): - if variable["Class"] in self.ClassList: - variable["Number"] = num + 1 - data.append(variable) - self.Table.SetData(data) - self.Table.ResetView(self.VariablesGrid) - - def SaveValues(self, buffer = True): - words = self.TagName.split("::") - if self.ElementType == "config": - self.Controler.SetConfigurationGlobalVars(words[1], self.Values) - elif self.ElementType == "resource": - self.Controler.SetConfigurationResourceGlobalVars(words[1], words[2], self.Values) - else: - if self.ReturnType.IsEnabled(): - self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection()) - self.Controler.SetPouInterfaceVars(words[1], self.Values) - if buffer: - self.Controler.BufferProject() - self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) - -#------------------------------------------------------------------------------- -# Highlights showing functions -#------------------------------------------------------------------------------- - - def OnRefreshHighlightsTimer(self, event): - self.Table.ResetView(self.VariablesGrid) - event.Skip() - - def AddVariableHighlight(self, infos, highlight_type): - if isinstance(infos[0], TupleType): - for i in xrange(*infos[0]): - self.Table.AddHighlight((i,) + infos[1:], highlight_type) - else: - self.Table.AddHighlight(infos, highlight_type) - self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) - - def ClearHighlights(self, highlight_type=None): - self.Table.ClearHighlights(highlight_type) - self.Table.ResetView(self.VariablesGrid) - - - -class LocationCellControl(wx.PyControl): - - def _init_coll_MainSizer_Items(self, parent): - parent.AddWindow(self.Location, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.BrowseButton, 0, border=0, flag=wx.GROW) - - def _init_coll_MainSizer_Growables(self, parent): - parent.AddGrowableCol(0) - parent.AddGrowableRow(0) - - def _init_sizers(self): - self.MainSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) - - self._init_coll_MainSizer_Items(self.MainSizer) - self._init_coll_MainSizer_Growables(self.MainSizer) - - self.SetSizer(self.MainSizer) - - def _init_ctrls(self, prnt): - wx.Control.__init__(self, id=-1, - name='LocationCellControl', parent=prnt, - size=wx.DefaultSize, style=0) - - # create location text control - self.Location = wx.TextCtrl(id=-1, name='Location', parent=self, - pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TE_PROCESS_ENTER) - self.Location.Bind(wx.EVT_KEY_DOWN, self.OnLocationChar) - - # create browse button - self.BrowseButton = wx.Button(id=-1, label='...', - name='BrowseButton', parent=self, pos=wx.Point(0, 0), - size=wx.Size(30, 0), style=0) - self.BrowseButton.Bind(wx.EVT_BUTTON, self.OnBrowseButtonClick) - - self.Bind(wx.EVT_SIZE, self.OnSize) - - self._init_sizers() - - ''' - Custom cell editor control with a text box and a button that launches - the BrowseLocationsDialog. - ''' - def __init__(self, parent, locations): - self._init_ctrls(parent) - self.Locations = locations - self.VarType = None - - def SetVarType(self, vartype): - self.VarType = vartype - - def SetValue(self, value): - self.Location.SetValue(value) - - def GetValue(self): - return self.Location.GetValue() - - def OnSize(self, event): - self.Layout() - - def OnBrowseButtonClick(self, event): - # pop up the location browser dialog - dialog = BrowseLocationsDialog(self, self.VarType, self.Locations) - if dialog.ShowModal() == wx.ID_OK: - infos = dialog.GetValues() - - # set the location - self.Location.SetValue(infos["location"]) - - dialog.Destroy() - - self.Location.SetFocus() - - def OnLocationChar(self, event): - keycode = event.GetKeyCode() - if keycode == wx.WXK_RETURN or keycode == wx.WXK_TAB: - self.Parent.Parent.ProcessEvent(event) - self.Parent.Parent.SetFocus() - else: - event.Skip() - - def SetInsertionPoint(self, i): - self.Location.SetInsertionPoint(i) - - def SetFocus(self): - self.Location.SetFocus() - -class LocationCellEditor(wx.grid.PyGridCellEditor): - ''' - Grid cell editor that uses LocationCellControl to display a browse button. - ''' - def __init__(self, table, controler): - wx.grid.PyGridCellEditor.__init__(self) - self.Table = table - self.Controler = controler - - def __del__(self): - self.CellControl = None - - def Create(self, parent, id, evt_handler): - locations = self.Controler.GetVariableLocationTree() - if len(locations) > 0: - self.CellControl = LocationCellControl(parent, locations) - else: - self.CellControl = wx.TextCtrl(parent, -1) - self.SetControl(self.CellControl) - if evt_handler: - self.CellControl.PushEventHandler(evt_handler) - - def BeginEdit(self, row, col, grid): - self.CellControl.SetValue(self.Table.GetValueByName(row, 'Location')) - if isinstance(self.CellControl, LocationCellControl): - self.CellControl.SetVarType(self.Controler.GetBaseType(self.Table.GetValueByName(row, 'Type'))) - self.CellControl.SetFocus() - - def EndEdit(self, row, col, grid): - loc = self.CellControl.GetValue() - old_loc = self.Table.GetValueByName(row, 'Location') - if loc != old_loc: - self.Table.SetValueByName(row, 'Location', loc) - return True - return False - - def SetSize(self, rect): - self.CellControl.SetDimensions(rect.x + 1, rect.y, - rect.width, rect.height, - wx.SIZE_ALLOW_MINUS_ONE) - - def Clone(self): - return LocationCellEditor(self.Table, self.Controler) - -def GetDirChoiceOptions(): - _ = lambda x : x - return [(_("All"), [LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY]), - (_("Input"), [LOCATION_VAR_INPUT]), - (_("Output"), [LOCATION_VAR_OUTPUT]), - (_("Memory"), [LOCATION_VAR_MEMORY])] -DIRCHOICE_OPTIONS_FILTER = dict([(_(option), filter) for option, filter in GetDirChoiceOptions()]) - -# turn LOCATIONDATATYPES inside-out -LOCATION_SIZES = {} -for size, types in LOCATIONDATATYPES.iteritems(): - for type in types: - LOCATION_SIZES[type] = size - -[ID_BROWSELOCATIONSDIALOG, ID_BROWSELOCATIONSDIALOGLOCATIONSTREE, - ID_BROWSELOCATIONSDIALOGDIRCHOICE, ID_BROWSELOCATIONSDIALOGSTATICTEXT1, - ID_BROWSELOCATIONSDIALOGSTATICTEXT2, -] = [wx.NewId() for _init_ctrls in range(5)] - -class BrowseLocationsDialog(wx.Dialog): - - 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_MainSizer_Items(self, parent): - parent.AddWindow(self.staticText1, 0, border=20, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW) - parent.AddWindow(self.LocationsTree, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.GROW) - parent.AddSizer(self.ButtonGridSizer, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW) - - def _init_coll_MainSizer_Growables(self, parent): - parent.AddGrowableCol(0) - parent.AddGrowableRow(1) - - def _init_coll_ButtonGridSizer_Items(self, parent): - parent.AddWindow(self.staticText2, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL) - parent.AddWindow(self.DirChoice, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL) - parent.AddSizer(self.ButtonSizer, 0, border=0, flag=wx.ALIGN_RIGHT) - - def _init_coll_ButtonGridSizer_Growables(self, parent): - parent.AddGrowableCol(2) - parent.AddGrowableRow(0) - - def _init_sizers(self): - self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) - self.ButtonGridSizer = wx.FlexGridSizer(cols=3, hgap=5, rows=1, vgap=0) - - self._init_coll_MainSizer_Items(self.MainSizer) - self._init_coll_MainSizer_Growables(self.MainSizer) - self._init_coll_ButtonGridSizer_Items(self.ButtonGridSizer) - self._init_coll_ButtonGridSizer_Growables(self.ButtonGridSizer) - - self.SetSizer(self.MainSizer) - - def _init_ctrls(self, prnt): - wx.Dialog.__init__(self, id=ID_BROWSELOCATIONSDIALOG, - name='BrowseLocationsDialog', parent=prnt, - size=wx.Size(600, 400), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER, - title=_('Browse Locations')) - - self.staticText1 = wx.StaticText(id=ID_BROWSELOCATIONSDIALOGSTATICTEXT1, - label=_('Locations available:'), name='staticText1', parent=self, - pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - - if wx.Platform == '__WXMSW__': - treestyle = wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER - else: - treestyle = wx.TR_HAS_BUTTONS|wx.TR_HIDE_ROOT|wx.TR_SINGLE|wx.SUNKEN_BORDER - self.LocationsTree = wx.TreeCtrl(id=ID_BROWSELOCATIONSDIALOGLOCATIONSTREE, - name='LocationsTree', parent=self, pos=wx.Point(0, 0), - size=wx.Size(0, 0), style=treestyle) - self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnLocationsTreeItemActivated, - id=ID_BROWSELOCATIONSDIALOGLOCATIONSTREE) - - self.staticText2 = wx.StaticText(id=ID_BROWSELOCATIONSDIALOGSTATICTEXT2, - label=_('Direction:'), name='staticText2', parent=self, - pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - - self.DirChoice = wx.ComboBox(id=ID_BROWSELOCATIONSDIALOGDIRCHOICE, - name='DirChoice', parent=self, pos=wx.Point(0, 0), - size=wx.DefaultSize, style=wx.CB_READONLY) - self.Bind(wx.EVT_COMBOBOX, self.OnDirChoice, id=ID_BROWSELOCATIONSDIALOGDIRCHOICE) - - self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) - if wx.VERSION >= (2, 5, 0): - self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId()) - else: - self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId()) - - self._init_sizers() - - def __init__(self, parent, var_type, locations): - self._init_ctrls(parent) - self.VarType = var_type - self.Locations = locations - - # Define Tree item icon list - self.TreeImageList = wx.ImageList(16, 16) - self.TreeImageDict = {} - - # Icons for items - for imgname, itemtype in [ - ("CONFIGURATION", LOCATION_PLUGIN), - ("RESOURCE", LOCATION_MODULE), - ("PROGRAM", LOCATION_GROUP), - ("VAR_INPUT", LOCATION_VAR_INPUT), - ("VAR_OUTPUT", LOCATION_VAR_OUTPUT), - ("VAR_LOCAL", LOCATION_VAR_MEMORY)]: - self.TreeImageDict[itemtype]=self.TreeImageList.Add(wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%imgname))) - - # Assign icon list to TreeCtrls - self.LocationsTree.SetImageList(self.TreeImageList) - - # Set a options for the choice - for option, filter in GetDirChoiceOptions(): - self.DirChoice.Append(_(option)) - self.DirChoice.SetStringSelection(_("All")) - self.RefreshFilter() - - self.RefreshLocationsTree() - - def RefreshFilter(self): - self.Filter = DIRCHOICE_OPTIONS_FILTER[self.DirChoice.GetStringSelection()] - - def RefreshLocationsTree(self): - root = self.LocationsTree.GetRootItem() - if not root.IsOk(): - if wx.Platform == '__WXMSW__': - root = self.LocationsTree.AddRoot(_('Plugins')) - else: - root = self.LocationsTree.AddRoot("") - self.GenerateLocationsTreeBranch(root, self.Locations) - self.LocationsTree.Expand(root) - - def GenerateLocationsTreeBranch(self, root, locations): - to_delete = [] - if wx.VERSION >= (2, 6, 0): - item, root_cookie = self.LocationsTree.GetFirstChild(root) - else: - item, root_cookie = self.LocationsTree.GetFirstChild(root, 0) - for loc_infos in locations: - infos = loc_infos.copy() - if infos["type"] in [LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP] or\ - infos["type"] in self.Filter and (infos["IEC_type"] == self.VarType or - infos["IEC_type"] is None and LOCATION_SIZES[self.VarType] == infos["size"]): - children = [child for child in infos.pop("children")] - if not item.IsOk(): - item = self.LocationsTree.AppendItem(root, infos["name"]) - if wx.Platform != '__WXMSW__': - item, root_cookie = self.LocationsTree.GetNextChild(root, root_cookie) - else: - self.LocationsTree.SetItemText(item, infos["name"]) - self.LocationsTree.SetPyData(item, infos) - self.LocationsTree.SetItemImage(item, self.TreeImageDict[infos["type"]]) - self.GenerateLocationsTreeBranch(item, children) - item, root_cookie = self.LocationsTree.GetNextChild(root, root_cookie) - while item.IsOk(): - to_delete.append(item) - item, root_cookie = self.LocationsTree.GetNextChild(root, root_cookie) - for item in to_delete: - self.LocationsTree.Delete(item) - - def OnLocationsTreeItemActivated(self, event): - infos = self.LocationsTree.GetPyData(event.GetItem()) - if infos["type"] not in [LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP]: - wx.CallAfter(self.EndModal, wx.ID_OK) - event.Skip() - - def OnDirChoice(self, event): - self.RefreshFilter() - self.RefreshLocationsTree() - - def GetValues(self): - selected = self.LocationsTree.GetSelection() - return self.LocationsTree.GetPyData(selected) - - def OnOK(self, event): - selected = self.LocationsTree.GetSelection() - var_infos = None - if selected.IsOk(): - var_infos = self.LocationsTree.GetPyData(selected) - if var_infos is None or var_infos["type"] in [LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP]: - message = wx.MessageDialog(self, _("A location must be selected!"), _("Error"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() - else: - self.EndModal(wx.ID_OK) diff -r bd8c7a033b17 -r 9aa96a36cf33 Viewer.py --- a/Viewer.py Mon Nov 07 10:55:17 2011 +0100 +++ b/Viewer.py Tue Nov 08 21:59:22 2011 +0100 @@ -37,6 +37,7 @@ from dialogs import * from graphics import * +from controls import EditorPanel SCROLLBAR_UNIT = 10 WINDOW_BORDER = 10 @@ -264,7 +265,7 @@ self.ParentWindow.RefreshBuffer() self.ParentWindow.RefreshScrollBars() self.ParentWindow.RefreshVisibleElements() - self.ParentWindow.ParentWindow.RefreshVariablePanel(tagname) + self.ParentWindow.RefreshVariablePanel() self.ParentWindow.Refresh(False) elif values[1] == "location": if len(values) > 2 and pou_type == "program": @@ -282,7 +283,7 @@ var_type = LOCATIONDATATYPES.get(values[0][2], ["BOOL"])[0] if not var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.GetEditedElementVariables(tagname, self.ParentWindow.Debug)]: self.ParentWindow.Controler.AddEditedElementPouVar(tagname, var_type, var_name, values[0], values[4]) - self.ParentWindow.ParentWindow.RefreshVariablePanel(tagname) + self.ParentWindow.RefreshVariablePanel() self.ParentWindow.AddVariableBlock(x, y, scaling, var_class, var_name, var_type) elif values[3] == tagname: if values[1] == "Output": @@ -340,7 +341,7 @@ manipulating graphic elements """ -class Viewer(wx.ScrolledWindow, DebugViewer): +class Viewer(EditorPanel, DebugViewer): if wx.VERSION < (2, 6, 0): def Bind(self, event, function, id = None): @@ -446,16 +447,24 @@ self._init_coll_AlignmentMenu_Items(self.AlignmentMenu) self._init_coll_ContextualMenu_Items(self.ContextualMenu) + def _init_Editor(self, prnt): + self.Editor = wx.ScrolledWindow(prnt, name="Viewer", + pos=wx.Point(0, 0), size=wx.Size(0, 0), + style=wx.HSCROLL | wx.VSCROLL | wx.ALWAYS_SHOW_SB) + # Create a new Viewer def __init__(self, parent, tagname, window, controler, debug = False, instancepath = ""): - wx.ScrolledWindow.__init__(self, parent, pos=wx.Point(0, 0), size=wx.Size(0, 0), - style=wx.HSCROLL | wx.VSCROLL | wx.ALWAYS_SHOW_SB) + self.VARIABLE_PANEL_TYPE = controler.GetPouType(tagname.split("::")[1]) + + EditorPanel.__init__(self, parent, tagname, window, controler) DebugViewer.__init__(self, controler, debug) + self._init_menus() + # Adding a rubberband to Viewer - self.rubberBand = RubberBand(drawingSurface=self) - self.SetBackgroundColour(wx.Colour(255,255,255)) - self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) + self.rubberBand = RubberBand(viewer=self) + self.Editor.SetBackgroundColour(wx.Colour(255,255,255)) + self.Editor.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) self.ResetView() self.Scaling = None self.DrawGrid = True @@ -482,16 +491,13 @@ self.SavedMode = False self.CurrentLanguage = "FBD" - self.ParentWindow = window - self.Controler = controler - if not self.Debug: - self.SetDropTarget(ViewerDropTarget(self)) + self.Editor.SetDropTarget(ViewerDropTarget(self)) self.NewDataRefreshRect = None self.NewDataRefreshRect_lock = Lock() - dc = wx.ClientDC(self) + dc = wx.ClientDC(self.Editor) font = wx.Font(faces["size"], wx.SWISS, wx.NORMAL, wx.NORMAL, faceName = faces["mono"]) dc.SetFont(font) width, height = dc.GetTextExtent("ABCDEFGHIJKLMNOPQRSTUVWXYZ") @@ -504,7 +510,8 @@ self.MiniTextDC = wx.MemoryDC() self.MiniTextDC.SetFont(wx.Font(faces["size"] * 0.75, wx.SWISS, wx.NORMAL, wx.NORMAL, faceName = faces["helv"])) - self.SetScale(len(ZOOM_FACTORS) / 2) + self.CurrentScale = None + self.SetScale(len(ZOOM_FACTORS) / 2, False) self.RefreshHighlightsTimer = wx.Timer(self, -1) self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) @@ -512,21 +519,21 @@ self.ResetView() # Link Viewer event to corresponding methods - self.Bind(wx.EVT_PAINT, self.OnPaint) - self.Bind(wx.EVT_LEFT_DOWN, self.OnViewerLeftDown) - self.Bind(wx.EVT_LEFT_UP, self.OnViewerLeftUp) - self.Bind(wx.EVT_LEFT_DCLICK, self.OnViewerLeftDClick) - self.Bind(wx.EVT_RIGHT_DOWN, self.OnViewerRightDown) - self.Bind(wx.EVT_RIGHT_UP, self.OnViewerRightUp) - self.Bind(wx.EVT_MIDDLE_DOWN, self.OnViewerMiddleDown) - self.Bind(wx.EVT_MIDDLE_UP, self.OnViewerMiddleUp) - self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveViewer) - self.Bind(wx.EVT_MOTION, self.OnViewerMotion) - self.Bind(wx.EVT_CHAR, self.OnChar) - self.Bind(wx.EVT_SCROLLWIN, self.OnScrollWindow) - self.Bind(wx.EVT_SCROLLWIN_THUMBRELEASE, self.OnScrollStop) - self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheelWindow) - self.Bind(wx.EVT_SIZE, self.OnMoveWindow) + self.Editor.Bind(wx.EVT_PAINT, self.OnPaint) + self.Editor.Bind(wx.EVT_LEFT_DOWN, self.OnViewerLeftDown) + self.Editor.Bind(wx.EVT_LEFT_UP, self.OnViewerLeftUp) + self.Editor.Bind(wx.EVT_LEFT_DCLICK, self.OnViewerLeftDClick) + self.Editor.Bind(wx.EVT_RIGHT_DOWN, self.OnViewerRightDown) + self.Editor.Bind(wx.EVT_RIGHT_UP, self.OnViewerRightUp) + self.Editor.Bind(wx.EVT_MIDDLE_DOWN, self.OnViewerMiddleDown) + self.Editor.Bind(wx.EVT_MIDDLE_UP, self.OnViewerMiddleUp) + self.Editor.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveViewer) + self.Editor.Bind(wx.EVT_MOTION, self.OnViewerMotion) + self.Editor.Bind(wx.EVT_CHAR, self.OnChar) + self.Editor.Bind(wx.EVT_SCROLLWIN, self.OnScrollWindow) + self.Editor.Bind(wx.EVT_SCROLLWIN_THUMBRELEASE, self.OnScrollStop) + self.Editor.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheelWindow) + self.Editor.Bind(wx.EVT_SIZE, self.OnMoveWindow) def __del__(self): DebugViewer.__del__(self) @@ -537,32 +544,32 @@ global CURSORS if self.CurrentCursor != cursor: self.CurrentCursor = cursor - self.SetCursor(CURSORS[cursor]) + self.Editor.SetCursor(CURSORS[cursor]) def GetScrolledRect(self, rect): - rect.x, rect.y = self.CalcScrolledPosition(int(rect.x * self.ViewScale[0]), + rect.x, rect.y = self.Editor.CalcScrolledPosition(int(rect.x * self.ViewScale[0]), int(rect.y * self.ViewScale[1])) rect.width = int(rect.width * self.ViewScale[0]) + 2 rect.height = int(rect.height * self.ViewScale[1]) + 2 return rect + def GetTitle(self): + if self.Debug: + if len(self.InstancePath) > 15: + return "..." + self.InstancePath[-12:] + return self.InstancePath + return EditorPanel.GetTitle(self) + def GetScaling(self): return self.Scaling - def SetTagName(self, tagname): - self.TagName = tagname - - def GetTagName(self): - return self.TagName - def GetInstancePath(self): return self.InstancePath def IsViewing(self, tagname): if self.Debug: return self.InstancePath == tagname - else: - return self.TagName == tagname + return EditorPanel.IsViewing(self, tagname) # Returns a new id def GetNewId(self): @@ -575,28 +582,81 @@ self.Flush() self.ResetView() - def SetScale(self, scale_number, refresh=True): - self.CurrentScale = max(0, min(scale_number, len(ZOOM_FACTORS) - 1)) - self.ViewScale = (ZOOM_FACTORS[self.CurrentScale], ZOOM_FACTORS[self.CurrentScale]) - self.RefreshScaling(refresh) - + def SetScale(self, scale_number, refresh=True, mouse_event=None): + new_scale = max(0, min(scale_number, len(ZOOM_FACTORS) - 1)) + if self.CurrentScale != new_scale: + if refresh: + dc = self.GetLogicalDC() + self.CurrentScale = new_scale + self.ViewScale = (ZOOM_FACTORS[self.CurrentScale], ZOOM_FACTORS[self.CurrentScale]) + if refresh: + self.Editor.Freeze() + if mouse_event is None: + client_size = self.Editor.GetClientSize() + mouse_pos = wx.Point(client_size[0] / 2, client_size[1] / 2) + mouse_event = wx.MouseEvent(wx.EVT_MOUSEWHEEL.typeId) + mouse_event.m_x = mouse_pos.x + mouse_event.m_y = mouse_pos.y + else: + mouse_pos = mouse_event.GetPosition() + pos = mouse_event.GetLogicalPosition(dc) + xmax = self.GetScrollRange(wx.HORIZONTAL) - self.GetScrollThumb(wx.HORIZONTAL) + ymax = self.GetScrollRange(wx.VERTICAL) - self.GetScrollThumb(wx.VERTICAL) + scrollx = max(0, round(pos.x * self.ViewScale[0] - mouse_pos.x) / SCROLLBAR_UNIT) + scrolly = max(0, round(pos.y * self.ViewScale[1] - mouse_pos.y) / SCROLLBAR_UNIT) + if scrollx > xmax or scrolly > ymax: + self.RefreshScrollBars(max(0, scrollx - xmax), max(0, scrolly - ymax)) + self.Scroll(scrollx, scrolly) + else: + self.Scroll(scrollx, scrolly) + self.RefreshScrollBars() + self.RefreshScaling(refresh) + self.Editor.Thaw() + def GetScale(self): return self.CurrentScale def GetLogicalDC(self, buffered=False): if buffered: - bitmap = wx.EmptyBitmap(*self.GetClientSize()) + bitmap = wx.EmptyBitmap(*self.Editor.GetClientSize()) dc = wx.MemoryDC(bitmap) else: - dc = wx.ClientDC(self) + dc = wx.ClientDC(self.Editor) dc.SetFont(self.GetFont()) if wx.VERSION >= (2, 6, 0): - self.DoPrepareDC(dc) + self.Editor.DoPrepareDC(dc) else: - self.PrepareDC(dc) + self.Editor.PrepareDC(dc) dc.SetUserScale(self.ViewScale[0], self.ViewScale[1]) return dc - + + def RefreshRect(self, rect, eraseBackground=True): + self.Editor.RefreshRect(rect, eraseBackground) + + def Scroll(self, x, y): + self.Editor.Scroll(x, y) + + def GetScrollPos(self, orientation): + return self.Editor.GetScrollPos(orientation) + + def GetScrollRange(self, orientation): + return self.Editor.GetScrollRange(orientation) + + def GetScrollThumb(self, orientation): + return self.Editor.GetScrollThumb(orientation) + + def CalcUnscrolledPosition(self, x, y): + return self.Editor.CalcUnscrolledPosition(x, y) + + def GetViewStart(self): + return self.Editor.GetViewStart() + + def GetTextExtent(self, text): + return self.Editor.GetTextExtent(text) + + def GetFont(self): + return self.Editor.GetFont() + def GetMiniTextExtent(self, text): return self.MiniTextDC.GetTextExtent(text) @@ -656,12 +716,12 @@ return None def RefreshVisibleElements(self, xp = None, yp = None): - x, y = self.CalcUnscrolledPosition(0, 0) + x, y = self.Editor.CalcUnscrolledPosition(0, 0) if xp is not None: - x = xp * self.GetScrollPixelsPerUnit()[0] + x = xp * self.Editor.GetScrollPixelsPerUnit()[0] if yp is not None: - y = yp * self.GetScrollPixelsPerUnit()[1] - width, height = self.GetClientSize() + y = yp * self.Editor.GetScrollPixelsPerUnit()[1] + width, height = self.Editor.GetClientSize() screen = wx.Rect(int(x / self.ViewScale[0]), int(y / self.ViewScale[1]), int(width / self.ViewScale[0]), int(height / self.ViewScale[1])) for comment in self.Comments.itervalues(): @@ -732,7 +792,7 @@ def SetMode(self, mode): if self.Mode != mode or mode == MODE_SELECTION: if self.Mode == MODE_MOTION: - wx.CallAfter(self.SetCursor, wx.NullCursor) + wx.CallAfter(self.Editor.SetCursor, wx.NullCursor) self.Mode = mode self.SavedMode = False else: @@ -742,7 +802,7 @@ self.SelectedElement.SetSelected(False) self.SelectedElement = None if self.Mode == MODE_MOTION: - wx.CallAfter(self.SetCursor, wx.StockCursor(wx.CURSOR_HAND)) + wx.CallAfter(self.Editor.SetCursor, wx.StockCursor(wx.CURSOR_HAND)) self.SavedMode = True # Return current drawing mode @@ -755,7 +815,29 @@ self.ParentWindow.RefreshTitle() self.ParentWindow.RefreshFileMenu() self.ParentWindow.RefreshEditMenu() - + + def GetBufferState(self): + if not self.Debug: + return self.Controler.GetBufferState() + return False, False + + def Undo(self): + if not self.Debug: + self.Controler.LoadPrevious() + self.ParentWindow.CloseTabsWithoutModel() + self.ParentWindow.RefreshEditor() + + def Redo(self): + if not self.Debug: + self.Controler.LoadNext() + self.ParentWindow.CloseTabsWithoutModel() + self.ParentWindow.RefreshEditor() + + def HasNoModel(self): + if not self.Debug: + return self.Controler.GetEditedElement(self.TagName) is None + return False + # Refresh the current scaling def RefreshScaling(self, refresh=True): properties = self.Controler.GetProjectProperties(self.Debug) @@ -767,7 +849,7 @@ height = max(2, int(scaling[1] * self.ViewScale[1])) bitmap = wx.EmptyBitmap(width, height) dc = wx.MemoryDC(bitmap) - dc.SetBackground(wx.Brush(self.GetBackgroundColour())) + dc.SetBackground(wx.Brush(self.Editor.GetBackgroundColour())) dc.Clear() dc.SetPen(MiterPen(wx.Colour(180, 180, 180))) dc.DrawPoint(0, 0) @@ -810,11 +892,10 @@ else: DebugViewer.RefreshNewData(self) - def ResetBuffer(self): - pass - # Refresh Viewer elements - def RefreshView(self, selection=None): + def RefreshView(self, variablepanel=True, selection=None): + EditorPanel.RefreshView(self, variablepanel) + self.Inhibit(True) self.current_id = 0 # Start by reseting Viewer @@ -890,7 +971,7 @@ def RefreshScrollBars(self, width_incr=0, height_incr=0): xstart, ystart = self.GetViewStart() - window_size = self.GetClientSize() + window_size = self.Editor.GetClientSize() maxx, maxy = self.GetMaxSize() maxx = max(maxx + WINDOW_BORDER, (xstart * SCROLLBAR_UNIT + window_size[0]) / self.ViewScale[0]) maxy = max(maxy + WINDOW_BORDER, (ystart * SCROLLBAR_UNIT + window_size[1]) / self.ViewScale[1]) @@ -900,7 +981,7 @@ maxy = max(maxy, extent.y + extent.height) maxx = int(maxx * self.ViewScale[0]) maxy = int(maxy * self.ViewScale[1]) - self.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, + self.Editor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, round(maxx / SCROLLBAR_UNIT) + width_incr, round(maxy / SCROLLBAR_UNIT) + height_incr, xstart, ystart, True) @@ -1119,7 +1200,7 @@ menu.Enable(new_id, True) else: menu.Enable(new_id, False) - self.PopupMenu(menu) + self.Editor.PopupMenu(menu) def PopupBlockMenu(self, connector = None): if connector is not None and connector.IsCompatible("BOOL"): @@ -1149,7 +1230,7 @@ self.ContextualMenu.Check(ID_VIEWERCONTEXTUALMENUITEMS3, True) else: self.ContextualMenu.Check(ID_VIEWERCONTEXTUALMENUITEMS0, True) - self.PopupMenu(self.ContextualMenu) + self.Editor.PopupMenu(self.ContextualMenu) def PopupWireMenu(self, delete=True): self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS0, False) @@ -1163,7 +1244,7 @@ self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS14, False) self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS16, False) self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS17, True) - self.PopupMenu(self.ContextualMenu) + self.Editor.PopupMenu(self.ContextualMenu) def PopupDivergenceMenu(self, connector): self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS0, False) @@ -1177,7 +1258,7 @@ self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS14, False) self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS16, False) self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS17, True) - self.PopupMenu(self.ContextualMenu) + self.Editor.PopupMenu(self.ContextualMenu) def PopupGroupMenu(self): self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS0, False) @@ -1191,7 +1272,7 @@ self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS14, True) self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS16, False) self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS17, True) - self.PopupMenu(self.ContextualMenu) + self.Editor.PopupMenu(self.ContextualMenu) def PopupDefaultMenu(self, block = True): self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS0, False) @@ -1205,7 +1286,7 @@ self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS14, False) self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS16, False) self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS17, block) - self.PopupMenu(self.ContextualMenu) + self.Editor.PopupMenu(self.ContextualMenu) #------------------------------------------------------------------------------- # Menu items functions @@ -1319,7 +1400,7 @@ dc = self.GetLogicalDC() pos = event.GetLogicalPosition(dc) if event.ShiftDown() and not event.ControlDown() and self.SelectedElement is not None: - element = self.FindElement(pos, True) + element = self.FindElement(event, True) if element is not None: if isinstance(self.SelectedElement, Graphic_Group): self.SelectedElement.SetSelected(False) @@ -1570,7 +1651,7 @@ else: if not event.Dragging(): if self.Debug: - tooltip_pos = self.ClientToScreen(event.GetPosition()) + tooltip_pos = self.Editor.ClientToScreen(event.GetPosition()) tooltip_pos.x += 10 tooltip_pos.y += 10 highlighted = self.FindElement(event) @@ -1613,7 +1694,7 @@ self.HighlightedElement.SetHighlighted(False) self.HighlightedElement = None data = wx.TextDataObject(str((iec_path, "debug"))) - dragSource = wx.DropSource(self) + dragSource = wx.DropSource(self.Editor) dragSource.SetData(data) dragSource.DoDragDrop() self.UpdateScrollPos(event) @@ -1635,7 +1716,7 @@ if (event.Dragging() and self.SelectedElement is not None) or self.rubberBand.IsShown(): position = event.GetPosition() move_window = wx.Point() - window_size = self.GetClientSize() + window_size = self.Editor.GetClientSize() xstart, ystart = self.GetViewStart() if position.x < SCROLL_ZONE and xstart > 0: move_window.x = -1 @@ -1648,7 +1729,7 @@ if move_window.x != 0 or move_window.y != 0: self.RefreshVisibleElements(xp = xstart + move_window.x, yp = ystart + move_window.y) self.Scroll(xstart + move_window.x, ystart + move_window.y) - self.RefreshScrollBars() + self.RefreshScrollBars(move_window.x, move_window.y) #------------------------------------------------------------------------------- # Keyboard event functions @@ -1733,17 +1814,23 @@ if self.IsBlock(self.SelectedElement) or self.IsComment(self.SelectedElement): block = self.CopyBlock(self.SelectedElement, wx.Point(*self.SelectedElement.GetPosition())) event = wx.MouseEvent() - event.m_x, event.m_y = self.ScreenToClient(wx.GetMousePosition()) + event.m_x, event.m_y = self.Editor.ScreenToClient(wx.GetMousePosition()) dc = self.GetLogicalDC() self.SelectedElement.OnLeftUp(event, dc, self.Scaling) self.SelectedElement.SetSelected(False) block.OnLeftDown(event, dc, self.Scaling) self.SelectedElement = block self.SelectedElement.SetSelected(True) - self.ParentWindow.RefreshVariablePanel(self.TagName) + self.RefreshVariablePanel() self.RefreshVisibleElements() else: event.Skip() + elif keycode == ord("+"): + self.SetScale(self.CurrentScale + 1) + self.ParentWindow.RefreshDisplayMenu() + elif keycode == ord("-"): + self.SetScale(self.CurrentScale - 1) + self.ParentWindow.RefreshDisplayMenu() else: event.Skip() @@ -1803,7 +1890,7 @@ self.RefreshBuffer() self.RefreshScrollBars() self.RefreshVisibleElements() - self.ParentWindow.RefreshVariablePanel(self.TagName) + self.RefreshVariablePanel() self.ParentWindow.RefreshInstancesTree() block.Refresh() dialog.Destroy() @@ -2114,7 +2201,7 @@ self.RefreshBuffer() self.RefreshScrollBars() self.RefreshVisibleElements() - self.ParentWindow.RefreshVariablePanel(self.TagName) + self.RefreshVariablePanel() self.ParentWindow.RefreshInstancesTree() if old_values["executionOrder"] != new_values["executionOrder"]: self.RefreshView() @@ -2527,7 +2614,7 @@ self.Controler.RemoveEditedElementInstance(self.TagName, block.GetId()) for element in elements: element.RefreshModel() - wx.CallAfter(self.ParentWindow.RefreshVariablePanel, self.TagName) + wx.CallAfter(self.RefreshVariablePanel) wx.CallAfter(self.ParentWindow.RefreshInstancesTree) def DeleteVariable(self, variable): @@ -2665,7 +2752,7 @@ self.SelectedElement = None self.RefreshBuffer() self.RefreshScrollBars() - self.ParentWindow.RefreshVariablePanel(self.TagName) + self.RefreshVariablePanel() self.ParentWindow.RefreshInstancesTree() self.RefreshRect(self.GetScrolledRect(rect), False) @@ -2678,8 +2765,8 @@ def Paste(self): if not self.Debug: element = self.ParentWindow.GetCopyBuffer() - mouse_pos = self.ScreenToClient(wx.GetMousePosition()) - middle = wx.Rect(0, 0, *self.GetClientSize()).InsideXY(mouse_pos.x, mouse_pos.y) + mouse_pos = self.Editor.ScreenToClient(wx.GetMousePosition()) + middle = wx.Rect(0, 0, *self.Editor.GetClientSize()).InsideXY(mouse_pos.x, mouse_pos.y) if middle: x, y = self.CalcUnscrolledPosition(mouse_pos.x, mouse_pos.y) else: @@ -2688,11 +2775,11 @@ result = self.Controler.PasteEditedElementInstances(self.TagName, element, new_pos, middle, self.Debug) if not isinstance(result, (StringType, UnicodeType)): self.RefreshBuffer() - self.RefreshView(result) - self.ParentWindow.RefreshVariablePanel(self.TagName) + self.RefreshView(selection=result) + self.RefreshVariablePanel() self.ParentWindow.RefreshInstancesTree() else: - message = wx.MessageDialog(self, result, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self.Editor, result, "Error", wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() @@ -2819,38 +2906,22 @@ rotation = event.GetWheelRotation() / event.GetWheelDelta() if event.ShiftDown(): x, y = self.GetViewStart() - xp = max(0, min(x - rotation * 3, self.GetVirtualSize()[0] / self.GetScrollPixelsPerUnit()[0])) + xp = max(0, min(x - rotation * 3, self.Editor.GetVirtualSize()[0] / self.Editor.GetScrollPixelsPerUnit()[0])) self.RefreshVisibleElements(xp = xp) self.Scroll(xp, y) elif event.ControlDown(): dc = self.GetLogicalDC() - self.Freeze() - pos = event.GetLogicalPosition(dc) - mouse_pos = event.GetPosition() - self.SetScale(self.CurrentScale + rotation, False) - xmax = self.GetScrollRange(wx.HORIZONTAL) - self.GetScrollThumb(wx.HORIZONTAL) - ymax = self.GetScrollRange(wx.VERTICAL) - self.GetScrollThumb(wx.VERTICAL) - scrollx = max(0, round(pos.x * self.ViewScale[0] - mouse_pos.x) / SCROLLBAR_UNIT) - scrolly = max(0, round(pos.y * self.ViewScale[1] - mouse_pos.y) / SCROLLBAR_UNIT) - if scrollx > xmax or scrolly > ymax: - self.RefreshScrollBars(max(0, scrollx - xmax), max(0, scrolly - ymax)) - self.Scroll(scrollx, scrolly) - else: - self.Scroll(scrollx, scrolly) - self.RefreshScrollBars() - self.RefreshVisibleElements() - self.Refresh() - self.Thaw() + self.SetScale(self.CurrentScale + rotation, mouse_event = event) self.ParentWindow.RefreshDisplayMenu() else: x, y = self.GetViewStart() - yp = max(0, min(y - rotation * 3, self.GetVirtualSize()[1] / self.GetScrollPixelsPerUnit()[1])) + yp = max(0, min(y - rotation * 3, self.Editor.GetVirtualSize()[1] / self.Editor.GetScrollPixelsPerUnit()[1])) self.RefreshVisibleElements(yp = yp) self.Scroll(x, yp) def OnMoveWindow(self, event): if not USE_AUI: - self.GetBestSize() + self.Editor.GetBestSize() self.RefreshScrollBars() self.RefreshVisibleElements() event.Skip() @@ -2863,22 +2934,22 @@ else: dc.SetFont(self.GetFont()) else: - dc.SetBackground(wx.Brush(self.GetBackgroundColour())) + dc.SetBackground(wx.Brush(self.Editor.GetBackgroundColour())) dc.Clear() dc.BeginDrawing() if self.Scaling is not None and self.DrawGrid and not printing: dc.SetPen(wx.TRANSPARENT_PEN) dc.SetBrush(self.GridBrush) xstart, ystart = self.GetViewStart() - window_size = self.GetClientSize() - width, height = self.GetVirtualSize() + window_size = self.Editor.GetClientSize() + width, height = self.Editor.GetVirtualSize() width = int(max(width, xstart * SCROLLBAR_UNIT + window_size[0]) / self.ViewScale[0]) height = int(max(height, ystart * SCROLLBAR_UNIT + window_size[1]) / self.ViewScale[1]) dc.DrawRectangle(1, 1, width, height) if self.PageSize is not None and not printing: dc.SetPen(self.PagePen) xstart, ystart = self.GetViewStart() - window_size = self.GetClientSize() + window_size = self.Editor.GetClientSize() for x in xrange(self.PageSize[0] - (xstart * SCROLLBAR_UNIT) % self.PageSize[0], int(window_size[0] / self.ViewScale[0]), self.PageSize[0]): dc.DrawLine(xstart * SCROLLBAR_UNIT + x + 1, int(ystart * SCROLLBAR_UNIT / self.ViewScale[0]), xstart * SCROLLBAR_UNIT + x + 1, int((ystart * SCROLLBAR_UNIT + window_size[1]) / self.ViewScale[0])) @@ -2916,7 +2987,7 @@ def OnPaint(self, event): dc = self.GetLogicalDC(True) self.DoDrawing(dc) - wx.BufferedPaintDC(self, dc.GetAsBitmap()) + wx.BufferedPaintDC(self.Editor, dc.GetAsBitmap()) if self.Debug: DebugViewer.RefreshNewData(self) event.Skip() diff -r bd8c7a033b17 -r 9aa96a36cf33 controls/DurationCellEditor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/controls/DurationCellEditor.py Tue Nov 08 21:59:22 2011 +0100 @@ -0,0 +1,144 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import wx + +from dialogs.DurationEditorDialog import DurationEditorDialog + +class DurationCellControl(wx.PyControl): + + def _init_coll_MainSizer_Items(self, parent): + parent.AddWindow(self.Duration, 0, border=0, flag=wx.GROW) + parent.AddWindow(self.EditButton, 0, border=0, flag=wx.GROW) + + def _init_coll_MainSizer_Growables(self, parent): + parent.AddGrowableCol(0) + parent.AddGrowableRow(0) + + def _init_sizers(self): + self.MainSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) + + self._init_coll_MainSizer_Items(self.MainSizer) + self._init_coll_MainSizer_Growables(self.MainSizer) + + self.SetSizer(self.MainSizer) + + def _init_ctrls(self, prnt): + wx.Control.__init__(self, id=-1, + name='DurationCellControl', parent=prnt, + size=wx.DefaultSize, style=0) + + # create location text control + self.Duration = wx.TextCtrl(id=-1, name='Duration', parent=self, + pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TE_PROCESS_ENTER) + self.Duration.Bind(wx.EVT_KEY_DOWN, self.OnDurationChar) + + # create browse button + self.EditButton = wx.Button(id=-1, label='...', + name='EditButton', parent=self, pos=wx.Point(0, 0), + size=wx.Size(30, 0), style=0) + self.EditButton.Bind(wx.EVT_BUTTON, self.OnEditButtonClick) + + self.Bind(wx.EVT_SIZE, self.OnSize) + + self._init_sizers() + + ''' + Custom cell editor control with a text box and a button that launches + the DurationEditorDialog. + ''' + def __init__(self, parent): + self._init_ctrls(parent) + + def SetValue(self, value): + self.Duration.SetValue(value) + + def GetValue(self): + return self.Duration.GetValue() + + def OnSize(self, event): + self.Layout() + + def OnEditButtonClick(self, event): + # pop up the Duration Editor dialog + dialog = DurationEditorDialog(self) + dialog.SetDuration(self.Duration.GetValue()) + if dialog.ShowModal() == wx.ID_OK: + # set the duration + self.Duration.SetValue(dialog.GetDuration()) + + dialog.Destroy() + + self.Duration.SetFocus() + + def OnDurationChar(self, event): + keycode = event.GetKeyCode() + if keycode == wx.WXK_RETURN or keycode == wx.WXK_TAB: + self.Parent.Parent.ProcessEvent(event) + self.Parent.Parent.SetFocus() + else: + event.Skip() + + def SetInsertionPoint(self, i): + self.Duration.SetInsertionPoint(i) + + def SetFocus(self): + self.Duration.SetFocus() + +class DurationCellEditor(wx.grid.PyGridCellEditor): + ''' + Grid cell editor that uses DurationCellControl to display an edit button. + ''' + def __init__(self, table): + wx.grid.PyGridCellEditor.__init__(self) + self.Table = table + + def __del__(self): + self.CellControl = None + + def Create(self, parent, id, evt_handler): + self.CellControl = DurationCellControl(parent) + self.SetControl(self.CellControl) + if evt_handler: + self.CellControl.PushEventHandler(evt_handler) + + def BeginEdit(self, row, col, grid): + self.CellControl.SetValue(self.Table.GetValueByName(row, 'Interval')) + self.CellControl.SetFocus() + + def EndEdit(self, row, col, grid): + duration = self.CellControl.GetValue() + old_duration = self.Table.GetValueByName(row, 'Interval') + if duration != old_duration: + self.Table.SetValueByName(row, 'Interval', duration) + return True + return False + + def SetSize(self, rect): + self.CellControl.SetDimensions(rect.x + 1, rect.y, + rect.width, rect.height, + wx.SIZE_ALLOW_MINUS_ONE) + + def Clone(self): + return DurationCellEditor(self.Table) diff -r bd8c7a033b17 -r 9aa96a36cf33 controls/EditorPanel.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/controls/EditorPanel.py Tue Nov 08 21:59:22 2011 +0100 @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import wx + +from VariablePanel import VariablePanel + +class EditorPanel(wx.SplitterWindow): + + ID = wx.NewId() + VARIABLE_PANEL_TYPE = None + + if wx.VERSION < (2, 6, 0): + def Bind(self, event, function, id = None): + if id is not None: + event(self, id, function) + else: + event(self, function) + + def _init_Editor(self, prnt): + self.Editor = None + + def _init_ctrls(self, prnt): + wx.SplitterWindow.__init__(self, id=self.ID, name='MainSplitter', parent=prnt, + size=wx.Size(0, 0), style=wx.SUNKEN_BORDER|wx.SP_3D) + self.SetNeedUpdating(True) + self.SetMinimumPaneSize(1) + + self._init_Editor(self) + + if self.VARIABLE_PANEL_TYPE is not None: + self.VariableEditor = VariablePanel(self, self, self.Controler, self.VARIABLE_PANEL_TYPE) + self.VariableEditor.SetTagName(self.TagName) + + if self.Editor is not None: + self.SplitHorizontally(self.VariableEditor, self.Editor, 200) + else: + self.Initialize(self.VariableEditor) + + else: + self.VariableEditor = None + + if self.Editor is not None: + self.Initialize(self.Editor) + + def __init__(self, parent, tagname, window, controler): + self.ParentWindow = window + self.Controler = controler + self.TagName = tagname + self.Icon = None + + self._init_ctrls(parent) + + def SetTagName(self, tagname): + self.TagName = tagname + if self.VARIABLE_PANEL_TYPE is not None: + self.VariableEditor.SetTagName(tagname) + + def GetTagName(self): + return self.TagName + + def GetTitle(self): + return "-".join(self.TagName.split("::")[1:]) + + def GetIcon(self): + return self.Icon + + def SetIcon(self, icon): + self.Icon = icon + + def IsViewing(self, tagname): + return self.TagName == tagname + + def IsDebugging(self): + return False + + def SetMode(self, mode): + pass + + def ResetBuffer(self): + pass + + def GetBufferState(self): + if self.Controler is not None: + return self.Controler.GetBufferState() + return False, False + + def Undo(self): + if self.Controler is not None: + self.Controler.LoadPrevious() + self.RefreshView() + + def Redo(self): + if self.Controler is not None: + self.Controler.LoadNext() + self.RefreshView() + + def HasNoModel(self): + return False + + def RefreshView(self, variablepanel=True): + if variablepanel: + self.RefreshVariablePanel() + + def RefreshVariablePanel(self): + if self.VariableEditor is not None: + self.VariableEditor.RefreshView() + + def _Refresh(self, *args): + self.ParentWindow._Refresh(*args) + + def RefreshScaling(self, refresh=True): + pass + + def ClearHighlights(self, highlight_type=None): + if self.VariableEditor is not None: + self.VariableEditor.ClearHighlights(highlight_type) diff -r bd8c7a033b17 -r 9aa96a36cf33 controls/LocationCellEditor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/controls/LocationCellEditor.py Tue Nov 08 21:59:22 2011 +0100 @@ -0,0 +1,158 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import wx + +from dialogs.BrowseLocationsDialog import BrowseLocationsDialog + +class LocationCellControl(wx.PyControl): + + def _init_coll_MainSizer_Items(self, parent): + parent.AddWindow(self.Location, 0, border=0, flag=wx.GROW) + parent.AddWindow(self.BrowseButton, 0, border=0, flag=wx.GROW) + + def _init_coll_MainSizer_Growables(self, parent): + parent.AddGrowableCol(0) + parent.AddGrowableRow(0) + + def _init_sizers(self): + self.MainSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) + + self._init_coll_MainSizer_Items(self.MainSizer) + self._init_coll_MainSizer_Growables(self.MainSizer) + + self.SetSizer(self.MainSizer) + + def _init_ctrls(self, prnt): + wx.Control.__init__(self, id=-1, + name='LocationCellControl', parent=prnt, + size=wx.DefaultSize, style=0) + + # create location text control + self.Location = wx.TextCtrl(id=-1, name='Location', parent=self, + pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TE_PROCESS_ENTER) + self.Location.Bind(wx.EVT_KEY_DOWN, self.OnLocationChar) + + # create browse button + self.BrowseButton = wx.Button(id=-1, label='...', + name='BrowseButton', parent=self, pos=wx.Point(0, 0), + size=wx.Size(30, 0), style=0) + self.BrowseButton.Bind(wx.EVT_BUTTON, self.OnBrowseButtonClick) + + self.Bind(wx.EVT_SIZE, self.OnSize) + + self._init_sizers() + + ''' + Custom cell editor control with a text box and a button that launches + the BrowseLocationsDialog. + ''' + def __init__(self, parent, locations): + self._init_ctrls(parent) + self.Locations = locations + self.VarType = None + + def SetVarType(self, vartype): + self.VarType = vartype + + def SetValue(self, value): + self.Location.SetValue(value) + + def GetValue(self): + return self.Location.GetValue() + + def OnSize(self, event): + self.Layout() + + def OnBrowseButtonClick(self, event): + # pop up the location browser dialog + dialog = BrowseLocationsDialog(self, self.VarType, self.Locations) + if dialog.ShowModal() == wx.ID_OK: + infos = dialog.GetValues() + + # set the location + self.Location.SetValue(infos["location"]) + + dialog.Destroy() + + self.Location.SetFocus() + + def OnLocationChar(self, event): + keycode = event.GetKeyCode() + if keycode == wx.WXK_RETURN or keycode == wx.WXK_TAB: + self.Parent.Parent.ProcessEvent(event) + self.Parent.Parent.SetFocus() + else: + event.Skip() + + def SetInsertionPoint(self, i): + self.Location.SetInsertionPoint(i) + + def SetFocus(self): + self.Location.SetFocus() + +class LocationCellEditor(wx.grid.PyGridCellEditor): + ''' + Grid cell editor that uses LocationCellControl to display a browse button. + ''' + def __init__(self, table, controler): + wx.grid.PyGridCellEditor.__init__(self) + self.Table = table + self.Controler = controler + + def __del__(self): + self.CellControl = None + + def Create(self, parent, id, evt_handler): + locations = self.Controler.GetVariableLocationTree() + if len(locations) > 0: + self.CellControl = LocationCellControl(parent, locations) + else: + self.CellControl = wx.TextCtrl(parent, -1) + self.SetControl(self.CellControl) + if evt_handler: + self.CellControl.PushEventHandler(evt_handler) + + def BeginEdit(self, row, col, grid): + self.CellControl.SetValue(self.Table.GetValueByName(row, 'Location')) + if isinstance(self.CellControl, LocationCellControl): + self.CellControl.SetVarType(self.Controler.GetBaseType(self.Table.GetValueByName(row, 'Type'))) + self.CellControl.SetFocus() + + def EndEdit(self, row, col, grid): + loc = self.CellControl.GetValue() + old_loc = self.Table.GetValueByName(row, 'Location') + if loc != old_loc: + self.Table.SetValueByName(row, 'Location', loc) + return True + return False + + def SetSize(self, rect): + self.CellControl.SetDimensions(rect.x + 1, rect.y, + rect.width, rect.height, + wx.SIZE_ALLOW_MINUS_ONE) + + def Clone(self): + return LocationCellEditor(self.Table, self.Controler) + diff -r bd8c7a033b17 -r 9aa96a36cf33 controls/VariablePanel.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/controls/VariablePanel.py Tue Nov 08 21:59:22 2011 +0100 @@ -0,0 +1,898 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import wx, wx.grid + +from types import TupleType, StringType, UnicodeType + +from plcopen.structures import LOCATIONDATATYPES, TestIdentifier, IEC_KEYWORDS +from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD +from dialogs import ArrayTypeDialog +from CustomGrid import CustomGrid +from LocationCellEditor import LocationCellEditor + +# 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, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, TYPESTREE, + INSTANCESTREE, LIBRARYTREE, SCALING +] = range(9) + +#------------------------------------------------------------------------------- +# Variables Editor Panel +#------------------------------------------------------------------------------- + +def GetVariableTableColnames(location): + _ = lambda x : x + if location: + return ["#", _("Name"), _("Class"), _("Type"), _("Location"), _("Initial Value"), _("Option"), _("Documentation")] + return ["#", _("Name"), _("Class"), _("Type"), _("Initial Value"), _("Option"), _("Documentation")] + +def GetOptions(constant=True, retain=True, non_retain=True): + _ = lambda x : x + options = [""] + if constant: + options.append(_("Constant")) + if retain: + options.append(_("Retain")) + if non_retain: + options.append(_("Non-Retain")) + return options +OPTIONS_DICT = dict([(_(option), option) for option in GetOptions()]) + +def GetFilterChoiceTransfer(): + _ = lambda x : x + return {_("All"): _("All"), _("Interface"): _("Interface"), + _(" Input"): _("Input"), _(" Output"): _("Output"), _(" InOut"): _("InOut"), + _(" External"): _("External"), _("Variables"): _("Variables"), _(" Local"): _("Local"), + _(" Temp"): _("Temp"), _("Global"): _("Global")}#, _("Access") : _("Access")} +VARIABLE_CHOICES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().iterkeys()]) +VARIABLE_CLASSES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().itervalues()]) + +CheckOptionForClass = {"Local": lambda x: x, + "Temp": lambda x: "", + "Input": lambda x: {"Retain": "Retain", "Non-Retain": "Non-Retain"}.get(x, ""), + "InOut": lambda x: "", + "Output": lambda x: {"Retain": "Retain", "Non-Retain": "Non-Retain"}.get(x, ""), + "Global": lambda x: {"Constant": "Constant", "Retain": "Retain"}.get(x, ""), + "External": lambda x: {"Constant": "Constant"}.get(x, "") + } + +class VariableTable(wx.grid.PyGridTableBase): + + """ + A custom wx.grid.Grid Table using user supplied data + """ + def __init__(self, parent, data, colnames): + # The base class must be initialized *first* + wx.grid.PyGridTableBase.__init__(self) + self.data = data + self.old_value = None + self.colnames = colnames + self.Highlights = {} + self.Parent = parent + # XXX + # we need to store the row length and collength to + # see if the table has changed size + self._rows = self.GetNumberRows() + self._cols = self.GetNumberCols() + + def GetNumberCols(self): + return len(self.colnames) + + def GetNumberRows(self): + return len(self.data) + + def GetColLabelValue(self, col, translate=True): + if col < len(self.colnames): + if translate: + return _(self.colnames[col]) + return self.colnames[col] + + def GetRowLabelValues(self, row, translate=True): + return row + + def GetValue(self, row, col): + if row < self.GetNumberRows(): + if col == 0: + return self.data[row]["Number"] + colname = self.GetColLabelValue(col, False) + value = self.data[row].get(colname, "") + if colname == "Type" and isinstance(value, TupleType): + if value[0] == "array": + return "ARRAY [%s] OF %s" % (",".join(map(lambda x : "..".join(x), value[2])), value[1]) + if not isinstance(value, (StringType, UnicodeType)): + value = str(value) + if colname in ["Class", "Option"]: + return _(value) + return value + + def SetValue(self, row, col, value): + if col < len(self.colnames): + colname = self.GetColLabelValue(col, False) + if colname == "Name": + self.old_value = self.data[row][colname] + elif colname == "Class": + value = VARIABLE_CLASSES_DICT[value] + self.SetValueByName(row, "Option", CheckOptionForClass[value](self.GetValueByName(row, "Option"))) + if value == "External": + self.SetValueByName(row, "Initial Value", "") + elif colname == "Option": + value = OPTIONS_DICT[value] + self.data[row][colname] = value + + def GetValueByName(self, row, colname): + if row < self.GetNumberRows(): + return self.data[row].get(colname) + + def SetValueByName(self, row, colname, value): + if row < self.GetNumberRows(): + self.data[row][colname] = value + + def GetOldValue(self): + return self.old_value + + def ResetView(self, grid): + """ + (wx.grid.Grid) -> Reset the grid view. Call this to + update the grid if rows and columns have been added or deleted + """ + grid.BeginBatch() + for current, new, delmsg, addmsg in [ + (self._rows, self.GetNumberRows(), wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED), + (self._cols, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED), + ]: + if new < current: + msg = wx.grid.GridTableMessage(self,delmsg,new,current-new) + grid.ProcessTableMessage(msg) + elif new > current: + msg = wx.grid.GridTableMessage(self,addmsg,new-current) + grid.ProcessTableMessage(msg) + self.UpdateValues(grid) + grid.EndBatch() + + self._rows = self.GetNumberRows() + self._cols = self.GetNumberCols() + # update the column rendering scheme + self._updateColAttrs(grid) + + # update the scrollbars and the displayed part of the grid + grid.AdjustScrollbars() + grid.ForceRefresh() + + def UpdateValues(self, grid): + """Update all displayed values""" + # This sends an event to the grid table to update all of the values + msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES) + grid.ProcessTableMessage(msg) + + def _updateColAttrs(self, grid): + """ + wx.grid.Grid -> update the column attributes to add the + appropriate renderer given the column name. + + Otherwise default to the default renderer. + """ + for row in range(self.GetNumberRows()): + var_class = self.GetValueByName(row, "Class") + var_type = self.GetValueByName(row, "Type") + row_highlights = self.Highlights.get(row, {}) + for col in range(self.GetNumberCols()): + editor = None + renderer = None + colname = self.GetColLabelValue(col, False) + if colname == "Option": + options = GetOptions(constant = var_class in ["Local", "External", "Global"], + retain = self.Parent.ElementType != "function" and var_class in ["Local", "Input", "Output", "Global"], + non_retain = self.Parent.ElementType != "function" and var_class in ["Local", "Input", "Output"]) + if len(options) > 1: + editor = wx.grid.GridCellChoiceEditor() + editor.SetParameters(",".join(map(_, options))) + else: + grid.SetReadOnly(row, col, True) + elif col != 0 and self.GetValueByName(row, "Edit"): + grid.SetReadOnly(row, col, False) + if colname == "Name": + if self.Parent.PouIsUsed and var_class in ["Input", "Output", "InOut"]: + grid.SetReadOnly(row, col, True) + else: + editor = wx.grid.GridCellTextEditor() + renderer = wx.grid.GridCellStringRenderer() + elif colname == "Initial Value": + if var_class != "External": + if self.Parent.Controler.IsEnumeratedType(var_type): + editor = wx.grid.GridCellChoiceEditor() + editor.SetParameters(",".join(self.Parent.Controler.GetEnumeratedDataValues(var_type))) + else: + editor = wx.grid.GridCellTextEditor() + renderer = wx.grid.GridCellStringRenderer() + else: + grid.SetReadOnly(row, col, True) + elif colname == "Location": + if var_class in ["Local", "Global"] and self.Parent.Controler.IsLocatableType(var_type): + editor = LocationCellEditor(self, self.Parent.Controler) + renderer = wx.grid.GridCellStringRenderer() + else: + grid.SetReadOnly(row, col, True) + elif colname == "Class": + if len(self.Parent.ClassList) == 1 or self.Parent.PouIsUsed and var_class in ["Input", "Output", "InOut"]: + grid.SetReadOnly(row, col, True) + else: + editor = wx.grid.GridCellChoiceEditor() + excluded = [] + if self.Parent.PouIsUsed: + excluded.extend(["Input","Output","InOut"]) + if self.Parent.IsFunctionBlockType(var_type): + excluded.extend(["Local","Temp"]) + editor.SetParameters(",".join([_(choice) for choice in self.Parent.ClassList if choice not in excluded])) + elif colname != "Documentation": + grid.SetReadOnly(row, col, True) + + grid.SetCellEditor(row, col, editor) + grid.SetCellRenderer(row, col, renderer) + + highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1] + grid.SetCellBackgroundColour(row, col, highlight_colours[0]) + grid.SetCellTextColour(row, col, highlight_colours[1]) + if wx.Platform == '__WXMSW__': + grid.SetRowMinimalHeight(row, 20) + else: + grid.SetRowMinimalHeight(row, 28) + grid.AutoSizeRow(row, False) + + def SetData(self, data): + self.data = data + + def GetData(self): + return self.data + + def GetCurrentIndex(self): + return self.CurrentIndex + + def SetCurrentIndex(self, index): + self.CurrentIndex = index + + def AppendRow(self, row_content): + self.data.append(row_content) + + def RemoveRow(self, row_index): + self.data.pop(row_index) + + def GetRow(self, row_index): + return self.data[row_index] + + def Empty(self): + self.data = [] + self.editors = [] + + def AddHighlight(self, infos, highlight_type): + row_highlights = self.Highlights.setdefault(infos[0], {}) + col_highlights = row_highlights.setdefault(infos[1], []) + col_highlights.append(highlight_type) + + def ClearHighlights(self, highlight_type=None): + if highlight_type is None: + self.Highlights = {} + else: + for row, row_highlights in self.Highlights.iteritems(): + row_items = row_highlights.items() + for col, col_highlights in row_items: + if highlight_type in col_highlights: + col_highlights.remove(highlight_type) + if len(col_highlights) == 0: + row_highlights.pop(col) + + +class VariableDropTarget(wx.TextDropTarget): + ''' + This allows dragging a variable location from somewhere to the Location + column of a variable row. + + The drag source should be a TextDataObject containing a Python tuple like: + ('%ID0.0.0', 'location', 'REAL') + + c_ext/CFileEditor.py has an example of this (you can drag a C extension + variable to the Location column of the variable panel). + ''' + def __init__(self, parent): + wx.TextDropTarget.__init__(self) + self.ParentWindow = parent + + def OnDropText(self, x, y, data): + x, y = self.ParentWindow.VariablesGrid.CalcUnscrolledPosition(x, y) + col = self.ParentWindow.VariablesGrid.XToCol(x) + row = self.ParentWindow.VariablesGrid.YToRow(y - self.ParentWindow.VariablesGrid.GetColLabelSize()) + if col != wx.NOT_FOUND and row != wx.NOT_FOUND: + if self.ParentWindow.Table.GetColLabelValue(col, False) != "Location": + return + message = None + if not self.ParentWindow.Table.GetValueByName(row, "Edit"): + message = _("Can't give a location to a function block instance") + elif self.ParentWindow.Table.GetValueByName(row, "Class") not in ["Local", "Global"]: + message = _("Can only give a location to local or global variables") + else: + try: + values = eval(data) + except: + message = _("Invalid value \"%s\" for location")%data + values = None + if not isinstance(values, TupleType): + message = _("Invalid value \"%s\" for location")%data + values = None + if values is not None and values[1] == "location": + location = values[0] + variable_type = self.ParentWindow.Table.GetValueByName(row, "Type") + base_type = self.ParentWindow.Controler.GetBaseType(variable_type) + message = None + if location.startswith("%"): + if base_type != values[2]: + message = _("Incompatible data types between \"%s\" and \"%s\"")%(values[2], variable_type) + else: + self.ParentWindow.Table.SetValue(row, col, location) + self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid) + self.ParentWindow.SaveValues() + else: + if location[0].isdigit() and base_type != "BOOL": + message = _("Incompatible size of data between \"%s\" and \"BOOL\"")%location + elif location[0] not in LOCATIONDATATYPES: + message = _("Unrecognized data size \"%s\"")%location[0] + elif base_type not in LOCATIONDATATYPES[location[0]]: + message = _("Incompatible size of data between \"%s\" and \"%s\"")%(location, variable_type) + else: + dialog = wx.SingleChoiceDialog(self.ParentWindow, _("Select a variable class:"), _("Variable class"), ["Input", "Output", "Memory"], wx.OK|wx.CANCEL) + if dialog.ShowModal() == wx.ID_OK: + selected = dialog.GetSelection() + if selected == 0: + location = "%I" + location + elif selected == 1: + location = "%Q" + location + else: + location = "%M" + location + self.ParentWindow.Table.SetValue(row, col, location) + self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid) + self.ParentWindow.SaveValues() + dialog.Destroy() + if message is not None: + wx.CallAfter(self.ShowMessage, message) + + def ShowMessage(self, message): + message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + +[ID_VARIABLEEDITORPANEL, ID_VARIABLEEDITORPANELVARIABLESGRID, + ID_VARIABLEEDITORCONTROLPANEL, ID_VARIABLEEDITORPANELRETURNTYPE, + ID_VARIABLEEDITORPANELCLASSFILTER, ID_VARIABLEEDITORPANELADDBUTTON, + ID_VARIABLEEDITORPANELDELETEBUTTON, ID_VARIABLEEDITORPANELUPBUTTON, + ID_VARIABLEEDITORPANELDOWNBUTTON, ID_VARIABLEEDITORPANELSTATICTEXT1, + ID_VARIABLEEDITORPANELSTATICTEXT2, ID_VARIABLEEDITORPANELSTATICTEXT3, +] = [wx.NewId() for _init_ctrls in range(12)] + +class VariablePanel(wx.Panel): + + 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_MainSizer_Items(self, parent): + parent.AddWindow(self.ControlPanel, 0, border=5, flag=wx.GROW|wx.ALL) + parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW) + + def _init_coll_MainSizer_Growables(self, parent): + parent.AddGrowableCol(0) + parent.AddGrowableRow(1) + + def _init_coll_ControlPanelSizer_Items(self, parent): + parent.AddWindow(self.staticText1, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL) + parent.AddWindow(self.ReturnType, 0, border=0, flag=0) + parent.AddWindow(self.staticText2, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL) + parent.AddWindow(self.ClassFilter, 0, border=0, flag=0) + parent.AddWindow(self.AddButton, 0, border=0, flag=0) + parent.AddWindow(self.DeleteButton, 0, border=0, flag=0) + parent.AddWindow(self.UpButton, 0, border=0, flag=0) + parent.AddWindow(self.DownButton, 0, border=0, flag=0) + + def _init_coll_ControlPanelSizer_Growables(self, parent): + parent.AddGrowableCol(3) + parent.AddGrowableRow(0) + + def _init_sizers(self): + self.MainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=0) + self.ControlPanelSizer = wx.FlexGridSizer(cols=8, hgap=5, rows=1, vgap=5) + + self._init_coll_MainSizer_Items(self.MainSizer) + self._init_coll_MainSizer_Growables(self.MainSizer) + self._init_coll_ControlPanelSizer_Items(self.ControlPanelSizer) + self._init_coll_ControlPanelSizer_Growables(self.ControlPanelSizer) + + self.ControlPanel.SetSizer(self.ControlPanelSizer) + self.SetSizer(self.MainSizer) + + def _init_ctrls(self, prnt): + wx.Panel.__init__(self, id=ID_VARIABLEEDITORPANEL, + name='VariableEditorPanel', parent=prnt, pos=wx.Point(0, 0), + size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) + + self.VariablesGrid = CustomGrid(id=ID_VARIABLEEDITORPANELVARIABLESGRID, + name='VariablesGrid', parent=self, pos=wx.Point(0, 0), + size=wx.Size(0, 0), style=wx.VSCROLL) + self.VariablesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False, + 'Sans')) + self.VariablesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL, + False, 'Sans')) + self.VariablesGrid.SetSelectionBackground(wx.WHITE) + self.VariablesGrid.SetSelectionForeground(wx.BLACK) + if wx.VERSION >= (2, 6, 0): + self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange) + self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) + self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) + else: + wx.grid.EVT_GRID_CELL_CHANGE(self.VariablesGrid, self.OnVariablesGridCellChange) + wx.grid.EVT_GRID_CELL_LEFT_CLICK(self.VariablesGrid, self.OnVariablesGridCellLeftClick) + wx.grid.EVT_GRID_EDITOR_SHOWN(self.VariablesGrid, self.OnVariablesGridEditorShown) + + self.ControlPanel = wx.ScrolledWindow(id=ID_VARIABLEEDITORCONTROLPANEL, + name='ControlPanel', parent=self, pos=wx.Point(0, 0), + size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) + self.ControlPanel.SetScrollRate(10, 0) + + self.staticText1 = wx.StaticText(id=ID_VARIABLEEDITORPANELSTATICTEXT1, + label=_('Return Type:'), name='staticText1', parent=self.ControlPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) + + self.ReturnType = wx.ComboBox(id=ID_VARIABLEEDITORPANELRETURNTYPE, + name='ReturnType', parent=self.ControlPanel, pos=wx.Point(0, 0), + size=wx.Size(145, 28), style=wx.CB_READONLY) + self.Bind(wx.EVT_COMBOBOX, self.OnReturnTypeChanged, id=ID_VARIABLEEDITORPANELRETURNTYPE) + + self.staticText2 = wx.StaticText(id=ID_VARIABLEEDITORPANELSTATICTEXT2, + label=_('Class Filter:'), name='staticText2', parent=self.ControlPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) + + self.ClassFilter = wx.ComboBox(id=ID_VARIABLEEDITORPANELCLASSFILTER, + name='ClassFilter', parent=self.ControlPanel, pos=wx.Point(0, 0), + size=wx.Size(145, 28), style=wx.CB_READONLY) + self.Bind(wx.EVT_COMBOBOX, self.OnClassFilter, id=ID_VARIABLEEDITORPANELCLASSFILTER) + + self.AddButton = wx.Button(id=ID_VARIABLEEDITORPANELADDBUTTON, label=_('Add'), + name='AddButton', parent=self.ControlPanel, pos=wx.Point(0, 0), + size=wx.DefaultSize, style=0) + + self.DeleteButton = wx.Button(id=ID_VARIABLEEDITORPANELDELETEBUTTON, label=_('Delete'), + name='DeleteButton', parent=self.ControlPanel, pos=wx.Point(0, 0), + size=wx.DefaultSize, style=0) + + self.UpButton = wx.Button(id=ID_VARIABLEEDITORPANELUPBUTTON, label='^', + name='UpButton', parent=self.ControlPanel, pos=wx.Point(0, 0), + size=wx.Size(28, 28), style=0) + + self.DownButton = wx.Button(id=ID_VARIABLEEDITORPANELDOWNBUTTON, label='v', + name='DownButton', parent=self.ControlPanel, pos=wx.Point(0, 0), + size=wx.Size(28, 28), style=0) + + self._init_sizers() + + def __init__(self, parent, window, controler, element_type): + self._init_ctrls(parent) + self.ParentWindow = window + self.Controler = controler + self.ElementType = element_type + + self.RefreshHighlightsTimer = wx.Timer(self, -1) + self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) + + self.Filter = "All" + self.FilterChoices = [] + self.FilterChoiceTransfer = GetFilterChoiceTransfer() + + self.DefaultValue = { "Name" : "", "Class" : "", "Type" : "INT", "Location" : "", + "Initial Value" : "", "Option" : "", + "Documentation" : "", "Edit" : True + } + + if element_type in ["config", "resource"]: + self.DefaultTypes = {"All" : "Global"} + else: + self.DefaultTypes = {"All" : "Local", "Interface" : "Input", "Variables" : "Local"} + + if element_type in ["config", "resource"] \ + or element_type in ["program", "transition", "action"]: + # this is an element that can have located variables + self.Table = VariableTable(self, [], GetVariableTableColnames(True)) + + if element_type in ["config", "resource"]: + self.FilterChoices = ["All", "Global"]#,"Access"] + else: + self.FilterChoices = ["All", + "Interface", " Input", " Output", " InOut", " External", + "Variables", " Local", " Temp"]#,"Access"] + + # these condense the ColAlignements list + l = wx.ALIGN_LEFT + c = wx.ALIGN_CENTER + + # Num Name Class Type Loc Init Option Doc + self.ColSizes = [40, 80, 70, 80, 80, 80, 100, 80] + self.ColAlignements = [c, l, l, l, l, l, l, l] + + else: + # this is an element that cannot have located variables + self.Table = VariableTable(self, [], GetVariableTableColnames(False)) + + if element_type == "function": + self.FilterChoices = ["All", + "Interface", " Input", " Output", " InOut", + "Variables", " Local"] + else: + self.FilterChoices = ["All", + "Interface", " Input", " Output", " InOut", " External", + "Variables", " Local", " Temp"] + + # these condense the ColAlignements list + l = wx.ALIGN_LEFT + c = wx.ALIGN_CENTER + + # Num Name Class Type Init Option Doc + self.ColSizes = [40, 80, 70, 80, 80, 100, 160] + self.ColAlignements = [c, l, l, l, l, l, l] + + for choice in self.FilterChoices: + self.ClassFilter.Append(_(choice)) + + reverse_transfer = {} + for filter, choice in self.FilterChoiceTransfer.items(): + reverse_transfer[choice] = filter + self.ClassFilter.SetStringSelection(_(reverse_transfer[self.Filter])) + self.RefreshTypeList() + + self.VariablesGrid.SetTable(self.Table) + self.VariablesGrid.SetButtons({"Add": self.AddButton, + "Delete": self.DeleteButton, + "Up": self.UpButton, + "Down": self.DownButton}) + + def _AddVariable(new_row): + if not self.PouIsUsed or self.Filter not in ["Interface", "Input", "Output", "InOut"]: + row_content = self.DefaultValue.copy() + if self.Filter in self.DefaultTypes: + row_content["Class"] = self.DefaultTypes[self.Filter] + else: + row_content["Class"] = self.Filter + if self.Filter == "All" and len(self.Values) > 0: + self.Values.insert(new_row, row_content) + else: + self.Values.append(row_content) + new_row = self.Table.GetNumberRows() + self.SaveValues() + self.RefreshValues() + return new_row + return self.VariablesGrid.GetGridCursorRow() + setattr(self.VariablesGrid, "_AddRow", _AddVariable) + + def _DeleteVariable(row): + if (self.Table.GetValueByName(row, "Edit") and + (not self.PouIsUsed or self.Table.GetValueByName(row, "Class") not in ["Input", "Output", "InOut"])): + self.Values.remove(self.Table.GetRow(row)) + self.SaveValues() + self.RefreshValues() + setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) + + def _MoveVariable(row, move): + if (self.Filter == "All" and + (not self.PouIsUsed or self.Table.GetValueByName(row, "Class") not in ["Input", "Output", "InOut"])): + new_row = max(0, min(row + move, len(self.Values) - 1)) + if new_row != row: + self.Values.insert(new_row, self.Values.pop(row)) + self.SaveValues() + self.RefreshValues() + return new_row + return row + setattr(self.VariablesGrid, "_MoveRow", _MoveVariable) + + def _RefreshButtons(): + table_length = len(self.Table.data) + row_class = None + row_edit = True + row = 0 + if table_length > 0: + row = self.VariablesGrid.GetGridCursorRow() + row_edit = self.Table.GetValueByName(row, "Edit") + if self.PouIsUsed: + row_class = self.Table.GetValueByName(row, "Class") + self.AddButton.Enable(not self.PouIsUsed or self.Filter not in ["Interface", "Input", "Output", "InOut"]) + self.DeleteButton.Enable(table_length > 0 and row_edit and row_class not in ["Input", "Output", "InOut"]) + self.UpButton.Enable(table_length > 0 and row > 0 and self.Filter == "All" and row_class not in ["Input", "Output", "InOut"]) + self.DownButton.Enable(table_length > 0 and row < table_length - 1 and self.Filter == "All" and row_class not in ["Input", "Output", "InOut"]) + setattr(self.VariablesGrid, "RefreshButtons", _RefreshButtons) + + self.VariablesGrid.SetRowLabelSize(0) + for col in range(self.Table.GetNumberCols()): + attr = wx.grid.GridCellAttr() + attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE) + self.VariablesGrid.SetColAttr(col, attr) + self.VariablesGrid.SetColMinimalWidth(col, self.ColSizes[col]) + self.VariablesGrid.AutoSizeColumn(col, False) + + def __del__(self): + self.RefreshHighlightsTimer.Stop() + + def SetTagName(self, tagname): + self.TagName = tagname + + def IsFunctionBlockType(self, name): + bodytype = self.Controler.GetEditedElementBodyType(self.TagName) + pouname, poutype = self.Controler.GetEditedElementType(self.TagName) + if poutype != "function" and bodytype in ["ST", "IL"]: + return False + else: + return name in self.Controler.GetFunctionBlockTypes(self.TagName) + + def RefreshView(self): + self.PouNames = self.Controler.GetProjectPouNames() + + words = self.TagName.split("::") + if self.ElementType == "config": + self.PouIsUsed = False + returnType = None + self.Values = self.Controler.GetConfigurationGlobalVars(words[1]) + elif self.ElementType == "resource": + self.PouIsUsed = False + returnType = None + self.Values = self.Controler.GetConfigurationResourceGlobalVars(words[1], words[2]) + else: + if self.ElementType == "function": + self.ReturnType.Clear() + for base_type in self.Controler.GetDataTypes(self.TagName, True): + self.ReturnType.Append(base_type) + returnType = self.Controler.GetEditedElementInterfaceReturnType(self.TagName) + else: + returnType = None + self.PouIsUsed = self.Controler.PouIsUsed(words[1]) + self.Values = self.Controler.GetEditedElementInterfaceVars(self.TagName) + + if returnType is not None: + self.ReturnType.SetStringSelection(returnType) + self.ReturnType.Enable(True) + self.staticText1.Show() + self.ReturnType.Show() + else: + self.ReturnType.Enable(False) + self.staticText1.Hide() + self.ReturnType.Hide() + + self.RefreshValues() + self.VariablesGrid.RefreshButtons() + + def OnReturnTypeChanged(self, event): + words = self.TagName.split("::") + self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection()) + self.Controler.BufferProject() + self.ParentWindow.RefreshView(variablepanel = False) + self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) + event.Skip() + + def OnClassFilter(self, event): + self.Filter = self.FilterChoiceTransfer[VARIABLE_CHOICES_DICT[self.ClassFilter.GetStringSelection()]] + self.RefreshTypeList() + self.RefreshValues() + self.VariablesGrid.RefreshButtons() + event.Skip() + + def RefreshTypeList(self): + if self.Filter == "All": + self.ClassList = [self.FilterChoiceTransfer[choice] for choice in self.FilterChoices if self.FilterChoiceTransfer[choice] not in ["All","Interface","Variables"]] + elif self.Filter == "Interface": + self.ClassList = ["Input","Output","InOut","External"] + elif self.Filter == "Variables": + self.ClassList = ["Local","Temp"] + else: + self.ClassList = [self.Filter] + + def OnVariablesGridCellChange(self, event): + row, col = event.GetRow(), event.GetCol() + colname = self.Table.GetColLabelValue(col, False) + value = self.Table.GetValue(row, col) + + if colname == "Name" and value != "": + if not TestIdentifier(value): + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%value, _("Error"), wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + event.Veto() + elif value.upper() in IEC_KEYWORDS: + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%value, _("Error"), wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + event.Veto() + elif value.upper() in self.PouNames: + message = wx.MessageDialog(self, _("A POU named \"%s\" already exists!")%value, _("Error"), wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + event.Veto() + elif value.upper() in [var["Name"].upper() for var in self.Values if var != self.Table.data[row]]: + message = wx.MessageDialog(self, _("A variable with \"%s\" as name already exists in this pou!")%value, _("Error"), wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + event.Veto() + else: + self.SaveValues(False) + old_value = self.Table.GetOldValue() + if old_value != "": + self.Controler.UpdateEditedElementUsedVariable(self.TagName, old_value, value) + self.Controler.BufferProject() + self.ParentWindow.RefreshView(variablepanel = False) + self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) + event.Skip() + else: + self.SaveValues() + if colname == "Class": + self.ParentWindow.RefreshView(variablepanel = False) + event.Skip() + + def OnVariablesGridEditorShown(self, event): + row, col = event.GetRow(), event.GetCol() + + label_value = self.Table.GetColLabelValue(col) + if label_value == "Type": + type_menu = wx.Menu(title='') # the root menu + + # build a submenu containing standard IEC types + base_menu = wx.Menu(title='') + for base_type in self.Controler.GetBaseTypes(): + new_id = wx.NewId() + AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type) + self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), id=new_id) + + type_menu.AppendMenu(wx.NewId(), _("Base Types"), base_menu) + + # build a submenu containing user-defined types + datatype_menu = wx.Menu(title='') + + # TODO : remove complextypes argument when matiec can manage complex types in pou interface + datatypes = self.Controler.GetDataTypes(basetypes = False) + for datatype in datatypes: + new_id = wx.NewId() + AppendMenu(datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype) + self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id) + + type_menu.AppendMenu(wx.NewId(), _("User Data Types"), datatype_menu) + + # build a submenu containing function block types + bodytype = self.Controler.GetEditedElementBodyType(self.TagName) + pouname, poutype = self.Controler.GetEditedElementType(self.TagName) + classtype = self.Table.GetValueByName(row, "Class") + + new_id = wx.NewId() + AppendMenu(type_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Array")) + self.Bind(wx.EVT_MENU, self.VariableArrayTypeFunction, id=new_id) + + if classtype in ["Input", "Output", "InOut", "External", "Global"] or \ + poutype != "function" and bodytype in ["ST", "IL"]: + functionblock_menu = wx.Menu(title='') + fbtypes = self.Controler.GetFunctionBlockTypes(self.TagName) + for functionblock_type in fbtypes: + new_id = wx.NewId() + AppendMenu(functionblock_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=functionblock_type) + self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(functionblock_type), id=new_id) + + type_menu.AppendMenu(wx.NewId(), _("Function Block Types"), functionblock_menu) + + rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col)) + corner_x = rect.x + rect.width + corner_y = rect.y + self.VariablesGrid.GetColLabelSize() + + # pop up this new menu + self.VariablesGrid.PopupMenuXY(type_menu, corner_x, corner_y) + event.Veto() + else: + event.Skip() + + def GetVariableTypeFunction(self, base_type): + def VariableTypeFunction(event): + row = self.VariablesGrid.GetGridCursorRow() + self.Table.SetValueByName(row, "Type", base_type) + self.Table.ResetView(self.VariablesGrid) + self.SaveValues(False) + self.ParentWindow.RefreshView(variablepanel = False) + self.Controler.BufferProject() + self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) + return VariableTypeFunction + + def VariableArrayTypeFunction(self, event): + row = self.VariablesGrid.GetGridCursorRow() + dialog = ArrayTypeDialog(self, + self.Controler.GetDataTypes(self.TagName), + self.Table.GetValueByName(row, "Type")) + if dialog.ShowModal() == wx.ID_OK: + self.Table.SetValueByName(row, "Type", dialog.GetValue()) + self.Table.ResetView(self.VariablesGrid) + self.SaveValues(False) + self.ParentWindow.RefreshView(variablepanel = False) + self.Controler.BufferProject() + self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) + dialog.Destroy() + + def OnVariablesGridCellLeftClick(self, event): + row = event.GetRow() + if event.GetCol() == 0 and self.Table.GetValueByName(row, "Edit"): + row = event.GetRow() + var_name = self.Table.GetValueByName(row, "Name") + var_class = self.Table.GetValueByName(row, "Class") + var_type = self.Table.GetValueByName(row, "Type") + data = wx.TextDataObject(str((var_name, var_class, var_type, self.TagName))) + dragSource = wx.DropSource(self.VariablesGrid) + dragSource.SetData(data) + dragSource.DoDragDrop() + event.Skip() + + def RefreshValues(self): + data = [] + for num, variable in enumerate(self.Values): + if variable["Class"] in self.ClassList: + variable["Number"] = num + 1 + data.append(variable) + self.Table.SetData(data) + self.Table.ResetView(self.VariablesGrid) + + def SaveValues(self, buffer = True): + words = self.TagName.split("::") + if self.ElementType == "config": + self.Controler.SetConfigurationGlobalVars(words[1], self.Values) + elif self.ElementType == "resource": + self.Controler.SetConfigurationResourceGlobalVars(words[1], words[2], self.Values) + else: + if self.ReturnType.IsEnabled(): + self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection()) + self.Controler.SetPouInterfaceVars(words[1], self.Values) + if buffer: + self.Controler.BufferProject() + self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) + +#------------------------------------------------------------------------------- +# Highlights showing functions +#------------------------------------------------------------------------------- + + def OnRefreshHighlightsTimer(self, event): + self.Table.ResetView(self.VariablesGrid) + event.Skip() + + def AddVariableHighlight(self, infos, highlight_type): + if isinstance(infos[0], TupleType): + for i in xrange(*infos[0]): + self.Table.AddHighlight((i,) + infos[1:], highlight_type) + else: + self.Table.AddHighlight(infos, highlight_type) + self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) + + def ClearHighlights(self, highlight_type=None): + self.Table.ClearHighlights(highlight_type) + self.Table.ResetView(self.VariablesGrid) diff -r bd8c7a033b17 -r 9aa96a36cf33 controls/__init__.py --- a/controls/__init__.py Mon Nov 07 10:55:17 2011 +0100 +++ b/controls/__init__.py Tue Nov 08 21:59:22 2011 +0100 @@ -25,4 +25,8 @@ # Package initialization from CustomEditableListBox import CustomEditableListBox -from CustomGrid import CustomGrid \ No newline at end of file +from CustomGrid import CustomGrid +from EditorPanel import EditorPanel +from DurationCellEditor import DurationCellEditor +from LocationCellEditor import LocationCellEditor +from VariablePanel import VariablePanel \ No newline at end of file diff -r bd8c7a033b17 -r 9aa96a36cf33 dialogs/BrowseLocationsDialog.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dialogs/BrowseLocationsDialog.py Tue Nov 08 21:59:22 2011 +0100 @@ -0,0 +1,218 @@ +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os + +import wx + +from plcopen.structures import LOCATIONDATATYPES +from PLCControler import LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY + +CWD = os.path.split(os.path.split(os.path.realpath(__file__))[0])[0] + +def GetDirChoiceOptions(): + _ = lambda x : x + return [(_("All"), [LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY]), + (_("Input"), [LOCATION_VAR_INPUT]), + (_("Output"), [LOCATION_VAR_OUTPUT]), + (_("Memory"), [LOCATION_VAR_MEMORY])] +DIRCHOICE_OPTIONS_FILTER = dict([(_(option), filter) for option, filter in GetDirChoiceOptions()]) + +# turn LOCATIONDATATYPES inside-out +LOCATION_SIZES = {} +for size, types in LOCATIONDATATYPES.iteritems(): + for type in types: + LOCATION_SIZES[type] = size + +[ID_BROWSELOCATIONSDIALOG, ID_BROWSELOCATIONSDIALOGLOCATIONSTREE, + ID_BROWSELOCATIONSDIALOGDIRCHOICE, ID_BROWSELOCATIONSDIALOGSTATICTEXT1, + ID_BROWSELOCATIONSDIALOGSTATICTEXT2, +] = [wx.NewId() for _init_ctrls in range(5)] + +class BrowseLocationsDialog(wx.Dialog): + + 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_MainSizer_Items(self, parent): + parent.AddWindow(self.staticText1, 0, border=20, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW) + parent.AddWindow(self.LocationsTree, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.GROW) + parent.AddSizer(self.ButtonGridSizer, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW) + + def _init_coll_MainSizer_Growables(self, parent): + parent.AddGrowableCol(0) + parent.AddGrowableRow(1) + + def _init_coll_ButtonGridSizer_Items(self, parent): + parent.AddWindow(self.staticText2, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL) + parent.AddWindow(self.DirChoice, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL) + parent.AddSizer(self.ButtonSizer, 0, border=0, flag=wx.ALIGN_RIGHT) + + def _init_coll_ButtonGridSizer_Growables(self, parent): + parent.AddGrowableCol(2) + parent.AddGrowableRow(0) + + def _init_sizers(self): + self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) + self.ButtonGridSizer = wx.FlexGridSizer(cols=3, hgap=5, rows=1, vgap=0) + + self._init_coll_MainSizer_Items(self.MainSizer) + self._init_coll_MainSizer_Growables(self.MainSizer) + self._init_coll_ButtonGridSizer_Items(self.ButtonGridSizer) + self._init_coll_ButtonGridSizer_Growables(self.ButtonGridSizer) + + self.SetSizer(self.MainSizer) + + def _init_ctrls(self, prnt): + wx.Dialog.__init__(self, id=ID_BROWSELOCATIONSDIALOG, + name='BrowseLocationsDialog', parent=prnt, + size=wx.Size(600, 400), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER, + title=_('Browse Locations')) + + self.staticText1 = wx.StaticText(id=ID_BROWSELOCATIONSDIALOGSTATICTEXT1, + label=_('Locations available:'), name='staticText1', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) + + if wx.Platform == '__WXMSW__': + treestyle = wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER + else: + treestyle = wx.TR_HAS_BUTTONS|wx.TR_HIDE_ROOT|wx.TR_SINGLE|wx.SUNKEN_BORDER + self.LocationsTree = wx.TreeCtrl(id=ID_BROWSELOCATIONSDIALOGLOCATIONSTREE, + name='LocationsTree', parent=self, pos=wx.Point(0, 0), + size=wx.Size(0, 0), style=treestyle) + self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnLocationsTreeItemActivated, + id=ID_BROWSELOCATIONSDIALOGLOCATIONSTREE) + + self.staticText2 = wx.StaticText(id=ID_BROWSELOCATIONSDIALOGSTATICTEXT2, + label=_('Direction:'), name='staticText2', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) + + self.DirChoice = wx.ComboBox(id=ID_BROWSELOCATIONSDIALOGDIRCHOICE, + name='DirChoice', parent=self, pos=wx.Point(0, 0), + size=wx.DefaultSize, style=wx.CB_READONLY) + self.Bind(wx.EVT_COMBOBOX, self.OnDirChoice, id=ID_BROWSELOCATIONSDIALOGDIRCHOICE) + + self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) + if wx.VERSION >= (2, 5, 0): + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId()) + else: + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId()) + + self._init_sizers() + + def __init__(self, parent, var_type, locations): + self._init_ctrls(parent) + self.VarType = var_type + self.Locations = locations + + # Define Tree item icon list + self.TreeImageList = wx.ImageList(16, 16) + self.TreeImageDict = {} + + # Icons for items + for imgname, itemtype in [ + ("CONFIGURATION", LOCATION_PLUGIN), + ("RESOURCE", LOCATION_MODULE), + ("PROGRAM", LOCATION_GROUP), + ("VAR_INPUT", LOCATION_VAR_INPUT), + ("VAR_OUTPUT", LOCATION_VAR_OUTPUT), + ("VAR_LOCAL", LOCATION_VAR_MEMORY)]: + self.TreeImageDict[itemtype]=self.TreeImageList.Add(wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%imgname))) + + # Assign icon list to TreeCtrls + self.LocationsTree.SetImageList(self.TreeImageList) + + # Set a options for the choice + for option, filter in GetDirChoiceOptions(): + self.DirChoice.Append(_(option)) + self.DirChoice.SetStringSelection(_("All")) + self.RefreshFilter() + + self.RefreshLocationsTree() + + def RefreshFilter(self): + self.Filter = DIRCHOICE_OPTIONS_FILTER[self.DirChoice.GetStringSelection()] + + def RefreshLocationsTree(self): + root = self.LocationsTree.GetRootItem() + if not root.IsOk(): + if wx.Platform == '__WXMSW__': + root = self.LocationsTree.AddRoot(_('Plugins')) + else: + root = self.LocationsTree.AddRoot("") + self.GenerateLocationsTreeBranch(root, self.Locations) + self.LocationsTree.Expand(root) + + def GenerateLocationsTreeBranch(self, root, locations): + to_delete = [] + if wx.VERSION >= (2, 6, 0): + item, root_cookie = self.LocationsTree.GetFirstChild(root) + else: + item, root_cookie = self.LocationsTree.GetFirstChild(root, 0) + for loc_infos in locations: + infos = loc_infos.copy() + if infos["type"] in [LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP] or\ + infos["type"] in self.Filter and (infos["IEC_type"] == self.VarType or + infos["IEC_type"] is None and LOCATION_SIZES[self.VarType] == infos["size"]): + children = [child for child in infos.pop("children")] + if not item.IsOk(): + item = self.LocationsTree.AppendItem(root, infos["name"]) + if wx.Platform != '__WXMSW__': + item, root_cookie = self.LocationsTree.GetNextChild(root, root_cookie) + else: + self.LocationsTree.SetItemText(item, infos["name"]) + self.LocationsTree.SetPyData(item, infos) + self.LocationsTree.SetItemImage(item, self.TreeImageDict[infos["type"]]) + self.GenerateLocationsTreeBranch(item, children) + item, root_cookie = self.LocationsTree.GetNextChild(root, root_cookie) + while item.IsOk(): + to_delete.append(item) + item, root_cookie = self.LocationsTree.GetNextChild(root, root_cookie) + for item in to_delete: + self.LocationsTree.Delete(item) + + def OnLocationsTreeItemActivated(self, event): + infos = self.LocationsTree.GetPyData(event.GetItem()) + if infos["type"] not in [LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP]: + wx.CallAfter(self.EndModal, wx.ID_OK) + event.Skip() + + def OnDirChoice(self, event): + self.RefreshFilter() + self.RefreshLocationsTree() + + def GetValues(self): + selected = self.LocationsTree.GetSelection() + return self.LocationsTree.GetPyData(selected) + + def OnOK(self, event): + selected = self.LocationsTree.GetSelection() + var_infos = None + if selected.IsOk(): + var_infos = self.LocationsTree.GetPyData(selected) + if var_infos is None or var_infos["type"] in [LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP]: + message = wx.MessageDialog(self, _("A location must be selected!"), _("Error"), wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + else: + self.EndModal(wx.ID_OK) diff -r bd8c7a033b17 -r 9aa96a36cf33 dialogs/__init__.py --- a/dialogs/__init__.py Mon Nov 07 10:55:17 2011 +0100 +++ b/dialogs/__init__.py Tue Nov 08 21:59:22 2011 +0100 @@ -38,3 +38,4 @@ from ArrayTypeDialog import ArrayTypeDialog from DurationEditorDialog import DurationEditorDialog from SearchInProjectDialog import SearchInProjectDialog +from BrowseLocationsDialog import BrowseLocationsDialog diff -r bd8c7a033b17 -r 9aa96a36cf33 graphics/GraphicCommons.py --- a/graphics/GraphicCommons.py Mon Nov 07 10:55:17 2011 +0100 +++ b/graphics/GraphicCommons.py Tue Nov 08 21:59:22 2011 +0100 @@ -393,8 +393,9 @@ class RubberBand: # Create a rubberband by indicated on which window it must be drawn - def __init__(self, drawingSurface): - self.drawingSurface = drawingSurface + def __init__(self, viewer): + self.Viewer = viewer + self.drawingSurface = viewer.Editor self.Reset() # Method that initializes the internal attributes of the rubberband @@ -451,7 +452,7 @@ # Method that erase the last box and draw the new box def Redraw(self, dc = None): if not dc: - dc = self.drawingSurface.GetLogicalDC() + dc = self.Viewer.GetLogicalDC() scalex, scaley = dc.GetUserScale() dc.SetUserScale(1, 1) dc.SetPen(wx.Pen(wx.WHITE, 1, wx.DOT)) @@ -470,7 +471,7 @@ # Erase last box def Erase(self, dc = None): if not dc: - dc = self.drawingSurface.GetLogicalDC() + dc = self.Viewer.GetLogicalDC() scalex, scaley = dc.GetUserScale() dc.SetUserScale(1, 1) dc.SetPen(wx.Pen(wx.WHITE, 1, wx.DOT)) @@ -484,7 +485,7 @@ # Draw current box def Draw(self, dc = None): if not dc: - dc = self.drawingSurface.GetLogicalDC() + dc = self.Viewer.GetLogicalDC() scalex, scaley = dc.GetUserScale() dc.SetUserScale(1, 1) dc.SetPen(wx.Pen(wx.WHITE, 1, wx.DOT)) diff -r bd8c7a033b17 -r 9aa96a36cf33 plcopen/structures.py --- a/plcopen/structures.py Mon Nov 07 10:55:17 2011 +0100 +++ b/plcopen/structures.py Tue Nov 08 21:59:22 2011 +0100 @@ -602,8 +602,9 @@ # Keywords for Pou Declaration -POU_KEYWORDS = ["FUNCTION", "END_FUNCTION", "FUNCTION_BLOCK", "END_FUNCTION_BLOCK", - "PROGRAM", "END_PROGRAM", "EN", "ENO", "F_EDGE", "R_EDGE"] +POU_BLOCK_START_KEYWORDS = ["FUNCTION", "FUNCTION_BLOCK", "PROGRAM"] +POU_BLOCK_END_KEYWORDS = ["END_FUNCTION", "END_FUNCTION_BLOCK", "END_PROGRAM"] +POU_KEYWORDS = ["EN", "ENO", "F_EDGE", "R_EDGE"] + POU_BLOCK_START_KEYWORDS + POU_BLOCK_END_KEYWORDS for category in BlockTypes: for block in category["list"]: if block["name"] not in POU_KEYWORDS: @@ -611,25 +612,27 @@ # Keywords for Type Declaration -TYPE_KEYWORDS = ["TYPE", "END_TYPE", "STRUCT", "END_STRUCT", "ARRAY", "OF", "T", - "D", "TIME_OF_DAY", "DATE_AND_TIME"] +TYPE_BLOCK_START_KEYWORDS = ["TYPE", "STRUCT"] +TYPE_BLOCK_END_KEYWORDS = ["END_TYPE", "END_STRUCT"] +TYPE_KEYWORDS = ["ARRAY", "OF", "T", "D", "TIME_OF_DAY", "DATE_AND_TIME"] + TYPE_BLOCK_START_KEYWORDS + TYPE_BLOCK_END_KEYWORDS TYPE_KEYWORDS.extend([keyword for keyword in TypeHierarchy.keys() if keyword not in TYPE_KEYWORDS]) # Keywords for Variable Declaration -VAR_KEYWORDS = ["VAR", "VAR_INPUT", "VAR_OUTPUT", "VAR_IN_OUT", "VAR_TEMP", - "VAR_EXTERNAL", "END_VAR", "AT", "CONSTANT", "RETAIN", "NON_RETAIN"] +VAR_BLOCK_START_KEYWORDS = ["VAR", "VAR_INPUT", "VAR_OUTPUT", "VAR_IN_OUT", "VAR_TEMP", "VAR_EXTERNAL"] +VAR_BLOCK_END_KEYWORDS = ["END_VAR"] +VAR_KEYWORDS = ["AT", "CONSTANT", "RETAIN", "NON_RETAIN"] + VAR_BLOCK_START_KEYWORDS + VAR_BLOCK_END_KEYWORDS # Keywords for Configuration Declaration -CONFIG_KEYWORDS = ["CONFIGURATION", "END_CONFIGURATION", "RESOURCE", "ON", "END_RESOURCE", - "PROGRAM", "WITH", "READ_ONLY", "READ_WRITE", "TASK", "VAR_ACCESS", "VAR_CONFIG", - "VAR_GLOBAL", "END_VAR"] - +CONFIG_BLOCK_START_KEYWORDS = ["CONFIGURATION", "RESOURCE", "VAR_ACCESS", "VAR_CONFIG", "VAR_GLOBAL"] +CONFIG_BLOCK_END_KEYWORDS = ["END_CONFIGURATION", "END_RESOURCE", "END_VAR"] +CONFIG_KEYWORDS = ["ON", "PROGRAM", "WITH", "READ_ONLY", "READ_WRITE", "TASK"] + CONFIG_BLOCK_START_KEYWORDS + CONFIG_BLOCK_END_KEYWORDS # Keywords for Structured Function Chart -SFC_KEYWORDS = ["ACTION", "END_ACTION", "INITIAL_STEP", "STEP", "END_STEP", "TRANSITION", - "FROM", "TO", "END_TRANSITION"] +SFC_BLOCK_START_KEYWORDS = ["ACTION", "INITIAL_STEP", "STEP", "TRANSITION"] +SFC_BLOCK_END_KEYWORDS = ["END_ACTION", "END_STEP", "END_TRANSITION"] +SFC_KEYWORDS = ["FROM", "TO"] + SFC_BLOCK_START_KEYWORDS + SFC_BLOCK_START_KEYWORDS # Keywords for Instruction List @@ -645,12 +648,17 @@ "RETURN", "NOT", "MOD", "AND", "XOR", "OR"] + ST_BLOCK_START_KEYWORDS + ST_BLOCK_END_KEYWORDS # All the keywords of IEC +IEC_BLOCK_START_KEYWORDS = [] +IEC_BLOCK_END_KEYWORDS = [] IEC_KEYWORDS = ["E", "TRUE", "FALSE"] -IEC_KEYWORDS.extend([keyword for keyword in POU_KEYWORDS if keyword not in IEC_KEYWORDS]) -IEC_KEYWORDS.extend([keyword for keyword in TYPE_KEYWORDS if keyword not in IEC_KEYWORDS]) -IEC_KEYWORDS.extend([keyword for keyword in VAR_KEYWORDS if keyword not in IEC_KEYWORDS]) -IEC_KEYWORDS.extend([keyword for keyword in CONFIG_KEYWORDS if keyword not in IEC_KEYWORDS]) -IEC_KEYWORDS.extend([keyword for keyword in SFC_KEYWORDS if keyword not in IEC_KEYWORDS]) -IEC_KEYWORDS.extend([keyword for keyword in IL_KEYWORDS if keyword not in IEC_KEYWORDS]) -IEC_KEYWORDS.extend([keyword for keyword in ST_KEYWORDS if keyword not in IEC_KEYWORDS]) - +for all_keywords, keywords_list in [(IEC_BLOCK_START_KEYWORDS, [POU_BLOCK_START_KEYWORDS, TYPE_BLOCK_START_KEYWORDS, + VAR_BLOCK_START_KEYWORDS, CONFIG_BLOCK_START_KEYWORDS, + SFC_BLOCK_START_KEYWORDS, ST_BLOCK_START_KEYWORDS]), + (IEC_BLOCK_END_KEYWORDS, [POU_BLOCK_END_KEYWORDS, TYPE_BLOCK_END_KEYWORDS, + VAR_BLOCK_END_KEYWORDS, CONFIG_BLOCK_END_KEYWORDS, + SFC_BLOCK_END_KEYWORDS, ST_BLOCK_END_KEYWORDS]), + (IEC_KEYWORDS, [POU_KEYWORDS, TYPE_KEYWORDS, VAR_KEYWORDS, CONFIG_KEYWORDS, + SFC_KEYWORDS, IL_KEYWORDS, ST_KEYWORDS])]: + for keywords in keywords_list: + all_keywords.extend([keyword for keyword in keywords if keyword not in all_keywords]) +