--- 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()
--- 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:
--- 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()
--- 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
#-------------------------------------------------------------------------------
--- 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)
-
--- 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()
#-------------------------------------------------------------------------------
--- 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)
--- 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()
--- /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)
--- /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)
--- /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)
+
--- /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)
--- 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
--- /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)
--- 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
--- 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))
--- 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])
+