class DataTypeEditor(EditorPanel): def _init_Editor(self, parent): self.Editor = wx.Panel(parent, style=wx.SUNKEN_BORDER) self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) self.MainSizer.AddGrowableCol(0) self.MainSizer.AddGrowableRow(1) top_sizer = wx.BoxSizer(wx.HORIZONTAL) self.MainSizer.AddSizer(top_sizer, border=5, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) derivation_type_label = wx.StaticText(self.Editor, label=_('Derivation Type:')) top_sizer.AddWindow(derivation_type_label, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT) self.DerivationType = wx.ComboBox(self.Editor, size=wx.Size(200, -1), style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnDerivationTypeChanged, self.DerivationType) top_sizer.AddWindow(self.DerivationType, border=5, flag=wx.GROW | wx.RIGHT) typeinfos_staticbox = wx.StaticBox(self.Editor, label=_('Type infos:')) typeinfos_sizer = wx.StaticBoxSizer(typeinfos_staticbox, wx.HORIZONTAL) self.MainSizer.AddSizer(typeinfos_sizer, border=5, flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT) # Panel for Directly derived data types self.DirectlyPanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) typeinfos_sizer.AddWindow(self.DirectlyPanel, 1) directly_panel_sizer = wx.BoxSizer(wx.HORIZONTAL) directly_basetype_label = wx.StaticText(self.DirectlyPanel, label=_('Base Type:')) directly_panel_sizer.AddWindow(directly_basetype_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.DirectlyBaseType = wx.ComboBox(self.DirectlyPanel, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.DirectlyBaseType) directly_panel_sizer.AddWindow(self.DirectlyBaseType, 1, border=5, flag=wx.GROW | wx.ALL) directly_initialvalue_label = wx.StaticText(self.DirectlyPanel, label=_('Initial Value:')) directly_panel_sizer.AddWindow(directly_initialvalue_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.DirectlyInitialValue = wx.TextCtrl(self.DirectlyPanel, style=wx.TE_PROCESS_ENTER | wx.TE_RICH) self.Bind(wx.EVT_TEXT_ENTER, self.OnReturnKeyPressed, self.DirectlyInitialValue) directly_panel_sizer.AddWindow(self.DirectlyInitialValue, 1, border=5, flag=wx.ALL) self.DirectlyPanel.SetSizer(directly_panel_sizer) # Panel for Subrange data types self.SubrangePanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) typeinfos_sizer.AddWindow(self.SubrangePanel, 1) subrange_panel_sizer = wx.GridSizer(cols=4, hgap=5, rows=3, vgap=0) subrange_basetype_label = wx.StaticText(self.SubrangePanel, label=_('Base Type:')) subrange_panel_sizer.AddWindow(subrange_basetype_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.SubrangeBaseType = wx.ComboBox(self.SubrangePanel, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnSubrangeBaseTypeChanged, self.SubrangeBaseType) subrange_panel_sizer.AddWindow(self.SubrangeBaseType, 1, border=5, flag=wx.GROW | wx.ALL) subrange_initialvalue_label = wx.StaticText(self.SubrangePanel, label=_('Initial Value:')) subrange_panel_sizer.AddWindow(subrange_initialvalue_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.SubrangeInitialValue = wx.SpinCtrl(self.SubrangePanel, style=wx.TAB_TRAVERSAL) self.Bind(wx.EVT_SPINCTRL, self.OnInfosChanged, self.SubrangeInitialValue) subrange_panel_sizer.AddWindow(self.SubrangeInitialValue, 1, border=5, flag=wx.GROW | wx.ALL) subrange_minimum_label = wx.StaticText(self.SubrangePanel, label=_('Minimum:')) subrange_panel_sizer.AddWindow(subrange_minimum_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.SubrangeMinimum = wx.SpinCtrl(self.SubrangePanel, style=wx.TAB_TRAVERSAL) self.Bind(wx.EVT_SPINCTRL, self.OnSubrangeMinimumChanged, self.SubrangeMinimum) subrange_panel_sizer.AddWindow(self.SubrangeMinimum, 1, border=5, flag=wx.GROW | wx.ALL) for i in xrange(2): subrange_panel_sizer.AddWindow(wx.Size(0, 0), 1) subrange_maximum_label = wx.StaticText(self.SubrangePanel, label=_('Maximum:')) subrange_panel_sizer.AddWindow(subrange_maximum_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.SubrangeMaximum = wx.SpinCtrl(self.SubrangePanel, style=wx.TAB_TRAVERSAL) self.Bind(wx.EVT_SPINCTRL, self.OnSubrangeMaximumChanged, self.SubrangeMaximum) subrange_panel_sizer.AddWindow(self.SubrangeMaximum, 1, border=5, flag=wx.GROW | wx.ALL) self.SubrangePanel.SetSizer(subrange_panel_sizer) # Panel for Enumerated data types self.EnumeratedPanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) typeinfos_sizer.AddWindow(self.EnumeratedPanel, 1) enumerated_panel_sizer = wx.BoxSizer(wx.HORIZONTAL) self.EnumeratedValues = CustomEditableListBox( self.EnumeratedPanel, label=_("Values:"), style=(wx.gizmos.EL_ALLOW_NEW | wx.gizmos.EL_ALLOW_EDIT | wx.gizmos.EL_ALLOW_DELETE)) setattr(self.EnumeratedValues, "_OnLabelEndEdit", self.OnEnumeratedValueEndEdit) for func in [ "_OnAddButton", "_OnDelButton", "_OnUpButton", "_OnDownButton" ]: setattr(self.EnumeratedValues, func, self.OnEnumeratedValuesChanged) enumerated_panel_sizer.AddWindow(self.EnumeratedValues, 1, border=5, flag=wx.GROW | wx.ALL) enumerated_panel_rightsizer = wx.BoxSizer(wx.HORIZONTAL) enumerated_panel_sizer.AddSizer(enumerated_panel_rightsizer, 1) enumerated_initialvalue_label = wx.StaticText( self.EnumeratedPanel, label=_('Initial Value:')) enumerated_panel_rightsizer.AddWindow(enumerated_initialvalue_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.EnumeratedInitialValue = wx.ComboBox(self.EnumeratedPanel, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.EnumeratedInitialValue) enumerated_panel_rightsizer.AddWindow(self.EnumeratedInitialValue, 1, border=5, flag=wx.ALL) self.EnumeratedPanel.SetSizer(enumerated_panel_sizer) # Panel for Array data types self.ArrayPanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) typeinfos_sizer.AddWindow(self.ArrayPanel, 1) array_panel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=0) array_panel_sizer.AddGrowableCol(0) array_panel_sizer.AddGrowableCol(1) array_panel_sizer.AddGrowableRow(1) array_panel_leftSizer = wx.BoxSizer(wx.HORIZONTAL) array_panel_sizer.AddSizer(array_panel_leftSizer, flag=wx.GROW) array_basetype_label = wx.StaticText(self.ArrayPanel, label=_('Base Type:')) array_panel_leftSizer.AddWindow(array_basetype_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.ArrayBaseType = wx.ComboBox(self.ArrayPanel, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.ArrayBaseType) array_panel_leftSizer.AddWindow(self.ArrayBaseType, 1, border=5, flag=wx.GROW | wx.ALL) array_panel_rightsizer = wx.BoxSizer(wx.HORIZONTAL) array_panel_sizer.AddSizer(array_panel_rightsizer, flag=wx.GROW) array_initialvalue_label = wx.StaticText(self.ArrayPanel, label=_('Initial Value:')) array_panel_rightsizer.AddWindow(array_initialvalue_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.ArrayInitialValue = wx.TextCtrl(self.ArrayPanel, style=wx.TE_PROCESS_ENTER | wx.TE_RICH) self.Bind(wx.EVT_TEXT_ENTER, self.OnReturnKeyPressed, self.ArrayInitialValue) array_panel_rightsizer.AddWindow(self.ArrayInitialValue, 1, border=5, flag=wx.ALL) self.ArrayDimensions = CustomEditableListBox( self.ArrayPanel, label=_("Dimensions:"), style=(wx.gizmos.EL_ALLOW_NEW | wx.gizmos.EL_ALLOW_EDIT | wx.gizmos.EL_ALLOW_DELETE)) for func in [ "_OnLabelEndEdit", "_OnAddButton", "_OnDelButton", "_OnUpButton", "_OnDownButton" ]: setattr(self.ArrayDimensions, func, self.OnDimensionsChanged) array_panel_sizer.AddWindow(self.ArrayDimensions, 0, border=5, flag=wx.GROW | wx.ALL) self.ArrayPanel.SetSizer(array_panel_sizer) # Panel for Structure data types self.StructurePanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) typeinfos_sizer.AddWindow(self.StructurePanel, 1) structure_panel_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) structure_panel_sizer.AddGrowableCol(0) structure_panel_sizer.AddGrowableRow(1) structure_button_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) structure_button_sizer.AddGrowableCol(0) structure_button_sizer.AddGrowableRow(0) structure_panel_sizer.AddSizer(structure_button_sizer, 0, border=5, flag=wx.ALL | wx.GROW) structure_elements_label = wx.StaticText(self.StructurePanel, label=_('Elements :')) structure_button_sizer.AddWindow(structure_elements_label, flag=wx.ALIGN_BOTTOM) for name, bitmap, help in [ ("StructureAddButton", "add_element", _("Add element")), ("StructureDeleteButton", "remove_element", _("Remove element")), ("StructureUpButton", "up", _("Move element up")), ("StructureDownButton", "down", _("Move element down")) ]: button = wx.lib.buttons.GenBitmapButton(self.StructurePanel, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) button.SetToolTipString(help) setattr(self, name, button) structure_button_sizer.AddWindow(button) self.StructureElementsGrid = CustomGrid(self.StructurePanel, size=wx.Size(0, 150), style=wx.VSCROLL) self.StructureElementsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnStructureElementsGridCellChange) self.StructureElementsGrid.Bind( wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnStructureElementsGridEditorShown) structure_panel_sizer.AddWindow(self.StructureElementsGrid, flag=wx.GROW) self.StructurePanel.SetSizer(structure_panel_sizer) self.Editor.SetSizer(self.MainSizer) def __init__(self, parent, tagname, window, controler): EditorPanel.__init__(self, parent, tagname, window, controler) self.StructureElementDefaultValue = { "Name": "", "Type": DefaultType, "Initial Value": "" } self.StructureElementsTable = ElementsTable(self, [], GetElementsTableColnames()) self.StructureColSizes = [40, 150, 100, 250] self.StructureColAlignements = [ wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT ] self.StructureElementsGrid.SetTable(self.StructureElementsTable) self.StructureElementsGrid.SetButtons({ "Add": self.StructureAddButton, "Delete": self.StructureDeleteButton, "Up": self.StructureUpButton, "Down": self.StructureDownButton }) def _AddStructureElement(new_row): self.StructureElementsTable.InsertRow( new_row, self.StructureElementDefaultValue.copy()) self.RefreshTypeInfos() self.StructureElementsTable.ResetView(self.StructureElementsGrid) return new_row setattr(self.StructureElementsGrid, "_AddRow", _AddStructureElement) def _DeleteStructureElement(row): self.StructureElementsTable.RemoveRow(row) self.RefreshTypeInfos() self.StructureElementsTable.ResetView(self.StructureElementsGrid) setattr(self.StructureElementsGrid, "_DeleteRow", _DeleteStructureElement) def _MoveStructureElement(row, move): new_row = self.StructureElementsTable.MoveRow(row, move) if new_row != row: self.RefreshTypeInfos() self.StructureElementsTable.ResetView( self.StructureElementsGrid) return new_row setattr(self.StructureElementsGrid, "_MoveRow", _MoveStructureElement) self.StructureElementsGrid.SetRowLabelSize(0) for col in range(self.StructureElementsTable.GetNumberCols()): attr = wx.grid.GridCellAttr() attr.SetAlignment(self.StructureColAlignements[col], wx.ALIGN_CENTRE) self.StructureElementsGrid.SetColAttr(col, attr) self.StructureElementsGrid.SetColMinimalWidth( col, self.StructureColSizes[col]) self.StructureElementsGrid.AutoSizeColumn(col, False) self.StructureElementsGrid.RefreshButtons() for datatype in GetDatatypeTypes(): self.DerivationType.Append(_(datatype)) self.SubrangePanel.Hide() self.EnumeratedPanel.Hide() self.ArrayPanel.Hide() self.StructurePanel.Hide() self.CurrentPanel = "Directly" self.Highlights = [] self.Initializing = False self.HighlightControls = { ("Directly", "base"): self.DirectlyBaseType, ("Directly", "initial"): self.DirectlyInitialValue, ("Subrange", "base"): self.SubrangeBaseType, ("Subrange", "lower"): self.SubrangeMinimum, ("Subrange", "upper"): self.SubrangeMaximum, ("Subrange", "initial"): self.SubrangeInitialValue, ("Enumerated", "value"): self.EnumeratedValues, ("Enumerated", "initial"): self.EnumeratedInitialValue, ("Array", "initial"): self.ArrayInitialValue, ("Array", "base"): self.ArrayBaseType, ("Array", "range"): self.ArrayDimensions, } self.RefreshHighlightsTimer = wx.Timer(self, -1) self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) def __del__(self): self.RefreshHighlightsTimer.Stop() def GetBufferState(self): return self.Controler.GetBufferState() def Undo(self): self.Controler.LoadPrevious() self.ParentWindow.CloseTabsWithoutModel() def Redo(self): self.Controler.LoadNext() self.ParentWindow.CloseTabsWithoutModel() def HasNoModel(self): return self.Controler.GetEditedElement(self.TagName) is None def RefreshView(self): self.Initializing = True self.DirectlyBaseType.Clear() self.ArrayBaseType.Clear() for datatype in self.Controler.GetDataTypes(self.TagName): self.DirectlyBaseType.Append(datatype) self.ArrayBaseType.Append(datatype) self.DirectlyBaseType.SetSelection(0) self.SubrangeBaseType.Clear() words = self.TagName.split("::") for base_type in self.Controler.GetSubrangeBaseTypes(words[1]): self.SubrangeBaseType.Append(base_type) self.SubrangeBaseType.SetSelection(0) self.RefreshBoundsRange() type_infos = self.Controler.GetDataTypeInfos(self.TagName) if type_infos is not None: datatype = type_infos["type"] self.DerivationType.SetStringSelection(_(datatype)) if type_infos["type"] == "Directly": self.DirectlyBaseType.SetStringSelection( type_infos["base_type"]) self.DirectlyInitialValue.SetValue(type_infos["initial"]) elif type_infos["type"] == "Subrange": self.SubrangeBaseType.SetStringSelection( type_infos["base_type"]) self.RefreshBoundsRange() self.SubrangeMinimum.SetValue(int(type_infos["min"])) self.SubrangeMaximum.SetValue(int(type_infos["max"])) self.RefreshSubrangeInitialValueRange() if type_infos["initial"] != "": self.SubrangeInitialValue.SetValue( int(type_infos["initial"])) else: self.SubrangeInitialValue.SetValue(type_infos["min"]) elif type_infos["type"] == "Enumerated": self.EnumeratedValues.SetStrings(type_infos["values"]) self.RefreshEnumeratedValues() self.EnumeratedInitialValue.SetStringSelection( type_infos["initial"]) elif type_infos["type"] == "Array": self.ArrayBaseType.SetStringSelection(type_infos["base_type"]) self.ArrayDimensions.SetStrings( map(lambda x: "..".join(x), type_infos["dimensions"])) self.ArrayInitialValue.SetValue(type_infos["initial"]) elif type_infos["type"] == "Structure": self.StructureElementsTable.SetData(type_infos["elements"]) self.RefreshDisplayedInfos() self.ShowHighlights() self.StructureElementsTable.ResetView(self.StructureElementsGrid) self.StructureElementsGrid.RefreshButtons() self.Initializing = False def OnDerivationTypeChanged(self, event): wx.CallAfter(self.RefreshDisplayedInfos) wx.CallAfter(self.RefreshTypeInfos) event.Skip() def OnReturnKeyPressed(self, event): self.RefreshTypeInfos() def OnInfosChanged(self, event): self.RefreshTypeInfos() event.Skip() def OnSubrangeBaseTypeChanged(self, event): self.RefreshBoundsRange() self.RefreshTypeInfos() event.Skip() def OnSubrangeMinimumChanged(self, event): if not self.Initializing: wx.CallAfter( self.SubrangeMinimum.SetValue, min(self.SubrangeMaximum.GetValue(), self.SubrangeMinimum.GetValue())) wx.CallAfter(self.RefreshSubrangeInitialValueRange) wx.CallAfter(self.RefreshTypeInfos) event.Skip() def OnSubrangeMaximumChanged(self, event): if not self.Initializing: wx.CallAfter( self.SubrangeMaximum.SetValue, max(self.SubrangeMinimum.GetValue(), self.SubrangeMaximum.GetValue())) wx.CallAfter(self.RefreshSubrangeInitialValueRange) wx.CallAfter(self.RefreshTypeInfos) event.Skip() def OnDimensionsChanged(self, event): wx.CallAfter(self.RefreshTypeInfos) event.Skip() def OnEnumeratedValueEndEdit(self, event): text = event.GetText() values = self.EnumeratedValues.GetStrings() index = event.GetIndex() if index >= len(values) or values[index].upper() != text.upper(): if text.upper() in [value.upper() for value in values]: message = wx.MessageDialog( self, _("\"%s\" value already defined!") % text, _("Error"), wx.OK | wx.ICON_ERROR) message.ShowModal() message.Destroy() event.Veto() elif text.upper() in IEC_KEYWORDS: message = wx.MessageDialog( self, _("\"%s\" is a keyword. It can't be used!") % text, _("Error"), wx.OK | wx.ICON_ERROR) message.ShowModal() message.Destroy() else: initial_selected = None if index < len( values ) and self.EnumeratedInitialValue.GetStringSelection( ) == values[index]: initial_selected = text wx.CallAfter(self.RefreshEnumeratedValues, initial_selected) wx.CallAfter(self.RefreshTypeInfos) event.Skip() else: event.Skip() def OnEnumeratedValuesChanged(self, event): wx.CallAfter(self.RefreshEnumeratedValues) wx.CallAfter(self.RefreshTypeInfos) event.Skip() def ShowErrorMessage(self, message): dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() def OnStructureElementsGridCellChange(self, event): row, col = event.GetRow(), event.GetCol() colname = self.StructureElementsTable.GetColLabelValue(col, False) value = self.StructureElementsTable.GetValue(row, col) if colname == "Name": message = None if not TestIdentifier(value): message = _("\"%s\" is not a valid identifier!") % value elif value.upper() in IEC_KEYWORDS: message = _("\"%s\" is a keyword. It can't be used!") % value # elif value.upper() in self.PouNames: # message = _("A pou with \"%s\" as name exists!")%value elif value.upper() in [ var["Name"].upper() for idx, var in enumerate( self.StructureElementsTable.GetData()) if idx != row ]: message = _( "An element named \"%s\" already exists in this structure!" ) % value else: self.RefreshTypeInfos() wx.CallAfter(self.StructureElementsTable.ResetView, self.StructureElementsGrid) # old_value = self.Table.GetOldValue() # if old_value != "": # self.Controler.UpdateEditedElementUsedVariable(self.TagName, old_value, value) # self.Controler.BufferProject() event.Skip() if message is not None: event.Veto() wx.CallAfter(self.ShowErrorMessage, message) else: self.RefreshTypeInfos() wx.CallAfter(self.StructureElementsTable.ResetView, self.StructureElementsGrid) event.Skip() def OnStructureElementsGridSelectCell(self, event): wx.CallAfter(self.RefreshStructureButtons) event.Skip() def OnStructureElementsGridEditorShown(self, event): row, col = event.GetRow(), event.GetCol() if self.StructureElementsTable.GetColLabelValue(col, False) == "Type": type_menu = wx.Menu(title='') base_menu = wx.Menu(title='') for base_type in self.Controler.GetBaseTypes(): new_id = wx.NewId() AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type) self.Bind(wx.EVT_MENU, self.GetElementTypeFunction(base_type), id=new_id) type_menu.AppendMenu(wx.NewId(), _("Base Types"), base_menu) datatype_menu = wx.Menu(title='') for datatype in self.Controler.GetDataTypes(self.TagName, False): new_id = wx.NewId() AppendMenu(datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype) self.Bind(wx.EVT_MENU, self.GetElementTypeFunction(datatype), id=new_id) type_menu.AppendMenu(wx.NewId(), _("User Data Types"), datatype_menu) new_id = wx.NewId() AppendMenu(type_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Array")) self.Bind(wx.EVT_MENU, self.ElementArrayTypeFunction, id=new_id) # functionblock_menu = wx.Menu(title='') # bodytype = self.Controler.GetEditedElementBodyType(self.TagName) # pouname, poutype = self.Controler.GetEditedElementType(self.TagName) # if classtype in ["Input","Output","InOut","External","Global"] or poutype != "function" and bodytype in ["ST", "IL"]: # for functionblock_type in self.Controler.GetFunctionBlockTypes(self.TagName): # 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.StructureElementsGrid.BlockToDeviceRect((row, col), (row, col)) self.StructureElementsGrid.PopupMenuXY( type_menu, rect.x + rect.width, rect.y + self.StructureElementsGrid.GetColLabelSize()) type_menu.Destroy() event.Veto() else: event.Skip() def GetElementTypeFunction(self, base_type): def ElementTypeFunction(event): row = self.StructureElementsGrid.GetGridCursorRow() self.StructureElementsTable.SetValueByName(row, "Type", base_type) self.RefreshTypeInfos() self.StructureElementsTable.ResetView(self.StructureElementsGrid) return ElementTypeFunction def ElementArrayTypeFunction(self, event): row = self.StructureElementsGrid.GetGridCursorRow() dialog = ArrayTypeDialog( self, self.Controler.GetDataTypes(self.TagName), self.StructureElementsTable.GetValueByName(row, "Type")) if dialog.ShowModal() == wx.ID_OK: self.StructureElementsTable.SetValueByName(row, "Type", dialog.GetValue()) self.RefreshTypeInfos() self.StructureElementsTable.ResetView(self.StructureElementsGrid) dialog.Destroy() def RefreshDisplayedInfos(self): selected = DATATYPE_TYPES_DICT[ self.DerivationType.GetStringSelection()] if selected != self.CurrentPanel: if self.CurrentPanel == "Directly": self.DirectlyPanel.Hide() elif self.CurrentPanel == "Subrange": self.SubrangePanel.Hide() elif self.CurrentPanel == "Enumerated": self.EnumeratedPanel.Hide() elif self.CurrentPanel == "Array": self.ArrayPanel.Hide() elif self.CurrentPanel == "Structure": self.StructurePanel.Hide() self.CurrentPanel = selected if selected == "Directly": self.DirectlyPanel.Show() elif selected == "Subrange": self.SubrangePanel.Show() elif selected == "Enumerated": self.EnumeratedPanel.Show() elif selected == "Array": self.ArrayPanel.Show() elif selected == "Structure": self.StructurePanel.Show() self.MainSizer.Layout() def RefreshEnumeratedValues(self, initial_selected=None): if initial_selected is None: initial_selected = self.EnumeratedInitialValue.GetStringSelection() self.EnumeratedInitialValue.Clear() self.EnumeratedInitialValue.Append("") for value in self.EnumeratedValues.GetStrings(): self.EnumeratedInitialValue.Append(value) self.EnumeratedInitialValue.SetStringSelection(initial_selected) def RefreshBoundsRange(self): range = self.Controler.GetDataTypeRange( self.SubrangeBaseType.GetStringSelection()) if range is not None: min_value, max_value = range self.SubrangeMinimum.SetRange(min_value, max_value) self.SubrangeMinimum.SetValue( min(max(min_value, self.SubrangeMinimum.GetValue()), max_value)) self.SubrangeMaximum.SetRange(min_value, max_value) self.SubrangeMaximum.SetValue( min(max(min_value, self.SubrangeMaximum.GetValue()), max_value)) def RefreshSubrangeInitialValueRange(self): self.SubrangeInitialValue.SetRange(self.SubrangeMinimum.GetValue(), self.SubrangeMaximum.GetValue()) def RefreshTypeInfos(self): selected = DATATYPE_TYPES_DICT[ self.DerivationType.GetStringSelection()] infos = {"type": selected} if selected == "Directly": infos["base_type"] = self.DirectlyBaseType.GetStringSelection() infos["initial"] = self.DirectlyInitialValue.GetValue() elif selected == "Subrange": infos["base_type"] = self.SubrangeBaseType.GetStringSelection() infos["min"] = str(self.SubrangeMinimum.GetValue()) infos["max"] = str(self.SubrangeMaximum.GetValue()) initial_value = self.SubrangeInitialValue.GetValue() if initial_value == infos["min"]: infos["initial"] = "" else: infos["initial"] = str(initial_value) elif selected == "Enumerated": infos["values"] = self.EnumeratedValues.GetStrings() infos["initial"] = self.EnumeratedInitialValue.GetStringSelection() elif selected == "Array": infos["base_type"] = self.ArrayBaseType.GetStringSelection() infos["dimensions"] = [] for dimensions in self.ArrayDimensions.GetStrings(): result = DIMENSION_MODEL.match(dimensions) if result is None: message = wx.MessageDialog( self, _("\"%s\" value isn't a valid array dimension!") % dimensions, _("Error"), wx.OK | wx.ICON_ERROR) message.ShowModal() message.Destroy() self.RefreshView() return bounds = result.groups() if int(bounds[0]) >= int(bounds[1]): message = wx.MessageDialog( self, _("\"%s\" value isn't a valid array dimension!\nRight value must be greater than left value." ) % dimensions, _("Error"), wx.OK | wx.ICON_ERROR) message.ShowModal() message.Destroy() self.RefreshView() return infos["dimensions"].append(bounds) infos["initial"] = self.ArrayInitialValue.GetValue() elif selected == "Structure": infos["elements"] = self.StructureElementsTable.GetData() infos["initial"] = "" self.Controler.SetDataTypeInfos(self.TagName, infos) self.ParentWindow.RefreshTitle() self.ParentWindow.RefreshFileMenu() self.ParentWindow.RefreshEditMenu() # ------------------------------------------------------------------------------- # Highlights showing functions # ------------------------------------------------------------------------------- def OnRefreshHighlightsTimer(self, event): self.RefreshView() event.Skip() def ClearHighlights(self, highlight_type=None): if highlight_type is None: self.Highlights = [] else: self.Highlights = [(infos, start, end, highlight) for (infos, start, end, highlight) in self.Highlights if highlight != highlight_type] for control in self.HighlightControls.itervalues(): if isinstance(control, (wx.ComboBox, wx.SpinCtrl)): control.SetBackgroundColour(wx.NullColour) control.SetForegroundColour(wx.NullColour) elif isinstance(control, wx.TextCtrl): value = control.GetValue() control.SetStyle(0, len(value), wx.TextAttr(wx.NullColour)) elif isinstance(control, wx.gizmos.EditableListBox): listctrl = control.GetListCtrl() for i in xrange(listctrl.GetItemCount()): listctrl.SetItemBackgroundColour(i, wx.NullColour) listctrl.SetItemTextColour(i, wx.NullColour) self.StructureElementsTable.ClearHighlights(highlight_type) self.RefreshView() def AddHighlight(self, infos, start, end, highlight_type): self.Highlights.append((infos, start, end, highlight_type)) self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) def ShowHighlights(self): type_infos = self.Controler.GetDataTypeInfos(self.TagName) for infos, start, end, highlight_type in self.Highlights: if infos[0] == "struct": self.StructureElementsTable.AddHighlight( infos[1:], highlight_type) else: control = self.HighlightControls.get( (type_infos["type"], infos[0]), None) if control is not None: if isinstance(control, (wx.ComboBox, wx.SpinCtrl)): control.SetBackgroundColour(highlight_type[0]) control.SetForegroundColour(highlight_type[1]) elif isinstance(control, wx.TextCtrl): control.SetStyle( start[1], end[1] + 1, wx.TextAttr(highlight_type[1], highlight_type[0])) elif isinstance(control, wx.gizmos.EditableListBox): listctrl = control.GetListCtrl() listctrl.SetItemBackgroundColour( infos[1], highlight_type[0]) listctrl.SetItemTextColour(infos[1], highlight_type[1]) listctrl.Select(listctrl.FocusedItem, False)
class ActionBlockDialog(wx.Dialog): def __init__(self, parent): wx.Dialog.__init__(self, parent, title=_('Edit action block properties')) main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(1) top_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) top_sizer.AddGrowableCol(0) top_sizer.AddGrowableRow(0) main_sizer.AddSizer(top_sizer, border=20, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) actions_label = wx.StaticText(self, label=_('Actions:')) top_sizer.AddWindow(actions_label, flag=wx.ALIGN_BOTTOM) for name, bitmap, help in [ ("AddButton", "add_element", _("Add action")), ("DeleteButton", "remove_element", _("Remove action")), ("UpButton", "up", _("Move action up")), ("DownButton", "down", _("Move action down")) ]: button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) button.SetToolTipString(help) setattr(self, name, button) top_sizer.AddWindow(button) self.ActionsGrid = CustomGrid(self, size=wx.Size(-1, 250), style=wx.VSCROLL) self.ActionsGrid.DisableDragGridSize() self.ActionsGrid.EnableScrolling(False, True) self.ActionsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnActionsGridCellChange) main_sizer.AddSizer(self.ActionsGrid, border=20, flag=wx.GROW | wx.LEFT | wx.RIGHT) button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE) self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) main_sizer.AddSizer(button_sizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) self.SetSizer(main_sizer) self.Table = ActionTable(self, [], GetActionTableColnames()) typelist = GetTypeList() self.TypeList = ",".join(map(_, typelist)) self.TranslateType = dict([(_(value), value) for value in typelist]) self.ColSizes = [60, 90, 130, 200, 50] self.ColAlignements = [ wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT ] self.ActionsGrid.SetTable(self.Table) self.ActionsGrid.SetDefaultValue( _ActionInfos("N", "Action", "", "", "")) self.ActionsGrid.SetButtons({ "Add": self.AddButton, "Delete": self.DeleteButton, "Up": self.UpButton, "Down": self.DownButton }) self.ActionsGrid.SetRowLabelSize(0) for col in range(self.Table.GetNumberCols()): attr = wx.grid.GridCellAttr() attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE) self.ActionsGrid.SetColAttr(col, attr) self.ActionsGrid.SetColMinimalWidth(col, self.ColSizes[col]) self.ActionsGrid.AutoSizeColumn(col, False) self.Table.ResetView(self.ActionsGrid) self.ActionsGrid.SetFocus() self.ActionsGrid.RefreshButtons() self.Fit() def OnOK(self, event): self.ActionsGrid.CloseEditControl() self.EndModal(wx.ID_OK) def OnActionsGridCellChange(self, event): wx.CallAfter(self.Table.ResetView, self.ActionsGrid) event.Skip() def SetQualifierList(self, list): self.QualifierList = ",".join(list) self.DurationList = list def SetVariableList(self, list): self.VariableList = "," + ",".join( [variable.Name for variable in list]) def SetActionList(self, list): self.ActionList = "," + ",".join(list) def SetValues(self, actions): for action in actions: row = action.copy() if row.type == "reference" and row.value in self.ActionList: row.type = "Action" elif row.type == "reference" and row.value in self.VariableList: row.type = "Variable" else: row.type = "Inline" self.Table.AppendRow(row) self.Table.ResetView(self.ActionsGrid) if len(actions) > 0: self.ActionsGrid.SetGridCursor(0, 0) self.ActionsGrid.RefreshButtons() def GetValues(self): actions = self.Table.GetData() for action in actions: if action.type in ["Action", "Variable"]: action.type = "reference" else: action.type = "inline" return actions
class VariablesEditor(wx.Panel): def __init__(self, parent, window, controler): wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL) main_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=4) main_sizer.AddGrowableCol(1) main_sizer.AddGrowableRow(0) controls_sizer = wx.BoxSizer(wx.VERTICAL) main_sizer.AddSizer(controls_sizer, border=5, flag=wx.ALL) for name, bitmap, help in [ ("AddVariableButton", "add_element", _("Add variable")), ("DeleteVariableButton", "remove_element", _("Remove variable")), ("UpVariableButton", "up", _("Move variable up")), ("DownVariableButton", "down", _("Move variable down")) ]: button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) button.SetToolTipString(help) setattr(self, name, button) controls_sizer.AddWindow(button, border=5, flag=wx.BOTTOM) self.VariablesGrid = CustomGrid(self, style=wx.VSCROLL) self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange) self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) main_sizer.AddWindow(self.VariablesGrid, flag=wx.GROW) self.SetSizer(main_sizer) self.ParentWindow = window self.Controler = controler self.VariablesDefaultValue = { "Name": "LocalVar0", "Type": DefaultType, "Initial": "", "Description": "", "OnChange": "", "Options": "" } self.Table = VariablesTable(self, [], self.GetVariableTableColnames()) self.ColAlignements = [wx.ALIGN_RIGHT] + \ [wx.ALIGN_LEFT]*(len(self.VariablesDefaultValue)) self.ColSizes = [20, 150 ] + [130] * (len(self.VariablesDefaultValue) - 1) self.VariablesGrid.SetTable(self.Table) self.VariablesGrid.SetButtons({ "Add": self.AddVariableButton, "Delete": self.DeleteVariableButton, "Up": self.UpVariableButton, "Down": self.DownVariableButton }) def _AddVariable(new_row): if new_row > 0: row_content = self.Table.data[new_row - 1].copy() old_name = row_content['Name'] row_content['Name'] =\ self.Controler.GenerateNewName(old_name, old_name+'%d') else: row_content = self.VariablesDefaultValue.copy() self.Table.InsertRow(new_row, row_content) self.RefreshModel() self.RefreshView() return new_row setattr(self.VariablesGrid, "_AddRow", _AddVariable) def _DeleteVariable(row): self.Table.RemoveRow(row) self.RefreshModel() self.RefreshView() setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) def _MoveVariable(row, move): new_row = self.Table.MoveRow(row, move) if new_row != row: self.RefreshModel() self.RefreshView() return new_row setattr(self.VariablesGrid, "_MoveRow", _MoveVariable) self.VariablesGrid.SetRowLabelSize(0) for col in range(self.Table.GetNumberCols()): attr = wx.grid.GridCellAttr() attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE) self.VariablesGrid.SetColAttr(col, attr) self.VariablesGrid.SetColSize(col, self.ColSizes[col]) self.Table.ResetView(self.VariablesGrid) def GetVariableTableColnames(self): _ = NoTranslate return [ "#", _("Name"), _("Type"), _("Initial"), _("Description"), _("OnChange"), _("Options") ] def RefreshModel(self): self.Controler.SetVariables(self.Table.GetData()) self.RefreshBuffer() # Buffer the last model state def RefreshBuffer(self): self.Controler.BufferCodeFile() self.ParentWindow.RefreshTitle() self.ParentWindow.RefreshFileMenu() self.ParentWindow.RefreshEditMenu() self.ParentWindow.RefreshPageTitles() def RefreshView(self): self.Table.SetData(self.Controler.GetVariables()) self.Table.ResetView(self.VariablesGrid) self.VariablesGrid.RefreshButtons() def DoGetBestSize(self): return self.ParentWindow.GetPanelBestSize() def ShowErrorMessage(self, message): dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() def OnVariablesGridCellChange(self, event): row, col = event.GetRow(), event.GetCol() colname = self.Table.GetColLabelValue(col, False) value = self.Table.GetValue(row, col) message = None if colname == "Name" and value != "": if not TestIdentifier(value): message = _("\"%s\" is not a valid identifier!") % value elif value.upper() in IEC_KEYWORDS: message = _("\"%s\" is a keyword. It can't be used!") % value elif value.upper() in [ var["Name"].upper() for var_row, var in enumerate(self.Table.data) if var_row != row ]: message = _( "A variable with \"%s\" as name already exists!") % value else: self.RefreshModel() wx.CallAfter(self.RefreshView) else: self.RefreshModel() wx.CallAfter(self.RefreshView) if message is not None: event.Veto() wx.CallAfter(self.ShowErrorMessage, message) else: event.Skip() def OnVariablesGridEditorShown(self, event): row, col = event.GetRow(), event.GetCol() if self.Table.GetColLabelValue(col, False) == "Type": type_menu = wx.Menu(title='') base_menu = wx.Menu(title='') for base_type in self.Controler.GetBaseTypes(): new_id = wx.NewId() base_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type) self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), id=new_id) type_menu.AppendMenu(wx.NewId(), "Base Types", base_menu) datatype_menu = wx.Menu(title='') for datatype in self.Controler.GetDataTypes(): new_id = wx.NewId() datatype_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype) self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id) type_menu.AppendMenu(wx.NewId(), "User Data Types", datatype_menu) rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col)) self.VariablesGrid.PopupMenuXY( type_menu, rect.x + rect.width, rect.y + self.VariablesGrid.GetColLabelSize()) type_menu.Destroy() event.Veto() 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.RefreshModel() self.RefreshView() event.Skip() return VariableTypeFunction def OnVariablesGridCellLeftClick(self, event): if event.GetCol() == 0: row = event.GetRow() data_type = self.Table.GetValueByName(row, "Type") var_name = self.Table.GetValueByName(row, "Name") data = wx.TextDataObject( str((var_name, "Global", data_type, self.Controler.GetCurrentLocation()))) dragSource = wx.DropSource(self.VariablesGrid) dragSource.SetData(data) dragSource.DoDragDrop() return event.Skip()
class MBRequestDataPanel(wx.Panel): def __init__(self, parent, window, controler): wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL) """ main sizer """ requestPanelSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=4) requestPanelSizer.AddGrowableCol(1) requestPanelSizer.AddGrowableRow(0) """ sizer with control buttons """ controls_sizer = wx.BoxSizer(wx.VERTICAL) requestPanelSizer.AddSizer(controls_sizer, border=5, flag=wx.ALL) for name, bitmap, help in [ ("AddVariableButton", "add_element", _("Add variable")), ("DeleteVariableButton", "remove_element", _("Remove variable")), ("UpVariableButton", "up", _("Move variable up")), ("DownVariableButton", "down", _("Move variable down")) ]: button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) button.SetToolTipString(help) setattr(self, name, button) controls_sizer.AddWindow(button, border=5, flag=wx.BOTTOM) """ variable grid """ self.VariablesGrid = CustomGrid(self, style=wx.VSCROLL) self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange) self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) requestPanelSizer.AddWindow(self.VariablesGrid, flag=wx.GROW) """ add header to grid """ mainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=4) mainSizer.AddGrowableRow(1) mainSizer.AddGrowableCol(0) headerSizer = wx.BoxSizer(wx.HORIZONTAL) label = wx.StaticText(self, label=" Request data") font = wx.Font(14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) label.SetFont(font) headerSizer.Add(label) self.masterSelectCmbx = ComboBoxWithLabel( self, "", ("Master0", "Master1", "Master2")) wx.EVT_COMBOBOX(self, self.masterSelectCmbx.cmbbox.GetId(), self.OnChangeMasterOption) headerSizer.Add(self.masterSelectCmbx, flag=wx.ALIGN_CENTER_VERTICAL) mainSizer.AddSizer(headerSizer, flag=wx.GROW) mainSizer.AddSizer(requestPanelSizer, flag=wx.GROW) self.SetSizer(mainSizer) self.ParentWindow = window self.Controler = controler """ request defaule data value """ self.VariablesDefaultValue = { "Name": "", "Address": "1", "Len": "1", "Data type": "WORD", "Modbus type": HOLDING_REGISTER_READ, "Description": DESCRIPTION, "Device ID": "1", "Transfer method": "Periodic", "Period (ms)": "100", "Timeout (ms)": "100", } self.Table = MBRequestDataTable(self) self.ColAlignements = [wx.ALIGN_RIGHT] + \ [wx.ALIGN_LEFT]*(len(self.VariablesDefaultValue)) self.ColSizes = [20, 150 ] + [100] * (len(self.VariablesDefaultValue) - 1) self.VariablesGrid.SetTable(self.Table) self.VariablesGrid.SetButtons({ "Add": self.AddVariableButton, "Delete": self.DeleteVariableButton, "Up": self.UpVariableButton, "Down": self.DownVariableButton }) """ handlers for adding variable """ def _AddVariable(new_row): if new_row > 0: row_content = self.Table.data[new_row - 1].copy() newAddr = int(row_content["Address"]) newLen = int(row_content["Len"]) if row_content["Data type"] in ("REAL", "INT"): newLen = newLen * 2 newAddr = newAddr + newLen row_content["Address"] = str(newAddr) result = VARIABLE_NAME_SUFFIX_MODEL.search(row_content["Name"]) if result is not None: name = row_content["Name"][:result.start(1)] suffix = result.group(1) if suffix != "": start_idx = int(suffix) else: start_idx = 0 else: name = row_content["Name"] start_idx = 0 row_content["Name"] = self.Controler.GenerateNewName( name + "%d", start_idx) else: row_content = self.VariablesDefaultValue.copy() self.Table.InsertRow(new_row, row_content) self.RefreshModel() self.RefreshView() return new_row setattr(self.VariablesGrid, "_AddRow", _AddVariable) """ handlers for deleting variable """ def _DeleteVariable(row): self.Table.RemoveRow(row) self.RefreshModel() self.RefreshView() setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) """ handlers for moving varible """ def _MoveVariable(row, move): new_row = self.Table.MoveRow(row, move) if new_row != row: self.RefreshModel() self.RefreshView() return new_row setattr(self.VariablesGrid, "_MoveRow", _MoveVariable) self.VariablesGrid.SetRowLabelSize(0) for col in range(self.Table.GetNumberCols()): attr = wx.grid.GridCellAttr() attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE) self.VariablesGrid.SetColAttr(col, attr) self.VariablesGrid.SetColSize(col, self.ColSizes[col]) self.Table.ResetView(self.VariablesGrid) def OnChangeMasterOption(self, event): masterOptionOnFrame = self.masterSelectCmbx.cmbbox.GetStringSelection() masterOptionInXml = [ i for i in self.Controler.GetVariables() if i["Name"] == MASTER_OPTION ] if len(masterOptionInXml) > 0: if masterOptionOnFrame != masterOptionInXml[0]: self.RefreshModel() else: self.RefreshModel() event.Skip() def GetMasterOption(self): return { "Name": "Master option", "Address": "", "Len": "", "Device ID": "", "Data type": u"WORD", "Transfer method": "", "Period (ms)": "100", "Timeout (ms)": "100", "Description": MASTER_OPTION, "Modbus type": self.masterSelectCmbx.cmbbox.GetStringSelection() } def RefreshModel(self): controllerVariables = self.Controler.GetVariables() controllerVariables = [ i for i in controllerVariables if i["Description"] not in (DESCRIPTION, MASTER_OPTION) ] controllerVariables += self.Table.GetData() controllerVariables.append(self.GetMasterOption()) self.Controler.SetVariables(controllerVariables) self.RefreshBuffer() def RefreshView(self): varForTable = self.Controler.GetVariables() varForTable = [ i for i in varForTable if i["Description"] == DESCRIPTION ] self.Table.SetData(varForTable) self.Table.ResetView(self.VariablesGrid) varForTable = self.Controler.GetVariables() varForTable = [i for i in varForTable if i["Name"] == MASTER_OPTION] if len(varForTable) > 0: self.masterSelectCmbx.cmbbox.SetStringSelection( varForTable[0]["Modbus type"]) self.VariablesGrid.RefreshButtons() def OnVariablesGridCellChange(self, event): row, col = event.GetRow(), event.GetCol() colname = self.Table.GetColLabelValue(col, False) value = self.Table.GetValue(row, col) message = None if colname == "Modbus type": self.VariablesGrid.SetCellValue(row, col + 1, "WORD") if colname == "Len": modbusType = self.Table.GetValue(row, 4) # Modubs type value if modbusType in (HOLDING_REGISTER_READ, INPUT_REGISTER_READ): if int(value) > MAX_SIMULTANEOUS_REGISTERS_READ: value = MAX_SIMULTANEOUS_REGISTERS_READ self.VariablesGrid.SetCellValue( row, col, str(MAX_SIMULTANEOUS_REGISTERS_READ)) if modbusType == HOLDING_REGISTER_WRITE: if int(value) > MAX_SIMULTANEOUS_REGISTERS_WRITE: self.VariablesGrid.SetCellValue( row, col, str(MAX_SIMULTANEOUS_REGISTERS_WRITE)) if modbusType in (COIL_READ, DISCRETE_INPUT_READ): if int(value) > MAX_SIMULTANEOUS_COIL_DISC_READ: self.VariablesGrid.SetCellValue( row, col, str(MAX_SIMULTANEOUS_COIL_DISC_READ)) if modbusType == COIL_WRITE: if int(value) > MAX_SIMULTANEOUS_COIL_WRITE: self.VariablesGrid.SetCellValue( row, col, str(MAX_SIMULTANEOUS_COIL_WRITE)) if colname == "Name" and value != "": if not TestIdentifier(value): message = _("\"%s\" is not a valid identifier!") % value elif value.upper() in IEC_KEYWORDS: message = _("\"%s\" is a keyword. It can't be used!") % value elif value.upper() in [ var["Name"].upper() for var_row, var in enumerate(self.Table.data) if var_row != row ]: message = _( "A variable with \"%s\" as name already exists!") % value else: self.RefreshModel() wx.CallAfter(self.RefreshView) else: self.RefreshModel() wx.CallAfter(self.RefreshView) if message is not None: dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() event.Veto() else: event.Skip() def DoGetBestSize(self): return self.ParentWindow.GetPanelBestSize() def OnVariablesGridEditorShown(self, event): event.Skip() def GetVariableTypeFunction(self, base_type): def VariableTypeFunction(event): row = self.VariablesGrid.GetGridCursorRow() self.Table.SetValueByName(row, "Data type", base_type) self.Table.ResetView(self.VariablesGrid) self.RefreshModel() self.RefreshView() event.Skip() return VariableTypeFunction def OnVariablesGridCellLeftClick(self, event): if event.GetCol() == 0: row = event.GetRow() data_type = self.Table.GetValueByName(row, "Data type") var_name = self.Table.GetValueByName(row, "Name") data = wx.TextDataObject( str((var_name, "Global", data_type, self.Controler.GetCurrentLocation()))) dragSource = wx.DropSource(self.VariablesGrid) dragSource.SetData(data) dragSource.DoDragDrop() return event.Skip() def RefreshBuffer(self): self.Controler.BufferCodeFile() self.ParentWindow.RefreshTitle() self.ParentWindow.RefreshFileMenu() self.ParentWindow.RefreshEditMenu() self.ParentWindow.RefreshPageTitles()
class RequestTablePanel(wx.Panel): def __init__(self, parent, window, controler): wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL) """ main sizer """ requestPanelSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=4) requestPanelSizer.AddGrowableCol(1) requestPanelSizer.AddGrowableRow(0) """ sizer with control buttons """ controls_sizer = wx.BoxSizer(wx.VERTICAL) requestPanelSizer.AddSizer(controls_sizer, border=5, flag=wx.ALL) for name, bitmap, help in [ ("AddVariableButton", "add_element", _("Add variable")), ("DeleteVariableButton", "remove_element", _("Remove variable")), ("UpVariableButton", "up", _("Move variable up")), ("DownVariableButton", "down", _("Move variable down")) ]: button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) button.SetToolTipString(help) setattr(self, name, button) controls_sizer.AddWindow(button, border=5, flag=wx.BOTTOM) """ variable grid """ self.VariablesGrid = CustomGrid(self, style=wx.VSCROLL) self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange) self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) requestPanelSizer.AddWindow(self.VariablesGrid, flag=wx.GROW) """ add header to grid """ mainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=4) mainSizer.AddGrowableRow(1) mainSizer.AddGrowableCol(0) headerSizer = wx.BoxSizer(wx.HORIZONTAL) self.ipAddressDefault = { "Name": "ipAddres", "Address": "10.10.10.10", "Device ID": "", "Data type": "", "Transfer method": "", "Len": "1", "Modbus type": "", "Device ID": "1", "Period (ms)": "100", "Description": DESCRIPTION_IP, } self.portDefault = { "Name": "port", "Address": "502", "Device ID": "", "Data type": "", "Transfer method": "", "Len": "1", "Modbus type": "", "Device ID": "1", "Period (ms)": "100", "Description": DESCRIPTION_PORT } # виджеты для текста IP (label) labelIP = wx.StaticText(self, label=" Ip address: ") font = wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) labelIP.SetFont(font) headerSizer.Add(labelIP) """ поле для IP """ self.ip_address = IpAddrCtrl(self, size=(120, 22)) wx.EVT_TEXT(self, self.ip_address.GetId(), self.OnChangeIp) """ wx.EVT_COMBOBOX(self, self.masterSelectCmbx.cmbbox.GetId(), self.OnChangeMasterOption) """ headerSizer.Add(self.ip_address, flag=wx.ALIGN_CENTER_VERTICAL) """ виджеты для текста порта (label) """ labelPort = wx.StaticText(self, label=" Port: ") font = wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) labelPort.SetFont(font) headerSizer.Add(labelPort) """ поле для порта """ self.port = IntCtrl(self, min=0, max=65535, limited=True, size=(70, 21)) wx.EVT_TEXT(self, self.port.GetId(), self.OnChangePort) wx.EVT_TEXT(self, self.port.GetId(), self.OnChangePort) headerSizer.Add(self.port, flag=wx.ALIGN_CENTER_VERTICAL) mainSizer.AddSizer(headerSizer, flag=wx.GROW) mainSizer.AddSizer(requestPanelSizer, flag=wx.GROW) self.SetSizer(mainSizer) self.ParentWindow = window self.Controler = controler self.VariablesDefaultValue = { "Name": "", "Address": "1", "Len": "1", "Data type": "WORD", "Modbus type": HOLDING_REGISTER_READ, "Description": DESCRIPTION, "Device ID": "1", "Transfer method": "Periodic", "Period (ms)": "100" } self.Table = MBRequestDataTable(self) self.ColAlignements = [wx.ALIGN_RIGHT] + \ [wx.ALIGN_LEFT]*(len(self.VariablesDefaultValue)) self.ColSizes = [20, 150 ] + [100] * (len(self.VariablesDefaultValue) - 1) self.VariablesGrid.SetTable(self.Table) self.VariablesGrid.SetButtons({ "Add": self.AddVariableButton, "Delete": self.DeleteVariableButton, "Up": self.UpVariableButton, "Down": self.DownVariableButton }) """ handlers for adding variable """ def _AddVariable(new_row): if new_row > 0: row_content = self.Table.data[new_row - 1].copy() newAddr = int(row_content["Address"]) newLen = int(row_content["Len"]) if row_content["Data type"] in ("REAL", "INT"): newLen = newLen * 2 newAddr = newAddr + newLen row_content["Address"] = str(newAddr) result = VARIABLE_NAME_SUFFIX_MODEL.search(row_content["Name"]) if result is not None: name = row_content["Name"][:result.start(1)] suffix = result.group(1) if suffix != "": start_idx = int(suffix) else: start_idx = 0 else: name = row_content["Name"] start_idx = 0 row_content["Name"] = self.Controler.GenerateNewName( name + "%d", start_idx) else: row_content = self.VariablesDefaultValue.copy() self.Table.InsertRow(new_row, row_content) self.RefreshModel() self.RefreshView() return new_row setattr(self.VariablesGrid, "_AddRow", _AddVariable) """ handlers for deleting variable """ def _DeleteVariable(row): self.Table.RemoveRow(row) self.RefreshModel() self.RefreshView() setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) """ handlers for moving varible """ def _MoveVariable(row, move): new_row = self.Table.MoveRow(row, move) if new_row != row: self.RefreshModel() self.RefreshView() return new_row setattr(self.VariablesGrid, "_MoveRow", _MoveVariable) self.VariablesGrid.SetRowLabelSize(0) for col in range(self.Table.GetNumberCols()): attr = wx.grid.GridCellAttr() attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE) self.VariablesGrid.SetColAttr(col, attr) self.VariablesGrid.SetColSize(col, self.ColSizes[col]) self.Table.ResetView(self.VariablesGrid) self.Bind(wx.EVT_SHOW, self.OnShow) def OnChangeMasterOption(self, event): masterOptionOnFrame = self.masterSelectCmbx.cmbbox.GetStringSelection() masterOptionInXml = [ i for i in self.Controler.GetVariables() if i["Name"] == MASTER_OPTION ] if len(masterOptionInXml) > 0: if masterOptionOnFrame != masterOptionInXml[0]: self.RefreshModel() else: self.RefreshModel() event.Skip() def GetMasterOption(self): return { "Name": "Master option", "Address": "", "Len": "", "Device ID": "", "Data type": u"WORD", "Transfer method": "", "Period (ms)": "", "Description": MASTER_OPTION, "Modbus type": "0" } def RefreshModel(self): ipAddress = self.ipAddressDefault.copy() ipAddress["Address"] = self.ip_address.GetValue() controllerVariables = self.Controler.GetVariables() controllerVariables = [ i for i in controllerVariables if i["Description"] not in (DESCRIPTION, MASTER_OPTION) ] controllerVariables += self.Table.GetData() controllerVariables.append(self.GetMasterOption()) controllerVariables.append(ipAddress) controllerVariables.append(self.portDefault) self.Controler.SetVariables(controllerVariables) self.RefreshBuffer() def RefreshView(self): varForTable = self.Controler.GetVariables() varForTable = [ i for i in varForTable if i["Description"] == DESCRIPTION ] self.Table.SetData(varForTable) self.Table.ResetView(self.VariablesGrid) varForTable = self.Controler.GetVariables() varForTable = [i for i in varForTable if i["Name"] == MASTER_OPTION] #if len(varForTable) > 0: #self.masterSelectCmbx.cmbbox.SetStringSelection(varForTable[0]["Modbus type"]) self.VariablesGrid.RefreshButtons() varForTable = self.Controler.GetVariables() varForTable = [ i for i in varForTable if i["Description"] == DESCRIPTION_IP ] if len(varForTable) == 0: varForTable = [] varForTable.append(self.ipAddressDefault) self.ip_address.SetValue(varForTable[0]["Address"]) varForTable = self.Controler.GetVariables() vars = [i for i in varForTable if i["Description"] == DESCRIPTION_PORT] if len(vars) == 0: vars = [] vars.append(self.portDefault) # if self.port.GetLineText != vars[0]["Address"]: # print vars self.port.SetValue(int(vars[0]["Address"])) def OnShow(self, event): pass # print 'kek' # используется для событий, когда изменяются поля ip-адреса и порта def OnChangeIp(self, event): ipAddress = self.ipAddressDefault.copy() ipAddress["Address"] = self.ip_address.GetValue().replace(' ', '') # port = self.portDefault.copy() # port["Address"] = self.port.GetLineText(0) controllerVariables = self.Controler.GetVariables() # valuesOnFrame = self.GetData() valueIPOnWidget = self.ip_address.GetValue() controllerVariablesIP = [ i for i in controllerVariables if i["Description"] == (DESCRIPTION_IP) ] # valuePortOnWidget = self.port.GetLineText() controllerVariablesIP = [ i for i in controllerVariables if i["Description"] == (DESCRIPTION_PORT) ] if not (ipAddress in controllerVariables): controllerVariables = [ i for i in controllerVariables if i["Description"] != DESCRIPTION_IP ] controllerVariables.append(ipAddress) # controllerVariables.append(port) self.Controler.SetVariables(controllerVariables) self.RefreshBuffer() event.Skip() def OnChangePort(self, event): portAddress = self.portDefault.copy() portAddress["Address"] = self.port.GetLineText(0) controllerVariables = self.Controler.GetVariables() if not (portAddress in controllerVariables): controllerVariables = [ i for i in controllerVariables if i["Description"] != DESCRIPTION_PORT ] controllerVariables.append(portAddress) self.Controler.SetVariables(controllerVariables) self.RefreshBuffer() event.Skip() # def GetData(self): # """ # Считывает с GUI настроенные пользователем параметры и возвращает их в виде списка # словарей # """ def OnVariablesGridCellChange(self, event): row, col = event.GetRow(), event.GetCol() colname = self.Table.GetColLabelValue(col, False) value = self.Table.GetValue(row, col) message = None if colname == "Modbus type": self.VariablesGrid.SetCellValue(row, col + 1, "WORD") if colname == "Len": modbusType = self.Table.GetValue(row, 4) # Modubs type value if modbusType in (HOLDING_REGISTER_READ, INPUT_REGISTER_READ): if int(value) > MAX_SIMULTANEOUS_REGISTERS_READ: value = MAX_SIMULTANEOUS_REGISTERS_READ self.VariablesGrid.SetCellValue( row, col, str(MAX_SIMULTANEOUS_REGISTERS_READ)) if modbusType == HOLDING_REGISTER_WRITE: if int(value) > MAX_SIMULTANEOUS_REGISTERS_WRITE: self.VariablesGrid.SetCellValue( row, col, str(MAX_SIMULTANEOUS_REGISTERS_WRITE)) if modbusType in (COIL_READ, DISCRETE_INPUT_READ): if int(value) > MAX_SIMULTANEOUS_COIL_DISC_READ: self.VariablesGrid.SetCellValue( row, col, str(MAX_SIMULTANEOUS_COIL_DISC_READ)) if modbusType == COIL_WRITE: if int(value) > MAX_SIMULTANEOUS_COIL_WRITE: self.VariablesGrid.SetCellValue( row, col, str(MAX_SIMULTANEOUS_COIL_WRITE)) if colname == "Name" and value != "": if not TestIdentifier(value): message = _("\"%s\" is not a valid identifier!") % value elif value.upper() in IEC_KEYWORDS: message = _("\"%s\" is a keyword. It can't be used!") % value elif value.upper() in [ var["Name"].upper() for var_row, var in enumerate(self.Table.data) if var_row != row ]: message = _( "A variable with \"%s\" as name already exists!") % value else: self.RefreshModel() wx.CallAfter(self.RefreshView) else: self.RefreshModel() wx.CallAfter(self.RefreshView) if message is not None: dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() event.Veto() else: event.Skip() def DoGetBestSize(self): return self.ParentWindow.GetPanelBestSize() def OnVariablesGridEditorShown(self, event): event.Skip() def GetVariableTypeFunction(self, base_type): def VariableTypeFunction(event): row = self.VariablesGrid.GetGridCursorRow() self.Table.SetValueByName(row, "Data type", base_type) self.Table.ResetView(self.VariablesGrid) self.RefreshModel() self.RefreshView() event.Skip() return VariableTypeFunction def OnVariablesGridCellLeftClick(self, event): if event.GetCol() == 0: row = event.GetRow() data_type = self.Table.GetValueByName(row, "Data type") var_name = self.Table.GetValueByName(row, "Name") data = wx.TextDataObject( str((var_name, "Global", data_type, self.Controler.GetCurrentLocation()))) dragSource = wx.DropSource(self.VariablesGrid) dragSource.SetData(data) dragSource.DoDragDrop() return event.Skip() def RefreshBuffer(self): self.Controler.BufferCodeFile() self.ParentWindow.RefreshTitle() self.ParentWindow.RefreshFileMenu() self.ParentWindow.RefreshEditMenu() self.ParentWindow.RefreshPageTitles()
class DebugVariablePanel(wx.Panel, DebugViewer): def __init__(self, parent, producer): wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL) DebugViewer.__init__(self, producer, True) main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(1) button_sizer = wx.BoxSizer(wx.HORIZONTAL) main_sizer.AddSizer(button_sizer, border=5, flag=wx.ALIGN_RIGHT | wx.ALL) for name, bitmap, help in [ ("DeleteButton", "remove_element", _("Remove debug variable")), ("UpButton", "up", _("Move debug variable up")), ("DownButton", "down", _("Move debug variable down")) ]: button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) button.SetToolTipString(help) setattr(self, name, button) button_sizer.AddWindow(button, border=5, flag=wx.LEFT) self.VariablesGrid = CustomGrid(self, size=wx.Size(0, 150), style=wx.VSCROLL) self.VariablesGrid.SetDropTarget(DebugVariableDropTarget(self)) self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, self.OnVariablesGridCellRightClick) main_sizer.AddWindow(self.VariablesGrid, flag=wx.GROW) self.SetSizer(main_sizer) self.HasNewData = False self.Table = DebugVariableTable(self, [], GetDebugVariablesTableColnames()) self.VariablesGrid.SetTable(self.Table) self.VariablesGrid.SetButtons({ "Delete": self.DeleteButton, "Up": self.UpButton, "Down": self.DownButton }) def _AddVariable(new_row): return self.VariablesGrid.GetGridCursorRow() setattr(self.VariablesGrid, "_AddRow", _AddVariable) def _DeleteVariable(row): item = self.Table.GetItem(row) self.RemoveDataConsumer(item) self.Table.RemoveItem(row) self.RefreshGrid() setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) def _MoveVariable(row, move): new_row = max(0, min(row + move, self.Table.GetNumberRows() - 1)) if new_row != row: self.Table.MoveItem(row, new_row) self.RefreshGrid() return new_row setattr(self.VariablesGrid, "_MoveRow", _MoveVariable) self.VariablesGrid.SetRowLabelSize(0) for col in range(self.Table.GetNumberCols()): attr = wx.grid.GridCellAttr() attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTER) self.VariablesGrid.SetColAttr(col, attr) self.VariablesGrid.SetColSize(col, 100) self.Table.ResetView(self.VariablesGrid) self.VariablesGrid.RefreshButtons() def RefreshNewData(self): if self.HasNewData: self.HasNewData = False self.RefreshGrid() DebugViewer.RefreshNewData(self) def RefreshGrid(self): self.Freeze() self.Table.ResetView(self.VariablesGrid) self.VariablesGrid.RefreshButtons() self.Thaw() def UnregisterObsoleteData(self): items = [(idx, item) for idx, item in enumerate(self.Table.GetData())] items.reverse() for idx, item in items: iec_path = item.GetVariable().upper() if self.GetDataType(iec_path) is None: self.RemoveDataConsumer(item) self.Table.RemoveItem(idx) else: self.AddDataConsumer(iec_path, item) self.Freeze() self.Table.ResetView(self.VariablesGrid) self.VariablesGrid.RefreshButtons() self.Thaw() def ResetGrid(self): self.DeleteDataConsumers() self.Table.Empty() self.Freeze() self.Table.ResetView(self.VariablesGrid) self.VariablesGrid.RefreshButtons() self.Thaw() def GetForceVariableMenuFunction(self, iec_path, item): iec_type = self.GetDataType(iec_path) def ForceVariableFunction(event): if iec_type is not None: dialog = ForceVariableDialog(self, iec_type, str(item.GetValue())) if dialog.ShowModal() == wx.ID_OK: self.ForceDataValue(iec_path, dialog.GetValue()) return ForceVariableFunction def GetReleaseVariableMenuFunction(self, iec_path): def ReleaseVariableFunction(event): self.ReleaseDataValue(iec_path) return ReleaseVariableFunction def OnVariablesGridCellRightClick(self, event): row, col = event.GetRow(), event.GetCol() if self.Table.GetColLabelValue(col, False) == "Value": iec_path = self.Table.GetValueByName(row, "Variable").upper() menu = wx.Menu(title='') new_id = wx.NewId() AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Force value")) self.Bind(wx.EVT_MENU, self.GetForceVariableMenuFunction( iec_path.upper(), self.Table.GetItem(row)), id=new_id) new_id = wx.NewId() AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Release value")) self.Bind(wx.EVT_MENU, self.GetReleaseVariableMenuFunction(iec_path.upper()), id=new_id) if self.Table.IsForced(row): menu.Enable(new_id, True) else: menu.Enable(new_id, False) self.PopupMenu(menu) menu.Destroy() event.Skip() def InsertValue(self, iec_path, idx=None, force=False): if idx is None: idx = self.Table.GetNumberRows() for item in self.Table.GetData(): if iec_path == item.GetVariable(): return item = VariableTableItem(self, iec_path, "") result = self.AddDataConsumer(iec_path.upper(), item) if result is not None or force: self.Table.InsertItem(idx, item) self.RefreshGrid() def GetDebugVariables(self): return [item.GetVariable() for item in self.Table.GetData()]