Example #1
0
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)
Example #2
0
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
Example #3
0
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()
Example #4
0
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()
Example #5
0
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()
Example #6
0
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()]