# HG changeset patch # User 'Laurent Bessard ' # Date 1249652950 -7200 # Node ID 323c8d76f6f25a68bb5407dbfe525330382e3a47 # Parent 546053de142642ad90a1b6bfd1f90b3a79353efa# Parent d07815f10ca8138ab552c174f6b95189d95b59e1 Merged changes diff -r d07815f10ca8 -r 323c8d76f6f2 DataTypeEditor.py --- a/DataTypeEditor.py Mon Jul 27 12:01:43 2009 +0200 +++ b/DataTypeEditor.py Fri Aug 07 15:49:10 2009 +0200 @@ -41,6 +41,10 @@ # Structure Elements Table #------------------------------------------------------------------------------- +def GetElementsTableColnames(): + _ = lambda x : x + return ["#", _("Name"), _("Type"), _("Initial Value")] + class ElementsTable(wx.grid.PyGridTableBase): """ @@ -66,23 +70,25 @@ def GetNumberRows(self): return len(self.data) - def GetColLabelValue(self, col): + def GetColLabelValue(self, col, translate=True): if col < len(self.colnames): + if translate: + return _(self.colnames[col]) return self.colnames[col] - def GetRowLabelValues(self, row): + def GetRowLabelValues(self, row, translate=True): return row def GetValue(self, row, col): if row < self.GetNumberRows(): if col == 0: return row + 1 - name = str(self.data[row].get(self.GetColLabelValue(col), "")) + name = str(self.data[row].get(self.GetColLabelValue(col, False), "")) return name def SetValue(self, row, col, value): if col < len(self.colnames): - colname = self.GetColLabelValue(col) + colname = self.GetColLabelValue(col, False) if colname == "Name": self.old_value = self.data[row][colname] self.data[row][colname] = value @@ -140,13 +146,11 @@ Otherwise default to the default renderer. """ - typelist = None - accesslist = None for row in range(self.GetNumberRows()): for col in range(self.GetNumberCols()): editor = None renderer = None - colname = self.GetColLabelValue(col) + colname = self.GetColLabelValue(col, False) if col != 0: grid.SetReadOnly(row, col, False) if colname == "Name": @@ -163,7 +167,7 @@ grid.SetCellEditor(row, col, editor) grid.SetCellRenderer(row, col, renderer) - if row in self.Errors and self.Errors[row][0] == colname.lower(): + if self.Errors.has_key(row) and self.Errors[row][0] == colname.lower(): grid.SetCellBackgroundColour(row, col, wx.Colour(255, 255, 0)) grid.SetCellTextColour(row, col, wx.RED) grid.MakeCellVisible(row, col) @@ -204,7 +208,7 @@ self.Errors = {} #------------------------------------------------------------------------------- -# Configuration Editor class +# Datatype Editor class #------------------------------------------------------------------------------- [ID_DATATYPEEDITOR, ID_DATATYPEEDITORSTATICBOX, @@ -227,6 +231,11 @@ ID_DATATYPEEDITORSTATICTEXT11, ] = [wx.NewId() for _init_ctrls in range(35)] +def GetDatatypeTypes(): + _ = lambda x : x + return [_("Directly"), _("Subrange"), _("Enumerated"), _("Array"), _("Structure")] +DATATYPE_TYPES_DICT = dict([(_(datatype), datatype) for datatype in GetDatatypeTypes()]) + class DataTypeEditor(wx.Panel): def _init_coll_MainSizer_Items(self, parent): @@ -238,8 +247,8 @@ parent.AddGrowableRow(1) def _init_coll_TopSizer_Items(self, parent): - parent.AddWindow(self.staticText1, 0, border=5, flag=wx.GROW|wx.LEFT) - parent.AddWindow(self.DerivationType, 0, border=0, flag=wx.GROW) + parent.AddWindow(self.staticText1, 0, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT) + parent.AddWindow(self.DerivationType, 0, border=5, flag=wx.GROW|wx.RIGHT) def _init_coll_TypeInfosSizer_Items(self, parent): parent.AddWindow(self.DirectlyPanel, 1, border=0, flag=wx.ALL) @@ -249,31 +258,34 @@ parent.AddWindow(self.StructurePanel, 1, border=0, flag=wx.GROW|wx.ALL) def _init_coll_DirectlyPanelSizer_Items(self, parent): - parent.AddWindow(self.staticText2, 1, border=5, flag=wx.GROW|wx.ALL) + parent.AddWindow(self.staticText2, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) parent.AddWindow(self.DirectlyBaseType, 1, border=5, flag=wx.GROW|wx.ALL) - parent.AddWindow(self.staticText3, 1, border=5, flag=wx.GROW|wx.ALL) + parent.AddWindow(self.staticText3, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) parent.AddWindow(self.DirectlyInitialValue, 1, border=5, flag=wx.GROW|wx.ALL) def _init_coll_SubrangePanelSizer_Items(self, parent): - parent.AddWindow(self.staticText4, 1, border=5, flag=wx.GROW|wx.ALL) + parent.AddWindow(self.staticText4, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) parent.AddWindow(self.SubrangeBaseType, 1, border=5, flag=wx.GROW|wx.ALL) - parent.AddWindow(self.staticText5, 1, border=5, flag=wx.GROW|wx.ALL) + parent.AddWindow(self.staticText5, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) parent.AddWindow(self.SubrangeInitialValue, 1, border=5, flag=wx.GROW|wx.ALL) - parent.AddWindow(self.staticText6, 1, border=5, flag=wx.GROW|wx.ALL) + parent.AddWindow(self.staticText6, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) parent.AddWindow(self.SubrangeMinimum, 1, border=5, flag=wx.GROW|wx.ALL) parent.AddWindow(wx.Size(0, 0), 1, border=5, flag=wx.GROW|wx.ALL) parent.AddWindow(wx.Size(0, 0), 1, border=5, flag=wx.GROW|wx.ALL) - parent.AddWindow(self.staticText7, 1, border=5, flag=wx.GROW|wx.ALL) + parent.AddWindow(self.staticText7, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) parent.AddWindow(self.SubrangeMaximum, 1, border=5, flag=wx.GROW|wx.ALL) def _init_coll_EnumeratedPanelSizer_Items(self, parent): - parent.AddWindow(self.EnumeratedValues, 2, border=5, flag=wx.GROW|wx.ALL) - parent.AddWindow(self.staticText8, 1, border=5, flag=wx.GROW|wx.ALL) + parent.AddWindow(self.EnumeratedValues, 1, border=5, flag=wx.GROW|wx.ALL) + parent.AddSizer(self.EnumeratedPanelRightSizer, 1, border=0, flag=0) + + def _init_coll_EnumeratedPanelRightSizer_Items(self, parent): + parent.AddWindow(self.staticText8, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) parent.AddWindow(self.EnumeratedInitialValue, 1, border=5, flag=wx.ALL) def _init_coll_ArrayPanelSizer_Items(self, parent): parent.AddSizer(self.ArrayPanelLeftSizer, 0, border=0, flag=wx.GROW) - parent.AddSizer(self.ArrayPanelRightSizer, 0, border=0, flag=wx.GROW) + parent.AddSizer(self.ArrayPanelRightSizer, 0, border=0, flag=0) parent.AddWindow(self.ArrayDimensions, 0, border=5, flag=wx.GROW|wx.ALL) def _init_coll_ArrayPanelSizer_Growables(self, parent): @@ -282,15 +294,15 @@ parent.AddGrowableRow(1) def _init_coll_ArrayPanelLeftSizer_Items(self, parent): - parent.AddWindow(self.staticText9, 1, border=5, flag=wx.GROW|wx.ALL) + parent.AddWindow(self.staticText9, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) parent.AddWindow(self.ArrayBaseType, 1, border=5, flag=wx.GROW|wx.ALL) def _init_coll_ArrayPanelRightSizer_Items(self, parent): - parent.AddWindow(self.staticText10, 1, border=5, flag=wx.GROW|wx.ALL) + parent.AddWindow(self.staticText10, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) parent.AddWindow(self.ArrayInitialValue, 1, border=5, flag=wx.GROW|wx.ALL) def _init_coll_StructurePanelSizer_Items(self, parent): - parent.AddWindow(self.staticText11, 0, border=5, flag=wx.GROW|wx.ALL) + parent.AddWindow(self.staticText11, 0, border=5, flag=wx.ALL) parent.AddWindow(self.StructureElementsGrid, 0, border=0, flag=wx.GROW) parent.AddSizer(self.StructurePanelButtonSizer, 0, border=0, flag=wx.ALIGN_RIGHT) @@ -299,22 +311,23 @@ parent.AddGrowableRow(1) def _init_coll_StructurePanelButtonSizer_Items(self, parent): - parent.AddWindow(self.StructureAddButton, 1, border=5, flag=wx.GROW|wx.ALL) - parent.AddWindow(self.StructureDeleteButton, 1, border=5, flag=wx.GROW|wx.ALL) - parent.AddWindow(self.StructureUpButton, 1, border=5, flag=wx.GROW|wx.ALL) - parent.AddWindow(self.StructureDownButton, 1, border=5, flag=wx.GROW|wx.ALL) + parent.AddWindow(self.StructureAddButton, 0, border=5, flag=wx.ALL) + parent.AddWindow(self.StructureDeleteButton, 0, border=5, flag=wx.ALL) + parent.AddWindow(self.StructureUpButton, 0, border=5, flag=wx.ALL) + parent.AddWindow(self.StructureDownButton, 0, border=5, flag=wx.ALL) def _init_sizers(self): self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) self.TopSizer = wx.BoxSizer(wx.HORIZONTAL) self.TypeInfosSizer = wx.StaticBoxSizer(self.staticbox, wx.HORIZONTAL) self.DirectlyPanelSizer = wx.BoxSizer(wx.HORIZONTAL) - self.SubrangePanelSizer = wx.GridSizer(cols=4, hgap=0, rows=3, vgap=0) + self.SubrangePanelSizer = wx.GridSizer(cols=4, hgap=5, rows=3, vgap=0) self.EnumeratedPanelSizer = wx.BoxSizer(wx.HORIZONTAL) - self.ArrayPanelSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=2, vgap=0) + self.EnumeratedPanelRightSizer = wx.BoxSizer(wx.HORIZONTAL) + self.ArrayPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=0) self.ArrayPanelLeftSizer = wx.BoxSizer(wx.HORIZONTAL) self.ArrayPanelRightSizer = wx.BoxSizer(wx.HORIZONTAL) - self.StructurePanelSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=0) + self.StructurePanelSizer = wx.FlexGridSizer(cols=1, hgap=5, rows=3, vgap=0) self.StructurePanelButtonSizer = wx.BoxSizer(wx.HORIZONTAL) self._init_coll_MainSizer_Items(self.MainSizer) self._init_coll_MainSizer_Growables(self.MainSizer) @@ -323,6 +336,7 @@ self._init_coll_DirectlyPanelSizer_Items(self.DirectlyPanelSizer) self._init_coll_SubrangePanelSizer_Items(self.SubrangePanelSizer) self._init_coll_EnumeratedPanelSizer_Items(self.EnumeratedPanelSizer) + self._init_coll_EnumeratedPanelRightSizer_Items(self.EnumeratedPanelRightSizer) self._init_coll_ArrayPanelSizer_Items(self.ArrayPanelSizer) self._init_coll_ArrayPanelSizer_Growables(self.ArrayPanelSizer) self._init_coll_ArrayPanelLeftSizer_Items(self.ArrayPanelLeftSizer) @@ -343,12 +357,12 @@ size=wx.Size(0, 0), style=wx.SUNKEN_BORDER) self.staticbox = wx.StaticBox(id=ID_DATATYPEEDITORSTATICBOX, - label='Type infos:', name='staticBox1', parent=self, - pos=wx.Point(0, 0), size=wx.Size(10, 0), style=0) + label=_('Type infos:'), name='staticBox1', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.staticText1 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT1, - label='Derivation Type:', name='staticText1', parent=self, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Derivation Type:'), name='staticText1', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.DerivationType = wx.ComboBox(id=ID_DATATYPEEDITORDERIVATIONTYPE, name='DerivationType', parent=self, pos=wx.Point(0, 0), @@ -362,8 +376,8 @@ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText2 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT2, - label='Base Type:', name='staticText2', parent=self.DirectlyPanel, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Base Type:'), name='staticText2', parent=self.DirectlyPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.DirectlyBaseType = wx.ComboBox(id=ID_DATATYPEEDITORDIRECTLYBASETYPE, name='DirectlyBaseType', parent=self.DirectlyPanel, pos=wx.Point(0, 0), @@ -371,8 +385,8 @@ self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, id=ID_DATATYPEEDITORDIRECTLYBASETYPE) self.staticText3 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT3, - label='Initial Value:', name='staticText3', parent=self.DirectlyPanel, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Initial Value:'), name='staticText3', parent=self.DirectlyPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.DirectlyInitialValue = wx.TextCtrl(id=ID_DATATYPEEDITORDIRECTLYINITIALVALUE, name='DirectlyInitialValue', parent=self.DirectlyPanel, pos=wx.Point(0, 0), @@ -386,8 +400,8 @@ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText4 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT4, - label='Base Type:', name='staticText4', parent=self.SubrangePanel, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Base Type:'), name='staticText4', parent=self.SubrangePanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.SubrangeBaseType = wx.ComboBox(id=ID_DATATYPEEDITORSUBRANGEBASETYPE, name='SubrangeBaseType', parent=self.SubrangePanel, pos=wx.Point(0, 0), @@ -395,8 +409,8 @@ self.Bind(wx.EVT_COMBOBOX, self.OnSubrangeBaseTypeChanged, id=ID_DATATYPEEDITORSUBRANGEBASETYPE) self.staticText5 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT5, - label='Initial Value:', name='staticText5', parent=self.SubrangePanel, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Initial Value:'), name='staticText5', parent=self.SubrangePanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.SubrangeInitialValue = wx.SpinCtrl(id=ID_DATATYPEEDITORSUBRANGEINITIALVALUE, name='SubrangeInitialValue', parent=self.SubrangePanel, pos=wx.Point(0, 0), @@ -404,8 +418,8 @@ self.Bind(wx.EVT_SPINCTRL, self.OnInfosChanged, id=ID_DATATYPEEDITORSUBRANGEINITIALVALUE) self.staticText6 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT6, - label='Minimum:', name='staticText6', parent=self.SubrangePanel, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Minimum:'), name='staticText6', parent=self.SubrangePanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.SubrangeMinimum = wx.SpinCtrl(id=ID_DATATYPEEDITORSUBRANGEMINIMUM, name='SubrangeMinimum', parent=self.SubrangePanel, pos=wx.Point(0, 0), @@ -413,8 +427,8 @@ self.Bind(wx.EVT_SPINCTRL, self.OnSubrangeMinimumChanged, id=ID_DATATYPEEDITORSUBRANGEMINIMUM) self.staticText7 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT7, - label='Maximum:', name='staticText7', parent=self.SubrangePanel, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Maximum:'), name='staticText7', parent=self.SubrangePanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.SubrangeMaximum = wx.SpinCtrl(id=ID_DATATYPEEDITORSUBRANGEMAXIMUM, name='SubrangeMaximum', parent=self.SubrangePanel, pos=wx.Point(0, 0), @@ -428,17 +442,26 @@ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.EnumeratedValues = wx.gizmos.EditableListBox(id=ID_DATATYPEEDITORENUMERATEDVALUES, - name='EnumeratedValues', parent=self.EnumeratedPanel, label="Values:", pos=wx.Point(0, 0), + name='EnumeratedValues', parent=self.EnumeratedPanel, label=_("Values:"), pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.gizmos.EL_ALLOW_NEW | wx.gizmos.EL_ALLOW_EDIT | wx.gizmos.EL_ALLOW_DELETE) self.EnumeratedValues.GetListCtrl().Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEnumeratedValueEndEdit) - self.EnumeratedValues.GetNewButton().Bind(wx.EVT_BUTTON, self.OnEnumeratedValuesChanged) - self.EnumeratedValues.GetDelButton().Bind(wx.EVT_BUTTON, self.OnEnumeratedValuesChanged) - self.EnumeratedValues.GetUpButton().Bind(wx.EVT_BUTTON, self.OnEnumeratedValuesChanged) - self.EnumeratedValues.GetDownButton().Bind(wx.EVT_BUTTON, self.OnEnumeratedValuesChanged) + self.EnumeratedValues.GetEditButton().SetToolTipString(_("Edit item")) + new_button = self.EnumeratedValues.GetNewButton() + new_button.SetToolTipString(_("New item")) + new_button.Bind(wx.EVT_BUTTON, self.OnEnumeratedValuesChanged) + del_button = self.EnumeratedValues.GetDelButton() + del_button.SetToolTipString(_("Delete item")) + del_button.Bind(wx.EVT_BUTTON, self.OnEnumeratedValuesChanged) + up_button = self.EnumeratedValues.GetUpButton() + up_button.SetToolTipString(_("Move up")) + up_button.Bind(wx.EVT_BUTTON, self.OnEnumeratedValuesChanged) + down_button = self.EnumeratedValues.GetDownButton() + down_button.SetToolTipString(_("Move down")) + down_button.Bind(wx.EVT_BUTTON, self.OnEnumeratedValuesChanged) self.staticText8 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT8, - label='Initial Value:', name='staticText8', parent=self.EnumeratedPanel, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Initial Value:'), name='staticText8', parent=self.EnumeratedPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.EnumeratedInitialValue = wx.ComboBox(id=ID_DATATYPEEDITORENUMERATEDINITIALVALUE, name='EnumeratedInitialValue', parent=self.EnumeratedPanel, pos=wx.Point(0, 0), @@ -452,8 +475,8 @@ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText9 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT9, - label='Base Type:', name='staticText9', parent=self.ArrayPanel, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Base Type:'), name='staticText9', parent=self.ArrayPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.ArrayBaseType = wx.ComboBox(id=ID_DATATYPEEDITORARRAYBASETYPE, name='SubrangeBaseType', parent=self.ArrayPanel, pos=wx.Point(0, 0), @@ -461,17 +484,26 @@ self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, id=ID_DATATYPEEDITORARRAYBASETYPE) self.ArrayDimensions = wx.gizmos.EditableListBox(id=ID_DATATYPEEDITORARRAYDIMENSIONS, - name='ArrayDimensions', parent=self.ArrayPanel, label="Dimensions:", pos=wx.Point(0, 0), + name='ArrayDimensions', parent=self.ArrayPanel, label=_("Dimensions:"), pos=wx.Point(0, 0), size=wx.Size(0, 24), style=wx.gizmos.EL_ALLOW_NEW | wx.gizmos.EL_ALLOW_EDIT | wx.gizmos.EL_ALLOW_DELETE) self.ArrayDimensions.GetListCtrl().Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnDimensionsChanged) - self.ArrayDimensions.GetNewButton().Bind(wx.EVT_BUTTON, self.OnDimensionsChanged) - self.ArrayDimensions.GetDelButton().Bind(wx.EVT_BUTTON, self.OnDimensionsChanged) - self.ArrayDimensions.GetUpButton().Bind(wx.EVT_BUTTON, self.OnDimensionsChanged) - self.ArrayDimensions.GetDownButton().Bind(wx.EVT_BUTTON, self.OnDimensionsChanged) + self.ArrayDimensions.GetEditButton().SetToolTipString(_("Edit item")) + new_button = self.ArrayDimensions.GetNewButton() + new_button.SetToolTipString(_("New item")) + new_button.Bind(wx.EVT_BUTTON, self.OnDimensionsChanged) + del_button = self.ArrayDimensions.GetDelButton() + del_button.SetToolTipString(_("Delete item")) + del_button.Bind(wx.EVT_BUTTON, self.OnDimensionsChanged) + up_button = self.ArrayDimensions.GetUpButton() + up_button.SetToolTipString(_("Move up")) + up_button.Bind(wx.EVT_BUTTON, self.OnDimensionsChanged) + down_button = self.ArrayDimensions.GetDownButton() + down_button.SetToolTipString(_("Move down")) + down_button.Bind(wx.EVT_BUTTON, self.OnDimensionsChanged) self.staticText10 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT10, - label='Initial Value:', name='staticText10', parent=self.ArrayPanel, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Initial Value:'), name='staticText10', parent=self.ArrayPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.ArrayInitialValue = wx.TextCtrl(id=ID_DATATYPEEDITORARRAYINITIALVALUE, name='ArrayInitialValue', parent=self.ArrayPanel, pos=wx.Point(0, 0), @@ -485,8 +517,8 @@ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText11 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT11, - label='Elements :', name='staticText11', parent=self.StructurePanel, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Elements :'), name='staticText11', parent=self.StructurePanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.StructureElementsGrid = wx.grid.Grid(id=ID_DATATYPEEDITORSTRUCTUREELEMENTSGRID, name='StructureElementsGrid', parent=self.StructurePanel, pos=wx.Point(0, 0), @@ -504,14 +536,14 @@ wx.grid.EVT_GRID_CELL_CHANGE(self.StructureElementsGrid, self.OnStructureElementsGridCellChange) wx.grid.EVT_GRID_EDITOR_SHOWN(self.StructureElementsGrid, self.OnStructureElementsGridEditorShown) - self.StructureAddButton = wx.Button(id=ID_DATATYPEEDITORSTRUCTUREADDBUTTON, label='Add', + self.StructureAddButton = wx.Button(id=ID_DATATYPEEDITORSTRUCTUREADDBUTTON, label=_('Add'), name='StructureAddButton', parent=self.StructurePanel, pos=wx.Point(0, 0), - size=wx.Size(72, 32), style=0) + size=wx.DefaultSize, style=0) self.Bind(wx.EVT_BUTTON, self.OnStructureAddButton, id=ID_DATATYPEEDITORSTRUCTUREADDBUTTON) - self.StructureDeleteButton = wx.Button(id=ID_DATATYPEEDITORSTRUCTUREDELETEBUTTON, label='Delete', + self.StructureDeleteButton = wx.Button(id=ID_DATATYPEEDITORSTRUCTUREDELETEBUTTON, label=_('Delete'), name='StructureDeleteButton', parent=self.StructurePanel, pos=wx.Point(0, 0), - size=wx.Size(72, 32), style=0) + size=wx.DefaultSize, style=0) self.Bind(wx.EVT_BUTTON, self.OnStructureDeleteButton, id=ID_DATATYPEEDITORSTRUCTUREDELETEBUTTON) self.StructureUpButton = wx.Button(id=ID_DATATYPEEDITORSTRUCTUREUPBUTTON, label='^', @@ -530,7 +562,7 @@ self._init_ctrls(parent) self.StructureElementDefaultValue = {"Name" : "", "Type" : "INT", "Initial Value" : ""} - self.StructureElementsTable = ElementsTable(self, [], ["#", "Name", "Type", "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] @@ -540,13 +572,11 @@ attr = wx.grid.GridCellAttr() attr.SetAlignment(self.StructureColAlignements[col], wx.ALIGN_CENTRE) self.StructureElementsGrid.SetColAttr(col, attr) - self.StructureElementsGrid.SetColSize(col, self.StructureColSizes[col]) - - self.DerivationType.Append("Directly") - self.DerivationType.Append("Subrange") - self.DerivationType.Append("Enumerated") - self.DerivationType.Append("Array") - self.DerivationType.Append("Structure") + self.StructureElementsGrid.SetColMinimalWidth(col, self.StructureColSizes[col]) + self.StructureElementsGrid.AutoSizeColumn(col, False) + + for datatype in GetDatatypeTypes(): + self.DerivationType.Append(_(datatype)) self.SubrangePanel.Hide() self.EnumeratedPanel.Hide() self.ArrayPanel.Hide() @@ -590,15 +620,16 @@ self.RefreshBoundsRange() type_infos = self.Controler.GetDataTypeInfos(self.TagName) if type_infos is not None: - self.DerivationType.SetStringSelection(type_infos["type"]) + 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(type_infos["min"]) - self.SubrangeMaximum.SetValue(type_infos["max"]) + 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"])) @@ -610,7 +641,7 @@ 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(map(str, x)), type_infos["dimensions"])) + 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"]) @@ -663,12 +694,12 @@ 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 = 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 = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%text, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() else: @@ -723,12 +754,12 @@ value = self.StructureElementsTable.GetValue(row, col) if colname == "Name": if not TestIdentifier(value): - message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%value, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%value, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() event.Veto() elif value.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%value, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%value, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() event.Veto() @@ -738,7 +769,7 @@ ## message.Destroy() ## event.Veto() elif value.upper() in [var["Name"].upper() for idx, var in enumerate(self.StructureElementsTable.GetData()) if idx != row]: - message = wx.MessageDialog(self, "A element with \"%s\" as name exists in this structure!"%value, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("A element with \"%s\" as name exists in this structure!")%value, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() event.Veto() @@ -764,13 +795,13 @@ 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) + type_menu.AppendMenu(wx.NewId(), _("Base Types"), base_menu) datatype_menu = wx.Menu(title='') for datatype in self.Controler.GetDataTypes(self.TagName, False, self.ParentWindow.Debug): 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) + type_menu.AppendMenu(wx.NewId(), _("User Data Types"), datatype_menu) ## functionblock_menu = wx.Menu(title='') ## bodytype = self.Controler.GetEditedElementBodyType(self.TagName, self.ParentWindow.Debug) ## pouname, poutype = self.Controler.GetEditedElementType(self.TagName, self.ParentWindow.Debug) @@ -779,7 +810,7 @@ ## 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) +## 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()) event.Veto() @@ -796,7 +827,7 @@ return ElementTypeFunction def RefreshDisplayedInfos(self): - selected = self.DerivationType.GetStringSelection() + selected = DATATYPE_TYPES_DICT[self.DerivationType.GetStringSelection()] if selected != self.CurrentPanel: if self.CurrentPanel == "Directly": self.DirectlyPanel.Hide() @@ -842,15 +873,15 @@ self.SubrangeInitialValue.SetRange(self.SubrangeMinimum.GetValue(), self.SubrangeMaximum.GetValue()) def RefreshTypeInfos(self): - selected = self.DerivationType.GetStringSelection() + 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"] = self.SubrangeMinimum.GetValue() - infos["max"] = self.SubrangeMaximum.GetValue() + infos["min"] = str(self.SubrangeMinimum.GetValue()) + infos["max"] = str(self.SubrangeMaximum.GetValue()) initial_value = self.SubrangeInitialValue.GetValue() if initial_value == infos["min"]: infos["initial"] = "" @@ -865,19 +896,19 @@ 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 = 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 bounds[0] >= 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 = 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(map(int, bounds)) + infos["dimensions"].append(bounds) infos["initial"] = self.ArrayInitialValue.GetValue() elif selected == "Structure": infos["elements"] = self.StructureElementsTable.GetData() diff -r d07815f10ca8 -r 323c8d76f6f2 Dialogs.py --- a/Dialogs.py Mon Jul 27 12:01:43 2009 +0200 +++ b/Dialogs.py Fri Aug 07 15:49:10 2009 +0200 @@ -77,21 +77,24 @@ parent.AddGrowableRow(2) def _init_coll_RightUpGridSizer_Items(self, parent): - parent.AddWindow(self.staticText2, 0, border=4, flag=wx.GROW|wx.TOP) + parent.AddWindow(self.staticText2, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) parent.AddWindow(self.BlockName, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.staticText3, 0, border=4, flag=wx.GROW|wx.TOP) + parent.AddWindow(self.staticText3, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) parent.AddWindow(self.Inputs, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.staticText4, 0, border=4, flag=wx.GROW|wx.TOP) + parent.AddWindow(self.staticText4, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) parent.AddWindow(self.ExecutionOrder, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.staticText5, 0, border=4, flag=wx.GROW|wx.TOP) + parent.AddWindow(self.staticText5, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) parent.AddWindow(self.ExecutionControl, 0, border=0, flag=wx.GROW) - + + def _init_coll_RightUpGridSizer_Growables(self, parent): + parent.AddGrowableCol(1) + def _init_sizers(self): self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) self.MainSizer = wx.BoxSizer(wx.HORIZONTAL) self.LeftBoxSizer = wx.StaticBoxSizer(self.staticbox1, wx.VERTICAL) self.RightGridSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=5) - self.RightUpGridSizer = wx.GridSizer(cols=2, hgap=5, rows=4, vgap=5) + self.RightUpGridSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=4, vgap=5) self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1) @@ -100,6 +103,7 @@ self._init_coll_RightGridSizer_Items(self.RightGridSizer) self._init_coll_RightGridSizer_Growables(self.RightGridSizer) self._init_coll_RightUpGridSizer_Items(self.RightUpGridSizer) + self._init_coll_RightUpGridSizer_Growables(self.RightUpGridSizer) self.SetSizer(self.flexGridSizer1) @@ -107,32 +111,32 @@ wx.Dialog.__init__(self, id=ID_BLOCKPROPERTIESDIALOG, name='BlockPropertiesDialog', parent=prnt, pos=wx.Point(376, 223), size=wx.Size(600, 400), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER, - title='Block Properties') + title=_('Block Properties')) self.SetClientSize(wx.Size(600, 400)) self.staticbox1 = wx.StaticBox(id=ID_BLOCKPROPERTIESDIALOGSTATICTEXT1, - label='Type:', name='staticBox1', parent=self, + label=_('Type:'), name='staticBox1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=0) self.staticText2 = wx.StaticText(id=ID_BLOCKPROPERTIESDIALOGSTATICTEXT2, - label='Name:', name='staticText2', parent=self, - pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) + label=_('Name:'), name='staticText2', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.staticText3 = wx.StaticText(id=ID_BLOCKPROPERTIESDIALOGSTATICTEXT2, - label='Inputs:', name='staticText4', parent=self, - pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) + label=_('Inputs:'), name='staticText4', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.staticText4 = wx.StaticText(id=ID_BLOCKPROPERTIESDIALOGSTATICTEXT4, - label='Execution Order:', name='staticText4', parent=self, - pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) + label=_('Execution Order:'), name='staticText4', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.staticText5 = wx.StaticText(id=ID_BLOCKPROPERTIESDIALOGSTATICTEXT5, - label='Execution Control:', name='staticText5', parent=self, - pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) + label=_('Execution Control:'), name='staticText5', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.staticText6 = wx.StaticText(id=ID_BLOCKPROPERTIESDIALOGSTATICTEXT6, - label='Preview:', name='staticText6', parent=self, - pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) + label=_('Preview:'), name='staticText6', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) if wx.Platform == '__WXMSW__': treestyle = wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER @@ -234,27 +238,27 @@ block_name = self.BlockName.GetValue() name_enabled = self.BlockName.IsEnabled() if not selected.IsOk() or self.TypeTree.GetItemParent(selected) == self.TypeTree.GetRootItem() or selected == self.TypeTree.GetRootItem(): - message = wx.MessageDialog(self, "Form isn't complete. Valid block type must be selected!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("Form isn't complete. Valid block type must be selected!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif name_enabled and block_name == "": - message = wx.MessageDialog(self, "Form isn't complete. Name must be filled!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("Form isn't complete. Name must be filled!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif name_enabled and not TestIdentifier(block_name): - message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%block_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%block_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif name_enabled and block_name.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%block_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%block_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif name_enabled and block_name.upper() in self.PouNames: - message = wx.MessageDialog(self, "\"%s\" pou already exists!"%block_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" pou already exists!")%block_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif name_enabled and block_name.upper() in self.PouElementNames: - message = wx.MessageDialog(self, "\"%s\" element for this pou already exists!"%block_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" element for this pou already exists!")%block_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() else: @@ -262,12 +266,13 @@ def SetBlockList(self, blocktypes): if wx.Platform == '__WXMSW__': - root = self.TypeTree.AddRoot("Block Types") + root = self.TypeTree.AddRoot(_("Block Types")) else: root = self.TypeTree.AddRoot("") self.TypeTree.SetPyData(root, {"type" : CATEGORY}) for category in blocktypes: - category_item = self.TypeTree.AppendItem(root, category["name"]) + category_name = category["name"] + category_item = self.TypeTree.AppendItem(root, _(category_name)) self.TypeTree.SetPyData(category_item, {"type" : CATEGORY}) for blocktype in category["list"]: blocktype_item = self.TypeTree.AppendItem(category_item, blocktype["name"]) @@ -330,7 +335,8 @@ self.Inputs.SetValue(len(blocktype["inputs"])) self.Inputs.Enable(blocktype["extensible"]) self.BlockName.Enable(blocktype["type"] != "function") - self.TypeDesc.SetValue(blocktype["comment"]) + comment = blocktype["comment"] + self.TypeDesc.SetValue(_(comment) + blocktype.get("usage", "")) wx.CallAfter(self.RefreshPreview) else: self.BlockName.Enable(False) @@ -416,6 +422,11 @@ ID_VARIABLEPROPERTIESDIALOGSTATICTEXT4, ID_VARIABLEPROPERTIESDIALOGSTATICTEXT5 ] = [wx.NewId() for _init_ctrls in range(12)] +VARIABLE_CLASSES_DICT = {INPUT : _("Input"), + INOUT : _("InOut"), + OUTPUT : _("Output")} +VARIABLE_CLASSES_DICT_REVERSE = dict([(value, key) for key, value in VARIABLE_CLASSES_DICT.iteritems()]) + class VariablePropertiesDialog(wx.Dialog): if wx.VERSION < (2, 6, 0): @@ -490,27 +501,27 @@ wx.Dialog.__init__(self, id=ID_VARIABLEPROPERTIESDIALOG, name='VariablePropertiesDialog', parent=prnt, pos=wx.Point(376, 223), size=wx.Size(400, 380), style=wx.DEFAULT_DIALOG_STYLE, - title='Variable Properties') + title=_('Variable Properties')) self.SetClientSize(wx.Size(400, 380)) self.staticText1 = wx.StaticText(id=ID_VARIABLEPROPERTIESDIALOGSTATICTEXT1, - label='Class:', name='staticText1', parent=self, + label=_('Class:'), name='staticText1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText2 = wx.StaticText(id=ID_VARIABLEPROPERTIESDIALOGSTATICTEXT2, - label='Expression:', name='staticText2', parent=self, + label=_('Expression:'), name='staticText2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText3 = wx.StaticText(id=ID_VARIABLEPROPERTIESDIALOGSTATICTEXT3, - label='Execution Order:', name='staticText3', parent=self, + label=_('Execution Order:'), name='staticText3', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText4 = wx.StaticText(id=ID_VARIABLEPROPERTIESDIALOGSTATICTEXT4, - label='Name:', name='staticText4', parent=self, + label=_('Name:'), name='staticText4', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText5 = wx.StaticText(id=ID_VARIABLEPROPERTIESDIALOGSTATICTEXT5, - label='Preview:', name='staticText5', parent=self, + label=_('Preview:'), name='staticText5', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.Class = wx.ComboBox(id=ID_VARIABLEPROPERTIESDIALOGCLASS, @@ -561,28 +572,30 @@ self.Variable = None self.VarList = [] self.MinVariableSize = None + + for choice in VARIABLE_CLASSES_DICT.itervalues(): + self.Class.Append(choice) + self.Class.SetStringSelection(VARIABLE_CLASSES_DICT[INPUT]) + self.RefreshNameList() - - for choice in ["Input", "Output", "InOut"]: - self.Class.Append(choice) - self.Class.SetStringSelection("Input") def SetPreviewFont(self, font): self.Preview.SetFont(font) def RefreshNameList(self): selected = self.VariableName.GetStringSelection() + var_class = VARIABLE_CLASSES_DICT_REVERSE[self.Class.GetStringSelection()] self.VariableName.Clear() self.VariableName.Append("") for name, var_type, value_type in self.VarList: - if var_type != "Input" or self.Class.GetStringSelection() == "Input": + if var_type != "Input" or var_class == INPUT: self.VariableName.Append(name) if selected != "" and self.VariableName.FindString(selected) != wx.NOT_FOUND: self.VariableName.SetStringSelection(selected) self.Expression.Enable(False) else: self.VariableName.SetStringSelection("") - self.Expression.Enable(self.Class.GetStringSelection() == "Input") + self.Expression.Enable(var_class == INPUT) self.VariableName.Enable(self.VariableName.GetCount() > 0) def SetMinVariableSize(self, size): @@ -596,12 +609,7 @@ value_type = values.get("type", None) value_name = values.get("name", None) if value_type: - if value_type == INPUT: - self.Class.SetStringSelection("Input") - if value_type == OUTPUT: - self.Class.SetStringSelection("Output") - if value_type == INOUT: - self.Class.SetStringSelection("InOut") + self.Class.SetStringSelection(VARIABLE_CLASSES_DICT[value_type]) self.RefreshNameList() if value_name: if self.VariableName.FindString(value_name) != wx.NOT_FOUND: @@ -616,13 +624,7 @@ def GetValues(self): values = {} - classtype = self.Class.GetStringSelection() - if classtype == "Input": - values["type"] = INPUT - elif classtype == "Output": - values["type"] = OUTPUT - elif classtype == "InOut": - values["type"] = INOUT + values["type"] = VARIABLE_CLASSES_DICT_REVERSE[self.Class.GetStringSelection()] expression = self.Expression.GetValue() if self.Expression.IsEnabled() and expression != "": values["name"] = expression @@ -643,11 +645,11 @@ else: value = self.VariableName.GetStringSelection() if value == "": - message = wx.MessageDialog(self, "At least a variable or an expression must be selected!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("At least a variable or an expression must be selected!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif value.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%value, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%value, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() else: @@ -661,7 +663,7 @@ def OnNameChanged(self, event): if self.VariableName.GetStringSelection() != "": self.Expression.Enable(False) - elif self.Class.GetStringSelection() == "Input": + elif VARIABLE_CLASSES_DICT_REVERSE[self.Class.GetStringSelection()] == INPUT: self.Expression.Enable(True) self.RefreshPreview() event.Skip() @@ -691,13 +693,8 @@ for var_name, var_type, value_type in self.VarList: if var_name == name: type = value_type - classtype = self.Class.GetStringSelection() - if classtype == "Input": - self.Variable = FBD_Variable(self.Preview, INPUT, name, type, executionOrder = self.ExecutionOrder.GetValue()) - elif classtype == "Output": - self.Variable = FBD_Variable(self.Preview, OUTPUT, name, type, executionOrder = self.ExecutionOrder.GetValue()) - elif classtype == "InOut": - self.Variable = FBD_Variable(self.Preview, INOUT, name, type, executionOrder = self.ExecutionOrder.GetValue()) + classtype = VARIABLE_CLASSES_DICT_REVERSE[self.Class.GetStringSelection()] + self.Variable = FBD_Variable(self.Preview, classtype, name, type, executionOrder = self.ExecutionOrder.GetValue()) width, height = self.MinVariableSize min_width, min_height = self.Variable.GetMinSize() width, height = max(min_width, width), max(min_height, height) @@ -784,29 +781,29 @@ wx.Dialog.__init__(self, id=ID_CONNECTIONPROPERTIESDIALOG, name='ConnectionPropertiesDialog', parent=prnt, pos=wx.Point(376, 223), size=wx.Size(350, 220), style=wx.DEFAULT_DIALOG_STYLE, - title='Connection Properties') + title=_('Connection Properties')) self.SetClientSize(wx.Size(350, 220)) self.staticText1 = wx.StaticText(id=ID_CONNECTIONPROPERTIESDIALOGSTATICTEXT1, - label='Type:', name='staticText1', parent=self, + label=_('Type:'), name='staticText1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText2 = wx.StaticText(id=ID_CONNECTIONPROPERTIESDIALOGSTATICTEXT2, - label='Name:', name='staticText2', parent=self, + label=_('Name:'), name='staticText2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText3 = wx.StaticText(id=ID_CONNECTIONPROPERTIESDIALOGSTATICTEXT3, - label='Preview:', name='staticText3', parent=self, + label=_('Preview:'), name='staticText3', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.radioButton1 = wx.RadioButton(id=ID_CONNECTIONPROPERTIESDIALOGRADIOBUTTON1, - label='Connector', name='radioButton1', parent=self, + label=_('Connector'), name='radioButton1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=wx.RB_GROUP) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_CONNECTIONPROPERTIESDIALOGRADIOBUTTON1) self.radioButton1.SetValue(True) self.radioButton2 = wx.RadioButton(id=ID_CONNECTIONPROPERTIESDIALOGRADIOBUTTON2, - label='Continuation', name='radioButton2', parent=self, + label=_('Continuation'), name='radioButton2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_CONNECTIONPROPERTIESDIALOGRADIOBUTTON2) self.radioButton2.SetValue(False) @@ -882,23 +879,23 @@ def OnOK(self, event): connection_name = self.ConnectionName.GetValue() if connection_name == "": - message = wx.MessageDialog(self, "Form isn't complete. Name must be filled!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("Form isn't complete. Name must be filled!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif not TestIdentifier(connection_name): - message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%connection_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%connection_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif connection_name.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%connection_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%connection_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif connection_name.upper() in self.PouNames: - message = wx.MessageDialog(self, "\"%s\" pou already exists!"%connection_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" pou already exists!")%connection_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif connection_name.upper() in self.PouElementNames: - message = wx.MessageDialog(self, "\"%s\" element for this pou already exists!"%connection_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" element for this pou already exists!")%connection_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() else: @@ -1022,45 +1019,45 @@ self.SetClientSize(wx.Size(350, 260 + extra_size)) self.staticText1 = wx.StaticText(id=ID_LDELEMENTDIALOGSTATICTEXT1, - label='Modifier:', name='staticText1', parent=self, + label=_('Modifier:'), name='staticText1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText2 = wx.StaticText(id=ID_LDELEMENTDIALOGSTATICTEXT2, - label='Name:', name='staticText2', parent=self, + label=_('Name:'), name='staticText2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText3 = wx.StaticText(id=ID_LDELEMENTDIALOGSTATICTEXT3, - label='Preview:', name='staticText3', parent=self, + label=_('Preview:'), name='staticText3', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.radioButton1 = wx.RadioButton(id=ID_LDELEMENTDIALOGRADIOBUTTON1, - label="Normal", name='radioButton1', parent=self, + label=_("Normal"), name='radioButton1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=wx.RB_GROUP) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_LDELEMENTDIALOGRADIOBUTTON1) self.radioButton1.SetValue(True) self.radioButton2 = wx.RadioButton(id=ID_LDELEMENTDIALOGRADIOBUTTON2, - label="Negated", name='radioButton2', parent=self, + label=_("Negated"), name='radioButton2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_LDELEMENTDIALOGRADIOBUTTON2) self.radioButton3 = wx.RadioButton(id=ID_LDELEMENTDIALOGRADIOBUTTON3, - label="Set", name='radioButton3', parent=self, + label=_("Set"), name='radioButton3', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_LDELEMENTDIALOGRADIOBUTTON3) self.radioButton4 = wx.RadioButton(id=ID_LDELEMENTDIALOGRADIOBUTTON4, - label="Reset", name='radioButton4', parent=self, + label=_("Reset"), name='radioButton4', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_LDELEMENTDIALOGRADIOBUTTON4) self.radioButton5 = wx.RadioButton(id=ID_LDELEMENTDIALOGRADIOBUTTON5, - label="Rising Edge", name='radioButton5', parent=self, + label=_("Rising Edge"), name='radioButton5', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_LDELEMENTDIALOGRADIOBUTTON5) self.radioButton6 = wx.RadioButton(id=ID_LDELEMENTDIALOGRADIOBUTTON6, - label="Falling Edge", name='radioButton6', parent=self, + label=_("Falling Edge"), name='radioButton6', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_LDELEMENTDIALOGRADIOBUTTON6) @@ -1093,12 +1090,12 @@ def __init__(self, parent, controler, type): self.Type = type if type == "contact": - self._init_ctrls(parent, controler, "Edit Contact Values") + self._init_ctrls(parent, controler, _("Edit Contact Values")) self.Element = LD_Contact(self.Preview, CONTACT_NORMAL, "") self.radioButton3.Hide() self.radioButton4.Hide() elif type == "coil": - self._init_ctrls(parent, controler, "Edit Coil Values", 50) + self._init_ctrls(parent, controler, _("Edit Coil Values"), 50) self.Element = LD_Coil(self.Preview, COIL_NORMAL, "") @@ -1271,29 +1268,29 @@ wx.Dialog.__init__(self, id=ID_LDPOWERRAILDIALOG, name='PowerRailDialog', parent=prnt, pos=wx.Point(376, 223), size=wx.Size(350, 260), style=wx.DEFAULT_DIALOG_STYLE, - title='Power Rail Properties') + title=_('Power Rail Properties')) self.SetClientSize(wx.Size(350, 260)) self.staticText1 = wx.StaticText(id=ID_LDPOWERRAILDIALOGSTATICTEXT1, - label='Type:', name='staticText1', parent=self, + label=_('Type:'), name='staticText1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText2 = wx.StaticText(id=ID_LDPOWERRAILDIALOGSTATICTEXT2, - label='Pin number:', name='staticText2', parent=self, + label=_('Pin number:'), name='staticText2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText3 = wx.StaticText(id=ID_LDPOWERRAILDIALOGSTATICTEXT3, - label='Preview:', name='staticText3', parent=self, + label=_('Preview:'), name='staticText3', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.radioButton1 = wx.RadioButton(id=ID_LDPOWERRAILDIALOGRADIOBUTTON1, - label='Left PowerRail', name='radioButton1', parent=self, + label=_('Left PowerRail'), name='radioButton1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=wx.RB_GROUP) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_LDPOWERRAILDIALOGRADIOBUTTON1) self.radioButton1.SetValue(True) self.radioButton2 = wx.RadioButton(id=ID_LDPOWERRAILDIALOGRADIOBUTTON2, - label='Right PowerRail', name='radioButton2', parent=self, + label=_('Right PowerRail'), name='radioButton2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_LDPOWERRAILDIALOGRADIOBUTTON2) @@ -1451,19 +1448,19 @@ wx.Dialog.__init__(self, id=ID_STEPCONTENTDIALOG, name='StepContentDialog', parent=prnt, pos=wx.Point(376, 223), size=wx.Size(400, 250), style=wx.DEFAULT_DIALOG_STYLE, - title='Edit Step') + title=_('Edit Step')) self.SetClientSize(wx.Size(400, 250)) self.staticText1 = wx.StaticText(id=ID_STEPCONTENTDIALOGSTATICTEXT1, - label='Name:', name='staticText1', parent=self, + label=_('Name:'), name='staticText1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText2 = wx.StaticText(id=ID_STEPCONTENTDIALOGSTATICTEXT2, - label='Connectors:', name='staticText2', parent=self, + label=_('Connectors:'), name='staticText2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText3 = wx.StaticText(id=ID_STEPCONTENTDIALOGSTATICTEXT3, - label='Preview:', name='staticText4', parent=self, + label=_('Preview:'), name='staticText4', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.StepName = wx.TextCtrl(id=ID_STEPCONTENTDIALOGNAME, @@ -1472,17 +1469,17 @@ self.Bind(wx.EVT_TEXT, self.OnNameChanged, id=ID_STEPCONTENTDIALOGNAME) self.checkBox1 = wx.CheckBox(id=ID_STEPCONTENTDIALOGCHECKBOX1, - label="Input", name='checkBox1', parent=self, + label=_("Input"), name='checkBox1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_CHECKBOX, self.OnConnectorsChanged, id=ID_STEPCONTENTDIALOGCHECKBOX1) self.checkBox2 = wx.CheckBox(id=ID_STEPCONTENTDIALOGCHECKBOX2, - label="Output", name='checkBox2', parent=self, + label=_("Output"), name='checkBox2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_CHECKBOX, self.OnConnectorsChanged, id=ID_STEPCONTENTDIALOGCHECKBOX2) self.checkBox3 = wx.CheckBox(id=ID_STEPCONTENTDIALOGCHECKBOX3, - label="Action", name='checkBox3', parent=self, + label=_("Action"), name='checkBox3', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_CHECKBOX, self.OnConnectorsChanged, id=ID_STEPCONTENTDIALOGCHECKBOX3) @@ -1525,27 +1522,27 @@ def OnOK(self, event): step_name = self.StepName.GetValue() if step_name == "": - message = wx.MessageDialog(self, "You must type a name!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("You must type a name!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif not TestIdentifier(step_name): - message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%step_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%step_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif step_name.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%step_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%step_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif step_name.upper() in self.PouNames: - message = wx.MessageDialog(self, "A pou with \"%s\" as name exists!"%step_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("A pou with \"%s\" as name exists!")%step_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif step_name.upper() in self.Variables: - message = wx.MessageDialog(self, "A variable with \"%s\" as name exists!"%step_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("A variable with \"%s\" as name already exists in this pou!")%step_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif step_name.upper() in self.StepNames: - message = wx.MessageDialog(self, "\"%s\" step already exists!"%step_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" step already exists!")%step_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() else: @@ -1698,23 +1695,23 @@ wx.Dialog.__init__(self, id=ID_TRANSITIONCONTENTDIALOG, name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223), size=wx.Size(350, 300), style=wx.DEFAULT_DIALOG_STYLE, - title='Edit transition') + title=_('Edit transition')) self.SetClientSize(wx.Size(350, 300)) self.staticText1 = wx.StaticText(id=ID_TRANSITIONCONTENTDIALOGSTATICTEXT1, - label='Type:', name='staticText1', parent=self, + label=_('Type:'), name='staticText1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText2 = wx.StaticText(id=ID_TRANSITIONCONTENTDIALOGSTATICTEXT2, - label='Preview:', name='staticText2', parent=self, + label=_('Preview:'), name='staticText2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.staticText3 = wx.StaticText(id=ID_TRANSITIONCONTENTDIALOGSTATICTEXT3, - label='Priority:', name='staticText3', parent=self, + label=_('Priority:'), name='staticText3', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.radioButton1 = wx.RadioButton(id=ID_TRANSITIONCONTENTDIALOGRADIOBUTTON1, - label='Reference', name='radioButton1', parent=self, + label=_('Reference'), name='radioButton1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=wx.RB_GROUP) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_TRANSITIONCONTENTDIALOGRADIOBUTTON1) self.radioButton1.SetValue(True) @@ -1725,7 +1722,7 @@ self.Bind(wx.EVT_COMBOBOX, self.OnReferenceChanged, id=ID_TRANSITIONCONTENTDIALOGREFERENCE) self.radioButton2 = wx.RadioButton(id=ID_TRANSITIONCONTENTDIALOGRADIOBUTTON2, - label='Inline', name='radioButton2', parent=self, + label=_('Inline'), name='radioButton2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_TRANSITIONCONTENTDIALOGRADIOBUTTON2) self.radioButton2.SetValue(False) @@ -1737,7 +1734,7 @@ self.Inline.Enable(False) self.radioButton3 = wx.RadioButton(id=ID_TRANSITIONCONTENTDIALOGRADIOBUTTON3, - label='Connection', name='radioButton3', parent=self, + label=_('Connection'), name='radioButton3', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_TRANSITIONCONTENTDIALOGRADIOBUTTON3) self.radioButton3.SetValue(False) @@ -1791,19 +1788,19 @@ def OnOK(self, event): error = [] if self.radioButton1.GetValue() and self.Reference.GetStringSelection() == "": - error.append("Reference") + error.append(_("Reference")) if self.radioButton2.GetValue() and self.Inline.GetValue() == "": - error.append("Inline") + error.append(_("Inline")) if len(error) > 0: text = "" for i, item in enumerate(error): if i == 0: text += item elif i == len(error) - 1: - text += " and %s"%item + text += _(" and %s")%item else: - text += ", %s"%item - message = wx.MessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wx.OK|wx.ICON_ERROR) + text += _(", %s")%item + message = wx.MessageDialog(self, _("Form isn't complete. %s must be filled!")%text, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() else: @@ -1976,39 +1973,39 @@ wx.Dialog.__init__(self, id=ID_DIVERGENCECREATEDIALOG, name='DivergencePropertiesDialog', parent=prnt, pos=wx.Point(376, 223), size=wx.Size(500, 300), style=wx.DEFAULT_DIALOG_STYLE, - title='Create a new divergence or convergence') + title=_('Create a new divergence or convergence')) self.SetClientSize(wx.Size(500, 300)) self.staticText1 = wx.StaticText(id=ID_DIVERGENCECREATEDIALOGSTATICTEXT1, - label='Type:', name='staticText1', parent=self, + label=_('Type:'), name='staticText1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.radioButton1 = wx.RadioButton(id=ID_DIVERGENCECREATEDIALOGRADIOBUTTON1, - label='Selection Divergence', name='radioButton1', parent=self, + label=_('Selection Divergence'), name='radioButton1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=wx.RB_GROUP) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_DIVERGENCECREATEDIALOGRADIOBUTTON1) self.radioButton1.SetValue(True) self.radioButton2 = wx.RadioButton(id=ID_DIVERGENCECREATEDIALOGRADIOBUTTON2, - label='Selection Convergence', name='radioButton2', parent=self, + label=_('Selection Convergence'), name='radioButton2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_DIVERGENCECREATEDIALOGRADIOBUTTON2) self.radioButton2.SetValue(False) self.radioButton3 = wx.RadioButton(id=ID_DIVERGENCECREATEDIALOGRADIOBUTTON3, - label='Simultaneous Divergence', name='radioButton3', parent=self, + label=_('Simultaneous Divergence'), name='radioButton3', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_DIVERGENCECREATEDIALOGRADIOBUTTON3) self.radioButton3.SetValue(False) self.radioButton4 = wx.RadioButton(id=ID_DIVERGENCECREATEDIALOGRADIOBUTTON4, - label='Simultaneous Convergence', name='radioButton4', parent=self, + label=_('Simultaneous Convergence'), name='radioButton4', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, id=ID_DIVERGENCECREATEDIALOGRADIOBUTTON4) self.radioButton4.SetValue(False) self.staticText2 = wx.StaticText(id=ID_DIVERGENCECREATEDIALOGSTATICTEXT2, - label='Number of sequences:', name='staticText2', parent=self, + label=_('Number of sequences:'), name='staticText2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.Sequences = wx.SpinCtrl(id=ID_DIVERGENCECREATEDIALOGSEQUENCES, @@ -2017,7 +2014,7 @@ self.Bind(wx.EVT_SPINCTRL, self.OnSequencesChanged, id=ID_DIVERGENCECREATEDIALOGSEQUENCES) self.staticText3 = wx.StaticText(id=ID_DIVERGENCECREATEDIALOGSTATICTEXT3, - label='Preview:', name='staticText3', parent=self, + label=_('Preview:'), name='staticText3', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.Preview = wx.Panel(id=ID_DIVERGENCECREATEDIALOGPREVIEW, @@ -2103,6 +2100,14 @@ # Action Block Dialog #------------------------------------------------------------------------------- +def GetActionTableColnames(): + _ = lambda x: x + return [_("Qualifier"), _("Duration"), _("Type"), _("Value"), _("Indicator")] + +def GetTypeList(): + _ = lambda x: x + return [_("Action"), _("Variable"), _("Inline")] + class ActionTable(wx.grid.PyGridTableBase): """ @@ -2126,16 +2131,22 @@ def GetNumberRows(self): return len(self.data) - def GetColLabelValue(self, col): + def GetColLabelValue(self, col, translate=True): if col < len(self.colnames): - return self.colnames[col] - - def GetRowLabelValues(self, row): + colname = self.colnames[col] + if translate: + return _(colname) + return colname + + def GetRowLabelValues(self, row, translate=True): return row def GetValue(self, row, col): if row < self.GetNumberRows(): - name = str(self.data[row].get(self.GetColLabelValue(col), "")) + colname = self.GetColLabelValue(col, False) + name = str(self.data[row].get(colname, "")) + if colname == "Type": + return _(name) return name def GetValueByName(self, row, colname): @@ -2143,7 +2154,10 @@ def SetValue(self, row, col, value): if col < len(self.colnames): - self.data[row][self.GetColLabelValue(col)] = value + colname = self.GetColLabelValue(col, False) + if colname == "Type": + value = self.Parent.TranslateType[value] + self.data[row][colname] = value def ResetView(self, grid): """ @@ -2187,20 +2201,12 @@ Otherwise default to the default renderer. """ - for col in range(self.GetNumberCols()): - attr = wx.grid.GridCellAttr() - attr.SetAlignment(self.Parent.ColAlignements[col], wx.ALIGN_CENTRE) - grid.SetColAttr(col, attr) - grid.SetColSize(col, self.Parent.ColSizes[col]) - - typelist = None - accesslist = None for row in range(self.GetNumberRows()): for col in range(self.GetNumberCols()): editor = None renderer = None readonly = False - colname = self.GetColLabelValue(col) + colname = self.GetColLabelValue(col, False) if colname == "Qualifier": editor = wx.grid.GridCellChoiceEditor() editor.SetParameters(self.Parent.QualifierList) @@ -2319,11 +2325,11 @@ wx.Dialog.__init__(self, id=ID_ACTIONBLOCKDIALOG, name='ActionBlockDialog', parent=prnt, pos=wx.Point(376, 223), size=wx.Size(500, 300), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER, - title='Edit action block properties') + title=_('Edit action block properties')) self.SetClientSize(wx.Size(500, 300)) self.staticText1 = wx.StaticText(id=ID_ACTIONBLOCKDIALOGSTATICTEXT1, - label='Actions:', name='staticText1', parent=self, + label=_('Actions:'), name='staticText1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) self.ActionsGrid = wx.grid.Grid(id=ID_ACTIONBLOCKDIALOGVARIABLESGRID, @@ -2337,14 +2343,14 @@ self.ActionsGrid.EnableScrolling(False, True) self.ActionsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnActionsGridCellChange) - self.AddButton = wx.Button(id=ID_ACTIONBLOCKDIALOGADDBUTTON, label='Add', + self.AddButton = wx.Button(id=ID_ACTIONBLOCKDIALOGADDBUTTON, label=_('Add'), name='AddButton', parent=self, pos=wx.Point(0, 0), - size=wx.Size(72, 32), style=0) + size=wx.DefaultSize, style=0) self.Bind(wx.EVT_BUTTON, self.OnAddButton, id=ID_ACTIONBLOCKDIALOGADDBUTTON) - self.DeleteButton = wx.Button(id=ID_ACTIONBLOCKDIALOGDELETEBUTTON, label='Delete', + self.DeleteButton = wx.Button(id=ID_ACTIONBLOCKDIALOGDELETEBUTTON, label=_('Delete'), name='DeleteButton', parent=self, pos=wx.Point(0, 0), - size=wx.Size(72, 32), style=0) + size=wx.DefaultSize, style=0) self.Bind(wx.EVT_BUTTON, self.OnDeleteButton, id=ID_ACTIONBLOCKDIALOGDELETEBUTTON) self.UpButton = wx.Button(id=ID_ACTIONBLOCKDIALOGUPBUTTON, label='^', @@ -2369,14 +2375,23 @@ self._init_ctrls(parent) self.DefaultValue = {"Qualifier" : "N", "Duration" : "", "Type" : "Action", "Value" : "", "Indicator" : ""} - self.Table = ActionTable(self, [], ["Qualifier","Duration","Type","Value","Indicator"]) - self.TypeList = "Action,Variable,Inline" + 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, 80, 110, 80] self.ColAlignements = [wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT] self.ActionsGrid.SetTable(self.Table) 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) def OnOK(self, event): @@ -2490,27 +2505,27 @@ def OnOK(self, event): step_name = self.GetSizer().GetItem(1).GetWindow().GetValue() if step_name == "": - message = wx.MessageDialog(self, "You must type a name!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("You must type a name!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif not TestIdentifier(step_name): - message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%step_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%step_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif step_name.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%step_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%step_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif step_name.upper() in self.PouNames: - message = wx.MessageDialog(self, "A pou with \"%s\" as name exists!"%step_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("A pou with \"%s\" as name exists!")%step_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif step_name.upper() in self.Variables: - message = wx.MessageDialog(self, "A variable with \"%s\" as name exists!"%step_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("A variable with \"%s\" as name already exists in this pou!")%step_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif step_name.upper() in self.StepNames: - message = wx.MessageDialog(self, "\"%s\" step already exists!"%step_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" step already exists!")%step_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() else: @@ -2557,19 +2572,19 @@ def OnOK(self, event): step_name = self.GetSizer().GetItem(1).GetWindow().GetValue() if step_name == "": - message = wx.MessageDialog(self, "You must type a name!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("You must type a name!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif not TestIdentifier(step_name): - message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%step_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%step_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif step_name.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%step_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%step_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif step_name.upper() in self.PouNames: - message = wx.MessageDialog(self, "A pou with \"%s\" as name exists!"%step_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("A pou with \"%s\" as name exists!")%step_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() else: @@ -2579,4 +2594,4 @@ self.PouNames = [pou_name.upper() for pou_name in pou_names] def GetValue(self): - return self.GetSizer().GetItem(1).GetWindow().GetValue() \ No newline at end of file + return self.GetSizer().GetItem(1).GetWindow().GetValue() diff -r d07815f10ca8 -r 323c8d76f6f2 GraphicViewer.py --- a/GraphicViewer.py Mon Jul 27 12:01:43 2009 +0200 +++ b/GraphicViewer.py Fri Aug 07 15:49:10 2009 +0200 @@ -59,9 +59,9 @@ def _init_coll_RangeSizer_Items(self, parent): # generated method, don't edit - parent.AddWindow(self.staticbox1, 0, border=5, flag=wx.ALL) + parent.AddWindow(self.staticbox1, 0, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) parent.AddWindow(self.CanvasRange, 0, border=5, flag=wx.ALL) - parent.AddWindow(self.staticText2, 0, border=5, flag=wx.ALL) + parent.AddWindow(self.staticText2, 0, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL) parent.AddWindow(self.CanvasPosition, 0, border=5, flag=wx.GROW|wx.ALL) parent.AddWindow(self.ResetButton, 0, border=5, flag=wx.ALL) parent.AddWindow(self.CurrentButton, 0, border=5, flag=wx.ALL) @@ -103,8 +103,8 @@ self.Canvas.SetYSpec('border') self.staticbox1 = wx.StaticText(id=ID_GRAPHICVIEWERSTATICTEXT1, - label='Range:', name='staticText1', parent=self, - pos=wx.Point(0, 0), size=wx.Size(45, 17), style=0) + label=_('Range:'), name='staticText1', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.CanvasRange = wx.ComboBox(id=ID_GRAPHICVIEWERCANVASRANGE, name='CanvasRange', parent=self, pos=wx.Point(0, 0), @@ -114,8 +114,8 @@ self.Bind(wx.EVT_TEXT_ENTER, self.OnRangeChanged, id=ID_GRAPHICVIEWERCANVASRANGE) self.staticText2 = wx.StaticText(id=ID_GRAPHICVIEWERSTATICTEXT2, - label='Position:', name='staticText2', parent=self, - pos=wx.Point(0, 0), size=wx.Size(60, 17), style=0) + label=_('Position:'), name='staticText2', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.CanvasPosition = wx.ScrollBar(id=ID_GRAPHICVIEWERCANVASPOSITION, name='Position', parent=self, pos=wx.Point(0, 0), @@ -178,7 +178,7 @@ self.VariableGraphic = plot.PolyLine(self.Datas[self.CurrentValue:self.CurrentValue + self.CurrentRange], legend=var_name, colour=colours[0]) - self.GraphicsObject = plot.PlotGraphics([self.VariableGraphic], "%s Graphics" % var_name, "Tick", "Values") + self.GraphicsObject = plot.PlotGraphics([self.VariableGraphic], _("%s Graphics") % var_name, _("Tick"), _("Values")) datas_length = len(self.Datas) if datas_length > 1: start = self.Datas[self.CurrentValue][0] diff -r d07815f10ca8 -r 323c8d76f6f2 LDViewer.py --- a/LDViewer.py Mon Jul 27 12:01:43 2009 +0200 +++ b/LDViewer.py Fri Aug 07 15:49:10 2009 +0200 @@ -193,8 +193,8 @@ else: self.RungComments.insert(i, None) - def loadInstance(self, instance, ids): - Viewer.loadInstance(self, instance, ids) + def loadInstance(self, instance, ids, selection): + Viewer.loadInstance(self, instance, ids, selection) if self.GetDrawingMode() != FREEDRAWING_MODE: if instance["type"] == "leftPowerRail": element = self.FindElementById(instance["id"]) @@ -210,7 +210,7 @@ if rung not in rungs: rungs.append(rung) if len(rungs) > 1: - raise "ValueError", "Ladder element with id %d is on more than one rung."%instance["id"] + raise ValueError, _("Ladder element with id %d is on more than one rung.")%instance["id"] element = self.FindElementById(instance["id"]) self.Rungs[rungs[0]].SelectElement(element) for connector in element.GetConnectors(): @@ -225,7 +225,7 @@ if rung not in rungs: rungs.append(rung) if len(rungs) > 1: - raise "ValueError", "Ladder element with id %d is on more than one rung."%instance["id"] + raise ValueError, _("Ladder element with id %d is on more than one rung.")%instance["id"] element = self.FindElementById(instance["id"]) self.Rungs[rungs[0]].SelectElement(element) for wire, num in element.GetConnectors()["input"].GetWires(): @@ -358,7 +358,7 @@ else: element.OnLeftUp(event, dc, self.Scaling) self.SelectedElement.Refresh() - wx.CallAfter(self.SetCursor, wx.NullCursor) + wx.CallAfter(self.SetCurrentCursor, 0) event.Skip() def OnViewerRightUp(self, event): @@ -378,7 +378,7 @@ self.SelectedElement.SetSelected(True) self.SelectedElement.OnRightUp(event, dc, self.Scaling) self.SelectedElement.Refresh() - wx.CallAfter(self.SetCursor, wx.NullCursor) + wx.CallAfter(self.SetCurrentCursor, 0) event.Skip() def OnViewerLeftDClick(self, event): @@ -475,7 +475,7 @@ rung = Graphic_Group(self) # Create comment id = self.GetNewId() - comment = Comment(self, "Commentaire", id) + comment = Comment(self, _("Comment"), id) comment.SetPosition(startx, starty) comment.SetSize(LD_COMMENT_DEFAULTSIZE[0], LD_COMMENT_DEFAULTSIZE[1]) self.AddComment(comment) @@ -625,7 +625,7 @@ self.RefreshScrollBars() self.Refresh(False) else: - message = wx.MessageDialog(self, "You must select the wire where a contact should be added!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("You must select the wire where a contact should be added!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() @@ -847,16 +847,16 @@ self.RefreshScrollBars() self.Refresh(False) else: - message = wx.MessageDialog(self, "The group of block must be coherent!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("The group of block must be coherent!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() else: - message = wx.MessageDialog(self, "You must select the block or group of blocks around which a branch should be added!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("You must select the block or group of blocks around which a branch should be added!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() def AddLadderBlock(self): - message = wx.MessageDialog(self, "This option isn't available yet!", "Warning", wx.OK|wx.ICON_EXCLAMATION) + message = wx.MessageDialog(self, _("This option isn't available yet!"), _("Warning"), wx.OK|wx.ICON_EXCLAMATION) message.ShowModal() message.Destroy() diff -r d07815f10ca8 -r 323c8d76f6f2 PLCControler.py --- a/PLCControler.py Mon Jul 27 12:01:43 2009 +0200 +++ b/PLCControler.py Fri Aug 07 15:49:10 2009 +0200 @@ -26,8 +26,8 @@ from types import StringType, UnicodeType import cPickle import os,sys,re +import datetime from time import localtime -from datetime import * from plcopen import plcopen from plcopen.structures import * @@ -77,6 +77,16 @@ ScriptDirectory = os.path.split(os.path.realpath(__file__))[0] +def GetUneditableNames(): + _ = lambda x:x + return [_("User-defined POUs"), _("Functions"), _("Function Blocks"), + _("Programs"), _("Data Types"), _("Transitions"), _("Actions"), + _("Configurations"), _("Resources"), _("Properties")] +UNEDITABLE_NAMES = GetUneditableNames() +[USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS, + DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS, + RESOURCES, PROPERTIES] = UNEDITABLE_NAMES + #------------------------------------------------------------------------------- # Undo Buffer for PLCOpenEditor #------------------------------------------------------------------------------- @@ -211,7 +221,7 @@ def CreateNewProject(self, properties): # Create the project self.Project = plcopen.project() - properties["creationDateTime"] = datetime(*localtime()[:6]) + properties["creationDateTime"] = datetime.datetime(*localtime()[:6]) self.Project.setfileHeader(properties) self.Project.setcontentHeader(properties) self.SetFilePath("") @@ -280,7 +290,7 @@ self.FilePath = filepath if filepath == "": self.LastNewIndex += 1 - self.FileName = "Unnamed%d"%self.LastNewIndex + self.FileName = _("Unnamed%d")%self.LastNewIndex else: self.FileName = os.path.splitext(os.path.basename(filepath))[0] @@ -309,13 +319,13 @@ project = self.GetProject(debug) if project is not None: infos = {"name": project.getname(), "type": ITEM_PROJECT} - datatypes = {"name": "Data Types", "type": ITEM_DATATYPES, "values":[]} + datatypes = {"name": DATA_TYPES, "type": ITEM_DATATYPES, "values":[]} for datatype in project.getdataTypes(): datatypes["values"].append({"name": datatype.getname(), "type": ITEM_DATATYPE, "tagname": self.ComputeDataTypeName(datatype.getname()), "values": []}) - pou_types = {"function": {"name": "Functions", "type": ITEM_FUNCTION, "values":[]}, - "functionBlock": {"name": "Function Blocks", "type": ITEM_FUNCTIONBLOCK, "values":[]}, - "program": {"name": "Programs", "type": ITEM_PROGRAM, "values":[]}} + pou_types = {"function": {"name": FUNCTIONS, "type": ITEM_FUNCTION, "values":[]}, + "functionBlock": {"name": FUNCTION_BLOCKS, "type": ITEM_FUNCTIONBLOCK, "values":[]}, + "program": {"name": PROGRAMS, "type": ITEM_PROGRAM, "values":[]}} for pou in project.getpous(): pou_type = pou.getpouType() pou_infos = {"name": pou.getname(), "type": ITEM_POU, @@ -327,23 +337,23 @@ transitions.append({"name": transition.getname(), "type": ITEM_TRANSITION, "tagname": self.ComputePouTransitionName(pou.getname(), transition.getname()), "values": []}) - pou_values.append({"name": "Transitions", "type": ITEM_TRANSITIONS, "values": transitions}) + pou_values.append({"name": TRANSITIONS, "type": ITEM_TRANSITIONS, "values": transitions}) actions = [] for action in pou.getactionList(): actions.append({"name": action.getname(), "type": ITEM_ACTION, "tagname": self.ComputePouActionName(pou.getname(), action.getname()), "values": []}) - pou_values.append({"name": "Actions", "type": ITEM_ACTIONS, "values": actions}) + pou_values.append({"name": ACTIONS, "type": ITEM_ACTIONS, "values": actions}) if pou_type in pou_types: pou_infos["values"] = pou_values pou_types[pou_type]["values"].append(pou_infos) - configurations = {"name": "Configurations", "type": ITEM_CONFIGURATIONS, "values": []} + configurations = {"name": CONFIGURATIONS, "type": ITEM_CONFIGURATIONS, "values": []} for config in project.getconfigurations(): config_name = config.getname() config_infos = {"name": config_name, "type": ITEM_CONFIGURATION, "tagname": self.ComputeConfigurationName(config.getname()), "values": []} - resources = {"name": "Resources", "type": ITEM_RESOURCES, "values": []} + resources = {"name": RESOURCES, "type": ITEM_RESOURCES, "values": []} for resource in config.getresource(): resource_name = resource.getname() resource_infos = {"name": resource_name, "type": ITEM_RESOURCE, @@ -352,7 +362,7 @@ resources["values"].append(resource_infos) config_infos["values"] = [resources] configurations["values"].append(config_infos) - infos["values"] = [{"name": "Properties", "type": ITEM_PROPERTIES, "values": []}, + infos["values"] = [{"name": PROPERTIES, "type": ITEM_PROPERTIES, "values": []}, datatypes, pou_types["function"], pou_types["functionBlock"], pou_types["program"], configurations] return infos @@ -369,11 +379,11 @@ resource_infos = {"name" : resource.getname(), "type": ITEM_RESOURCE, "values": []} for task in resource.gettask(): for pou in task.getpouInstance(): - instance_infos = self.GetPouTopology(pou.getname(), pou.gettype(), debug=debug) + instance_infos = self.GetPouTopology(pou.getname(), pou.gettypeName(), debug=debug) if instance_infos is not None: resource_infos["values"].append(instance_infos) for pou in resource.getpouInstance(): - instance_infos = self.GetPouTopology(pou.getname(), pou.gettype(), debug=debug) + instance_infos = self.GetPouTopology(pou.getname(), pou.gettypeName(), debug=debug) if instance_infos is not None: resource_infos["values"].append(instance_infos) for varlist in resource.getglobalVars(): @@ -1165,7 +1175,7 @@ blocktypes = [category for category in BlockTypes + self.PluginTypes] project = self.GetProject(debug) if project is not None: - blocktypes.append({"name" : "User-defined POUs", "list": project.GetCustomBlockTypes(name, type == "function" or words[0] == "T")}) + blocktypes.append({"name" : USER_DEFINED_POUS, "list": project.GetCustomBlockTypes(name, type == "function" or words[0] == "T")}) return blocktypes # Return Function Block types checking for recursion @@ -1580,6 +1590,148 @@ return self.GetProjectPouVariables(words[1], debug) return [] + def GetEditedElementCopy(self, tagname, debug = False): + element = self.GetEditedElement(tagname, debug) + if element is not None: + name = element.__class__.__name__ + return element.generateXMLText(name.split("_")[-1], 0) + return "" + + def GetEditedElementInstancesCopy(self, tagname, blocks_id = None, wires = None, debug = False): + element = self.GetEditedElement(tagname, debug) + text = "" + if element is not None: + wires = dict([(wire, True) for wire in wires if wire[0] in blocks_id and wire[1] in blocks_id]) + for id in blocks_id: + instance = element.getinstance(id) + if instance is not None: + instance_copy = self.Copy(instance) + instance_copy.filterConnections(wires) + name = instance_copy.__class__.__name__ + text += instance_copy.generateXMLText(name.split("_")[-1], 0) + return text + + def GenerateNewName(self, tagname, name, format, exclude={}, debug=False): + names = exclude.copy() + names.update(dict([(varname.upper(), True) for varname in self.GetEditedElementVariables(tagname, debug)])) + element = self.GetEditedElement(tagname, debug) + if element is not None: + for instance in element.getinstances(): + if isinstance(instance, (plcopen.sfcObjects_step, plcopen.commonObjects_connector, plcopen.commonObjects_continuation)): + names[instance.getname()] = True + i = 1 + while names.get(name.upper(), False): + name = (format%i) + i += 1 + return name + + CheckPasteCompatibility = {"SFC": lambda name: True, + "LD": lambda name: not name.startswith("sfcObjects"), + "FBD": lambda name: name.startswith("fbdObjects") or name.startswith("commonObjects")} + + def PasteEditedElementInstances(self, tagname, text, new_pos, middle=False, debug=False): + element = self.GetEditedElement(tagname, debug) + element_name, element_type = self.GetEditedElementType(tagname, debug) + if element is not None: + bodytype = element.getbodyType() + + # Get edited element type scaling + scaling = None + project = self.GetProject(debug) + if project is not None: + properties = project.getcontentHeader() + scaling = properties["scaling"][bodytype] + + # Get ids already by all the instances in edited element + used_id = dict([(instance.getlocalId(), True) for instance in element.getinstances()]) + new_id = {} + + text = "%s"%text + + try: + tree = minidom.parseString(text) + except: + return _("Invalid plcopen element(s)!!!") + instances = [] + exclude = {} + for root in tree.childNodes: + if root.nodeType == tree.ELEMENT_NODE and root.nodeName == "paste": + for child in root.childNodes: + if child.nodeType == tree.ELEMENT_NODE: + classname = plcopen.ElementNameToClass[child.nodeName] + if not self.CheckPasteCompatibility[bodytype](classname): + return _("\"%s\" element can't be paste here!!!")%child.nodeName + classobj = getattr(plcopen, classname, None) + if classobj is not None: + instance = classobj() + instance.loadXMLTree(child) + if child.nodeName == "block": + blockname = instance.getinstanceName() + if blockname is not None: + blocktype = instance.gettypeName() + if element_type == "function": + return _("FunctionBlock \"%s\" can't be paste in a Function!!!")%blocktype + blockname = self.GenerateNewName(tagname, blockname, "Block%d", debug=debug) + exclude[blockname] = True + instance.setinstanceName(blockname) + self.AddEditedElementPouVar(tagname, blocktype, blockname) + elif child.nodeName == "step": + stepname = self.GenerateNewName(tagname, instance.getname(), "Step%d", exclude, debug) + exclude[stepname] = True + instance.setname(stepname) + localid = instance.getlocalId() + if not used_id.has_key(localid): + new_id[localid] = True + instances.append((child.nodeName, instance)) + + if len(instances) == 0: + return _("Invalid plcopen element(s)!!!") + + idx = 1 + translate_id = {} + bbox = plcopen.rect() + for name, instance in instances: + localId = instance.getlocalId() + bbox.union(instance.getBoundingBox()) + if used_id.has_key(localId): + while used_id.has_key(idx) or new_id.has_key(idx): + idx += 1 + new_id[idx] = True + instance.setlocalId(idx) + translate_id[localId] = idx + + x, y, width, height = bbox.bounding_box() + if middle: + new_pos[0] -= width / 2 + new_pos[1] -= height / 2 + else: + new_pos = map(lambda x: x + 30, new_pos) + if scaling[0] != 0 and scaling[1] != 0: + min_pos = map(lambda x: 30 / x, scaling) + minx = round(min_pos[0]) + if int(min_pos[0]) == round(min_pos[0]): + minx += 1 + miny = round(min_pos[1]) + if int(min_pos[1]) == round(min_pos[1]): + miny += 1 + minx *= scaling[0] + miny *= scaling[1] + new_pos = (max(minx, round(new_pos[0] / scaling[0]) * scaling[0]), + max(miny, round(new_pos[1] / scaling[1]) * scaling[1])) + else: + new_pos = (max(30, new_pos[0]), max(30, new_pos[1])) + diff = (new_pos[0] - x, new_pos[1] - y) + + connections = {} + for name, instance in instances: + connections.update(instance.updateConnectionsId(translate_id)) + if getattr(instance, "setexecutionOrderId", None) is not None: + instance.setexecutionOrderId(0) + instance.translate(*diff) + element.addinstance(name, instance) + + return new_id, connections + # Return the current pou editing informations def GetEditedElementInstanceInfos(self, tagname, id = None, exclude = [], debug = False): infos = {} @@ -1592,282 +1744,10 @@ else: instance = element.getrandomInstance(exclude) if instance is not None: - if id is not None: - infos["id"] = id - else: - infos["id"] = instance.getlocalId() - infos["x"] = instance.getx() - infos["y"] = instance.gety() - infos["height"] = instance.getheight() - infos["width"] = instance.getwidth() - if isinstance(instance, plcopen.fbdObjects_block): - infos["name"] = instance.getinstanceName() - infos["type"] = instance.gettypeName() - executionOrder = instance.getexecutionOrderId() - if executionOrder is not None: - infos["executionOrder"] = executionOrder - else: - infos["executionOrder"] = 0 - infos["connectors"] = {"inputs":[],"outputs":[]} - for variable in instance.inputVariables.getvariable(): - connector = {} - connector["name"] = variable.getformalParameter() - connector["position"] = variable.connectionPointIn.getrelPositionXY() - connector["negated"] = variable.getnegated() - connector["edge"] = variable.getedge() - connector["links"] = [] - connections = variable.connectionPointIn.getconnections() - if connections: - for link in connections: - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - connector["links"].append(dic) - infos["connectors"]["inputs"].append(connector) - for variable in instance.outputVariables.getvariable(): - connector = {} - connector["name"] = variable.getformalParameter() - connector["position"] = variable.connectionPointOut.getrelPositionXY() - connector["negated"] = variable.getnegated() - connector["edge"] = variable.getedge() - infos["connectors"]["outputs"].append(connector) - elif isinstance(instance, plcopen.fbdObjects_inVariable): - infos["name"] = instance.getexpression() - infos["value_type"] = self.GetEditedElementVarValueType(tagname, infos["name"], debug) - infos["type"] = "input" - executionOrder = instance.getexecutionOrderId() - if executionOrder is not None: - infos["executionOrder"] = executionOrder - else: - infos["executionOrder"] = 0 - infos["connector"] = {} - infos["connector"]["position"] = instance.connectionPointOut.getrelPositionXY() - infos["connector"]["negated"] = instance.getnegated() - infos["connector"]["edge"] = instance.getedge() - elif isinstance(instance, plcopen.fbdObjects_outVariable): - infos["name"] = instance.getexpression() - infos["value_type"] = self.GetEditedElementVarValueType(tagname, infos["name"], debug) - infos["type"] = "output" - executionOrder = instance.getexecutionOrderId() - if executionOrder is not None: - infos["executionOrder"] = executionOrder - else: - infos["executionOrder"] = 0 - infos["connector"] = {} - infos["connector"]["position"] = instance.connectionPointIn.getrelPositionXY() - infos["connector"]["negated"] = instance.getnegated() - infos["connector"]["edge"] = instance.getedge() - infos["connector"]["links"] = [] - connections = instance.connectionPointIn.getconnections() - if connections: - for link in connections: - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - infos["connector"]["links"].append(dic) - elif isinstance(instance, plcopen.fbdObjects_inOutVariable): - infos["name"] = instance.getexpression() - infos["value_type"] = self.GetEditedElementVarValueType(tagname, infos["name"], debug) - infos["type"] = "inout" - executionOrder = instance.getexecutionOrderId() - if executionOrder is not None: - infos["executionOrder"] = executionOrder - else: - infos["executionOrder"] = 0 - infos["connectors"] = {"input":{},"output":{}} - infos["connectors"]["output"]["position"] = instance.connectionPointOut.getrelPositionXY() - infos["connectors"]["output"]["negated"] = instance.getnegatedOut() - infos["connectors"]["output"]["edge"] = instance.getedgeOut() - infos["connectors"]["input"]["position"] = instance.connectionPointIn.getrelPositionXY() - infos["connectors"]["input"]["negated"] = instance.getnegatedIn() - infos["connectors"]["input"]["edge"] = instance.getedgeIn() - infos["connectors"]["input"]["links"] = [] - connections = instance.connectionPointIn.getconnections() - if connections: - for link in connections: - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - infos["connectors"]["input"]["links"].append(dic) - elif isinstance(instance, plcopen.commonObjects_continuation): - infos["name"] = instance.getname() - infos["type"] = "continuation" - infos["connector"] = {} - infos["connector"]["position"] = instance.connectionPointOut.getrelPositionXY() - elif isinstance(instance, plcopen.commonObjects_connector): - infos["name"] = instance.getname() - infos["type"] = "connection" - infos["connector"] = {} - infos["connector"]["position"] = instance.connectionPointIn.getrelPositionXY() - infos["connector"]["links"] = [] - connections = instance.connectionPointIn.getconnections() - if connections: - for link in connections: - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - infos["connector"]["links"].append(dic) - elif isinstance(instance, plcopen.commonObjects_comment): - infos["type"] = "comment" - infos["content"] = instance.getcontentText() - elif isinstance(instance, plcopen.ldObjects_leftPowerRail): - infos["type"] = "leftPowerRail" - infos["connectors"] = [] - for connection in instance.getconnectionPointOut(): - connector = {} - connector["position"] = connection.getrelPositionXY() - infos["connectors"].append(connector) - elif isinstance(instance, plcopen.ldObjects_rightPowerRail): - infos["type"] = "rightPowerRail" - infos["connectors"] = [] - for connection in instance.getconnectionPointIn(): - connector = {} - connector["position"] = connection.getrelPositionXY() - connector["links"] = [] - connections = connection.getconnections() - if connections: - for link in connection.getconnections(): - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - connector["links"].append(dic) - infos["connectors"].append(connector) - elif isinstance(instance, plcopen.ldObjects_contact): - infos["name"] = instance.getvariable() - infos["type"] = "contact" - executionOrder = instance.getexecutionOrderId() - if executionOrder is not None: - infos["executionOrder"] = executionOrder - else: - infos["executionOrder"] = 0 - infos["negated"] = instance.getnegated() - infos["edge"] = instance.getedge() - infos["connectors"] = {"input":{},"output":{}} - infos["connectors"]["input"]["position"] = instance.connectionPointIn.getrelPositionXY() - infos["connectors"]["input"]["links"] = [] - connections = instance.connectionPointIn.getconnections() - if connections: - for link in connections: - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - infos["connectors"]["input"]["links"].append(dic) - infos["connectors"]["output"]["position"] = instance.connectionPointOut.getrelPositionXY() - elif isinstance(instance, plcopen.ldObjects_coil): - infos["name"] = instance.getvariable() - infos["type"] = "coil" - executionOrder = instance.getexecutionOrderId() - if executionOrder is not None: - infos["executionOrder"] = executionOrder - else: - infos["executionOrder"] = 0 - infos["negated"] = instance.getnegated() - infos["edge"] = instance.getedge() - infos["storage"] = instance.getstorage() - infos["connectors"] = {"input":{},"output":{}} - infos["connectors"]["input"]["position"] = instance.connectionPointIn.getrelPositionXY() - infos["connectors"]["input"]["links"] = [] - connections = instance.connectionPointIn.getconnections() - if connections: - for link in connections: - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - infos["connectors"]["input"]["links"].append(dic) - infos["connectors"]["output"]["position"] = instance.connectionPointOut.getrelPositionXY() - elif isinstance(instance, plcopen.sfcObjects_step): - infos["name"] = instance.getname() - infos["type"] = "step" - infos["initial"] = instance.getinitialStep() - infos["connectors"] = {} - if instance.connectionPointIn: - infos["connectors"]["input"] = {} - infos["connectors"]["input"]["position"] = instance.connectionPointIn.getrelPositionXY() - infos["connectors"]["input"]["links"] = [] - connections = instance.connectionPointIn.getconnections() - if connections: - for link in connections: - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - infos["connectors"]["input"]["links"].append(dic) - if instance.connectionPointOut: - infos["connectors"]["output"] = {"position" : instance.connectionPointOut.getrelPositionXY()} - if instance.connectionPointOutAction: - infos["connectors"]["action"] = {"position" : instance.connectionPointOutAction.getrelPositionXY()} - elif isinstance(instance, plcopen.sfcObjects_transition): - infos["type"] = "transition" - condition = instance.getconditionContent() - priority = instance.getpriority() - if priority == None: - infos["priority"] = 0 - else: - infos["priority"] = priority - infos["condition_type"] = condition["type"] - infos["connectors"] = {"input":{},"output":{}} - infos["connectors"]["input"]["position"] = instance.connectionPointIn.getrelPositionXY() - infos["connectors"]["input"]["links"] = [] - connections = instance.connectionPointIn.getconnections() - if connections: - for link in connections: - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - infos["connectors"]["input"]["links"].append(dic) - infos["connectors"]["output"]["position"] = instance.connectionPointOut.getrelPositionXY() - if infos["condition_type"] == "connection": - infos["connectors"]["connection"] = {} - infos["connectors"]["connection"]["links"] = [] - connections = instance.getconnections() - if connections: - for link in connections: - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - infos["connectors"]["connection"]["links"].append(dic) - infos["condition"] = None - else: - infos["condition"] = condition["value"] - elif isinstance(instance, (plcopen.sfcObjects_selectionDivergence, plcopen.sfcObjects_simultaneousDivergence)): - if isinstance(instance, plcopen.sfcObjects_selectionDivergence): - infos["type"] = "selectionDivergence" - else: - infos["type"] = "simultaneousDivergence" - infos["connectors"] = {"inputs":[],"outputs":[]} - connector = {} - connector["position"] = instance.connectionPointIn.getrelPositionXY() - connector["links"] = [] - connections = instance.connectionPointIn.getconnections() - if connections: - for link in connections: - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - connector["links"].append(dic) - infos["connectors"]["inputs"].append(connector) - for sequence in instance.getconnectionPointOut(): - connector = {} - connector["position"] = sequence.getrelPositionXY() - infos["connectors"]["outputs"].append(connector) - elif isinstance(instance, (plcopen.sfcObjects_selectionConvergence, plcopen.sfcObjects_simultaneousConvergence)): - if isinstance(instance, plcopen.sfcObjects_selectionConvergence): - infos["type"] = "selectionConvergence" - else: - infos["type"] = "simultaneousConvergence" - infos["connectors"] = {"inputs":[],"outputs":[]} - for sequence in instance.getconnectionPointIn(): - connector = {} - connector["position"] = sequence.getrelPositionXY() - connector["links"] = [] - connections = sequence.getconnections() - if connections: - for link in connections: - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - connector["links"].append(dic) - infos["connectors"]["inputs"].append(connector) - connector = {} - connector["position"] = instance.connectionPointOut.getrelPositionXY() - infos["connectors"]["outputs"].append(connector) - elif isinstance(instance, plcopen.sfcObjects_jumpStep): - infos["type"] = "jump" - infos["target"] = instance.gettargetName() - infos["connector"] = {} - infos["connector"]["position"] = instance.connectionPointIn.getrelPositionXY() - infos["connector"]["links"] = [] - connections = instance.connectionPointIn.getconnections() - if connections: - for link in connections: - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - infos["connector"]["links"].append(dic) - elif isinstance(instance, plcopen.commonObjects_actionBlock): - infos["type"] = "actionBlock" - infos["actions"] = instance.getactions() - infos["connector"] = {} - infos["connector"]["position"] = instance.connectionPointIn.getrelPositionXY() - infos["connector"]["links"] = [] - connections = instance.connectionPointIn.getconnections() - if connections: - for link in connections: - dic = {"refLocalId":link.getrefLocalId(),"points":link.getpoints(),"formalParameter":link.getformalParameter()} - infos["connector"]["links"].append(dic) + infos = instance.getinfos() + if infos["type"] in ["input", "output", "inout"]: + var_type = self.GetEditedElementVarValueType(tagname, infos["specific_values"]["name"], debug) + infos["specific_values"]["value_type"] = var_type return infos return None @@ -2067,39 +1947,29 @@ elif param == "y": variable.sety(value) elif param == "connectors": - if isinstance(variable, plcopen.fbdObjects_inVariable): - if value["output"].IsNegated(): - variable.setnegated(True) - if value["output"].GetEdge() != "none": - variable.setedge(value["output"].GetEdge()) - position = value["output"].GetRelPosition() + if len(value["outputs"]) > 0: + output = value["outputs"][0] + if len(value["inputs"]) > 0: + variable.setnegatedOut(output.IsNegated()) + variable.setedgeOut(output.GetEdge()) + else: + variable.setnegated(output.IsNegated()) + variable.setedge(output.GetEdge()) + position = output.GetRelPosition() variable.addconnectionPointOut() variable.connectionPointOut.setrelPositionXY(position.x, position.y) - elif isinstance(variable, plcopen.fbdObjects_outVariable): - if value["input"].IsNegated(): - variable.setnegated(True) - if value["input"].GetEdge() != "none": - variable.setedge(value["input"].GetEdge()) - position = value["input"].GetRelPosition() + if len(value["inputs"]) > 0: + input = value["inputs"][0] + if len(value["outputs"]) > 0: + variable.setnegatedIn(input.IsNegated()) + variable.setedgeIn(input.GetEdge()) + else: + variable.setnegated(input.IsNegated()) + variable.setedge(input.GetEdge()) + position = input.GetRelPosition() variable.addconnectionPointIn() variable.connectionPointIn.setrelPositionXY(position.x, position.y) - self.SetConnectionWires(variable.connectionPointIn, value["input"]) - elif isinstance(variable, plcopen.fbdObjects_inOutVariable): - if value["input"].IsNegated(): - variable.setnegatedIn(True) - if value["input"].GetEdge() != "none": - variable.setedgeIn(value["input"].GetEdge()) - if value["output"].IsNegated(): - variable.setnegatedOut(True) - if value["output"].GetEdge() != "none": - variable.setedgeOut(value["output"].GetEdge()) - position = value["output"].GetRelPosition() - variable.addconnectionPointOut() - variable.connectionPointOut.setrelPositionXY(position.x, position.y) - position = value["input"].GetRelPosition() - variable.addconnectionPointIn() - variable.connectionPointIn.setrelPositionXY(position.x, position.y) - self.SetConnectionWires(variable.connectionPointIn, value["input"]) + self.SetConnectionWires(variable.connectionPointIn, input) def AddEditedElementConnection(self, tagname, id, type): element = self.GetEditedElement(tagname) @@ -2193,14 +2063,14 @@ elif param == "connectors": if isinstance(powerrail, plcopen.ldObjects_leftPowerRail): powerrail.setconnectionPointOut([]) - for connector in value: + for connector in value["outputs"]: position = connector.GetRelPosition() connection = plcopen.leftPowerRail_connectionPointOut() connection.setrelPositionXY(position.x, position.y) powerrail.connectionPointOut.append(connection) elif isinstance(powerrail, plcopen.ldObjects_rightPowerRail): powerrail.setconnectionPointIn([]) - for connector in value: + for connector in value["inputs"]: position = connector.GetRelPosition() connection = plcopen.connectionPointIn() connection.setrelPositionXY(position.x, position.y) @@ -2245,12 +2115,12 @@ elif param == "y": contact.sety(value) elif param == "connectors": - input_connector = value["input"] + input_connector = value["inputs"][0] position = input_connector.GetRelPosition() contact.addconnectionPointIn() contact.connectionPointIn.setrelPositionXY(position.x, position.y) self.SetConnectionWires(contact.connectionPointIn, input_connector) - output_connector = value["output"] + output_connector = value["outputs"][0] position = output_connector.GetRelPosition() contact.addconnectionPointOut() contact.connectionPointOut.setrelPositionXY(position.x, position.y) @@ -2305,12 +2175,12 @@ elif param == "y": coil.sety(value) elif param == "connectors": - input_connector = value["input"] + input_connector = value["inputs"][0] position = input_connector.GetRelPosition() coil.addconnectionPointIn() coil.connectionPointIn.setrelPositionXY(position.x, position.y) self.SetConnectionWires(coil.connectionPointIn, input_connector) - output_connector = value["output"] + output_connector = value["outputs"][0] position = output_connector.GetRelPosition() coil.addconnectionPointOut() coil.connectionPointOut.setrelPositionXY(position.x, position.y) @@ -2342,24 +2212,24 @@ elif param == "y": step.sety(value) elif param == "connectors": - input_connector = value["input"] - if input_connector: + if len(value["inputs"]) > 0: + input_connector = value["inputs"][0] position = input_connector.GetRelPosition() step.addconnectionPointIn() step.connectionPointIn.setrelPositionXY(position.x, position.y) self.SetConnectionWires(step.connectionPointIn, input_connector) else: step.deleteconnectionPointIn() - output_connector = value["output"] - if output_connector: + if len(value["outputs"]) > 0: + output_connector = value["outputs"][0] position = output_connector.GetRelPosition() step.addconnectionPointOut() step.connectionPointOut.setrelPositionXY(position.x, position.y) else: step.deleteconnectionPointOut() - action_connector = value["action"] - if action_connector: - position = action_connector.GetRelPosition() + elif param == "action": + if value: + position = value.GetRelPosition() step.addconnectionPointOutAction() step.connectionPointOutAction.setrelPositionXY(position.x, position.y) else: @@ -2395,19 +2265,18 @@ else: transition.setpriority(None) elif param == "connectors": - input_connector = value["input"] + input_connector = value["inputs"][0] position = input_connector.GetRelPosition() transition.addconnectionPointIn() transition.connectionPointIn.setrelPositionXY(position.x, position.y) self.SetConnectionWires(transition.connectionPointIn, input_connector) - output_connector = value["output"] + output_connector = value["outputs"][0] position = output_connector.GetRelPosition() transition.addconnectionPointOut() transition.connectionPointOut.setrelPositionXY(position.x, position.y) - if infos.get("type", None) == "connection": - transition.setconditionContent("connection", None) - connection_connector = value["connection"] - self.SetConnectionWires(transition, connection_connector) + elif infos.get("type", None) == "connection" and param == "connection" and value: + transition.setconditionContent("connection", None) + self.SetConnectionWires(transition.condition.content["value"], value) def AddEditedElementDivergence(self, tagname, id, type): element = self.GetEditedElement(tagname) @@ -2567,17 +2436,19 @@ new_task.setname(task["Name"]) if task["Single"] != "": new_task.setsingle(task["Single"]) - result = duration_model.match(task["Interval"]).groups() - if reduce(lambda x, y: x or y != None, result): - values = [] - for value in result[:-1]: - if value != None: - values.append(int(value)) - else: - values.append(0) - if result[-1] is not None: - values.append(int(float(result[-1]) * 1000)) - new_task.setinterval(time(*values)) +## result = duration_model.match(task["Interval"]).groups() +## if reduce(lambda x, y: x or y != None, result): +## values = [] +## for value in result[:-1]: +## if value != None: +## values.append(int(value)) +## else: +## values.append(0) +## if result[-1] is not None: +## values.append(int(float(result[-1]) * 1000)) +## new_task.setinterval(datetime.time(*values)) + if task["Interval"] != "": + new_task.setinterval(task["Interval"]) new_task.setpriority(int(task["Priority"])) if task["Name"] != "": task_list[task["Name"]] = new_task @@ -2585,7 +2456,7 @@ for instance in instances: new_instance = plcopen.pouInstance() new_instance.setname(instance["Name"]) - new_instance.settype(instance["Type"]) + new_instance.settypeName(instance["Type"]) if instance["Task"] != "": task_list[instance["Task"]].appendpouInstance(new_instance) else: @@ -2608,19 +2479,20 @@ new_task["Single"] = "" interval = task.getinterval() if interval: - text = "" - if interval.hour != 0: - text += "%dh"%interval.hour - if interval.minute != 0: - text += "%dm"%interval.minute - if interval.second != 0: - text += "%ds"%interval.second - if interval.microsecond != 0: - if interval.microsecond % 1000 != 0: - text += "%.3fms"%(float(interval.microsecond) / 1000) - else: - text += "%dms"%(interval.microsecond / 1000) - new_task["Interval"] = text +## text = "" +## if interval.hour != 0: +## text += "%dh"%interval.hour +## if interval.minute != 0: +## text += "%dm"%interval.minute +## if interval.second != 0: +## text += "%ds"%interval.second +## if interval.microsecond != 0: +## if interval.microsecond % 1000 != 0: +## text += "%.3fms"%(float(interval.microsecond) / 1000) +## else: +## text += "%dms"%(interval.microsecond / 1000) +## new_task["Interval"] = text + new_task["Interval"] = interval else: new_task["Interval"] = "" new_task["Priority"] = str(task.getpriority()) @@ -2628,13 +2500,13 @@ for instance in task.getpouInstance(): new_instance = {} new_instance["Name"] = instance.getname() - new_instance["Type"] = instance.gettype() + new_instance["Type"] = instance.gettypeName() new_instance["Task"] = task.getname() instances_data.append(new_instance) for instance in instances: new_instance = {} new_instance["Name"] = instance.getname() - new_instance["Type"] = instance.gettype() + new_instance["Type"] = instance.gettypeName() new_instance["Task"] = "" instances_data.append(new_instance) return tasks_data, instances_data @@ -2660,14 +2532,14 @@ self.Buffering = False self.CurrentElementEditing = None return None - return "No PLC project found" + return _("No PLC project found") def SaveXMLFile(self, filepath = None): if not filepath and self.FilePath == "": return False else: contentheader = self.Project.getcontentHeader() - contentheader["modificationDateTime"] = datetime(*localtime()[:6]) + contentheader["modificationDateTime"] = datetime.datetime(*localtime()[:6]) self.Project.setcontentHeader(contentheader) text = "\n" diff -r d07815f10ca8 -r 323c8d76f6f2 PLCGenerator.py --- a/PLCGenerator.py Mon Jul 27 12:01:43 2009 +0200 +++ b/PLCGenerator.py Fri Aug 07 15:49:10 2009 +0200 @@ -143,9 +143,9 @@ max_value = basetype_content["value"].range.getupper() datatype_def += [(basetype_name, (tagname, "base")), (" (", ()), - ("%d"%min_value, (tagname, "lower")), + ("%s"%min_value, (tagname, "lower")), ("..", ()), - ("%d"%max_value, (tagname, "upper")), + ("%s"%max_value, (tagname, "upper")), (")",())] # Data type is an enumerated type elif basetype_content["name"] == "enum": @@ -167,9 +167,9 @@ # Array derived directly from an elementary type else: basetype_name = base_type["name"] - dimensions = [[("%d"%dimension.getlower(), (tagname, "range", i, "lower")), + dimensions = [[("%s"%dimension.getlower(), (tagname, "range", i, "lower")), ("..", ()), - ("%d"%dimension.getupper(), (tagname, "range", i, "upper"))] + ("%s"%dimension.getupper(), (tagname, "range", i, "upper"))] for i, dimension in enumerate(basetype_content["value"].getdimension())] datatype_def += [("ARRAY [", ())] datatype_def += JoinList([(",", ())], dimensions) @@ -229,7 +229,7 @@ program = pou_program.GenerateProgram(pou) self.Program += program else: - raise PLCGenException, "Undefined pou type \"%s\""%pou_type + raise PLCGenException, _("Undefined pou type \"%s\"")%pou_type # Generate a POU defined and used in text def GeneratePouProgramInText(self, text): @@ -356,16 +356,19 @@ # Interval argument if exists interval = task.getinterval() if interval: - resrce += [("INTERVAL := t#", ())] - if interval.hour != 0: - resrce += [("%dh"%interval.hour, (tagname, "task", task_number, "interval", "hour"))] - if interval.minute != 0: - resrce += [("%dm"%interval.minute, (tagname, "task", task_number, "interval", "minute"))] - if interval.second != 0: - resrce += [("%ds"%interval.second, (tagname, "task", task_number, "interval", "second"))] - if interval.microsecond != 0: - resrce += [("%dms"%(interval.microsecond / 1000), (tagname, "task", task_number, "interval", "millisecond"))] - resrce += [(",", ())] + resrce += [("INTERVAL := ", ()), + (interval, (tagname, "task", task_number, "interval")), + (",", ())] +## resrce += [("INTERVAL := t#", ())] +## if interval.hour != 0: +## resrce += [("%dh"%interval.hour, (tagname, "task", task_number, "interval", "hour"))] +## if interval.minute != 0: +## resrce += [("%dm"%interval.minute, (tagname, "task", task_number, "interval", "minute"))] +## if interval.second != 0: +## resrce += [("%ds"%interval.second, (tagname, "task", task_number, "interval", "second"))] +## if interval.microsecond != 0: +## resrce += [("%dms"%(interval.microsecond / 1000), (tagname, "task", task_number, "interval", "millisecond"))] +## resrce += [(",", ())] # Priority argument resrce += [("PRIORITY := ", ()), ("%d"%task.getpriority(), (tagname, "task", task_number, "priority")), @@ -380,7 +383,7 @@ (" WITH ", ()), (task.getname(), (tagname, "instance", instance_number, "task")), (" : ", ()), - (instance.gettype(), (tagname, "instance", instance_number, "type")), + (instance.gettypeName(), (tagname, "instance", instance_number, "type")), (";\n", ())] instance_number += 1 # Generate any program assign to no task @@ -388,7 +391,7 @@ resrce += [(" PROGRAM ", ()), (instance.getname(), (tagname, "instance", instance_number, "name")), (" : ", ()), - (instance.gettype(), (tagname, "instance", instance_number, "type")), + (instance.gettypeName(), (tagname, "instance", instance_number, "type")), (";\n", ())] instance_number += 1 resrce += [(" END_RESOURCE\n", ())] @@ -532,6 +535,8 @@ interface = pou.getinterface() if interface is not None: body = pou.getbody() + if isinstance(body, ListType): + body = body[0] body_content = body.getcontent() if self.Type == "FUNCTION": returntype_content = interface.getreturnType().getcontent() @@ -596,6 +601,8 @@ def ComputeConnectionTypes(self, pou): body = pou.getbody() + if isinstance(body, ListType): + body = body[0] body_content = body.getcontent() body_type = body_content["name"] if body_type in ["FBD", "LD", "SFC"]: @@ -662,7 +669,7 @@ for element in body.getcontentInstances(): if isinstance(element, plcopen.commonObjects_connector) and element.getname() == name: if connector is not None: - raise PLCGenException, "More than one connector found corresponding to \"%s\" continuation in \"%s\" POU"%(name, self.Name) + raise PLCGenException, _("More than one connector found corresponding to \"%s\" continuation in \"%s\" POU")%(name, self.Name) connector = element if connector is not None: undefined = [instance.connectionPointOut, connector.connectionPointIn] @@ -681,59 +688,64 @@ for connection in related: self.ConnectionTypes[connection] = var_type else: - raise PLCGenException, "No connector found corresponding to \"%s\" continuation in \"%s\" POU"%(name, self.Name) + raise PLCGenException, _("No connector found corresponding to \"%s\" continuation in \"%s\" POU")%(name, self.Name) elif isinstance(instance, plcopen.fbdObjects_block): block_infos = self.GetBlockType(instance.gettypeName()) - undefined = {} - for variable in instance.outputVariables.getvariable(): - output_name = variable.getformalParameter() - if output_name == "ENO": - for connection in self.ExtractRelatedConnections(variable.connectionPointOut): - self.ConnectionTypes[connection] = "BOOL" - else: - for oname, otype, oqualifier in block_infos["outputs"]: - if output_name == oname: - if otype.startswith("ANY"): - if not undefined.has_key(otype): - undefined[otype] = [] - undefined[otype].append(variable.connectionPointOut) - elif not self.ConnectionTypes.has_key(variable.connectionPointOut): - for connection in self.ExtractRelatedConnections(variable.connectionPointOut): - self.ConnectionTypes[connection] = otype - for variable in instance.inputVariables.getvariable(): - input_name = variable.getformalParameter() - if input_name == "EN": - for connection in self.ExtractRelatedConnections(variable.connectionPointIn): - self.ConnectionTypes[connection] = "BOOL" - for iname, itype, iqualifier in block_infos["inputs"]: - if input_name == iname: - connected = self.GetConnectedConnector(variable.connectionPointIn, body) - if itype.startswith("ANY"): - if not undefined.has_key(itype): - undefined[itype] = [] - undefined[itype].append(variable.connectionPointIn) - if connected: - undefined[itype].append(connected) + if block_infos is not None: + undefined = {} + for variable in instance.outputVariables.getvariable(): + output_name = variable.getformalParameter() + if output_name == "ENO": + for connection in self.ExtractRelatedConnections(variable.connectionPointOut): + self.ConnectionTypes[connection] = "BOOL" + else: + for oname, otype, oqualifier in block_infos["outputs"]: + if output_name == oname: + if otype.startswith("ANY"): + if not undefined.has_key(otype): + undefined[otype] = [] + undefined[otype].append(variable.connectionPointOut) + elif not self.ConnectionTypes.has_key(variable.connectionPointOut): + for connection in self.ExtractRelatedConnections(variable.connectionPointOut): + self.ConnectionTypes[connection] = otype + for variable in instance.inputVariables.getvariable(): + input_name = variable.getformalParameter() + if input_name == "EN": + for connection in self.ExtractRelatedConnections(variable.connectionPointIn): + self.ConnectionTypes[connection] = "BOOL" + for iname, itype, iqualifier in block_infos["inputs"]: + if input_name == iname: + connected = self.GetConnectedConnector(variable.connectionPointIn, body) + if itype.startswith("ANY"): + if not undefined.has_key(itype): + undefined[itype] = [] + undefined[itype].append(variable.connectionPointIn) + if connected: + undefined[itype].append(connected) + else: + self.ConnectionTypes[variable.connectionPointIn] = itype + if connected and not self.ConnectionTypes.has_key(connected): + for connection in self.ExtractRelatedConnections(connected): + self.ConnectionTypes[connection] = itype + for var_type, connections in undefined.items(): + related = [] + for connection in connections: + if self.ConnectionTypes.has_key(connection): + var_type = self.ConnectionTypes[connection] else: - self.ConnectionTypes[variable.connectionPointIn] = itype - if connected and not self.ConnectionTypes.has_key(connected): - for connection in self.ExtractRelatedConnections(connected): - self.ConnectionTypes[connection] = itype - for var_type, connections in undefined.items(): - related = [] - for connection in connections: - if self.ConnectionTypes.has_key(connection): - var_type = self.ConnectionTypes[connection] + related.extend(self.ExtractRelatedConnections(connection)) + if var_type.startswith("ANY") and len(related) > 0: + self.RelatedConnections.append(related) else: - related.extend(self.ExtractRelatedConnections(connection)) - if var_type.startswith("ANY") and len(related) > 0: - self.RelatedConnections.append(related) - else: - for connection in related: - self.ConnectionTypes[connection] = var_type - + for connection in related: + self.ConnectionTypes[connection] = var_type + else: + raise PLCGenException, _("No informations found for \"%s\" block")%(instance.gettypeName()) + def ComputeProgram(self, pou): body = pou.getbody() + if isinstance(body, ListType): + body = body[0] body_content = body.getcontent() body_type = body_content["name"] if body_type in ["IL","ST"]: @@ -861,7 +873,7 @@ for instance in body.getcontentInstances(): if isinstance(instance, plcopen.commonObjects_connector) and instance.getname() == name: if connector is not None: - raise PLCGenException, "More than one connector found corresponding to \"%s\" continuation in \"%s\" POU"%(name, self.Name) + raise PLCGenException, _("More than one connector found corresponding to \"%s\" continuation in \"%s\" POU")%(name, self.Name) connector = instance if connector is not None: connections = connector.connectionPointIn.getconnections() @@ -870,7 +882,7 @@ self.ComputedConnectors[name] = expression paths.append(str(expression)) else: - raise PLCGenException, "No connector found corresponding to \"%s\" continuation in \"%s\" POU"%(name, self.Name) + raise PLCGenException, _("No connector found corresponding to \"%s\" continuation in \"%s\" POU")%(name, self.Name) elif isinstance(next, plcopen.ldObjects_contact): contact_info = (self.TagName, "contact", next.getlocalId()) variable = str(self.ExtractModifier(next, [(next.getvariable(), contact_info + ("reference",))], contact_info)) @@ -958,7 +970,10 @@ connections = connectionPointIn.getconnections() if connections is not None and len(connections) == 1: instanceLocalId = connections[0].getrefLocalId() - return pou.body.getcontentInstance(instanceLocalId) + body = pou.getbody() + if isinstance(body, ListType): + body = body[0] + return body.getcontentInstance(instanceLocalId) return None def ExtractConvergenceInputs(self, convergence, pou): @@ -967,7 +982,10 @@ connections = connectionPointIn.getconnections() if len(connections) == 1: instanceLocalId = connections[0].getrefLocalId() - instances.append(pou.body.getcontentInstance(instanceLocalId)) + body = pou.getbody() + if isinstance(body, ListType): + body = body[0] + instances.append(body.getcontentInstance(instanceLocalId)) return instances def GenerateSFCStep(self, step, pou): @@ -984,7 +1002,10 @@ connections = step.connectionPointIn.getconnections() if len(connections) == 1: instanceLocalId = connections[0].getrefLocalId() - instance = pou.body.getcontentInstance(instanceLocalId) + body = pou.getbody() + if isinstance(body, ListType): + body = body[0] + instance = body.getcontentInstance(instanceLocalId) if isinstance(instance, plcopen.sfcObjects_transition): instances.append(instance) elif isinstance(instance, plcopen.sfcObjects_selectionConvergence): @@ -1010,7 +1031,10 @@ connections = jump.connectionPointIn.getconnections() if len(connections) == 1: instanceLocalId = connections[0].getrefLocalId() - instance = pou.body.getcontentInstance(instanceLocalId) + body = pou.getbody() + if isinstance(body, ListType): + body = body[0] + instance = body.getcontentInstance(instanceLocalId) if isinstance(instance, plcopen.sfcObjects_transition): instances.append(instance) elif isinstance(instance, plcopen.sfcObjects_selectionConvergence): @@ -1032,7 +1056,10 @@ connections = actionBlock.connectionPointIn.getconnections() if connections is not None and len(connections) == 1: stepLocalId = connections[0].getrefLocalId() - step = pou.body.getcontentInstance(stepLocalId) + body = pou.getbody() + if isinstance(body, ListType): + body = body[0] + step = body.getcontentInstance(stepLocalId) self.GenerateSFCStep(step, pou) step_name = step.getname() if step_name in self.SFCNetworks["Steps"].keys(): @@ -1073,7 +1100,10 @@ connections = transition.connectionPointIn.getconnections() if connections is not None and len(connections) == 1: instanceLocalId = connections[0].getrefLocalId() - instance = pou.body.getcontentInstance(instanceLocalId) + body = pou.getbody() + if isinstance(body, ListType): + body = body[0] + instance = body.getcontentInstance(instanceLocalId) if isinstance(instance, plcopen.sfcObjects_step): steps.append(instance) elif isinstance(instance, plcopen.sfcObjects_selectionDivergence): @@ -1119,6 +1149,8 @@ self.TagName = previous_tagname elif transitionValues["type"] == "connection": body = pou.getbody() + if isinstance(body, ListType): + body = body[0] connections = transition.getconnections() if connections is not None: expression = self.ComputeExpression(body, connections) @@ -1193,7 +1225,7 @@ elif len(transition_infos["from"]) == 1: self.Program += transition_infos["from"][0] else: - raise PLCGenException, "Transition with content \"%s\" not connected to a previous step in \"%s\" POU"%(transition_infos["content"], self.Name) + raise PLCGenException, _("Transition with content \"%s\" not connected to a previous step in \"%s\" POU")%(transition_infos["content"], self.Name) self.Program += [(" TO ", ())] if len(transition_infos["to"]) > 1: self.Program += [("(", ())] @@ -1202,7 +1234,7 @@ elif len(transition_infos["to"]) == 1: self.Program += transition_infos["to"][0] else: - raise PLCGenException, "Transition with content \"%s\" not connected to a next step in \"%s\" POU"%(transition_infos["content"], self.Name) + raise PLCGenException, _("Transition with content \"%s\" not connected to a next step in \"%s\" POU")%(transition_infos["content"], self.Name) self.Program += transition_infos["content"] self.Program += [("%sEND_TRANSITION\n\n"%self.CurrentIndent, ())] for [(step_name, step_infos)] in transition_infos["to"]: @@ -1220,9 +1252,9 @@ (self.ReturnType, (self.TagName, "return"))] program += [("\n", ())] if len(self.Interface) == 0: - raise PLCGenException, "No variable defined in \"%s\" POU"%self.Name + raise PLCGenException, _("No variable defined in \"%s\" POU")%self.Name if len(self.Program) == 0 : - raise PLCGenException, "No body defined in \"%s\" POU"%self.Name + raise PLCGenException, _("No body defined in \"%s\" POU")%self.Name var_number = 0 for list_type, retain, constant, located, variables in self.Interface: program += [(" %s"%list_type, ())] diff -r d07815f10ca8 -r 323c8d76f6f2 PLCOpenEditor.py --- a/PLCOpenEditor.py Mon Jul 27 12:01:43 2009 +0200 +++ b/PLCOpenEditor.py Fri Aug 07 15:49:10 2009 +0200 @@ -31,6 +31,75 @@ else: USE_AUI = False +import os, re, platform, sys, time, traceback, getopt +import cPickle + +CWD = os.path.split(os.path.realpath(__file__))[0] +base_folder = os.path.split(CWD)[0] +sys.path.append(base_folder) +from docutils import * + +from types import TupleType + +__version__ = "$Revision: 1.130 $" + +if __name__ == '__main__': + # Usage message displayed when help request or when error detected in + # command line + def usage(): + print "\nUsage of PLCOpenEditor.py :" + print "\n %s [Filepath]\n"%sys.argv[0] + + # Parse options given to PLCOpenEditor in command line + try: + opts, args = getopt.getopt(sys.argv[1:], "h", ["help"]) + except getopt.GetoptError: + # print help information and exit: + usage() + sys.exit(2) + + # Extract if help has been requested + for o, a in opts: + if o in ("-h", "--help"): + usage() + sys.exit() + + # Extract the optional filename to open + fileOpen = None + if len(args) > 1: + usage() + sys.exit() + elif len(args) == 1: + fileOpen = args[0] + + # Create wxApp (Need to create App before internationalization because of + # Windows) + app = wx.PySimpleApp() + +# Import module for internationalization +import gettext +import __builtin__ + +# Get folder containing translation files +localedir = os.path.join(CWD,"locale") +# Get the default language +langid = wx.LANGUAGE_DEFAULT +# Define translation domain (name of translation files) +domain = "PLCOpenEditor" + +# Define locale for wx +loc = __builtin__.__dict__.get('loc', None) +if loc is None: + loc = wx.Locale(langid) + __builtin__.__dict__['loc'] = loc +# Define location for searching translation files +loc.AddCatalogLookupPathPrefix(localedir) +# Define locale domain +loc.AddCatalog(domain) + +if __name__ == '__main__': + __builtin__.__dict__['_'] = wx.GetTranslation + from SFCViewer import * from LDViewer import * from Viewer import * @@ -41,18 +110,7 @@ from PLCControler import * from plcopen.structures import LOCATIONDATATYPES -import os, re, platform, sys, time, traceback, getopt - -base_folder = os.path.split(sys.path[0])[0] -sys.path.append(base_folder) -from docutils import * - -from types import TupleType - -__version__ = "$Revision$" - -CWD = os.path.split(os.path.realpath(__file__))[0] - +# Define PLCOpenEditor controls id [ID_PLCOPENEDITOR, ID_PLCOPENEDITORTREENOTEBOOK, ID_PLCOPENEDITORTYPESTREE, ID_PLCOPENEDITORINSTANCESTREE, ID_PLCOPENEDITORMAINSPLITTER, ID_PLCOPENEDITORSECONDSPLITTER, @@ -64,9 +122,11 @@ ID_PLCOPENEDITORLDTOOLBAR, ] = [wx.NewId() for _init_ctrls in range(17)] +# Define PLCOpenEditor FileMenu extra items id [ID_PLCOPENEDITORFILEMENUGENERATE, ] = [wx.NewId() for _init_coll_FileMenu_Items in range(1)] +# Define PLCOpenEditor EditMenu extra items id [ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, ID_PLCOPENEDITOREDITMENUADDDATATYPE, ID_PLCOPENEDITOREDITMENUADDFUNCTION, ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK, ID_PLCOPENEDITOREDITMENUADDPROGRAM, ID_PLCOPENEDITOREDITMENUADDCONFIGURATION, @@ -77,7 +137,7 @@ # ToolBars definitions #------------------------------------------------------------------------------- - +# Define PLCOpenEditor Toolbar items id [ID_PLCOPENEDITORTOOLBARSELECTION, ID_PLCOPENEDITORTOOLBARCOMMENT, ID_PLCOPENEDITORTOOLBARVARIABLE, ID_PLCOPENEDITORTOOLBARBLOCK, ID_PLCOPENEDITORTOOLBARCONNECTION, ID_PLCOPENEDITORTOOLBARWIRE, @@ -89,96 +149,149 @@ ID_PLCOPENEDITORTOOLBARJUMP, ] = [wx.NewId() for _init_coll_DefaultToolBar_Items in range(17)] +# Define behaviour of each Toolbar item according to current POU body type +# Informations meaning are in this order: +# - Item is toggled +# - PLCOpenEditor mode where item is displayed (could be more then one) +# - Item id +# - Item callback function name +# - Item icon filename +# - Item tooltip text ToolBarItems = { "FBD" : [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARCOMMENT, "OnCommentTool", - "add_comment.png", "Create a new comment"), + "add_comment.png", _("Create a new comment")), (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARVARIABLE, "OnVariableTool", - "add_variable.png", "Create a new variable"), + "add_variable.png", _("Create a new variable")), (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARBLOCK, "OnBlockTool", - "add_block.png", "Create a new block"), + "add_block.png", _("Create a new block")), (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARCONNECTION, "OnConnectionTool", - "add_connection.png", "Create a new connection")], + "add_connection.png", _("Create a new connection"))], "LD" : [(True, FREEDRAWING_MODE, ID_PLCOPENEDITORTOOLBARCOMMENT, "OnCommentTool", - "add_comment.png", "Create a new comment"), + "add_comment.png", _("Create a new comment")), (True, FREEDRAWING_MODE, ID_PLCOPENEDITORTOOLBARPOWERRAIL, "OnPowerRailTool", - "add_powerrail.png", "Create a new power rail"), + "add_powerrail.png", _("Create a new power rail")), (False, DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARRUNG, "OnRungTool", - "add_rung.png", "Create a new rung"), + "add_rung.png", _("Create a new rung")), (True, FREEDRAWING_MODE, ID_PLCOPENEDITORTOOLBARCOIL, "OnCoilTool", - "add_coil.png", "Create a new coil"), + "add_coil.png", _("Create a new coil")), (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARCONTACT, "OnContactTool", - "add_contact.png", "Create a new contact"), + "add_contact.png", _("Create a new contact")), (False, DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARBRANCH, "OnBranchTool", - "add_branch.png", "Create a new branch"), + "add_branch.png", _("Create a new branch")), (True, FREEDRAWING_MODE, ID_PLCOPENEDITORTOOLBARVARIABLE, "OnVariableTool", - "add_variable.png", "Create a new variable"), + "add_variable.png", _("Create a new variable")), (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARBLOCK, "OnBlockTool", - "add_block.png", "Create a new block"), + "add_block.png", _("Create a new block")), (True, FREEDRAWING_MODE, ID_PLCOPENEDITORTOOLBARCONNECTION, "OnConnectionTool", - "add_connection.png", "Create a new connection")], + "add_connection.png", _("Create a new connection"))], "SFC" : [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARCOMMENT, "OnCommentTool", - "add_comment.png", "Create a new comment"), + "add_comment.png", _("Create a new comment")), (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARINITIALSTEP, "OnInitialStepTool", - "add_initial_step.png", "Create a new initial step"), + "add_initial_step.png", _("Create a new initial step")), (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARSTEP, "OnStepTool", - "add_step.png", "Create a new step"), + "add_step.png", _("Create a new step")), (True, FREEDRAWING_MODE, ID_PLCOPENEDITORTOOLBARTRANSITION, "OnTransitionTool", - "add_transition.png", "Create a new transition"), + "add_transition.png", _("Create a new transition")), (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARACTIONBLOCK, "OnActionBlockTool", - "add_action.png", "Create a new action block"), + "add_action.png", _("Create a new action block")), (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARDIVERGENCE, "OnDivergenceTool", - "add_divergence.png", "Create a new divergence"), + "add_divergence.png", _("Create a new divergence")), (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, ID_PLCOPENEDITORTOOLBARJUMP, "OnJumpTool", - "add_jump.png", "Create a new jump"), + "add_jump.png", _("Create a new jump")), (True, FREEDRAWING_MODE, ID_PLCOPENEDITORTOOLBARVARIABLE, "OnVariableTool", - "add_variable.png", "Create a new variable"), + "add_variable.png", _("Create a new variable")), (True, FREEDRAWING_MODE, ID_PLCOPENEDITORTOOLBARBLOCK, "OnBlockTool", - "add_block.png", "Create a new block"), + "add_block.png", _("Create a new block")), (True, FREEDRAWING_MODE, ID_PLCOPENEDITORTOOLBARCONNECTION, "OnConnectionTool", - "add_connection.png", "Create a new connection"), + "add_connection.png", _("Create a new connection")), (True, FREEDRAWING_MODE, ID_PLCOPENEDITORTOOLBARPOWERRAIL, "OnPowerRailTool", - "add_powerrail.png", "Create a new power rail"), + "add_powerrail.png", _("Create a new power rail")), (True, FREEDRAWING_MODE, ID_PLCOPENEDITORTOOLBARCONTACT, "OnContactTool", - "add_contact.png", "Create a new contact")], + "add_contact.png", _("Create a new contact"))], "ST" : [], "IL" : [] } +#------------------------------------------------------------------------------- +# Helper Functions +#------------------------------------------------------------------------------- + +# Compatibility function for wx versions < 2.6 def AppendMenu(parent, help, id, kind, text): if wx.VERSION >= (2, 6, 0): parent.Append(help=help, id=id, kind=kind, text=text) else: parent.Append(helpString=help, id=id, kind=kind, item=text) +[TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, TYPESTREE, + INSTANCESTREE, LIBRARYTREE, SCALING +] = [wx.NewId() for _refresh_elements in range(9)] + +def GetShortcutKeyCallbackFunction(viewer_function): + def ShortcutKeyFunction(self, event): + control = self.FindFocus() + if isinstance(control, (Viewer, TextViewer)): + getattr(control, viewer_function)() + elif isinstance(control, wx.TextCtrl): + control.ProcessEvent(event) + event.Skip() + return ShortcutKeyFunction + +def GetParentName(tree, item, parent_type): + parent_item = tree.GetItemParent(item) + parent_item_type = tree.GetPyData(parent_item) + while parent_item_type != parent_type: + parent_item = tree.GetItemParent(parent_item) + parent_item_type = tree.GetPyData(parent_item) + return tree.GetItemText(parent_item) + +def GetDeleteElementFunction(remove_function, parent_type=None, check_function=None): + def DeleteElementFunction(self, selected): + name = self.TypesTree.GetItemText(selected) + if check_function is None or not check_function(self.Controler, name, self.Debug): + if parent_type is not None: + parent_name = GetParentName(self.TypesTree, selected, parent_type) + remove_function(self.Controler, parent_name, name) + else: + remove_function(self.Controler, name) + else: + self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!")%name) + return DeleteElementFunction + +#------------------------------------------------------------------------------- +# PLCOpenEditor Main Class +#------------------------------------------------------------------------------- + +UNEDITABLE_NAMES_DICT = dict([(_(name), name) for name in UNEDITABLE_NAMES]) + class PLCOpenEditor(wx.Frame): - CopyBuffer = None - + # Compatibility function for wx versions < 2.6 if wx.VERSION < (2, 6, 0): def Bind(self, event, function, id = None): if id is not None: @@ -187,50 +300,50 @@ event(self, function) def _init_coll_MenuBar_Menus(self, parent): - parent.Append(menu=self.FileMenu, title=u'File') + parent.Append(menu=self.FileMenu, title=_(u'File')) if not self.Debug: - parent.Append(menu=self.EditMenu, title=u'Edit') - parent.Append(menu=self.DisplayMenu, title=u'Display') - parent.Append(menu=self.HelpMenu, title=u'Help') + parent.Append(menu=self.EditMenu, title=_(u'Edit')) + parent.Append(menu=self.DisplayMenu, title=_(u'Display')) + parent.Append(menu=self.HelpMenu, title=_(u'Help')) def _init_coll_FileMenu_Items(self, parent): if self.ModeSolo: AppendMenu(parent, help='', id=wx.ID_NEW, - kind=wx.ITEM_NORMAL, text=u'New\tCTRL+N') + kind=wx.ITEM_NORMAL, text=_(u'New\tCTRL+N')) AppendMenu(parent, help='', id=wx.ID_OPEN, - kind=wx.ITEM_NORMAL, text=u'Open\tCTRL+O') + kind=wx.ITEM_NORMAL, text=_(u'Open\tCTRL+O')) AppendMenu(parent, help='', id=wx.ID_CLOSE, - kind=wx.ITEM_NORMAL, text=u'Close Tab\tCTRL+W') + kind=wx.ITEM_NORMAL, text=_(u'Close Tab\tCTRL+W')) if self.ModeSolo: AppendMenu(parent, help='', id=wx.ID_CLOSE_ALL, - kind=wx.ITEM_NORMAL, text=u'Close Project') + kind=wx.ITEM_NORMAL, text=_(u'Close Project')) parent.AppendSeparator() if not self.Debug: AppendMenu(parent, help='', id=wx.ID_SAVE, - kind=wx.ITEM_NORMAL, text=u'Save\tCTRL+S') + kind=wx.ITEM_NORMAL, text=_(u'Save\tCTRL+S')) if self.ModeSolo: AppendMenu(parent, help='', id=wx.ID_SAVEAS, - kind=wx.ITEM_NORMAL, text=u'Save As...\tCTRL+SHIFT+S') + kind=wx.ITEM_NORMAL, text=_(u'Save As...\tCTRL+SHIFT+S')) AppendMenu(parent, help='', id=ID_PLCOPENEDITORFILEMENUGENERATE, - kind=wx.ITEM_NORMAL, text=u'Generate Program\tCTRL+G') + kind=wx.ITEM_NORMAL, text=_(u'Generate Program\tCTRL+G')) parent.AppendSeparator() AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP, - kind=wx.ITEM_NORMAL, text=u'Page Setup') + kind=wx.ITEM_NORMAL, text=_(u'Page Setup')) AppendMenu(parent, help='', id=wx.ID_PREVIEW, - kind=wx.ITEM_NORMAL, text=u'Preview') + kind=wx.ITEM_NORMAL, text=_(u'Preview')) AppendMenu(parent, help='', id=wx.ID_PRINT, - kind=wx.ITEM_NORMAL, text=u'Print') + kind=wx.ITEM_NORMAL, text=_(u'Print')) if not self.Debug: parent.AppendSeparator() AppendMenu(parent, help='', id=wx.ID_PROPERTIES, - kind=wx.ITEM_NORMAL, text=u'Properties') + kind=wx.ITEM_NORMAL, text=_(u'Properties')) parent.AppendSeparator() if self.ModeSolo: AppendMenu(parent, help='', id=wx.ID_EXIT, - kind=wx.ITEM_NORMAL, text=u'Quit\tCTRL+Q') + kind=wx.ITEM_NORMAL, text=_(u'Quit\tCTRL+Q')) else: AppendMenu(parent, help='', id=wx.ID_STOP, - kind=wx.ITEM_NORMAL, text=u'Close\tCTRL+Q') + kind=wx.ITEM_NORMAL, text=_(u'Close\tCTRL+Q')) if self.ModeSolo: self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, id=wx.ID_NEW) @@ -256,35 +369,33 @@ def _init_coll_EditMenu_Items(self, parent): AppendMenu(parent, help='', id=wx.ID_UNDO, - kind=wx.ITEM_NORMAL, text=u'Undo\tCTRL+Z') + kind=wx.ITEM_NORMAL, text=_(u'Undo\tCTRL+Z')) AppendMenu(parent, help='', id=wx.ID_REDO, - kind=wx.ITEM_NORMAL, text=u'Redo\tCTRL+Y') - AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, - kind=wx.ITEM_CHECK, text=u'Enable Undo/Redo') + kind=wx.ITEM_NORMAL, text=_(u'Redo\tCTRL+Y')) parent.AppendSeparator() AppendMenu(parent, help='', id=wx.ID_CUT, - kind=wx.ITEM_NORMAL, text=u'Cut\tCTRL+X') + kind=wx.ITEM_NORMAL, text=_(u'Cut\tCTRL+X')) AppendMenu(parent, help='', id=wx.ID_COPY, - kind=wx.ITEM_NORMAL, text=u'Copy\tCTRL+C') + kind=wx.ITEM_NORMAL, text=_(u'Copy\tCTRL+C')) AppendMenu(parent, help='', id=wx.ID_PASTE, - kind=wx.ITEM_NORMAL, text=u'Paste\tCTRL+V') + kind=wx.ITEM_NORMAL, text=_(u'Paste\tCTRL+V')) parent.AppendSeparator() addmenu = wx.Menu(title='') - parent.AppendMenu(wx.ID_ADD, "Add Element", addmenu) + parent.AppendMenu(wx.ID_ADD, _("Add Element"), addmenu) AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDDATATYPE, - kind=wx.ITEM_NORMAL, text=u'Data Type') + kind=wx.ITEM_NORMAL, text=_(u'Data Type')) AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDFUNCTION, - kind=wx.ITEM_NORMAL, text=u'Function') + kind=wx.ITEM_NORMAL, text=_(u'Function')) AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK, - kind=wx.ITEM_NORMAL, text=u'Function Block') + kind=wx.ITEM_NORMAL, text=_(u'Function Block')) AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDPROGRAM, - kind=wx.ITEM_NORMAL, text=u'Program') + kind=wx.ITEM_NORMAL, text=_(u'Program')) AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDCONFIGURATION, - kind=wx.ITEM_NORMAL, text=u'Configuration') + kind=wx.ITEM_NORMAL, text=_(u'Configuration')) AppendMenu(parent, help='', id=wx.ID_SELECTALL, - kind=wx.ITEM_NORMAL, text=u'Select All\tCTRL+A') + kind=wx.ITEM_NORMAL, text=_(u'Select All\tCTRL+A')) AppendMenu(parent, help='', id=wx.ID_DELETE, - kind=wx.ITEM_NORMAL, text=u'Delete') + kind=wx.ITEM_NORMAL, text=_(u'Delete')) self.Bind(wx.EVT_MENU, self.OnUndoMenu, id=wx.ID_UNDO) self.Bind(wx.EVT_MENU, self.OnRedoMenu, id=wx.ID_REDO) self.Bind(wx.EVT_MENU, self.OnEnableUndoRedoMenu, id=ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO) @@ -306,13 +417,13 @@ def _init_coll_DisplayMenu_Items(self, parent): AppendMenu(parent, help='', id=wx.ID_REFRESH, - kind=wx.ITEM_NORMAL, text=u'Refresh\tF5') + kind=wx.ITEM_NORMAL, text=_(u'Refresh\tF5')) if not self.Debug and not self.ModeSolo: AppendMenu(parent, help='', id=wx.ID_CLEAR, - kind=wx.ITEM_NORMAL, text=u'Clear Errors\tCTRL+K') + kind=wx.ITEM_NORMAL, text=_(u'Clear Errors\tCTRL+K')) parent.AppendSeparator() zoommenu = wx.Menu(title='') - parent.AppendMenu(wx.ID_ZOOM_FIT, "ZOOM", zoommenu) + parent.AppendMenu(wx.ID_ZOOM_FIT, _("Zoom"), zoommenu) for idx, value in enumerate(ZOOM_FACTORS): new_id = wx.NewId() AppendMenu(zoommenu, help='', id=new_id, @@ -324,14 +435,14 @@ def _init_coll_HelpMenu_Items(self, parent): AppendMenu(parent, help='', id=wx.ID_HELP, - kind=wx.ITEM_NORMAL, text=u'PLCOpenEditor\tF1') + kind=wx.ITEM_NORMAL, text=_(u'PLCOpenEditor\tF1')) #AppendMenu(parent, help='', id=wx.ID_HELP_CONTENTS, # kind=wx.ITEM_NORMAL, text=u'PLCOpen\tF2') #AppendMenu(parent, help='', id=wx.ID_HELP_CONTEXT, # kind=wx.ITEM_NORMAL, text=u'IEC 61131-3\tF3') if self.ModeSolo: AppendMenu(parent, help='', id=wx.ID_ABOUT, - kind=wx.ITEM_NORMAL, text=u'About') + kind=wx.ITEM_NORMAL, text=_(u'About')) self.Bind(wx.EVT_MENU, self.OnPLCOpenEditorMenu, id=wx.ID_HELP) #self.Bind(wx.EVT_MENU, self.OnPLCOpenMenu, id=wx.ID_HELP_CONTENTS) self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT) @@ -371,7 +482,7 @@ def _init_ctrls(self, prnt): wx.Frame.__init__(self, id=ID_PLCOPENEDITOR, name=u'PLCOpenEditor', parent=prnt, pos=wx.DefaultPosition, size=wx.Size(1000, 600), - style=wx.DEFAULT_FRAME_STYLE, title=u'PLCOpenEditor') + style=wx.DEFAULT_FRAME_STYLE, title=_(u'PLCOpenEditor')) self._init_utils() self.SetClientSize(wx.Size(1000, 600)) self.SetMenuBar(self.MenuBar) @@ -383,7 +494,7 @@ self.Panes = {} self.TreeNoteBook = wx.aui.AuiNotebook(self) - self.AUIManager.AddPane(self.TreeNoteBook, wx.aui.AuiPaneInfo().Caption("Project").Left().Layer(1).BestSize(wx.Size(200, 500)).CloseButton(False)) + self.AUIManager.AddPane(self.TreeNoteBook, wx.aui.AuiPaneInfo().Caption(_("Project")).Left().Layer(1).BestSize(wx.Size(200, 500)).CloseButton(False)) else: self.MainSplitter = wx.SplitterWindow(id=ID_PLCOPENEDITORMAINSPLITTER, @@ -431,6 +542,10 @@ name='InstancesTree', parent=self.TreeNoteBook, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER) + + self.TabsImageList = wx.ImageList(16, 31) + self.TabsImageListIndexes = {} + if self.Debug: if wx.VERSION >= (2, 6, 0): self.InstancesTree.Bind(wx.EVT_RIGHT_UP, self.OnInstancesTreeRightUp) @@ -441,8 +556,8 @@ self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnInstancesTreeItemActivated, id=ID_PLCOPENEDITORINSTANCESTREE) - self.TreeNoteBook.AddPage(self.InstancesTree, "Instances") - self.TreeNoteBook.AddPage(self.TypesTree, "Types") + self.TreeNoteBook.AddPage(self.InstancesTree, _("Instances")) + self.TreeNoteBook.AddPage(self.TypesTree, _("Types")) if USE_AUI: self.TabsOpened = wx.aui.AuiNotebook(self) @@ -455,7 +570,7 @@ self.AUIManager.AddPane(self.TabsOpened, wx.aui.AuiPaneInfo().CentrePane()) self.DebugVariablePanel = DebugVariablePanel(self, self.Controler) - self.AUIManager.AddPane(self.DebugVariablePanel, wx.aui.AuiPaneInfo().Caption("Variables").Right().Layer(0).BestSize(wx.Size(250, 600)).CloseButton(False)) + self.AUIManager.AddPane(self.DebugVariablePanel, wx.aui.AuiPaneInfo().Caption(_("Variables")).Right().Layer(0).BestSize(wx.Size(250, 600)).CloseButton(False)) else: self.SecondSplitter = wx.SplitterWindow(id=ID_PLCOPENEDITORSECONDSPLITTER, name='SecondSplitter', parent=self.MainSplitter, point=wx.Point(0, 0), @@ -478,19 +593,19 @@ self.SecondSplitter.SplitVertically(self.TabsOpened, self.DebugVariablePanel, -250) else: - self.TreeNoteBook.AddPage(self.TypesTree, "Types") - self.TreeNoteBook.AddPage(self.InstancesTree, "Instances") + self.TreeNoteBook.AddPage(self.TypesTree, _("Types")) + self.TreeNoteBook.AddPage(self.InstancesTree, _("Instances")) if USE_AUI: ToolBar = wx.ToolBar(self, ID_PLCOPENEDITORTOOLBAR, wx.DefaultPosition, wx.DefaultSize, wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER) ToolBar.SetToolBitmapSize(wx.Size(25, 25)) ToolBar.AddRadioTool(ID_PLCOPENEDITORTOOLBARSELECTION, - wx.Bitmap(os.path.join(CWD, 'Images', 'select.png')), wx.NullBitmap, "Select an object") + wx.Bitmap(os.path.join(CWD, 'Images', 'select.png')), wx.NullBitmap, _("Select an object")) ToolBar.Realize() self.Panes["ToolBar"] = ToolBar self.AUIManager.AddPane(ToolBar, wx.aui.AuiPaneInfo(). - Name("ToolBar").Caption("Toolbar"). + Name("ToolBar").Caption(_("Toolbar")). ToolbarPane().Top(). LeftDockable(False).RightDockable(False)) else: @@ -498,7 +613,7 @@ ID_PLCOPENEDITORTOOLBAR, 'ToolBar') self.ToolBar.SetToolBitmapSize(wx.Size(25, 25)) self.ToolBar.AddRadioTool(ID_PLCOPENEDITORTOOLBARSELECTION, - wx.Bitmap(os.path.join(CWD, 'Images', 'select.png')), wx.NullBitmap, "Select an object") + wx.Bitmap(os.path.join(CWD, 'Images', 'select.png')), wx.NullBitmap, _("Select an object")) self.ToolBar.Realize() self.Bind(wx.EVT_TOOL, self.OnSelectionTool, @@ -506,7 +621,7 @@ if USE_AUI: self.VariablePanelIndexer = VariablePanelIndexer(self, self, self.Controler) - self.AUIManager.AddPane(self.VariablePanelIndexer, wx.aui.AuiPaneInfo().Caption("Variables").Bottom().Layer(0).BestSize(wx.Size(800, 200)).CloseButton(False)) + self.AUIManager.AddPane(self.VariablePanelIndexer, wx.aui.AuiPaneInfo().Caption(_("Variables")).Bottom().Layer(0).BestSize(wx.Size(800, 200)).CloseButton(False)) self.TabsOpened = wx.aui.AuiNotebook(self) self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, @@ -520,7 +635,7 @@ self.LibraryPanel = wx.Panel(id=ID_PLCOPENEDITORLIBRARYPANEL, name='LibraryPanel', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=0) - self.AUIManager.AddPane(self.LibraryPanel, wx.aui.AuiPaneInfo().Caption("Library").Right().Layer(0).BestSize(wx.Size(250, 400)).CloseButton(False)) + self.AUIManager.AddPane(self.LibraryPanel, wx.aui.AuiPaneInfo().Caption(_("Library")).Right().Layer(0).BestSize(wx.Size(250, 400)).CloseButton(False)) else: self.SecondSplitter = wx.SplitterWindow(id=ID_PLCOPENEDITORSECONDSPLITTER, name='SecondSplitter', parent=self.MainSplitter, point=wx.Point(0, 0), @@ -541,9 +656,7 @@ self.TabsOpened = wx.Notebook(id=ID_PLCOPENEDITORTABSOPENED, name='TabsOpened', parent=self.ThirdSplitter, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=0) - self.TabsImageList = wx.ImageList(16, 31) self.TabsOpened.SetImageList(self.TabsImageList) - self.TabsImageListIndexes = {} if wx.VERSION >= (2, 6, 0): self.TabsOpened.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPouSelectedChanged, id=ID_PLCOPENEDITORTABSOPENED) @@ -580,11 +693,19 @@ if USE_AUI: self.AUIManager.Update() + ## Constructor of the PLCOpenEditor class. + # @param parent The parent window. + # @param controler The controler been used by PLCOpenEditor (default: None). + # @param fileOpen The filepath to open if no controler defined (default: None). + # @param debug The filepath to open if no controler defined (default: False). def __init__(self, parent, controler = None, fileOpen = None, debug = False): + # Variable indicating that PLCOpenEditor was opened with a defined controler self.ModeSolo = controler == None self.Debug = debug if self.ModeSolo: + # If no controler defined, create a new one self.Controler = PLCControler() + # Open the filepath if defined if fileOpen is not None: self.Controler.OpenXMLFile(fileOpen) else: @@ -592,16 +713,18 @@ self._init_ctrls(parent) - self.SetIcon(wx.Icon(os.path.join(CWD,"Images","poe.ico"),wx.BITMAP_TYPE_ICO)) - - self.TypesTreeImageList = wx.ImageList(16, 16) - self.InstancesTreeImageList = wx.ImageList(16, 16) - self.TypesTreeImageDict = {} - self.InstancesTreeImageDict = {} + # Define PLCOpenEditor icon + self.SetIcon(wx.Icon(os.path.join(CWD,"Images", "poe.ico"),wx.BITMAP_TYPE_ICO)) + + # Define Tree item icon list + self.TreeImageList = wx.ImageList(16, 16) + self.TreeImageDict = {} + + # Icons for languages for language in LANGUAGES: - self.TypesTreeImageDict[language]=self.TypesTreeImageList.Add(wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%language))) - self.InstancesTreeImageDict[language]=self.InstancesTreeImageList.Add(wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%language))) - + self.TreeImageDict[language]=self.TreeImageList.Add(wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%language))) + + # Icons for other items for imgname, itemtype in [ #editables ("PROJECT", ITEM_PROJECT), @@ -629,10 +752,11 @@ ("CONFIGURATIONS", ITEM_CONFIGURATIONS), ("RESOURCES", ITEM_RESOURCES), ("PROPERTIES", ITEM_PROPERTIES)]: - self.TypesTreeImageDict[itemtype]=self.TypesTreeImageList.Add(wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%imgname))) - self.InstancesTreeImageDict[itemtype]=self.InstancesTreeImageList.Add(wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%imgname))) - self.TypesTree.AssignImageList(self.TypesTreeImageList) - self.InstancesTree.AssignImageList(self.InstancesTreeImageList) + self.TreeImageDict[itemtype]=self.TreeImageList.Add(wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%imgname))) + + # Assign icon list to TreeCtrls + self.TypesTree.SetImageList(self.TreeImageList) + self.InstancesTree.SetImageList(self.TreeImageList) self.CurrentToolBar = [] self.CurrentLanguage = "" @@ -643,6 +767,7 @@ if USE_AUI: self.AuiTabCtrl = [] + # Initialize Printing configuring elements self.PrintData = wx.PrintData() self.PrintData.SetPaperId(wx.PAPER_A4) self.PrintData.SetPrintMode(wx.PRINT_MODE_PRINTER) @@ -650,58 +775,69 @@ self.PageSetupData.SetMarginTopLeft(wx.Point(10, 15)) self.PageSetupData.SetMarginBottomRight(wx.Point(10, 20)) + # Refresh elements that need to if not self.ModeSolo or fileOpen is not None: - self.RefreshTypesTree() - self.RefreshInstancesTree() - self.RefreshLibraryTree() - - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshDisplayMenu() - self.RefreshTitle() - self.RefreshToolBar() - - def ResetSelectedItem(self): - self.SelectedItem = None - + self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE) + self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) + + +#------------------------------------------------------------------------------- +# General Functions +#------------------------------------------------------------------------------- + + ## Call PLCOpenEditor refresh functions. + # @param elements List of elements to refresh. + def _Refresh(self, *elements): + for element in elements: + self.RefreshFunctions[element](self) + + ## Callback function when AUINotebook Page closed with CloseButton + # @param event AUINotebook Event. def OnPageClose(self, event): + # Get Selected Tab selected = event.GetSelection() if selected >= 0: + # Remove corresponding VariablePanel if not self.Debug: tagname = self.TabsOpened.GetPage(selected).GetTagName() self.VariablePanelIndexer.RemoveVariablePanel(tagname) + # Refresh Tab selection if self.TabsOpened.GetPageCount() > 0: new_index = min(selected, self.TabsOpened.GetPageCount() - 1) self.TabsOpened.SetSelection(new_index) if not self.Debug: tagname = self.TabsOpened.GetPage(new_index).GetTagName() self.VariablePanelIndexer.ChangeVariablePanel(tagname) - self.RefreshTitle() - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshDisplayMenu() - self.RefreshToolBar() + # Refresh all window elements that have changed + self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) wx.CallAfter(self.RefreshTabCtrlEvent) event.Skip() - def OnPageDragged(self, event): - wx.CallAfter(self.RefreshTabCtrlEvent) - event.Skip() - def GetCopyBuffer(self): - return PLCOpenEditor.CopyBuffer - - def SetCopyBuffer(self, element): - PLCOpenEditor.CopyBuffer = element + data = None + if wx.TheClipboard.Open(): + dataobj = wx.TextDataObject() + if wx.TheClipboard.GetData(dataobj): + data = dataobj.GetText() + wx.TheClipboard.Close() + return data + + def SetCopyBuffer(self, text): + if wx.TheClipboard.Open(): + data = wx.TextDataObject() + data.SetText(text) + wx.TheClipboard.SetData(data) + wx.TheClipboard.Flush() + wx.TheClipboard.Close() self.RefreshEditMenu() def GetDrawingMode(self): return self.DrawingMode def RefreshTitle(self): - name = "PLCOpenEditor" + name = _("PLCOpenEditor") if self.Debug: - name += " (Debug)" + name += _(" (Debug)") if self.Controler.HasOpenedProject() > 0: self.SetTitle("%s - %s"%(name, self.Controler.GetFilename())) else: @@ -721,12 +857,8 @@ new_values["creationDateTime"] = old_values["creationDateTime"] if new_values != old_values: self.Controler.SetProjectProperties(None, new_values) - self.RefreshTitle() - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshDisplayMenu() - self.RefreshTypesTree() - self.RefreshScaling() + self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, + TYPESTREE, INSTANCESTREE, SCALING) dialog.Destroy() def OnCloseFrame(self, event): @@ -734,83 +866,106 @@ self.AUIManager.UnInit() self._onclose() event.Skip() - elif not self.Controler.ProjectIsSaved(): - dialog = wx.MessageDialog(self, "There are changes, do you want to save?", "Close Application", wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) - answer = dialog.ShowModal() - dialog.Destroy() - if answer == wx.ID_YES: - self.SaveProject() - event.Skip() - elif answer == wx.ID_NO: - self.Controler.Reset() - self.AUIManager.UnInit() - event.Skip() + elif self.CheckSaveBeforeClosing(): + event.Skip() + else: + event.Veto() + +#------------------------------------------------------------------------------- +# Notebook Unified Functions +#------------------------------------------------------------------------------- + + ## Function that generate bitmap for + # for wx.aui.AUINotebook. + # @param window Panel to display in tab. + # @param text title for the tab ctrl. + def GenerateBitmap(self, icon1_name, icon2_name = None): + # Find index of bitmap if already created + index = self.TabsImageListIndexes.get((icon1_name, icon2_name), None) + # Return index or bitmap if found + if index is not None: + if USE_AUI: + return self.TabsImageList.GetBitmap(index) else: - event.Veto() - else: - event.Skip() - -#------------------------------------------------------------------------------- -# Notebook Unified Functions -#------------------------------------------------------------------------------- - - def GenerateBitmap(self, icon1_name, icon2_name = None): - if not USE_AUI: - index = self.TabsImageListIndexes.get((icon1_name, icon2_name), None) - if index is not None: return index if icon2_name is None: + # Bitmap with only one icon tmp_bitmap = wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%icon1_name)) else: + # Bitmap with two icon icon1 = wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%icon1_name)) icon2 = wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%icon2_name)) + # Calculate bitmap size width = icon1.GetWidth() + icon2.GetWidth() - 1 height = max(icon1.GetHeight(), icon2.GetHeight()) + # Create bitmap with both icons tmp_bitmap = wx.EmptyBitmap(width, height) dc = wx.MemoryDC() dc.SelectObject(tmp_bitmap) dc.Clear() dc.DrawBitmap(icon1, 0, 0) dc.DrawBitmap(icon2, icon1.GetWidth() - 1, 0) + # Store bitmap in ImageList + index = self.TabsImageList.Add(tmp_bitmap) + # Save bitmap index in ImageList in dictionary + self.TabsImageListIndexes[(icon1_name, icon2_name)] = index if USE_AUI: return tmp_bitmap else: - index = self.TabsImageList.Add(tmp_bitmap) - self.TabsImageListIndexes[(icon1_name, icon2_name)] = index return index + ## Function that add a tab in Notebook, calling refresh for tab DClick event + # for wx.aui.AUINotebook. + # @param window Panel to display in tab. + # @param text title for the tab ctrl. def AddPage(self, window, text): self.TabsOpened.AddPage(window, text) self.RefreshTabCtrlEvent() - def RefreshTabCtrlEvent(self): - if USE_AUI: - auitabctrl = [] - for child in self.TabsOpened.GetChildren(): - if isinstance(child, wx.aui.AuiTabCtrl): - auitabctrl.append(child) - if child not in self.AuiTabCtrl: - child.Bind(wx.EVT_LEFT_DCLICK, self.GetTabsOpenedDClickFunction(child)) - self.AuiTabCtrl = auitabctrl - if self.TabsOpened.GetPageCount() == 0: - pane = self.AUIManager.GetPane(self.TabsOpened) - if pane.IsMaximized(): - self.AUIManager.RestorePane(pane) - self.AUIManager.Update() - + ## Function that fix difference in deleting all tabs between + # wx.Notebook and wx.aui.AUINotebook. def DeleteAllPages(self): if USE_AUI: for idx in xrange(self.TabsOpened.GetPageCount()): self.TabsOpened.DeletePage(0) else: self.TabsOpened.DeleteAllPages() - + self.RefreshTabCtrlEvent() + + ## Function that fix difference in setting picture on tab between + # wx.Notebook and wx.aui.AUINotebook. + # @param idx Tab index. + # @param bitmap wx.Bitmap to define on tab. + # @return True if operation succeeded def SetPageBitmap(self, idx, bitmap): if USE_AUI: return self.TabsOpened.SetPageBitmap(idx, bitmap) else: return self.TabsOpened.SetPageImage(idx, bitmap) +#------------------------------------------------------------------------------- +# Dialog Message Functions +#------------------------------------------------------------------------------- + + ## Function displaying an Error dialog in PLCOpenEditor. + # @param message The message to display. + def ShowErrorMessage(self, message): + dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR) + dialog.ShowModal() + dialog.Destroy() + + ## Function displaying an Error dialog in PLCOpenEditor. + # @return False if closing cancelled. + def CheckSaveBeforeClosing(self): + if not self.Controler.ProjectIsSaved(): + dialog = wx.MessageDialog(self, _("There are changes, do you want to save?"), _("Close Application"), wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) + answer = dialog.ShowModal() + dialog.Destroy() + if answer == wx.ID_YES: + self.SaveProject() + elif answer == wx.ID_CANCEL: + return False + return True #------------------------------------------------------------------------------- # File Menu Functions @@ -861,42 +1016,27 @@ if dialog.ShowModal() == wx.ID_OK: properties = dialog.GetValues() self.Controler.CreateNewProject(properties) - self.RefreshTitle() - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshTypesTree() - self.RefreshInstancesTree() - self.RefreshLibraryTree() + self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, + LIBRARYTREE) event.Skip() def OnOpenProjectMenu(self, event): - if not self.Controler.ProjectIsSaved(): - dialog = wx.MessageDialog(self, "There are changes, do you want to save?", "Close Application", wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) - answer = dialog.ShowModal() - dialog.Destroy() - if answer == wx.ID_YES: - self.SaveProject() - elif answer == wx.ID_CANCEL: - return + if not self.CheckSaveBeforeClosing(): + return filepath = self.Controler.GetFilePath() if filepath != "": directory = os.path.dirname(filepath) else: directory = os.getcwd() - dialog = wx.FileDialog(self, "Choose a file", directory, "", "PLCOpen files (*.xml)|*.xml|All files|*.*", wx.OPEN) + dialog = wx.FileDialog(self, _("Choose a file"), directory, "", _("PLCOpen files (*.xml)|*.xml|All files|*.*"), wx.OPEN) if dialog.ShowModal() == wx.ID_OK: filepath = dialog.GetPath() if os.path.isfile(filepath): self.DeleteAllPages() self.VariablePanelIndexer.RemoveAllPanels() self.Controler.OpenXMLFile(filepath) - self.RefreshTypesTree() - self.RefreshInstancesTree() - self.RefreshLibraryTree() - self.RefreshTitle() - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshToolBar() + self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE) + self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU) dialog.Destroy() event.Skip() @@ -913,29 +1053,18 @@ if not self.Debug: tagname = self.TabsOpened.GetPage(new_index).GetTagName() self.VariablePanelIndexer.ChangeVariablePanel(tagname) - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshToolBar() + self._Refresh(TOOLBAR, FILEMENU, EDITMENU) event.Skip() def OnCloseProjectMenu(self, event): - if not self.Controler.ProjectIsSaved(): - dialog = wx.MessageDialog(self, "There are changes, do you want to save?", "Close Application", wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) - answer = dialog.ShowModal() - dialog.Destroy() - if answer == wx.ID_YES: - self.SaveProject() - elif answer == wx.ID_CANCEL: - return + if not self.CheckSaveBeforeClosing(): + return self.DeleteAllPages() self.VariablePanelIndexer.RemoveAllPanels() self.TypesTree.DeleteAllItems() self.InstancesTree.DeleteAllItems() self.Controler.Reset() - self.RefreshTitle() - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshToolBar() + self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU) event.Skip() def OnSaveProjectMenu(self, event): @@ -950,23 +1079,23 @@ event.Skip() def OnGenerateProgramMenu(self, event): - dialog = wx.FileDialog(self, "Choose a file", os.getcwd(), self.Controler.GetProgramFilePath(), "ST files (*.st)|*.st|All files|*.*", wx.SAVE|wx.CHANGE_DIR) + dialog = wx.FileDialog(self, _("Choose a file"), os.getcwd(), self.Controler.GetProgramFilePath(), _("ST files (*.st)|*.st|All files|*.*"), wx.SAVE|wx.CHANGE_DIR) if dialog.ShowModal() == wx.ID_OK: filepath = dialog.GetPath() message_text = "" - header, icon = "Done", wx.ICON_INFORMATION + header, icon = _("Done"), wx.ICON_INFORMATION if os.path.isdir(os.path.dirname(filepath)): program, errors, warnings = self.Controler.GenerateProgram(filepath) - message_text += "".join(["warning: %s\n" for warning in warnings]) + message_text += "".join([_("warning: %s\n") for warning in warnings]) if len(errors) > 0: - message_text += "".join(["error: %s\n" for warning in warnings]) - message_text += "Can't generate program to file %s!"%filepath - header, icon = "Error", wx.ICON_ERROR + message_text += "".join([_("error: %s\n") for warning in warnings]) + message_text += _("Can't generate program to file %s!")%filepath + header, icon = _("Error"), wx.ICON_ERROR else: - message_text += "Program was successfully generated!" + message_text += _("Program was successfully generated!") else: - message_text += "%s is not a valid folder!"%os.path.dirname(filepath) - header, icon = "Error", wx.ICON_ERROR + message_text += _("\"%s\" is not a valid folder!")%os.path.dirname(filepath) + header, icon = _("Error"), wx.ICON_ERROR message = wx.MessageDialog(self, message_text, header, wx.OK|icon) message.ShowModal() message.Destroy() @@ -986,19 +1115,15 @@ directory, filename = os.path.split(filepath) else: directory, filename = os.getcwd(), "%(projectName)s.xml"%self.Controler.GetProjectProperties(self.Debug) - dialog = wx.FileDialog(self, "Choose a file", directory, filename, "PLCOpen files (*.xml)|*.xml|All files|*.*", wx.SAVE|wx.OVERWRITE_PROMPT) + dialog = wx.FileDialog(self, _("Choose a file"), directory, filename, _("PLCOpen files (*.xml)|*.xml|All files|*.*"), wx.SAVE|wx.OVERWRITE_PROMPT) if dialog.ShowModal() == wx.ID_OK: filepath = dialog.GetPath() if os.path.isdir(os.path.dirname(filepath)): result = self.Controler.SaveXMLFile(filepath) if not result: - message = wx.MessageDialog(self, "Can't save project to file %s!"%filepath, "Error", wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() + self.ShowErrorMessage(_("Can't save project to file %s!")%filepath) else: - message = wx.MessageDialog(self, "%s is not a valid folder!"%os.path.dirname(filepath), "Error", wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() + self.ShowErrorMessage(_("\"%s\" is not a valid folder!")%os.path.dirname(filepath)) self.RefreshTitle() dialog.Destroy() @@ -1022,7 +1147,7 @@ preview = wx.PrintPreview(printout, printout2, data) if preview.Ok(): - preview_frame = wx.PreviewFrame(preview, self, "Print preview") + preview_frame = wx.PreviewFrame(preview, self, _("Print preview")) preview_frame.Initialize() @@ -1041,7 +1166,7 @@ printout = GraphicPrintout(self.TabsOpened.GetPage(selected), page_size, margins) if not printer.Print(self, printout, True): - wx.MessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wx.OK) + self.ShowErrorMessage(_("There was a problem printing.\nPerhaps your current printer is not set correctly?")) printout.Destroy() event.Skip() @@ -1071,7 +1196,7 @@ if self.TabsOpened.GetPageCount() > 0: self.EditMenu.Enable(wx.ID_CUT, True) self.EditMenu.Enable(wx.ID_COPY, True) - if self.CopyBuffer is not None: + if self.GetCopyBuffer() is not None: self.EditMenu.Enable(wx.ID_PASTE, True) else: self.EditMenu.Enable(wx.ID_PASTE, False) @@ -1091,8 +1216,7 @@ self.EditMenu.Enable(wx.ID_ADD, False) self.EditMenu.Enable(wx.ID_DELETE, False) - def OnUndoMenu(self, event): - self.Controler.LoadPrevious() + def CloseTabsWithoutModel(self): idxs = range(self.TabsOpened.GetPageCount()) idxs.reverse() for idx in idxs: @@ -1100,70 +1224,32 @@ if self.Controler.GetEditedElement(tagname, self.Debug) is None: self.VariablePanelIndexer.RemoveVariablePanel(tagname) self.TabsOpened.DeletePage(idx) - selected = self.TabsOpened.GetSelection() - if selected != -1: - window = self.TabsOpened.GetPage(selected) - window.RefreshView() - self.VariablePanelIndexer.RefreshVariablePanel(window.GetTagName()) - self.RefreshTitle() - self.RefreshEditMenu() - self.RefreshTypesTree() - self.RefreshInstancesTree() - self.RefreshLibraryTree() - self.RefreshScaling() + + def OnUndoMenu(self, event): + self.Controler.LoadPrevious() + self.CloseTabsWithoutModel() + self.RefreshEditor() + self._Refresh(TITLE, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE, + SCALING) event.Skip() def OnRedoMenu(self, event): self.Controler.LoadNext() - idxs = range(self.TabsOpened.GetPageCount()) - idxs.reverse() - for idx in idxs: - tagname = self.TabsOpened.GetPage(idx).GetTagName() - if self.Controler.GetEditedElement(tagname, self.Debug) is None: - self.VariablePanelIndexer.RemoveVariablePanel(tagname) - self.TabsOpened.DeletePage(idx) - selected = self.TabsOpened.GetSelection() - if selected != -1: - window = self.TabsOpened.GetPage(selected) - window.RefreshView() - self.VariablePanelIndexer.RefreshVariablePanel(window.GetTagName()) - self.RefreshTitle() - self.RefreshEditMenu() - self.RefreshTypesTree() - self.RefreshInstancesTree() - self.RefreshLibraryTree() - self.RefreshScaling() - event.Skip() - + self.CloseTabsWithoutModel() + self.RefreshEditor() + self._Refresh(TITLE, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE, + SCALING) + event.Skip() + def OnEnableUndoRedoMenu(self, event): self.Controler.EnableProjectBuffer(event.IsChecked()) self.RefreshEditMenu() event.Skip() - def OnCutMenu(self, event): - control = self.FindFocus() - if isinstance(control, (Viewer, TextViewer)): - control.Cut() - elif isinstance(control, wx.TextCtrl): - control.ProcessEvent(event) - event.Skip() - - def OnCopyMenu(self, event): - control = self.FindFocus() - if isinstance(control, (Viewer, TextViewer)): - control.Copy() - elif isinstance(control, wx.TextCtrl): - control.ProcessEvent(event) - event.Skip() - - def OnPasteMenu(self, event): - control = self.FindFocus() - if isinstance(control, (Viewer, TextViewer)): - control.Paste() - elif isinstance(control, wx.TextCtrl): - control.ProcessEvent(event) - event.Skip() - + OnCutMenu = GetShortcutKeyCallbackFunction("Cut") + OnCopyMenu = GetShortcutKeyCallbackFunction("Copy") + OnPasteMenu = GetShortcutKeyCallbackFunction("Paste") + def OnSelectAllMenu(self, event): control = self.FindFocus() if isinstance(control, (Viewer, TextViewer)): @@ -1174,70 +1260,27 @@ control.SetMark(0, control.GetLastPosition() + 1) event.Skip() + DeleteFunctions = { + ITEM_DATATYPE: GetDeleteElementFunction(PLCControler.ProjectRemoveDataType, check_function=PLCControler.DataTypeIsUsed), + ITEM_POU: GetDeleteElementFunction(PLCControler.ProjectRemovePou, check_function=PLCControler.PouIsUsed), + ITEM_TRANSITION: GetDeleteElementFunction(PLCControler.ProjectRemovePouTransition, ITEM_POU), + ITEM_ACTION: GetDeleteElementFunction(PLCControler.ProjectRemovePouAction, ITEM_POU), + ITEM_CONFIGURATION: GetDeleteElementFunction(PLCControler.ProjectRemoveConfiguration), + ITEM_RESOURCE: GetDeleteElementFunction(PLCControler.ProjectRemoveConfigurationResource, ITEM_CONFIGURATION) + } + def OnDeleteMenu(self, event): window = self.FindFocus() - if window == self.TypesTree: + if window == self.TypesTree or window is None: selected = self.TypesTree.GetSelection() if selected.IsOk(): type = self.TypesTree.GetPyData(selected) - tagname = "" - if type == ITEM_DATATYPE: - name = self.TypesTree.GetItemText(selected) - if not self.Controler.DataTypeIsUsed(name, self.Debug): - self.Controler.ProjectRemoveDataType(name) - tagname = self.Controler.ComputeDataTypeName(name) - else: - message = wx.MessageDialog(self, "\"%s\" is used by one or more POUs. It can't be removed!"%name, "Error", wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() - elif type == ITEM_POU: - name = self.TypesTree.GetItemText(selected) - if not self.Controler.PouIsUsed(name, self.Debug): - self.Controler.ProjectRemovePou(name) - tagname = self.Controler.ComputePouName(name) - else: - message = wx.MessageDialog(self, "\"%s\" is used by one or more POUs. It can't be removed!"%name, "Error", wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() - elif type in [ITEM_TRANSITION, ITEM_ACTION]: - item = self.TypesTree.GetItemParent(selected) - item_type = self.TypesTree.GetPyData(item) - while item_type != ITEM_POU: - item = self.TypesTree.GetItemParent(item) - item_type = self.TypesTree.GetPyData(item) - pou_name = self.TypesTree.GetItemText(item) - if type == ITEM_TRANSITION: - transition = self.TypesTree.GetItemText(selected) - self.Controler.ProjectRemovePouTransition(pou_name, transition) - tagname = self.Controler.ComputePouTransitionName(pou_name, transition) - elif type == ITEM_ACTION: - action = self.TypesTree.GetItemText(selected) - self.Controler.ProjectRemovePouAction(pou_name, action) - tagname = self.Controler.ComputePouActionName(pou_name, action) - elif type == ITEM_CONFIGURATION: - name = self.TypesTree.GetItemText(selected) - self.Controler.ProjectRemoveConfiguration(name) - tagname = self.Controler.ComputeConfigurationName(name) - elif type == ITEM_RESOURCE: - resource = self.TypesTree.GetItemText(selected) - item = self.TypesTree.GetItemParent(selected) - item_type = self.TypesTree.GetPyData(item) - while item_type != ITEM_CONFIGURATION: - item = self.TypesTree.GetItemParent(item) - item_type = self.TypesTree.GetPyData(item) - config_name = self.TypesTree.GetItemText(item) - self.Controler.ProjectRemoveConfigurationResource(config_name, resource) - tagname = self.Controler.ComputeConfigurationResourceName(config_name, selected) - idx = self.IsOpened(tagname) - if idx is not None: - self.VariablePanelIndexer.RemoveVariablePanel(tagname) - self.TabsOpened.DeletePage(idx) - self.RefreshTitle() - self.RefreshEditMenu() - self.RefreshTypesTree() - self.RefreshInstancesTree() - self.RefreshLibraryTree() - self.RefreshToolBar() + function = self.DeleteFunctions.get(type, None) + if function is not None: + function(self, selected) + self.CloseTabsWithoutModel() + self._Refresh(TITLE, TOOLBAR, EDITMENU, TYPESTREE, + INSTANCESTREE, LIBRARYTREE) elif isinstance(window, (Viewer, TextViewer)): event = wx.KeyEvent(wx.EVT_CHAR._getEvtType()) event.m_keyCode = wx.WXK_DELETE @@ -1277,12 +1320,7 @@ self.DisplayMenu.Enable(wx.ID_ZOOM_FIT, False) def OnRefreshMenu(self, event): - selected = self.TabsOpened.GetSelection() - if selected != -1: - window = self.TabsOpened.GetPage(selected) - window.RefreshView() - if not self.Debug: - self.VariablePanelIndexer.RefreshVariablePanel(window.GetTagName()) + self.RefreshEditor(not self.Debug) event.Skip() def OnClearErrorsMenu(self, event): @@ -1305,6 +1343,25 @@ # Project Editor Panels Management Functions #------------------------------------------------------------------------------- + def OnPageDragged(self, event): + wx.CallAfter(self.RefreshTabCtrlEvent) + event.Skip() + + def RefreshTabCtrlEvent(self): + if USE_AUI: + auitabctrl = [] + for child in self.TabsOpened.GetChildren(): + if isinstance(child, wx.aui.AuiTabCtrl): + auitabctrl.append(child) + if child not in self.AuiTabCtrl: + child.Bind(wx.EVT_LEFT_DCLICK, self.GetTabsOpenedDClickFunction(child)) + self.AuiTabCtrl = auitabctrl + if self.TabsOpened.GetPageCount() == 0: + pane = self.AUIManager.GetPane(self.TabsOpened) + if pane.IsMaximized(): + self.AUIManager.RestorePane(pane) + self.AUIManager.Update() + def OnPouSelectedChanged(self, event): old_selected = self.TabsOpened.GetSelection() if old_selected >= 0: @@ -1322,10 +1379,7 @@ window.RefreshView() if not self.Debug: self.VariablePanelIndexer.ChangeVariablePanel(window.GetTagName()) - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshDisplayMenu() - self.RefreshToolBar() + self._Refresh(FILEMENU, EDITMENU, DISPLAYMENU, TOOLBAR) event.Skip() def RefreshEditor(self, variablepanel = True): @@ -1402,9 +1456,13 @@ self.GenerateTypesTreeBranch(root, infos) self.TypesTree.Expand(root) + def ResetSelectedItem(self): + self.SelectedItem = None + def GenerateTypesTreeBranch(self, root, infos, topology=False): to_delete = [] - self.TypesTree.SetItemText(root, infos["name"]) + item_name = infos["name"] + self.TypesTree.SetItemText(root, _(item_name)) self.TypesTree.SetPyData(root, infos["type"]) if infos.get("tagname", None) in self.Errors: self.TypesTree.SetItemBackgroundColour(root, wx.Colour(255, 255, 0)) @@ -1413,9 +1471,9 @@ self.TypesTree.SetItemBackgroundColour(root, wx.WHITE) self.TypesTree.SetItemTextColour(root, wx.BLACK) if infos["type"] == ITEM_POU: - self.TypesTree.SetItemImage(root, self.TypesTreeImageDict[self.Controler.GetPouBodyType(infos["name"], self.Debug)]) - else: - self.TypesTree.SetItemImage(root, self.TypesTreeImageDict[infos["type"]]) + self.TypesTree.SetItemImage(root, self.TreeImageDict[self.Controler.GetPouBodyType(infos["name"], self.Debug)]) + else: + self.TypesTree.SetItemImage(root, self.TreeImageDict[infos["type"]]) if wx.VERSION >= (2, 6, 0): item, root_cookie = self.TypesTree.GetFirstChild(root) @@ -1499,9 +1557,9 @@ new_name = event.GetLabel() if new_name != "": if not TestIdentifier(new_name): - message = "\"%s\" is not a valid identifier!"%new_name + message = _("\"%s\" is not a valid identifier!")%new_name elif new_name.upper() in IEC_KEYWORDS: - message = "\"%s\" is a keyword. It can't be used!"%new_name + message = _("\"%s\" is a keyword. It can't be used!")%new_name else: item = event.GetItem() old_name = self.TypesTree.GetItemText(item) @@ -1510,7 +1568,7 @@ self.Controler.SetProjectProperties(name = new_name) elif itemtype == ITEM_DATATYPE: if new_name.upper() in [name.upper() for name in self.Controler.GetProjectDataTypeNames(self.Debug) if name != old_name]: - message = "\"%s\" data type already exists!"%new_name + message = _("\"%s\" data type already exists!")%new_name abort = True if not abort: self.Controler.ChangeDataTypeName(old_name, new_name) @@ -1519,10 +1577,10 @@ self.RefreshPageTitles() elif itemtype == ITEM_POU: if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug) if name != old_name]: - message = "\"%s\" pou already exists!"%new_name + message = _("\"%s\" pou already exists!")%new_name abort = True elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables(debug = self.Debug)]: - messageDialog = wx.MessageDialog(self, "A variable is defined with \"%s\" as name. It can generate a conflict. Do you wish to continue?"%new_name, "Error", wx.YES_NO|wx.ICON_QUESTION) + messageDialog = wx.MessageDialog(self, _("A pou has an element with \"%s\" as name. It can generate a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION) if messageDialog.ShowModal() == wx.ID_NO: abort = True messageDialog.Destroy() @@ -1533,32 +1591,22 @@ self.RefreshLibraryTree() self.RefreshPageTitles() elif itemtype == ITEM_TRANSITION: - parent = self.TypesTree.GetItemParent(item) - parent_type = self.TypesTree.GetPyData(parent) - while parent_type != ITEM_POU: - parent = self.TypesTree.GetItemParent(parent) - parent_type = self.TypesTree.GetPyData(parent) - pou_name = self.TypesTree.GetItemText(parent) + pou_name = GetParentName(self.TypesTree, item, ITEM_POU) if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]: - message = "A pou with \"%s\" as name exists!"%new_name + message = _("A pou with \"%s\" as name exists!")%new_name elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables(pou_name, self.Debug) if name != old_name]: - message = "A variable with \"%s\" as name already exists in this pou!"%new_name + message = _("A variable with \"%s\" as name already exists in this pou!")%new_name else: self.Controler.ChangePouTransitionName(pou_name, old_name, new_name) self.RefreshEditorNames(self.Controler.ComputePouTransitionName(pou_name, old_name), self.Controler.ComputePouTransitionName(pou_name, new_name)) self.RefreshPageTitles() elif itemtype == ITEM_ACTION: - parent = self.TypesTree.GetItemParent(item) - parent_type = self.TypesTree.GetPyData(parent) - while parent_type != ITEM_POU: - parent = self.TypesTree.GetItemParent(parent) - parent_type = self.TypesTree.GetPyData(parent) - pou_name = self.TypesTree.GetItemText(parent) + pou_name = GetParentName(self.TypesTree, item, ITEM_POU) if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]: - message = "A pou with \"%s\" as name exists!"%new_name + message = _("A pou with \"%s\" as name exists!")%new_name elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables(pou_name, self.Debug) if name != old_name]: - message = "A variable with \"%s\" as name already exists in this pou!"%new_name + message = _("A variable with \"%s\" as name already exists in this pou!")%new_name else: self.Controler.ChangePouActionName(pou_name, old_name, new_name) self.RefreshEditorNames(self.Controler.ComputePouActionName(pou_name, old_name), @@ -1566,15 +1614,15 @@ self.RefreshPageTitles() elif itemtype == ITEM_CONFIGURATION: if new_name.upper() in [name.upper() for name in self.Controler.GetProjectConfigNames(self.Debug) if name != old_name]: - message = "\"%s\" config already exists!"%new_name + message = _("\"%s\" config already exists!")%new_name abort = True elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]: - messageDialog = wx.MessageDialog(self, "A pou is defined with \"%s\" as name. It can generate a conflict. Do you wish to continue?"%new_name, "Error", wx.YES_NO|wx.ICON_QUESTION) + messageDialog = wx.MessageDialog(self, _("A pou is defined with \"%s\" as name. It can generate a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION) if messageDialog.ShowModal() == wx.ID_NO: abort = True messageDialog.Destroy() elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables(debug = self.Debug)]: - messageDialog = wx.MessageDialog(self, "A variable is defined with \"%s\" as name. It can generate a conflict. Do you wish to continue?"%new_name, "Error", wx.YES_NO|wx.ICON_QUESTION) + messageDialog = wx.MessageDialog(self, _("A pou has an element with \"%s\" as name. It can generate a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION) if messageDialog.ShowModal() == wx.ID_NO: abort = True messageDialog.Destroy() @@ -1584,22 +1632,17 @@ self.Controler.ComputeConfigurationName(new_name)) self.RefreshPageTitles() elif itemtype == ITEM_RESOURCE: - parent = self.TypesTree.GetItemParent(item) - parent_type = self.TypesTree.GetPyData(parent) - while parent_type != ITEM_CONFIGURATION: - parent = self.TypesTree.GetItemParent(parent) - parent_type = self.TypesTree.GetPyData(parent) - config_name = self.TypesTree.GetItemText(parent) + config_name = GetParentName(self.TypesTree, item, ITEM_CONFIGURATION) if new_name.upper() in [name.upper() for name in self.Controler.GetProjectConfigNames(self.Debug)]: - message = "\"%s\" config already exists!"%new_name + message = _("\"%s\" config already exists!")%new_name abort = True elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]: - messageDialog = wx.MessageDialog(self, "A pou is defined with \"%s\" as name. It can generate a conflict. Do you wish to continue?"%new_name, "Error", wx.YES_NO|wx.ICON_QUESTION) + messageDialog = wx.MessageDialog(self, _("A pou is defined with \"%s\" as name. It can generate a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION) if messageDialog.ShowModal() == wx.ID_NO: abort = True messageDialog.Destroy() elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables(debug = self.Debug)]: - messageDialog = wx.MessageDialog(self, "A variable is defined with \"%s\" as name. It can generate a conflict. Do you wish to continue?"%new_name, "Error", wx.YES_NO|wx.ICON_QUESTION) + messageDialog = wx.MessageDialog(self, _("A pou has an element with \"%s\" as name. It can generate a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION) if messageDialog.ShowModal() == wx.ID_NO: abort = True messageDialog.Destroy() @@ -1610,25 +1653,21 @@ self.RefreshPageTitles() if message or abort: if message: - messageDialog = wx.MessageDialog(self, message, "Error", wx.OK|wx.ICON_ERROR) - messageDialog.ShowModal() - messageDialog.Destroy() + self.ShowErrorMessage(message) item = event.GetItem() wx.CallAfter(self.TypesTree.EditLabel, item) event.Veto() else: wx.CallAfter(self.RefreshTypesTree) self.RefreshEditor() - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshTitle() + self._Refresh(TITLE, FILEMENU, EDITMENU) event.Skip() def OnTypesTreeItemActivated(self, event): selected = event.GetItem() name = self.TypesTree.GetItemText(selected) data = self.TypesTree.GetPyData(selected) - if name == "Properties": + if UNEDITABLE_NAMES_DICT.get(name, name) == "Properties": self.ShowProperties() if data == ITEM_DATATYPE: self.EditProjectElement(data, self.Controler.ComputeDataTypeName(name)) @@ -1637,20 +1676,10 @@ elif data == ITEM_CONFIGURATION: self.EditProjectElement(data, self.Controler.ComputeConfigurationName(name)) elif data == ITEM_RESOURCE: - item = self.TypesTree.GetItemParent(selected) - item_type = self.TypesTree.GetPyData(item) - while item_type != ITEM_CONFIGURATION: - item = self.TypesTree.GetItemParent(item) - item_type = self.TypesTree.GetPyData(item) - config_name = self.TypesTree.GetItemText(item) + config_name = GetParentName(self.TypesTree, selected, ITEM_CONFIGURATION) self.EditProjectElement(data, self.Controler.ComputeConfigurationResourceName(config_name, name)) elif data in [ITEM_TRANSITION, ITEM_ACTION]: - item = self.TypesTree.GetItemParent(selected) - item_type = self.TypesTree.GetPyData(item) - while item_type != ITEM_POU: - item = self.TypesTree.GetItemParent(item) - item_type = self.TypesTree.GetPyData(item) - pou_name = self.TypesTree.GetItemText(item) + pou_name = GetParentName(self.TypesTree, selected, ITEM_POU) if data == ITEM_TRANSITION: tagname = self.Controler.ComputePouTransitionName(pou_name, name) elif data == ITEM_ACTION: @@ -1668,20 +1697,10 @@ elif data == ITEM_CONFIGURATION: self.EditProjectElement(data, self.Controler.ComputeConfigurationName(name), True) elif data == ITEM_RESOURCE: - item = self.TypesTree.GetItemParent(select_item) - item_type = self.TypesTree.GetPyData(item) - while item_type != ITEM_CONFIGURATION: - item = self.TypesTree.GetItemParent(item) - item_type = self.TypesTree.GetPyData(item) - config_name = self.TypesTree.GetItemText(item) + config_name = GetParentName(self.TypesTree, select_item, ITEM_CONFIGURATION) self.EditProjectElement(data, self.Controler.ComputeConfigurationResourceName(config_name, name), True) elif data in [ITEM_TRANSITION, ITEM_ACTION]: - item = self.TypesTree.GetItemParent(select_item) - item_type = self.TypesTree.GetPyData(item) - while item_type != ITEM_POU: - item = self.TypesTree.GetItemParent(item) - item_type = self.TypesTree.GetPyData(item) - pou_name = self.TypesTree.GetItemText(item) + pou_name = GetParentName(self.TypesTree, select_item, ITEM_POU) if data == ITEM_TRANSITION: tagname = self.Controler.ComputePouTransitionName(pou_name, name) elif data == ITEM_ACTION: @@ -1714,12 +1733,9 @@ if old_selected >= 0: self.TabsOpened.GetPage(old_selected).ResetBuffer() self.TabsOpened.SetSelection(openedidx) - self.TabsOpened.GetPage(openedidx).RefreshView() self.VariablePanelIndexer.ChangeVariablePanel(tagname) self.RefreshPageTitles() - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshToolBar() + self._Refresh(FILEMENU, EDITMENU, TOOLBAR) elif not onlyopened: if elementtype == ITEM_CONFIGURATION: new_window = ConfigurationEditor(self.TabsOpened, tagname, self, self.Controler) @@ -1765,9 +1781,7 @@ self.TabsOpened.SetSelection(i) window.SetFocus() self.RefreshPageTitles() - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshToolBar() + self._Refresh(FILEMENU, EDITMENU, TOOLBAR) def OnTypesTreeRightUp(self, event): if wx.Platform == '__WXMSW__': @@ -1780,78 +1794,72 @@ menu = wx.Menu(title='') if self.Controler.GetPouBodyType(name, self.Debug) == "SFC": new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Add Transition") + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Transition")) self.Bind(wx.EVT_MENU, self.GenerateAddTransitionFunction(name), id=new_id) new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Add Action") + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Action")) self.Bind(wx.EVT_MENU, self.GenerateAddActionFunction(name), id=new_id) menu.AppendSeparator() new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Create A New POU From") + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Create a new POU from")) self.Bind(wx.EVT_MENU, self.OnCreatePouFromMenu, id=new_id) pou_type = self.Controler.GetPouType(name, self.Debug) if pou_type in ["function", "functionBlock"]: change_menu = wx.Menu(title='') if pou_type == "function": new_id = wx.NewId() - AppendMenu(change_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Function Block") + AppendMenu(change_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Function Block")) self.Bind(wx.EVT_MENU, self.GenerateChangePouTypeFunction(name, "functionBlock"), id=new_id) new_id = wx.NewId() - AppendMenu(change_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Program") + AppendMenu(change_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Program")) self.Bind(wx.EVT_MENU, self.GenerateChangePouTypeFunction(name, "program"), id=new_id) - menu.AppendMenu(wx.NewId(), "Change POU Type To", change_menu) + menu.AppendMenu(wx.NewId(), _("Change POU Type To"), change_menu) new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Rename") + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Rename")) self.Bind(wx.EVT_MENU, self.OnRenamePouMenu, id=new_id) new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Delete") - self.Bind(wx.EVT_MENU, self.OnRemovePouMenu, id=new_id) + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Delete")) + self.Bind(wx.EVT_MENU, self.OnDeleteMenu, id=new_id) self.PopupMenu(menu) elif type == ITEM_CONFIGURATION: menu = wx.Menu(title='') new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Add Resource") + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Resource")) self.Bind(wx.EVT_MENU, self.GenerateAddResourceFunction(name), id=new_id) new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Delete") - self.Bind(wx.EVT_MENU, self.OnRemoveConfigurationMenu, id=new_id) + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Delete")) + self.Bind(wx.EVT_MENU, self.OnDeleteMenu, id=new_id) self.PopupMenu(menu) elif type in [ITEM_DATATYPE, ITEM_TRANSITION, ITEM_ACTION, ITEM_RESOURCE]: menu = wx.Menu(title='') new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Delete") - if type == ITEM_DATATYPE: - self.Bind(wx.EVT_MENU, self.OnRemoveDataTypeMenu, id=new_id) - elif type == ITEM_TRANSITION: - self.Bind(wx.EVT_MENU, self.OnRemoveTransitionMenu, id=new_id) - elif type == ITEM_ACTION: - self.Bind(wx.EVT_MENU, self.OnRemoveActionMenu, id=new_id) - elif type == ITEM_RESOURCE: - self.Bind(wx.EVT_MENU, self.OnRemoveResourceMenu, id=new_id) + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Delete")) + self.Bind(wx.EVT_MENU, self.OnDeleteMenu, id=new_id) self.PopupMenu(menu) elif type in ITEMS_UNEDITABLE: + name = UNEDITABLE_NAMES_DICT[name] if name == "Data Types": menu = wx.Menu(title='') new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Add DataType") + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add DataType")) self.Bind(wx.EVT_MENU, self.OnAddDataTypeMenu, id=new_id) self.PopupMenu(menu) elif name in ["Functions", "Function Blocks", "Programs"]: menu = wx.Menu(title='') new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Add Pou") + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Pou")) self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction({"Functions" : "function", "Function Blocks" : "functionBlock", "Programs" : "program"}[name]), id=new_id) self.PopupMenu(menu) elif name == "Configurations": menu = wx.Menu(title='') new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Add Configuration") + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Configuration")) self.Bind(wx.EVT_MENU, self.OnAddConfigurationMenu, id=new_id) self.PopupMenu(menu) elif name == "Transitions": menu = wx.Menu(title='') new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Add Transition") + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Transition")) parent = self.TypesTree.GetItemParent(item) parent_type = self.TypesTree.GetPyData(parent) while parent_type != ITEM_POU: @@ -1862,7 +1870,7 @@ elif name == "Actions": menu = wx.Menu(title='') new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Add Action") + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Action")) parent = self.TypesTree.GetItemParent(item) parent_type = self.TypesTree.GetPyData(parent) while parent_type != ITEM_POU: @@ -1873,7 +1881,7 @@ elif name == "Resources": menu = wx.Menu(title='') new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Add Resource") + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Resource")) parent = self.TypesTree.GetItemParent(item) parent_type = self.TypesTree.GetPyData(parent) while parent_type != ITEM_CONFIGURATION: @@ -1903,7 +1911,7 @@ else: self.InstancesTree.SetItemText(root, infos["name"]) self.InstancesTree.SetPyData(root, (infos["type"], infos.get("tagname", None))) - self.InstancesTree.SetItemImage(root, self.InstancesTreeImageDict[infos["type"]]) + self.InstancesTree.SetItemImage(root, self.TreeImageDict[infos["type"]]) if wx.VERSION >= (2, 6, 0): item, root_cookie = self.InstancesTree.GetFirstChild(root) @@ -2017,10 +2025,10 @@ menu = wx.Menu(title='') new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="Graphic Panel") + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Graphic Panel")) self.Bind(wx.EVT_MENU, self.AddVariableGraphicFunction(var_path), id=new_id) new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text="CSV Log") + AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("CSV Log")) self.PopupMenu(menu) event.Skip() @@ -2066,7 +2074,7 @@ root = self.LibraryTree.GetRootItem() if not root.IsOk(): if wx.Platform == '__WXMSW__': - root = self.LibraryTree.AddRoot("Block Types") + root = self.LibraryTree.AddRoot(_("Block Types")) self.LibraryTree.SetPyData(root, {"type" : CATEGORY}) else: root = self.LibraryTree.AddRoot("") @@ -2075,12 +2083,13 @@ else: category_item, root_cookie = self.LibraryTree.GetFirstChild(root, 0) for category in blocktypes: + category_name = category["name"] if not category_item.IsOk(): - category_item = self.LibraryTree.AppendItem(root, category["name"]) + category_item = self.LibraryTree.AppendItem(root, _(category_name)) if wx.Platform != '__WXMSW__': category_item, root_cookie = self.LibraryTree.GetNextChild(root, root_cookie) else: - self.LibraryTree.SetItemText(category_item, category["name"]) + self.LibraryTree.SetItemText(category_item, _(category_name)) self.LibraryTree.SetPyData(category_item, {"type" : CATEGORY}) if wx.VERSION >= (2, 6, 0): blocktype_item, category_cookie = self.LibraryTree.GetFirstChild(category_item) @@ -2113,7 +2122,8 @@ if pydata is not None and pydata["type"] != CATEGORY: blocktype = self.Controler.GetBlockType(self.LibraryTree.GetItemText(selected), pydata["inputs"], debug = self.Debug) if blocktype: - self.LibraryComment.SetValue(blocktype["comment"]) + comment = blocktype["comment"] + self.LibraryComment.SetValue(_(comment) + blocktype.get("usage", "")) else: self.LibraryComment.SetValue("") else: @@ -2346,7 +2356,7 @@ #------------------------------------------------------------------------------- def OnAddDataTypeMenu(self, event): - dialog = DataTypeDialog(self, "Add a new data type", "Please enter data type name", "", wx.OK|wx.CANCEL) + dialog = DataTypeDialog(self, _("Add a new data type"), _("Please enter data type name"), "", wx.OK|wx.CANCEL) dialog.SetDataTypeNames(self.Controler.GetProjectDataTypeNames(self.Debug)) if dialog.ShowModal() == wx.ID_OK: self.Controler.ProjectAddDataType(dialog.GetValue()) @@ -2403,7 +2413,7 @@ return OnAddActionMenu def OnAddConfigurationMenu(self, event): - dialog = ConfigurationNameDialog(self, "Please enter configuration name", "Add new configuration") + dialog = ConfigurationNameDialog(self, _("Please enter configuration name"), _("Add new configuration")) dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug)) dialog.SetPouElementNames(self.Controler.GetProjectPouVariables(debug = self.Debug)) if dialog.ShowModal() == wx.ID_OK: @@ -2418,7 +2428,7 @@ def GenerateAddResourceFunction(self, config_name): def OnAddResourceMenu(event): - dialog = ResourceNameDialog(self, "Please enter resource name", "Add new resource") + dialog = ResourceNameDialog(self, _("Please enter resource name"), _("Add new resource")) dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug)) dialog.SetPouElementNames(self.Controler.GetProjectPouVariables(debug = self.Debug)) if dialog.ShowModal() == wx.ID_OK: @@ -2448,7 +2458,7 @@ def OnCreatePouFromMenu(self, event): selected = self.TypesTree.GetSelection() if self.TypesTree.GetPyData(selected) == ITEM_POU: - dialog = PouNameDialog(self, "Please enter POU name", "Create a new POU from", "", wx.OK|wx.CANCEL) + dialog = PouNameDialog(self, _("Please enter POU name"), _("Create a new POU from"), "", wx.OK|wx.CANCEL) dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug)) if dialog.ShowModal() == wx.ID_OK: self.Controler.ProjectCreatePouFrom(dialog.GetValue(), self.TypesTree.GetItemText(selected)) @@ -2478,7 +2488,7 @@ self.RefreshTypesTree() self.RefreshToolBar() else: - message = wx.MessageDialog(self, "\"%s\" is used by one or more POUs. It can't be removed!"%name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is used by one or more POUs. It can't be removed!")%name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() event.Skip() @@ -2507,7 +2517,7 @@ self.RefreshLibraryTree() self.RefreshToolBar() else: - message = wx.MessageDialog(self, "\"%s\" is used by one or more POUs. It can't be removed!"%name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is used by one or more POUs. It can't be removed!")%name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() event.Skip() @@ -2593,7 +2603,7 @@ event.Skip() def OnPLCOpenEditorMenu(self, event): - wx.MessageBox("No documentation available.\nComing soon.") + wx.MessageBox(_("No documentation available.\nComing soon.")) #event.Skip() def OnPLCOpenMenu(self, event): @@ -2601,7 +2611,7 @@ event.Skip() def OnAboutMenu(self, event): - OpenHtmlFrame(self,"About PLCOpenEditor", os.path.join(CWD, "doc","about.html"), wx.Size(350, 350)) + OpenHtmlFrame(self,_("About PLCOpenEditor"), os.path.join(CWD, "doc","about.html"), wx.Size(350, 350)) event.Skip() @@ -2632,7 +2642,18 @@ for i in xrange(self.TabsOpened.GetPageCount()): viewer = self.TabsOpened.GetPage(i) viewer.ClearErrors() - + + RefreshFunctions = { + TITLE : RefreshTitle, + TOOLBAR : RefreshToolBar, + FILEMENU : RefreshFileMenu, + EDITMENU : RefreshEditMenu, + DISPLAYMENU : RefreshDisplayMenu, + TYPESTREE : RefreshTypesTree, + INSTANCESTREE : RefreshInstancesTree, + LIBRARYTREE : RefreshLibraryTree, + SCALING : RefreshScaling} + current_num = 0 def GetNewNum(): global current_num @@ -2651,16 +2672,16 @@ class ScalingPanel(wx.Panel): def _init_coll_ScalingPanelSizer_Items(self, parent): - parent.AddWindow(self.staticText1, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT) + parent.AddWindow(self.staticText1, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT) parent.AddWindow(self.XScale, 0, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT) - parent.AddWindow(self.staticText2, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT) + parent.AddWindow(self.staticText2, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM|wx.LEFT) parent.AddWindow(self.YScale, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.RIGHT) def _init_coll_ScalingPanelSizer_Growables(self, parent): parent.AddGrowableCol(1) def _init_sizers(self): - self.ScalingPanelSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=2, vgap=5) + self.ScalingPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5) self._init_coll_ScalingPanelSizer_Items(self.ScalingPanelSizer) self._init_coll_ScalingPanelSizer_Growables(self.ScalingPanelSizer) @@ -2673,16 +2694,16 @@ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText1 = wx.StaticText(id=ID_SCALINGPANELSTATICTEXT1, - label='X Scale:', name='staticText1', parent=self, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('X Scale:'), name='staticText1', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.XScale = wx.SpinCtrl(id=ID_SCALINGPANELXSCALE, name='XScale', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0, min=0, max=2**16) self.staticText2 = wx.StaticText(id=ID_SCALINGPANELSTATICTEXT2, - label='Y Scale:', name='staticText2', parent=self, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Y Scale:'), name='staticText2', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.YScale = wx.SpinCtrl(id=ID_SCALINGPANELYSCALE, name='YScale', parent=self, pos=wx.Point(0, 0), @@ -2737,37 +2758,37 @@ parent.AddGrowableRow(0) def _init_coll_ProjectPanelSizer_Items(self, parent): - parent.AddWindow(self.staticText1, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT) + parent.AddWindow(self.staticText1, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT) parent.AddWindow(self.ProjectName, 0, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT) - parent.AddWindow(self.staticText2, 0, border=10, flag=wx.GROW|wx.LEFT) + parent.AddWindow(self.staticText2, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT) parent.AddWindow(self.ProjectVersion, 0, border=10, flag=wx.GROW|wx.RIGHT) - parent.AddWindow(self.staticText3, 0, border=10, flag=wx.GROW|wx.LEFT) + parent.AddWindow(self.staticText3, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT) parent.AddWindow(self.ProductName, 0, border=10, flag=wx.GROW|wx.RIGHT) - parent.AddWindow(self.staticText4, 0, border=10, flag=wx.GROW|wx.LEFT) + parent.AddWindow(self.staticText4, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT) parent.AddWindow(self.ProductVersion, 0, border=10, flag=wx.GROW|wx.RIGHT) - parent.AddWindow(self.staticText5, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT) + parent.AddWindow(self.staticText5, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM|wx.LEFT) parent.AddWindow(self.ProductRelease, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.RIGHT) def _init_coll_ProjectPanelSizer_Growables(self, parent): parent.AddGrowableCol(1) def _init_coll_AuthorPanelSizer_Items(self, parent): - parent.AddWindow(self.staticText6, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT) + parent.AddWindow(self.staticText6, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT) parent.AddWindow(self.CompanyName, 0, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT) - parent.AddWindow(self.staticText7, 0, border=10, flag=wx.GROW|wx.LEFT) + parent.AddWindow(self.staticText7, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT) parent.AddWindow(self.CompanyURL, 0, border=10, flag=wx.GROW|wx.RIGHT) - parent.AddWindow(self.staticText8, 0, border=10, flag=wx.GROW|wx.LEFT) + parent.AddWindow(self.staticText8, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT) parent.AddWindow(self.AuthorName, 0, border=10, flag=wx.GROW|wx.RIGHT) - parent.AddWindow(self.staticText9, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT) + parent.AddWindow(self.staticText9, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM|wx.LEFT) parent.AddWindow(self.Organization, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.RIGHT) def _init_coll_AuthorPanelSizer_Growables(self, parent): parent.AddGrowableCol(1) def _init_coll_GraphicsPanelSizer_Items(self, parent): - parent.AddWindow(self.staticText12, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) + parent.AddWindow(self.staticText12, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT|wx.RIGHT) parent.AddSizer(self.GraphicsPageSizeSizer, 0, border=10, flag=wx.GROW|wx.LEFT|wx.RIGHT) - parent.AddWindow(self.staticText15, 0, border=10, flag=wx.GROW|wx.LEFT|wx.RIGHT) + parent.AddWindow(self.staticText15, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT) parent.AddWindow(self.ScalingNotebook, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT) def _init_coll_GraphicsPanelSizer_Growables(self, parent): @@ -2775,18 +2796,18 @@ parent.AddGrowableRow(3) def _init_coll_GraphicsPageSizeSizer_Items(self, parent): - parent.AddWindow(self.staticText13, 0, border=12, flag=wx.GROW|wx.LEFT) + parent.AddWindow(self.staticText13, 0, border=12, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT) parent.AddWindow(self.PageWidth, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.staticText14, 0, border=12, flag=wx.GROW|wx.LEFT) + parent.AddWindow(self.staticText14, 0, border=12, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT) parent.AddWindow(self.PageHeight, 0, border=0, flag=wx.GROW) def _init_coll_GraphicsPageSizeSizer_Growables(self, parent): parent.AddGrowableCol(1) def _init_coll_MiscellaneousPanelSizer_Items(self, parent): - parent.AddWindow(self.staticText10, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT) + parent.AddWindow(self.staticText10, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT) parent.AddWindow(self.Language, 0, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT) - parent.AddWindow(self.staticText11, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT) + parent.AddWindow(self.staticText11, 0, border=10, flag=wx.BOTTOM|wx.LEFT) parent.AddWindow(self.ContentDescription, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.RIGHT) def _init_coll_MiscellaneousPanelSizer_Growables(self, parent): @@ -2795,11 +2816,11 @@ def _init_sizers(self): self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) - self.ProjectPanelSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=5, vgap=15) - self.AuthorPanelSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=4, vgap=15) - self.GraphicsPanelSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=4, vgap=5) - self.GraphicsPageSizeSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=2, vgap=5) - self.MiscellaneousPanelSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=2, vgap=15) + self.ProjectPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=5, vgap=15) + self.AuthorPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=4, vgap=15) + self.GraphicsPanelSizer = wx.FlexGridSizer(cols=1, hgap=5, rows=4, vgap=5) + self.GraphicsPageSizeSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5) + self.MiscellaneousPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=15) self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1) @@ -2824,7 +2845,7 @@ wx.Dialog.__init__(self, id=ID_PROJECTDIALOG, name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223), size=wx.Size(500, 350), style=wx.DEFAULT_DIALOG_STYLE, - title='Project properties') + title=_('Project properties')) self.SetClientSize(wx.Size(500, 350)) self.MainNotebook = wx.Notebook(id=ID_PROJECTDIALOGMAINNOTEBOOK, @@ -2838,46 +2859,46 @@ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText1 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT1, - label='Project Name (required):', name='staticText1', parent=self.ProjectPanel, - pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0) + label=_('Project Name (required):'), name='staticText1', parent=self.ProjectPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.ProjectName = wx.TextCtrl(id=ID_PROJECTDIALOGPROJECTNAME, name='ProjectName', parent=self.ProjectPanel, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.staticText2 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT2, - label='Project Version (optional):', name='staticText2', parent=self.ProjectPanel, - pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0) + label=_('Project Version (optional):'), name='staticText2', parent=self.ProjectPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.ProjectVersion = wx.TextCtrl(id=ID_PROJECTDIALOGPROJECTVERSION, name='ProjectVersion', parent=self.ProjectPanel, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.staticText3 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT3, - label='Product Name (required):', name='staticText3', parent=self.ProjectPanel, - pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0) + label=_('Product Name (required):'), name='staticText3', parent=self.ProjectPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.ProductName = wx.TextCtrl(id=ID_PROJECTDIALOGPRODUCTNAME, name='ProductName', parent=self.ProjectPanel, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.staticText4 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT4, - label='Product Version (required):', name='staticText4', parent=self.ProjectPanel, - pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0) + label=_('Product Version (required):'), name='staticText4', parent=self.ProjectPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.ProductVersion = wx.TextCtrl(id=ID_PROJECTDIALOGPRODUCTVERSION, name='ProductVersion', parent=self.ProjectPanel, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.staticText5 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT5, - label='Product Release (optional):', name='staticText5', parent=self.ProjectPanel, - pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0) + label=_('Product Release (optional):'), name='staticText5', parent=self.ProjectPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.ProductRelease = wx.TextCtrl(id=ID_PROJECTDIALOGPRODUCTRELEASE, name='ProductRelease', parent=self.ProjectPanel, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) - self.MainNotebook.AddPage(self.ProjectPanel, "Project") + self.MainNotebook.AddPage(self.ProjectPanel, _("Project")) # Author Panel elements @@ -2886,38 +2907,38 @@ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText6 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT6, - label='Company Name (required):', name='staticText6', parent=self.AuthorPanel, - pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0) + label=_('Company Name (required):'), name='staticText6', parent=self.AuthorPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.CompanyName = wx.TextCtrl(id=ID_PROJECTDIALOGCOMPANYNAME, name='CompanyName', parent=self.AuthorPanel, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.staticText7 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT7, - label='Company URL (optional):', name='staticText7', parent=self.AuthorPanel, - pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0) + label=_('Company URL (optional):'), name='staticText7', parent=self.AuthorPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.CompanyURL = wx.TextCtrl(id=ID_PROJECTDIALOGCOMPANYURL, name='CompanyURL', parent=self.AuthorPanel, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.staticText8 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT8, - label='Author Name (optional):', name='staticText8', parent=self.AuthorPanel, - pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0) + label=_('Author Name (optional):'), name='staticText8', parent=self.AuthorPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.AuthorName = wx.TextCtrl(id=ID_PROJECTDIALOGAUTHORNAME, name='AuthorName', parent=self.AuthorPanel, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.staticText9 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT9, - label='Organization (optional):', name='staticText9', parent=self.AuthorPanel, - pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0) + label=_('Organization (optional):'), name='staticText9', parent=self.AuthorPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.Organization = wx.TextCtrl(id=ID_PROJECTDIALOGORGANIZATION, name='Organization', parent=self.AuthorPanel, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) - self.MainNotebook.AddPage(self.AuthorPanel, "Author") + self.MainNotebook.AddPage(self.AuthorPanel, _("Author")) # Graphics Panel elements @@ -2926,40 +2947,40 @@ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText12 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT12, - label='Page Size (optional):', name='staticText12', parent=self.GraphicsPanel, - pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0) + label=_('Page Size (optional):'), name='staticText12', parent=self.GraphicsPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.staticText13 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT13, - label='Width:', name='staticText13', parent=self.GraphicsPanel, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Width:'), name='staticText13', parent=self.GraphicsPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.PageWidth = wx.SpinCtrl(id=ID_PROJECTDIALOGPAGEWIDTH, name='PageWidth', parent=self.GraphicsPanel, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0, min=0, max=2**16) self.staticText14 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT14, - label='Height:', name='staticText14', parent=self.GraphicsPanel, - pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0) + label=_('Height:'), name='staticText14', parent=self.GraphicsPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.PageHeight = wx.SpinCtrl(id=ID_PROJECTDIALOGPAGEHEIGHT, name='PageHeight', parent=self.GraphicsPanel, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0, min=0, max=2**16) self.staticText15 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT15, - label='Scaling:', name='staticText15', parent=self.GraphicsPanel, - pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0) + label=_('Scaling:'), name='staticText15', parent=self.GraphicsPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.ScalingNotebook = wx.Notebook(id=ID_PROJECTDIALOGSCALINGNOTEBOOK, name='ScalingNotebook', parent=self.GraphicsPanel, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=0) self.Scalings = {} - for language in ["FBD", "LD", "SFC"]: + for language, translation in [("FBD",_("FBD")), ("LD",_("LD")), ("SFC",_("SFC"))]: window = ScalingPanel(self.ScalingNotebook) self.Scalings[language] = window - self.ScalingNotebook.AddPage(window, language) - - self.MainNotebook.AddPage(self.GraphicsPanel, "Graphics") + self.ScalingNotebook.AddPage(window, translation) + + self.MainNotebook.AddPage(self.GraphicsPanel, _("Graphics")) # Miscellaneous Panel elements @@ -2968,22 +2989,22 @@ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText10 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT10, - label='Language (optional):', name='staticText10', parent=self.MiscellaneousPanel, - pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0) + label=_('Language (optional):'), name='staticText10', parent=self.MiscellaneousPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.Language = wx.ComboBox(id=ID_PROJECTDIALOGLANGUAGE, name='Language', parent=self.MiscellaneousPanel, pos=wx.Point(0, 0), size=wx.Size(0, 28), style=wx.CB_READONLY) self.staticText11 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT11, - label='Content Description (optional):', name='staticText11', parent=self.MiscellaneousPanel, - pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0) + label=_('Content Description (optional):'), name='staticText11', parent=self.MiscellaneousPanel, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.ContentDescription = wx.TextCtrl(id=ID_PROJECTDIALOGCONTENTDESCRIPTION, name='ContentDescription', parent=self.MiscellaneousPanel, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=wx.TE_MULTILINE) - self.MainNotebook.AddPage(self.MiscellaneousPanel, "Miscellaneous") + self.MainNotebook.AddPage(self.MiscellaneousPanel, _("Miscellaneous")) self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId()) @@ -2993,7 +3014,7 @@ def __init__(self, parent): self._init_ctrls(parent) - languages = ["", "en-US", "fr-FR"] + languages = ["", "en-US", "fr-FR", "zh-CN"] for language in languages: self.Language.Append(language) @@ -3017,7 +3038,7 @@ text += " and %s"%item else: text += ", %s"%item - message = wx.MessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("Form isn't complete. %s must be filled!")%text, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() else: @@ -3094,7 +3115,7 @@ else: event(self, function) - def __init__(self, parent, message, caption = "Please enter text", defaultValue = "", + def __init__(self, parent, message, caption = _("Please enter text"), defaultValue = "", style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition): wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos) @@ -3109,19 +3130,19 @@ def OnOK(self, event): datatype_name = self.GetSizer().GetItem(1).GetWindow().GetValue() if datatype_name == "": - message = wx.MessageDialog(self, "You must type a name!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("You must type a name!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif not TestIdentifier(datatype_name): - message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%datatype_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%datatype_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif datatype_name.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%datatype_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%datatype_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif datatype_name.upper() in self.DataTypeNames: - message = wx.MessageDialog(self, "\"%s\" data type already exists!"%datatype_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" data type already exists!")%datatype_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() else: @@ -3142,6 +3163,21 @@ ID_POUDIALOGSTATICTEXT2, ID_POUDIALOGSTATICTEXT3, ] = [wx.NewId() for _init_ctrls in range(7)] +def GetTransitionLanguages(): + _ = lambda x : x + return [_("IL"), _("ST"), _("LD"), _("FBD")] +TRANSITION_LANGUAGES_DICT = dict([(_(language), language) for language in GetTransitionLanguages()]) + +def GetPouTypes(): + _ = lambda x : x + return [_("function"), _("functionBlock"), _("program")] +POU_TYPES_DICT = dict([(_(pou_type), pou_type) for pou_type in GetPouTypes()]) + +def GetPouLanguages(): + _ = lambda x : x + return [_("IL"), _("ST"), _("LD"), _("FBD"), _("SFC")] +POU_LANGUAGES_DICT = dict([(_(language), language) for language in GetPouLanguages()]) + class PouDialog(wx.Dialog): if wx.VERSION < (2, 6, 0): def Bind(self, event, function, id = None): @@ -3159,11 +3195,11 @@ parent.AddGrowableRow(0) def _init_coll_MainSizer_Items(self, parent): - parent.AddWindow(self.staticText1, 0, border=4, flag=wx.GROW|wx.TOP) + parent.AddWindow(self.staticText1, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) parent.AddWindow(self.PouName, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.staticText2, 0, border=4, flag=wx.GROW|wx.TOP) + parent.AddWindow(self.staticText2, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) parent.AddWindow(self.PouType, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.staticText3, 0, border=4, flag=wx.GROW|wx.TOP) + parent.AddWindow(self.staticText3, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) parent.AddWindow(self.Language, 0, border=0, flag=wx.GROW) def _init_coll_MainSizer_Growables(self, parent): @@ -3171,7 +3207,7 @@ def _init_sizers(self): self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) - self.MainSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=3, vgap=15) + self.MainSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=3, vgap=15) self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1) @@ -3184,20 +3220,20 @@ wx.Dialog.__init__(self, id=ID_POUDIALOG, name='PouDialog', parent=prnt, pos=wx.Point(376, 223), size=wx.Size(300, 200), style=wx.DEFAULT_DIALOG_STYLE, - title='Create a new POU') + title=_('Create a new POU')) self.SetClientSize(wx.Size(300, 200)) self.staticText1 = wx.StaticText(id=ID_POUDIALOGSTATICTEXT1, - label='POU Name:', name='staticText1', parent=self, - pos=wx.Point(0, 0), size=wx.Size(100, 17), style=0) + label=_('POU Name:'), name='staticText1', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.PouName = wx.TextCtrl(id=ID_POUDIALOGPOUNAME, name='POUName', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.staticText2 = wx.StaticText(id=ID_POUDIALOGSTATICTEXT2, - label='POU Type:', name='staticText2', parent=self, - pos=wx.Point(0, 0), size=wx.Size(100, 17), style=0) + label=_('POU Type:'), name='staticText2', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.PouType = wx.ComboBox(id=ID_POUDIALOGPOUTYPE, name='POUType', parent=self, pos=wx.Point(0, 0), @@ -3205,8 +3241,8 @@ self.Bind(wx.EVT_COMBOBOX, self.OnTypeChanged, id=ID_POUDIALOGPOUTYPE) self.staticText3 = wx.StaticText(id=ID_POUDIALOGSTATICTEXT3, - label='Language:', name='staticText3', parent=self, - pos=wx.Point(0, 0), size=wx.Size(100, 17), style=0) + label=_('Language:'), name='staticText3', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.Language = wx.ComboBox(id=ID_POUDIALOGLANGUAGE, name='Language', parent=self, pos=wx.Point(0, 0), @@ -3220,10 +3256,10 @@ def __init__(self, parent, pou_type = None): self._init_ctrls(parent) - for option in ["function", "functionBlock", "program"]: - self.PouType.Append(option) + for option in GetPouTypes(): + self.PouType.Append(_(option)) if pou_type is not None: - self.PouType.SetStringSelection(pou_type) + self.PouType.SetStringSelection(_(pou_type)) self.RefreshLanguage() self.PouNames = [] @@ -3233,37 +3269,37 @@ error = [] pou_name = self.PouName.GetValue() if pou_name == "": - error.append("POU Name") - if self.PouType.GetStringSelection() == "": - error.append("POU Type") - if self.Language.GetStringSelection() == "": - error.append("Language") + error.append(_("POU Name")) + if self.PouType.GetSelection() == -1: + error.append(_("POU Type")) + if self.Language.GetSelection() == -1: + error.append(_("Language")) if len(error) > 0: text = "" for i, item in enumerate(error): if i == 0: text += item elif i == len(error) - 1: - text += " and %s"%item + text += _(" and %s")%item else: - text += ", %s"%item - message = wx.MessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wx.OK|wx.ICON_ERROR) + text += _(", %s")%item + message = wx.MessageDialog(self, _("Form isn't complete. %s must be filled!")%text, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif not TestIdentifier(pou_name): - message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%pou_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%pou_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif pou_name.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%pou_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%pou_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif pou_name.upper() in self.PouNames: - message = wx.MessageDialog(self, "\"%s\" pou already exists!"%pou_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" pou already exists!")%pou_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif pou_name.upper() in self.PouElementNames: - message = wx.MessageDialog(self, "A pou has an element with \"%s\" for name. It can generate a conflict. Do you wish to continue?"%pou_name, "Warning", wx.YES_NO|wx.ICON_EXCLAMATION) + message = wx.MessageDialog(self, _("A pou has an element with \"%s\" as name. It can generate a conflict. Do you wish to continue?")%pou_name, _("Warning"), wx.YES_NO|wx.ICON_EXCLAMATION) result = message.ShowModal() message.Destroy() if result == wx.ID_YES: @@ -3272,13 +3308,13 @@ self.EndModal(wx.ID_OK) def RefreshLanguage(self): - selection = self.Language.GetStringSelection() + selection = POU_LANGUAGES_DICT.get(self.Language.GetStringSelection(), "") self.Language.Clear() - for option in ["IL","ST","LD","FBD","SFC"]: - if option != "SFC" or self.PouType.GetStringSelection() != "function": - self.Language.Append(option) - if self.Language.FindString(selection) != wx.NOT_FOUND: - self.Language.SetStringSelection(selection) + for language in GetPouLanguages(): + if language != "SFC" or POU_TYPES_DICT[self.PouType.GetStringSelection()] != "function": + self.Language.Append(language) + if self.Language.FindString(_(selection)) != wx.NOT_FOUND: + self.Language.SetStringSelection(_(selection)) def OnTypeChanged(self, event): self.RefreshLanguage() @@ -3295,15 +3331,15 @@ if item == "pouName": self.PouName.SetValue(value) elif item == "pouType": - self.PouType.SetStringSelection(value) + self.PouType.SetStringSelection(_(value)) elif item == "language": - self.Language.SetStringSelection(value) + self.Language.SetStringSelection(_(POU_LANGUAGES_DICT)) def GetValues(self): values = {} values["pouName"] = self.PouName.GetValue() - values["pouType"] = self.PouType.GetStringSelection() - values["language"] = self.Language.GetStringSelection() + values["pouType"] = POU_TYPES_DICT[self.PouType.GetStringSelection()] + values["language"] = POU_LANGUAGES_DICT[self.Language.GetStringSelection()] return values @@ -3316,6 +3352,11 @@ ID_POUTRANSITIONDIALOGSTATICTEXT2, ] = [wx.NewId() for _init_ctrls in range(5)] +def GetTransitionLanguages(): + _ = lambda x : x + return [_("IL"), _("ST"), _("LD"), _("FBD")] +TRANSITION_LANGUAGES_DICT = dict([(_(language), language) for language in GetTransitionLanguages()]) + class PouTransitionDialog(wx.Dialog): if wx.VERSION < (2, 6, 0): def Bind(self, event, function, id = None): @@ -3333,9 +3374,9 @@ parent.AddGrowableRow(0) def _init_coll_MainSizer_Items(self, parent): - parent.AddWindow(self.staticText1, 0, border=4, flag=wx.GROW|wx.TOP) + parent.AddWindow(self.staticText1, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) parent.AddWindow(self.TransitionName, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.staticText2, 0, border=4, flag=wx.GROW|wx.TOP) + parent.AddWindow(self.staticText2, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) parent.AddWindow(self.Language, 0, border=0, flag=wx.GROW) def _init_coll_MainSizer_Growables(self, parent): @@ -3343,7 +3384,7 @@ def _init_sizers(self): self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) - self.MainSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=2, vgap=15) + self.MainSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=15) self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1) @@ -3356,20 +3397,20 @@ wx.Dialog.__init__(self, id=ID_POUTRANSITIONDIALOG, name='PouTransitionDialog', parent=prnt, pos=wx.Point(376, 223), size=wx.Size(350, 200), style=wx.DEFAULT_DIALOG_STYLE, - title='Create a new transition') + title=_('Create a new transition')) self.SetClientSize(wx.Size(350, 160)) self.staticText1 = wx.StaticText(id=ID_POUTRANSITIONDIALOGSTATICTEXT1, - label='Transition Name:', name='staticText1', parent=self, - pos=wx.Point(0, 0), size=wx.Size(120, 17), style=0) + label=_('Transition Name:'), name='staticText1', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.TransitionName = wx.TextCtrl(id=ID_POUTRANSITIONDIALOGTRANSITIONNAME, name='TransitionName', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.staticText2 = wx.StaticText(id=ID_POUTRANSITIONDIALOGSTATICTEXT2, - label='Language:', name='staticText2', parent=self, - pos=wx.Point(0, 0), size=wx.Size(120, 17), style=0) + label=_('Language:'), name='staticText2', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.Language = wx.ComboBox(id=ID_POUTRANSITIONDIALOGLANGUAGE, name='Language', parent=self, pos=wx.Point(0, 0), @@ -3383,8 +3424,8 @@ def __init__(self, parent): self._init_ctrls(parent) - for option in ["IL","ST","LD","FBD"]: - self.Language.Append(option) + for language in GetTransitionLanguages(): + self.Language.Append(_(language)) self.PouNames = [] self.PouElementNames = [] @@ -3393,35 +3434,35 @@ error = [] transition_name = self.TransitionName.GetValue() if self.TransitionName.GetValue() == "": - error.append("Transition Name") - if self.Language.GetStringSelection() == "": - error.append("Language") + error.append(_("Transition Name")) + if self.Language.GetSelection() == -1: + error.append(_("Language")) if len(error) > 0: text = "" for i, item in enumerate(error): if i == 0: text += item elif i == len(error) - 1: - text += " and %s"%item + text += _(" and %s")%item else: - text += ", %s"%item - message = wx.MessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wx.OK|wx.ICON_ERROR) + text += _(", %s")%item + message = wx.MessageDialog(self, _("Form isn't complete. %s must be filled!")%text, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif not TestIdentifier(transition_name): - message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%transition_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%transition_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif transition_name.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%transition_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%transition_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif transition_name.upper() in self.PouNames: - message = wx.MessageDialog(self, "A pou with \"%s\" for name exists!"%transition_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("A pou with \"%s\" as name exists!")%transition_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif transition_name.upper() in self.PouElementNames: - message = wx.MessageDialog(self, "\"%s\" element for this pou already exists!"%transition_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" element for this pou already exists!")%transition_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() else: @@ -3438,12 +3479,12 @@ if item == "transitionName": self.TransitionName.SetValue(value) elif item == "language": - self.Language.SetStringSelection(value) + self.Language.SetSelection(_(value)) def GetValues(self): values = {} values["transitionName"] = self.TransitionName.GetValue() - values["language"] = self.Language.GetStringSelection() + values["language"] = TRANSITION_LANGUAGES_DICT[self.Language.GetStringSelection()] return values #------------------------------------------------------------------------------- @@ -3455,6 +3496,11 @@ ID_POUACTIONDIALOGSTATICTEXT2, ] = [wx.NewId() for _init_ctrls in range(5)] +def GetActionLanguages(): + _ = lambda x : x + return [_("IL"), _("ST"), _("LD"), _("FBD")] +ACTION_LANGUAGES_DICT = dict([(_(language), language) for language in GetActionLanguages()]) + class PouActionDialog(wx.Dialog): if wx.VERSION < (2, 6, 0): def Bind(self, event, function, id = None): @@ -3472,9 +3518,9 @@ parent.AddGrowableRow(0) def _init_coll_MainSizer_Items(self, parent): - parent.AddWindow(self.staticText1, 0, border=4, flag=wx.GROW|wx.TOP) + parent.AddWindow(self.staticText1, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) parent.AddWindow(self.ActionName, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.staticText2, 0, border=4, flag=wx.GROW|wx.TOP) + parent.AddWindow(self.staticText2, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) parent.AddWindow(self.Language, 0, border=0, flag=wx.GROW) def _init_coll_MainSizer_Growables(self, parent): @@ -3482,7 +3528,7 @@ def _init_sizers(self): self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) - self.MainSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=2, vgap=15) + self.MainSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=15) self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1) @@ -3495,20 +3541,20 @@ wx.Dialog.__init__(self, id=ID_POUACTIONDIALOG, name='PouActionDialog', parent=prnt, pos=wx.Point(376, 223), size=wx.Size(320, 200), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER, - title='Create a new action') + title=_('Create a new action')) self.SetClientSize(wx.Size(320, 160)) self.staticText1 = wx.StaticText(id=ID_POUACTIONDIALOGSTATICTEXT1, - label='Action Name:', name='staticText1', parent=self, - pos=wx.Point(0, 0), size=wx.Size(100, 17), style=0) + label=_('Action Name:'), name='staticText1', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.ActionName = wx.TextCtrl(id=ID_POUACTIONDIALOGACTIONNAME, name='ActionName', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) self.staticText2 = wx.StaticText(id=ID_POUACTIONDIALOGSTATICTEXT2, - label='Language:', name='staticText2', parent=self, - pos=wx.Point(0, 0), size=wx.Size(100, 17), style=0) + label=_('Language:'), name='staticText2', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.Language = wx.ComboBox(id=ID_POUACTIONDIALOGLANGUAGE, name='Language', parent=self, pos=wx.Point(0, 0), @@ -3522,8 +3568,8 @@ def __init__(self, parent): self._init_ctrls(parent) - for option in ["IL","ST","LD","FBD"]: - self.Language.Append(option) + for option in GetActionLanguages(): + self.Language.Append(_(option)) self.PouNames = [] self.PouElementNames = [] @@ -3532,35 +3578,35 @@ error = [] action_name = self.ActionName.GetValue() if action_name == "": - error.append("Action Name") - if self.Language.GetStringSelection() == "": - error.append("Language") + error.append(_("Action Name")) + if self.Language.GetSelection() == -1: + error.append(_("Language")) if len(error) > 0: text = "" for i, item in enumerate(error): if i == 0: text += item elif i == len(error) - 1: - text += " and %s"%item + text += _(" and %s")%item else: - text += ", %s"%item - message = wx.MessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wx.OK|wx.ICON_ERROR) + text += _(", %s")%item + message = wx.MessageDialog(self, _("Form isn't complete. %s must be filled!")%text, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif not TestIdentifier(action_name): - message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%action_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%action_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif action_name.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%action_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%action_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif action_name.upper() in self.PouNames: - message = wx.MessageDialog(self, "A pou with \"%s\" for name exists!"%action_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("A pou with \"%s\" as name exists!")%action_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif action_name.upper() in self.PouElementNames: - message = wx.MessageDialog(self, "\"%s\" element for this pou already exists!"%action_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" element for this pou already exists!")%action_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() else: @@ -3577,12 +3623,12 @@ if item == "actionName": self.ActionName.SetValue(value) elif item == "language": - self.Language.SetStringSelection(value) + self.Language.SetStringSelection(_(value)) def GetValues(self): values = {} values["actionName"] = self.ActionName.GetValue() - values["language"] = self.Language.GetStringSelection() + values["language"] = ACTION_LANGUAGES_DICT[self.Language.GetStringSelection()] return values #------------------------------------------------------------------------------- @@ -3598,7 +3644,7 @@ else: event(self, function) - def __init__(self, parent, message, caption = "Please enter configuration name", defaultValue = "", + def __init__(self, parent, message, caption = _("Please enter configuration name"), defaultValue = "", style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition): wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos) @@ -3615,23 +3661,23 @@ def OnOK(self, event): config_name = self.GetSizer().GetItem(1).GetWindow().GetValue() if config_name == "": - message = wx.MessageDialog(self, "You must type a name!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("You must type a name!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif not TestIdentifier(config_name): - message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%config_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%config_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif config_name.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%config_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%config_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif config_name.upper() in self.PouNames: - message = wx.MessageDialog(self, "A pou with \"%s\" as name exists!"%config_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("A pou with \"%s\" as name exists!")%config_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif config_name.upper() in self.PouElementNames: - message = wx.MessageDialog(self, "A pou has an element with \"%s\" for name. It can generate a conflict. Do you wish to continue?"%config_name, "Warning", wx.YES_NO|wx.ICON_EXCLAMATION) + message = wx.MessageDialog(self, _("A pou has an element with \"%s\" as name. It can generate a conflict. Do you wish to continue?")%config_name, _("Warning"), wx.YES_NO|wx.ICON_EXCLAMATION) result = message.ShowModal() message.Destroy() if result == wx.ID_YES: @@ -3661,7 +3707,7 @@ else: event(self, function) - def __init__(self, parent, message, caption = "Please enter resource name", defaultValue = "", + def __init__(self, parent, message, caption = _("Please enter resource name"), defaultValue = "", style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition): wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos) @@ -3678,23 +3724,23 @@ def OnOK(self, event): resource_name = self.GetSizer().GetItem(1).GetWindow().GetValue() if resource_name == "": - message = wx.MessageDialog(self, "You must type a name!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("You must type a name!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif not TestIdentifier(resource_name): - message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%resource_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%resource_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif resource_name.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%resource_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%resource_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif resource_name.upper() in self.PouNames: - message = wx.MessageDialog(self, "A pou with \"%s\" as name exists!"%resource_name, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("A pou with \"%s\" as name exists!")%resource_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() elif resource_name.upper() in self.PouElementNames: - message = wx.MessageDialog(self, "A pou has an element with \"%s\" for name. It can generate a conflict. Do you wish to continue?"%resource_name, "Warning", wx.YES_NO|wx.ICON_EXCLAMATION) + message = wx.MessageDialog(self, _("A pou has an element with \"%s\" as name. It can generate a conflict. Do you wish to continue?")%resource_name, _("Warning"), wx.YES_NO|wx.ICON_EXCLAMATION) result = message.ShowModal() message.Destroy() if result == wx.ID_YES: @@ -3796,6 +3842,25 @@ # Variables Editor Panel #------------------------------------------------------------------------------- +def GetVariableTableColnames(location): + _ = lambda x : x + if location: + return ["#", _("Name"), _("Class"), _("Type"), _("Location"), _("Initial Value"), _("Retain"), _("Constant")] + return ["#", _("Name"), _("Class"), _("Type"), _("Initial Value"), _("Retain"), _("Constant")] + +def GetAlternativeOptions(): + _ = lambda x : x + return [_("Yes"), _("No")] +ALTERNATIVE_OPTIONS_DICT = dict([(_(option), option) for option in GetAlternativeOptions()]) + +def GetFilterChoiceTransfer(): + _ = lambda x : x + return {_("All"): _("All"), _("Interface"): _("Interface"), + _(" Input"): _("Input"), _(" Output"): _("Output"), _(" InOut"): _("InOut"), + _(" External"): _("External"), _("Variables"): _("Variables"), _(" Local"): _("Local"), + _(" Temp"): _("Temp"), _("Global"): _("Global")}#, _("Access") : _("Access")} +VARIABLE_CLASSES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().itervalues()]) + class VariableTable(wx.grid.PyGridTableBase): """ @@ -3821,25 +3886,34 @@ def GetNumberRows(self): return len(self.data) - def GetColLabelValue(self, col): + def GetColLabelValue(self, col, translate=True): if col < len(self.colnames): + if translate: + return _(self.colnames[col]) return self.colnames[col] - def GetRowLabelValues(self, row): + def GetRowLabelValues(self, row, translate=True): return row def GetValue(self, row, col): if row < self.GetNumberRows(): if col == 0: return self.data[row]["Number"] - name = str(self.data[row].get(self.GetColLabelValue(col), "")) - return name + colname = self.GetColLabelValue(col, False) + value = str(self.data[row].get(colname, "")) + if colname in ["Class", "Retain", "Constant"]: + return _(value) + return value def SetValue(self, row, col, value): if col < len(self.colnames): - colname = self.GetColLabelValue(col) + colname = self.GetColLabelValue(col, False) if colname == "Name": self.old_value = self.data[row][colname] + elif colname == "Class": + value = VARIABLE_CLASSES_DICT[value] + elif colname in ["Retain", "Constant"]: + value = ALTERNATIVE_OPTIONS_DICT[value] self.data[row][colname] = value def GetValueByName(self, row, colname): @@ -3895,13 +3969,11 @@ Otherwise default to the default renderer. """ - typelist = None - accesslist = None for row in range(self.GetNumberRows()): for col in range(self.GetNumberCols()): editor = None renderer = None - colname = self.GetColLabelValue(col) + colname = self.GetColLabelValue(col, False) if col != 0 and self.GetValueByName(row, "Edit"): grid.SetReadOnly(row, col, False) if colname == "Name": @@ -3929,10 +4001,10 @@ excluded.extend(["Input","Output","InOut"]) if self.Parent.IsFunctionBlockType(self.data[row]["Type"]): excluded.extend(["Local","Temp"]) - editor.SetParameters(",".join([choice for choice in self.Parent.ClassList if choice not in excluded])) + editor.SetParameters(",".join([_(choice) for choice in self.Parent.ClassList if choice not in excluded])) elif colname in ["Retain", "Constant"]: editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters(self.Parent.OptionList) + editor.SetParameters(",".join(map(_, self.Parent.OptionList))) elif colname == "Type": editor = wx.grid.GridCellTextEditor() else: @@ -3991,21 +4063,21 @@ col = self.ParentWindow.VariablesGrid.XToCol(x) row = self.ParentWindow.VariablesGrid.YToRow(y - self.ParentWindow.VariablesGrid.GetColLabelSize()) if col != wx.NOT_FOUND and row != wx.NOT_FOUND: - if self.ParentWindow.Table.GetColLabelValue(col) != "Location": + if self.ParentWindow.Table.GetColLabelValue(col, False) != "Location": return message = None if not self.ParentWindow.Table.GetValueByName(row, "Edit"): - message = "Can't affect a location to a function block instance" + message = _("Can't affect a location to a function block instance") elif self.ParentWindow.Table.GetValueByName(row, "Class") not in ["Local", "Global"]: - message = "Can affect a location only to local or global variables" + message = _("Can affect a location only to local or global variables") else: try: values = eval(data) except: - message = "Invalid value \"%s\" for location"%data + message = _("Invalid value \"%s\" for location")%data values = None if not isinstance(values, TupleType): - message = "Invalid value \"%s\" for location"%data + message = _("Invalid value \"%s\" for location")%data values = None if values is not None and values[1] == "location": location = values[0] @@ -4014,20 +4086,20 @@ message = None if location.startswith("%"): if base_type != values[2]: - message = "Incompatible data types between \"%s\" and \"%s\""%(values[2], variable_type) + message = _("Incompatible data types between \"%s\" and \"%s\"")%(values[2], variable_type) else: self.ParentWindow.Table.SetValue(row, col, location) self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid) self.ParentWindow.SaveValues() else: if location[0].isdigit() and base_type != "BOOL": - message = "Incompatible size of data between \"%s\" and \"BOOL\""%location + message = _("Incompatible size of data between \"%s\" and \"BOOL\"")%location elif location[0] not in LOCATIONDATATYPES: - message = "Unrecognized data size \"%s\""%location[0] + message = _("Unrecognized data size \"%s\"")%location[0] elif base_type not in LOCATIONDATATYPES[location[0]]: - message = "Incompatible size of data between \"%s\" and \"%s\""%(location, variable_type) + message = _("Incompatible size of data between \"%s\" and \"%s\"")%(location, variable_type) else: - dialog = wx.SingleChoiceDialog(self.ParentWindow, "Select a variable class:", "Variable class", ["Input", "Output", "Memory"], wx.OK|wx.CANCEL) + dialog = wx.SingleChoiceDialog(self.ParentWindow, _("Select a variable class:"), _("Variable class"), ["Input", "Output", "Memory"], wx.OK|wx.CANCEL) if dialog.ShowModal() == wx.ID_OK: selected = dialog.GetSelection() if selected == 0: @@ -4044,7 +4116,7 @@ wx.CallAfter(self.ShowMessage, message) def ShowMessage(self, message): - message = wx.MessageDialog(self.ParentWindow, message, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() @@ -4152,8 +4224,8 @@ self.ControlPanel.SetScrollRate(0, 10) self.staticText1 = wx.StaticText(id=ID_VARIABLEEDITORPANELSTATICTEXT1, - label='Return Type:', name='staticText1', parent=self.ControlPanel, - pos=wx.Point(0, 0), size=wx.Size(95, 17), style=0) + label=_('Return Type:'), name='staticText1', parent=self.ControlPanel, + pos=wx.Point(0, 0), size=wx.Size(145, 17), style=0) self.ReturnType = wx.ComboBox(id=ID_VARIABLEEDITORPANELRETURNTYPE, name='ReturnType', parent=self.ControlPanel, pos=wx.Point(0, 0), @@ -4161,22 +4233,22 @@ self.Bind(wx.EVT_COMBOBOX, self.OnReturnTypeChanged, id=ID_VARIABLEEDITORPANELRETURNTYPE) self.staticText2 = wx.StaticText(id=ID_VARIABLEEDITORPANELSTATICTEXT2, - label='Class Filter:', name='staticText2', parent=self.ControlPanel, - pos=wx.Point(0, 0), size=wx.Size(95, 17), style=0) + label=_('Class Filter:'), name='staticText2', parent=self.ControlPanel, + pos=wx.Point(0, 0), size=wx.Size(145, 17), style=0) self.ClassFilter = wx.ComboBox(id=ID_VARIABLEEDITORPANELCLASSFILTER, name='ClassFilter', parent=self.ControlPanel, pos=wx.Point(0, 0), size=wx.Size(145, 28), style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnClassFilter, id=ID_VARIABLEEDITORPANELCLASSFILTER) - self.AddButton = wx.Button(id=ID_VARIABLEEDITORPANELADDBUTTON, label='Add', + self.AddButton = wx.Button(id=ID_VARIABLEEDITORPANELADDBUTTON, label=_('Add'), name='AddButton', parent=self.ControlPanel, pos=wx.Point(0, 0), - size=wx.Size(72, 32), style=0) + size=wx.DefaultSize, style=0) self.Bind(wx.EVT_BUTTON, self.OnAddButton, id=ID_VARIABLEEDITORPANELADDBUTTON) - self.DeleteButton = wx.Button(id=ID_VARIABLEEDITORPANELDELETEBUTTON, label='Delete', + self.DeleteButton = wx.Button(id=ID_VARIABLEEDITORPANELDELETEBUTTON, label=_('Delete'), name='DeleteButton', parent=self.ControlPanel, pos=wx.Point(0, 0), - size=wx.Size(72, 32), style=0) + size=wx.DefaultSize, style=0) self.Bind(wx.EVT_BUTTON, self.OnDeleteButton, id=ID_VARIABLEEDITORPANELDELETEBUTTON) self.UpButton = wx.Button(id=ID_VARIABLEEDITORPANELUPBUTTON, label='^', @@ -4199,10 +4271,7 @@ self.Filter = "All" self.FilterChoices = [] - self.FilterChoiceTransfer = {"All" : "All", "Interface" : "Interface", - " Input" : "Input", " Output" : "Output", " InOut" : "InOut", - " External" : "External", "Variables" : "Variables", " Local" : "Local", - " Temp" : "Temp", "Global" : "Global", "Access" : "Access"} + self.FilterChoiceTransfer = GetFilterChoiceTransfer() if element_type in ["config", "resource"]: self.DefaultTypes = {"All" : "Global"} @@ -4211,27 +4280,30 @@ self.DefaultTypes = {"All" : "Local", "Interface" : "Input", "Variables" : "Local"} self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No", "Edit" : True} if element_type in ["config", "resource"] or element_type in ["program", "transition", "action"]: - self.Table = VariableTable(self, [], ["#", "Name", "Class", "Type", "Location", "Initial Value", "Retain", "Constant"]) + self.Table = VariableTable(self, [], GetVariableTableColnames(True)) if element_type not in ["config", "resource"]: - self.FilterChoices = ["All","Interface"," Input"," Output"," InOut"," External","Variables"," Local"," Temp","Global","Access"] + self.FilterChoices = ["All", "Interface", " Input", " Output", " InOut", " External", "Variables", " Local", " Temp"]#,"Access"] else: - self.FilterChoices = ["All","Global","Access"] + self.FilterChoices = ["All", "Global"]#,"Access"] self.ColSizes = [40, 80, 70, 80, 80, 80, 60, 70] self.ColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_CENTER, wx.ALIGN_CENTER] else: - self.Table = VariableTable(self, [], ["#", "Name", "Class", "Type", "Initial Value", "Retain", "Constant"]) - self.FilterChoices = ["All","Interface"," Input"," Output"," InOut"," External","Variables"," Local"," Temp"] + self.Table = VariableTable(self, [], GetVariableTableColnames(False)) + if element_type == "function": + self.FilterChoices = ["All", "Interface", " Input", " Output", " InOut", "Variables", " Local", " Temp"] + else: + self.FilterChoices = ["All", "Interface", " Input", " Output", " InOut", " External", "Variables", " Local", " Temp"] self.ColSizes = [40, 120, 70, 80, 120, 60, 70] self.ColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_CENTER, wx.ALIGN_CENTER] for choice in self.FilterChoices: - self.ClassFilter.Append(choice) + self.ClassFilter.Append(_(choice)) reverse_transfer = {} for filter, choice in self.FilterChoiceTransfer.items(): reverse_transfer[choice] = filter - self.ClassFilter.SetStringSelection(reverse_transfer[self.Filter]) + self.ClassFilter.SetStringSelection(_(reverse_transfer[self.Filter])) self.RefreshTypeList() - self.OptionList = "Yes,No" + self.OptionList = GetAlternativeOptions() if element_type == "function": for base_type in self.Controler.GetBaseTypes(): @@ -4248,7 +4320,8 @@ 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.VariablesGrid.SetColMinimalWidth(col, self.ColSizes[col]) + self.VariablesGrid.AutoSizeColumn(col, False) def SetTagName(self, tagname): self.TagName = tagname @@ -4368,22 +4441,22 @@ value = self.Table.GetValue(row, col) if colname == "Name" and value != "": if not TestIdentifier(value): - message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%value, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%value, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() event.Veto() elif value.upper() in IEC_KEYWORDS: - message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%value, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%value, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() event.Veto() elif value.upper() in self.PouNames: - message = wx.MessageDialog(self, "A pou with \"%s\" as name exists!"%value, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("A pou with \"%s\" as name exists!")%value, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() event.Veto() elif value.upper() in [var["Name"].upper() for var in self.Values if var != self.Table.data[row]]: - message = wx.MessageDialog(self, "A variable with \"%s\" as name exists in this pou!"%value, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self, _("A variable with \"%s\" as name already exists in this pou!")%value, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() event.Veto() @@ -4415,13 +4488,13 @@ new_id = wx.NewId() AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type) self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), id=new_id) - type_menu.AppendMenu(wx.NewId(), "Base Types", base_menu) + type_menu.AppendMenu(wx.NewId(), _("Base Types"), base_menu) datatype_menu = wx.Menu(title='') for datatype in self.Controler.GetDataTypes(basetypes = False, debug = self.ParentWindow.Debug): new_id = wx.NewId() AppendMenu(datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype) self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id) - type_menu.AppendMenu(wx.NewId(), "User Data Types", datatype_menu) + type_menu.AppendMenu(wx.NewId(), _("User Data Types"), datatype_menu) functionblock_menu = wx.Menu(title='') bodytype = self.Controler.GetEditedElementBodyType(self.TagName, self.ParentWindow.Debug) pouname, poutype = self.Controler.GetEditedElementType(self.TagName, self.ParentWindow.Debug) @@ -4430,7 +4503,7 @@ 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) + type_menu.AppendMenu(wx.NewId(), _("Function Block Types"), functionblock_menu) rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col)) self.VariablesGrid.PopupMenuXY(type_menu, rect.x + rect.width, rect.y + self.VariablesGrid.GetColLabelSize()) event.Veto() @@ -4533,8 +4606,12 @@ self.Table.ResetView(self.VariablesGrid) #------------------------------------------------------------------------------- -# Variables Editor Panel -#------------------------------------------------------------------------------- +# Debug Variables Panel +#------------------------------------------------------------------------------- + +def GetDebugVariablesTableColnames(): + _ = lambda x : x + return [_("Variable"), _("Value")] class VariableTableItem(DebugDataConsumer): @@ -4586,21 +4663,23 @@ def GetNumberRows(self): return len(self.data) - def GetColLabelValue(self, col): + def GetColLabelValue(self, col, translate=True): if col < len(self.colnames): + if translate: + return _(self.colnames[col]) return self.colnames[col] - def GetRowLabelValues(self, row): + def GetRowLabelValues(self, row, translate=True): return row def GetValue(self, row, col): if row < self.GetNumberRows(): - return self.GetValueByName(row, self.GetColLabelValue(col)) + return self.GetValueByName(row, self.GetColLabelValue(col, False)) return "" def SetValue(self, row, col, value): if col < len(self.colnames): - self.SetValueByName(row, self.GetColLabelValue(col), value) + self.SetValueByName(row, self.GetColLabelValue(col, False), value) def GetValueByName(self, row, colname): if row < self.GetNumberRows(): @@ -4702,10 +4781,10 @@ try: values = eval(data) except: - message = "Invalid value \"%s\" for debug variable"%data + message = _("Invalid value \"%s\" for debug variable")%data values = None if not isinstance(values, TupleType): - message = "Invalid value \"%s\" for debug variable"%data + message = _("Invalid value \"%s\" for debug variable")%data values = None if values is not None and values[1] == "debug": self.ParentWindow.InsertValue(row, values[0]) @@ -4713,7 +4792,7 @@ wx.CallAfter(self.ShowMessage, message) def ShowMessage(self, message): - message = wx.MessageDialog(self.ParentWindow, message, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() @@ -4780,7 +4859,7 @@ size=wx.Size(32, 32), style=0) self.Bind(wx.EVT_BUTTON, self.OnDownButton, id=ID_DEBUGVARIABLEPANELDOWNBUTTON) - self.DeleteButton = wx.Button(id=ID_DEBUGVARIABLEPANELDELETEBUTTON, label='Delete', + self.DeleteButton = wx.Button(id=ID_DEBUGVARIABLEPANELDELETEBUTTON, label=_('Delete'), name='DeleteButton', parent=self, pos=wx.Point(0, 0), size=wx.Size(72, 32), style=0) self.Bind(wx.EVT_BUTTON, self.OnDeleteButton, id=ID_DEBUGVARIABLEPANELDELETEBUTTON) @@ -4793,7 +4872,7 @@ self.Controler = controler self.HasNewData = False - self.Table = DebugVariableTable(self, [], ["Variable", "Value"]) + self.Table = DebugVariableTable(self, [], GetDebugVariablesTableColnames()) self.VariablesGrid.SetTable(self.Table) self.VariablesGrid.SetRowLabelSize(0) @@ -4918,7 +4997,7 @@ block_name = " - ".join(self.Viewer.GetTagName().split("::")[1:]) text_width, text_height = dc.GetTextExtent(block_name) dc.DrawText(block_name, margin_left, margin_top - text_height - self.TextMargin) - dc.DrawText("Page: %d" % page, margin_left, margin_top + area_height + self.TextMargin) + dc.DrawText(_("Page: %d") % page, margin_left, margin_top + area_height + self.TextMargin) # Calculate the position on the DC for centering the graphic posX = area_width * ((page - 1) % self.PageGrid[0]) @@ -4948,12 +5027,12 @@ def Display_Exception_Dialog(e_type,e_value,e_tb): trcbck_lst = [] for i,line in enumerate(traceback.extract_tb(e_tb)): - trcbck = " " + str(i+1) + ". " + trcbck = " " + str(i+1) + _(". ") if line[0].find(os.getcwd()) == -1: - trcbck += "file : " + str(line[0]) + ", " - else: - trcbck += "file : " + str(line[0][len(os.getcwd()):]) + ", " - trcbck += "line : " + str(line[1]) + ", " + "function : " + str(line[2]) + trcbck += _("file : ") + str(line[0]) + _(", ") + else: + trcbck += _("file : ") + str(line[0][len(os.getcwd()):]) + _(", ") + trcbck += _("line : ") + str(line[1]) + _(", ") + _("function : ") + str(line[2]) trcbck_lst.append(trcbck) # Allow clicking.... @@ -4962,7 +5041,7 @@ cap.ReleaseMouse() dlg = wx.SingleChoiceDialog(None, - """ + _(""" An error happens. Click on OK for saving an error report. @@ -4973,9 +5052,9 @@ Error: -""" + - str(e_type) + " : " + str(e_value), - "Error", +""") + + str(e_type) + _(" : ") + str(e_value), + _("Error"), trcbck_lst) try: res = (dlg.ShowModal() == wx.ID_OK) @@ -4985,7 +5064,7 @@ return res def Display_Error_Dialog(e_value): - message = wx.MessageDialog(None, str(e_value), "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(None, str(e_value), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() @@ -5043,30 +5122,6 @@ sys.excepthook = handle_exception if __name__ == '__main__': - def usage(): - print "\nUsage of PLCOpenEditor.py :" - print "\n %s [Filepath]\n"%sys.argv[0] - - try: - opts, args = getopt.getopt(sys.argv[1:], "h", ["help"]) - except getopt.GetoptError: - # print help information and exit: - usage() - sys.exit(2) - - for o, a in opts: - if o in ("-h", "--help"): - usage() - sys.exit() - - fileOpen = None - if len(args) > 1: - usage() - sys.exit() - elif len(args) == 1: - fileOpen = args[0] - - app = wx.PySimpleApp() wx.InitAllImageHandlers() # Install a exception handle for bug reports diff -r d07815f10ca8 -r 323c8d76f6f2 RessourceEditor.py --- a/RessourceEditor.py Mon Jul 27 12:01:43 2009 +0200 +++ b/RessourceEditor.py Fri Aug 07 15:49:10 2009 +0200 @@ -74,6 +74,14 @@ # Resource Editor class #------------------------------------------------------------------------------- +def GetTasksTableColnames(): + _ = lambda x : x + return [_("Name"), _("Single"), _("Interval"), _("Priority")] + +def GetInstancesTableColnames(): + _ = lambda x : x + return [_("Name"), _("Type"), _("Task")] + class ResourceTable(wx.grid.PyGridTableBase): """ @@ -113,16 +121,18 @@ def GetNumberRows(self): return len(self.data) - def GetColLabelValue(self, col): + def GetColLabelValue(self, col, translate=True): if col < len(self.colnames): + if translate: + return _(self.colnames[col]) return self.colnames[col] - def GetRowLabelValues(self, row): + def GetRowLabelValues(self, row, translate=True): return row def GetValue(self, row, col): if row < self.GetNumberRows(): - name = str(self.data[row].get(self.GetColLabelValue(col), "")) + name = str(self.data[row].get(self.GetColLabelValue(col, False), "")) return name def GetValueByName(self, row, colname): @@ -130,7 +140,7 @@ def SetValue(self, row, col, value): if col < len(self.colnames): - self.data[row][self.GetColLabelValue(col)] = value + self.data[row][self.GetColLabelValue(col, False)] = value def SetValueByName(self, row, colname, value): if colname in self.colnames: @@ -188,7 +198,7 @@ for col in range(self.GetNumberCols()): editor = None renderer = None - colname = self.GetColLabelValue(col) + colname = self.GetColLabelValue(col, False) grid.SetReadOnly(row, col, False) if colname in ["Name","Interval"]: editor = wx.grid.GridCellTextEditor() @@ -345,8 +355,8 @@ size=wx.Size(0, 0), style=wx.SUNKEN_BORDER) self.staticText1 = wx.StaticText(id=ID_RESOURCEEDITORSTATICTEXT1, - label=u'Tasks:', name='staticText2', parent=self, pos=wx.Point(0, - 0), size=wx.Size(60, 17), style=wx.ALIGN_CENTER) + label=_(u'Tasks:'), name='staticText2', parent=self, pos=wx.Point(0, + 0), size=wx.DefaultSize, style=wx.ALIGN_CENTER) self.TasksGrid = wx.grid.Grid(id=ID_RESOURCEEDITORTASKSGRID, name='TasksGrid', parent=self, pos=wx.Point(0, 0), @@ -360,14 +370,14 @@ else: wx.grid.EVT_GRID_CELL_CHANGE(self.TasksGrid, self.OnTasksGridCellChange) - self.AddTaskButton = wx.Button(id=ID_RESOURCEEDITORADDTASKBUTTON, label='Add Task', + self.AddTaskButton = wx.Button(id=ID_RESOURCEEDITORADDTASKBUTTON, label=_('Add Task'), name='AddTaskButton', parent=self, pos=wx.Point(0, 0), - size=wx.Size(102, 32), style=0) + size=wx.DefaultSize, style=0) self.Bind(wx.EVT_BUTTON, self.OnAddTaskButton, id=ID_RESOURCEEDITORADDTASKBUTTON) - self.DeleteTaskButton = wx.Button(id=ID_RESOURCEEDITORDELETETASKBUTTON, label='Delete Task', + self.DeleteTaskButton = wx.Button(id=ID_RESOURCEEDITORDELETETASKBUTTON, label=_('Delete Task'), name='DeleteTaskButton', parent=self, pos=wx.Point(0, 0), - size=wx.Size(102, 32), style=0) + size=wx.DefaultSize, style=0) self.Bind(wx.EVT_BUTTON, self.OnDeleteTaskButton, id=ID_RESOURCEEDITORDELETETASKBUTTON) self.UpTaskButton = wx.Button(id=ID_RESOURCEEDITORUPTASKBUTTON, label='^', @@ -381,8 +391,8 @@ self.Bind(wx.EVT_BUTTON, self.OnDownTaskButton, id=ID_RESOURCEEDITORDOWNTASKBUTTON) self.staticText2 = wx.StaticText(id=ID_RESOURCEEDITORSTATICTEXT2, - label=u'Instances:', name='staticText1', parent=self, - pos=wx.Point(0, 0), size=wx.Size(85, 17), style=wx.ALIGN_CENTER) + label=_(u'Instances:'), name='staticText1', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=wx.ALIGN_CENTER) self.InstancesGrid = wx.grid.Grid(id=ID_RESOURCEEDITORINSTANCESGRID, name='InstancesGrid', parent=self, pos=wx.Point(0, 0), @@ -396,14 +406,14 @@ else: wx.grid.EVT_GRID_CELL_CHANGE(self.InstancesGrid, self.OnInstancesGridCellChange) - self.AddInstanceButton = wx.Button(id=ID_RESOURCEEDITORADDINSTANCEBUTTON, label='Add Instance', + self.AddInstanceButton = wx.Button(id=ID_RESOURCEEDITORADDINSTANCEBUTTON, label=_('Add Instance'), name='AddInstanceButton', parent=self, pos=wx.Point(0, 0), - size=wx.Size(122, 32), style=0) + size=wx.DefaultSize, style=0) self.Bind(wx.EVT_BUTTON, self.OnAddInstanceButton, id=ID_RESOURCEEDITORADDINSTANCEBUTTON) - self.DeleteInstanceButton = wx.Button(id=ID_RESOURCEEDITORDELETEINSTANCEBUTTON, label='Delete Instance', + self.DeleteInstanceButton = wx.Button(id=ID_RESOURCEEDITORDELETEINSTANCEBUTTON, label=_('Delete Instance'), name='DeleteInstanceButton', parent=self, pos=wx.Point(0, 0), - size=wx.Size(122, 32), style=0) + size=wx.DefaultSize, style=0) self.Bind(wx.EVT_BUTTON, self.OnDeleteInstanceButton, id=ID_RESOURCEEDITORDELETEINSTANCEBUTTON) self.UpInstanceButton = wx.Button(id=ID_RESOURCEEDITORUPINSTANCEBUTTON, label='^', @@ -426,7 +436,7 @@ self.TagName = tagname self.TasksDefaultValue = {"Name" : "", "Single" : "", "Interval" : "", "Priority" : 0} - self.TasksTable = ResourceTable(self, [], ["Name", "Single", "Interval", "Priority"]) + self.TasksTable = ResourceTable(self, [], GetTasksTableColnames()) self.TasksTable.SetColAlignements([wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT]) self.TasksTable.SetColSizes([200, 100, 100, 100]) self.TasksGrid.SetTable(self.TasksTable) @@ -434,7 +444,7 @@ self.TasksTable.ResetView(self.TasksGrid) self.InstancesDefaultValue = {"Name" : "", "Type" : "", "Task" : ""} - self.InstancesTable = ResourceTable(self, [], ["Name", "Type", "Task"]) + self.InstancesTable = ResourceTable(self, [], GetInstancesTableColnames()) self.InstancesTable.SetColAlignements([wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]) self.InstancesTable.SetColSizes([200, 150, 150]) self.InstancesGrid.SetTable(self.InstancesTable) @@ -593,4 +603,4 @@ self.TasksTable.AddError(infos[1:]) elif infos[0] == "instance": self.InstancesTable.AddError(infos[1:]) - \ No newline at end of file + diff -r d07815f10ca8 -r 323c8d76f6f2 SFCViewer.py --- a/SFCViewer.py Mon Jul 27 12:01:43 2009 +0200 +++ b/SFCViewer.py Fri Aug 07 15:49:10 2009 +0200 @@ -148,7 +148,7 @@ self.RemoveWire(output_wire) else: next = None - action = step.GetActionConnector() + action = step.GetActionConnected() if action: self.DeleteActionBlock(action.GetParentBlock()) step.Clean() @@ -230,7 +230,7 @@ else: self.SelectedElement.OnLeftUp(event, self.GetLogicalDC(), self.Scaling) self.SelectedElement.Refresh() - wx.CallAfter(self.SetCursor, wx.NullCursor) + wx.CallAfter(self.SetCurrentCursor, 0) elif self.Mode == MODE_WIRE and self.SelectedElement: self.SelectedElement.ResetPoints() self.SelectedElement.OnMotion(event, self.GetLogicalDC(), self.Scaling) @@ -256,7 +256,7 @@ self.SelectedElement.SetSelected(True) self.SelectedElement.OnRightUp(event, dc, self.Scaling) self.SelectedElement.Refresh() - wx.CallAfter(self.SetCursor, wx.NullCursor) + wx.CallAfter(self.SetCurrentCursor, 0) event.Skip() def OnViewerLeftDClick(self, event): @@ -359,7 +359,7 @@ #------------------------------------------------------------------------------- def AddInitialStep(self, pos): - dialog = StepNameDialog(self.ParentWindow, "Please enter step name", "Add a new initial step", "", wx.OK|wx.CANCEL) + dialog = StepNameDialog(self.ParentWindow, _("Please enter step name"), _("Add a new initial step"), "", wx.OK|wx.CANCEL) dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug)) dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)) dialog.SetStepNames([block.GetName() for block in self.Blocks if isinstance(block, SFC_Step)]) @@ -381,7 +381,7 @@ def AddStep(self): if self.SelectedElement in self.Wires or isinstance(self.SelectedElement, SFC_Step): - dialog = StepNameDialog(self.ParentWindow, "Add a new step", "Please enter step name", "", wx.OK|wx.CANCEL) + dialog = StepNameDialog(self.ParentWindow, _("Add a new step"), _("Please enter step name"), "", wx.OK|wx.CANCEL) dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug)) dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)) dialog.SetStepNames([block.GetName() for block in self.Blocks if isinstance(block, SFC_Step)]) @@ -695,7 +695,7 @@ for block in self.Blocks: if isinstance(block, SFC_Step): choices.append(block.GetName()) - dialog = wx.SingleChoiceDialog(self.ParentWindow, "Add a new jump", "Please choose a target", choices, wx.OK|wx.CANCEL) + dialog = wx.SingleChoiceDialog(self.ParentWindow, _("Add a new jump"), _("Please choose a target"), choices, wx.OK|wx.CANCEL) if dialog.ShowModal() == wx.ID_OK: value = dialog.GetStringSelection() self.SelectedElement.AddOutput() @@ -723,7 +723,7 @@ if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.EditStepContent(self, step) else: - dialog = StepNameDialog(self.ParentWindow, "Edit step name", "Please enter step name", step.GetName(), wx.OK|wx.CANCEL) + dialog = StepNameDialog(self.ParentWindow, _("Edit step name"), _("Please enter step name"), step.GetName(), wx.OK|wx.CANCEL) dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug)) dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)) dialog.SetStepNames([block.GetName() for block in self.Blocks if isinstance(block, SFC_Step) and block.GetName() != step.GetName()]) diff -r d07815f10ca8 -r 323c8d76f6f2 TextViewer.py --- a/TextViewer.py Mon Jul 27 12:01:43 2009 +0200 +++ b/TextViewer.py Fri Aug 07 15:49:10 2009 +0200 @@ -221,7 +221,7 @@ wx.CallAfter(self.RefreshModel) else: event.SetDragText("") - message = wx.MessageDialog(self.ParentWindow, "Variable don't belong to this POU!", "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self.ParentWindow, _("Variable don't belong to this POU!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() event.Skip() diff -r d07815f10ca8 -r 323c8d76f6f2 Viewer.py --- a/Viewer.py Mon Jul 27 12:01:43 2009 +0200 +++ b/Viewer.py Fri Aug 07 15:49:10 2009 +0200 @@ -41,6 +41,18 @@ WINDOW_BORDER = 10 SCROLL_ZONE = 10 +CURSORS = None + +def ResetCursors(): + global CURSORS + if CURSORS == None: + CURSORS = [wx.NullCursor, + wx.StockCursor(wx.CURSOR_HAND), + wx.StockCursor(wx.CURSOR_SIZENWSE), + wx.StockCursor(wx.CURSOR_SIZENESW), + wx.StockCursor(wx.CURSOR_SIZEWE), + wx.StockCursor(wx.CURSOR_SIZENS)] + def AppendMenu(parent, help, id, kind, text): if wx.VERSION >= (2, 6, 0): parent.Append(help=help, id=id, kind=kind, text=text) @@ -64,6 +76,102 @@ ZOOM_FACTORS = [math.sqrt(2) ** x for x in xrange(-6, 7)] + +def GetVariableCreationFunction(variable_type): + def variableCreationFunction(viewer, id, specific_values): + return FBD_Variable(viewer, variable_type, + specific_values["name"], + specific_values["value_type"], + id, + specific_values["executionOrder"]) + return variableCreationFunction + +def GetConnectorCreationFunction(connector_type): + def connectorCreationFunction(viewer, id, specific_values): + return FBD_Connector(viewer, connector_type, + specific_values["name"], id) + return connectorCreationFunction + +def commentCreationFunction(viewer, id, specific_values): + return Comment(viewer, specific_values["content"], id) + +def GetPowerRailCreationFunction(powerrail_type): + def powerRailCreationFunction(viewer, id, specific_values): + return LD_PowerRail(viewer, powerrail_type, id, + specific_values["connectors"]) + return powerRailCreationFunction + +CONTACT_TYPES = {(True, "none"): CONTACT_REVERSE, + (False, "rising"): CONTACT_RISING, + (False, "falling"): CONTACT_FALLING} + +def contactCreationFunction(viewer, id, specific_values): + contact_type = CONTACT_TYPES.get((specific_values.get("negated", False), + specific_values.get("edge", "none")), + CONTACT_NORMAL) + return LD_Contact(viewer, contact_type, specific_values["name"], id) + +COIL_TYPES = {(True, "none", "none"): COIL_REVERSE, + (False, "none", "set"): COIL_SET, + (False, "none", "reset"): COIL_RESET, + (False, "rising", "none"): COIL_RISING, + (False, "falling", "none"): COIL_FALLING} + +def coilCreationFunction(viewer, id, specific_values): + coil_type = COIL_TYPES.get((specific_values.get("negated", False), + specific_values.get("edge", "none"), + specific_values.get("storage", "none")), + COIL_NORMAL) + return LD_Coil(viewer, coil_type, specific_values["name"], id) + +def stepCreationFunction(viewer, id, specific_values): + step = SFC_Step(viewer, specific_values["name"], + specific_values.get("initial", False), id) + if specific_values.get("action", None): + step.AddAction() + connector = step.GetActionConnector() + connector.SetPosition(wx.Point(*specific_values["action"]["position"])) + return step + +def transitionCreationFunction(viewer, id, specific_values): + transition = SFC_Transition(viewer, specific_values["condition_type"], + specific_values.get("condition", None), + specific_values["priority"], id) + return transition + +def GetDivergenceCreationFunction(divergence_type): + def divergenceCreationFunction(viewer, id, specific_values): + return SFC_Divergence(viewer, divergence_type, + specific_values["connectors"], id) + return divergenceCreationFunction + +def jumpCreationFunction(viewer, id, specific_values): + return SFC_Jump(viewer, specific_values["target"], id) + +def actionBlockCreationFunction(viewer, id, specific_values): + return SFC_ActionBlock(viewer, specific_values["actions"], id) + +ElementCreationFunctions = { + "input": GetVariableCreationFunction(INPUT), + "output": GetVariableCreationFunction(OUTPUT), + "inout": GetVariableCreationFunction(INOUT), + "connector": GetConnectorCreationFunction(CONNECTOR), + "continuation": GetConnectorCreationFunction(CONTINUATION), + "comment": commentCreationFunction, + "leftPowerRail": GetPowerRailCreationFunction(LEFTRAIL), + "rightPowerRail": GetPowerRailCreationFunction(RIGHTRAIL), + "contact": contactCreationFunction, + "coil": coilCreationFunction, + "step": stepCreationFunction, + "transition": transitionCreationFunction, + "selectionDivergence": GetDivergenceCreationFunction(SELECTION_DIVERGENCE), + "selectionConvergence": GetDivergenceCreationFunction(SELECTION_CONVERGENCE), + "simultaneousDivergence": GetDivergenceCreationFunction(SIMULTANEOUS_DIVERGENCE), + "simultaneousConvergence": GetDivergenceCreationFunction(SIMULTANEOUS_CONVERGENCE), + "jump": jumpCreationFunction, + "actionBlock": actionBlockCreationFunction, +} + #------------------------------------------------------------------------------- # Graphic elements Viewer base class #------------------------------------------------------------------------------- @@ -100,27 +208,27 @@ try: values = eval(data) except: - message = "Invalid value \"%s\" for viewer block"%data + message = _("Invalid value \"%s\" for viewer block")%data values = None if not isinstance(values, TupleType): - message = "Invalid value \"%s\" for viewer block"%data + message = _("Invalid value \"%s\" for viewer block")%data values = None if values is not None: if values[1] == "debug": pass elif values[1] == "program": - message = "Programs can't be used by other POUs!" + message = _("Programs can't be used by other POUs!") elif values[1] in ["function", "functionBlock", "program"]: name, type = self.ParentWindow.Controler.GetEditedElementType(self.ParentWindow.GetTagName(), self.ParentWindow.Debug) words = self.ParentWindow.TagName.split("::") if name == values[0]: - message = "\"%s\" can't use itself!"%name + message = _("\"%s\" can't use itself!")%name elif type == "function" and values[1] != "function": - message = "Function Blocks can't be used in Functions!" + message = _("Function Blocks can't be used in Functions!") elif words[0] == "T" and values[1] != "function": - message = "Function Blocks can't be used in Transitions!" + message = _("Function Blocks can't be used in Transitions!") elif self.ParentWindow.Controler.PouIsUsedBy(name, values[0], self.ParentWindow.Debug): - message = "\"%s\" is already used by \"%s\"!"%(name, values[0]) + message = _("\"%s\" is already used by \"%s\"!")%(name, values[0]) else: blockname = values[2] if len(values) > 3: @@ -135,9 +243,9 @@ return dialog.Destroy() if blockname.upper() in [name.upper() for name in self.ParentWindow.Controler.GetProjectPouNames(self.ParentWindow.Debug)]: - message = "\"%s\" pou already exists!"%blockname + message = _("\"%s\" pou already exists!")%blockname elif blockname.upper() in [name.upper() for name in self.ParentWindow.Controler.GetEditedElementVariables(self.ParentWindow.GetTagName(), self.ParentWindow.Debug)]: - message = "\"%s\" element for this pou already exists!"%blockname + message = _("\"%s\" element for this pou already exists!")%blockname else: id = self.ParentWindow.GetNewId() block = FBD_Block(self.ParentWindow, values[0], blockname, id, inputs = blockinputs) @@ -175,9 +283,9 @@ else: self.AddParentVariableBlock(x, y, scaling, var_class, values[0], values[2]) else: - message = "Unknown variable \"%s\" this POU!" % values[0] + message = _("Unknown variable \"%s\" for this POU!") % values[0] else: - message = "Variable don't belong to this POU!" + message = _("Variable don't belong to this POU!") if message is not None: wx.CallAfter(self.ShowMessage, message) @@ -224,7 +332,7 @@ self.ParentWindow.Refresh(False) def ShowMessage(self, message): - message = wx.MessageDialog(self.ParentWindow, message, "Error", wx.OK|wx.ICON_ERROR) + message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() @@ -247,18 +355,18 @@ def _init_coll_AlignmentMenu_Items(self, parent): # Create menu items AppendMenu(parent, help='', id=ID_VIEWERALIGNMENTMENUITEMS0, - kind=wx.ITEM_NORMAL, text=u'Left') + kind=wx.ITEM_NORMAL, text=_(u'Left')) AppendMenu(parent, help='', id=ID_VIEWERALIGNMENTMENUITEMS1, - kind=wx.ITEM_NORMAL, text=u'Center') + kind=wx.ITEM_NORMAL, text=_(u'Center')) AppendMenu(parent, help='', id=ID_VIEWERALIGNMENTMENUITEMS2, - kind=wx.ITEM_NORMAL, text=u'Right') + kind=wx.ITEM_NORMAL, text=_(u'Right')) parent.AppendSeparator() AppendMenu(parent, help='', id=ID_VIEWERALIGNMENTMENUITEMS4, - kind=wx.ITEM_NORMAL, text=u'Top') + kind=wx.ITEM_NORMAL, text=_(u'Top')) AppendMenu(parent, help='', id=ID_VIEWERALIGNMENTMENUITEMS5, - kind=wx.ITEM_NORMAL, text=u'Middle') + kind=wx.ITEM_NORMAL, text=_(u'Middle')) AppendMenu(parent, help='', id=ID_VIEWERALIGNMENTMENUITEMS6, - kind=wx.ITEM_NORMAL, text=u'Bottom') + kind=wx.ITEM_NORMAL, text=_(u'Bottom')) # Link menu event to corresponding called functions self.Bind(wx.EVT_MENU, self.OnAlignLeftMenu, id=ID_VIEWERALIGNMENTMENUITEMS0) @@ -277,35 +385,35 @@ def _init_coll_ContextualMenu_Items(self, parent): # Create menu items AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS0, - kind=wx.ITEM_RADIO, text=u'No Modifier') + kind=wx.ITEM_RADIO, text=_(u'No Modifier')) AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS1, - kind=wx.ITEM_RADIO, text=u'Negated') + kind=wx.ITEM_RADIO, text=_(u'Negated')) AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS2, - kind=wx.ITEM_RADIO, text=u'Rising Edge') + kind=wx.ITEM_RADIO, text=_(u'Rising Edge')) AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS3, - kind=wx.ITEM_RADIO, text=u'Falling Edge') + kind=wx.ITEM_RADIO, text=_(u'Falling Edge')) parent.AppendSeparator() AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS5, - kind=wx.ITEM_NORMAL, text=u'Add Wire Segment') + kind=wx.ITEM_NORMAL, text=_(u'Add Wire Segment')) AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS6, - kind=wx.ITEM_NORMAL, text=u'Delete Wire Segment') + kind=wx.ITEM_NORMAL, text=_(u'Delete Wire Segment')) parent.AppendSeparator() AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS8, - kind=wx.ITEM_NORMAL, text=u'Add Divergence Branch') + kind=wx.ITEM_NORMAL, text=_(u'Add Divergence Branch')) AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS9, - kind=wx.ITEM_NORMAL, text=u'Delete Divergence Branch') + kind=wx.ITEM_NORMAL, text=_(u'Delete Divergence Branch')) parent.AppendSeparator() AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS11, - kind=wx.ITEM_NORMAL, text=u'Clear Execution Order') + kind=wx.ITEM_NORMAL, text=_(u'Clear Execution Order')) AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS12, - kind=wx.ITEM_NORMAL, text=u'Reset Execution Order') + kind=wx.ITEM_NORMAL, text=_(u'Reset Execution Order')) parent.AppendSeparator() - parent.AppendMenu(ID_VIEWERCONTEXTUALMENUITEMS14, "Alignment", self.AlignmentMenu) + parent.AppendMenu(ID_VIEWERCONTEXTUALMENUITEMS14, _("Alignment"), self.AlignmentMenu) parent.AppendSeparator() AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS16, - kind=wx.ITEM_NORMAL, text=u'Edit Block') + kind=wx.ITEM_NORMAL, text=_(u'Edit Block')) AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS17, - kind=wx.ITEM_NORMAL, text=u'Delete') + kind=wx.ITEM_NORMAL, text=_(u'Delete')) # Link menu event to corresponding called functions self.Bind(wx.EVT_MENU, self.OnNoModifierMenu, id=ID_VIEWERCONTEXTUALMENUITEMS0) @@ -364,8 +472,12 @@ self.StartMousePos = None self.StartScreenPos = None + # Initialize Cursors + ResetCursors() + self.CurrentCursor = 0 + # Initialize Block, Wire and Comment numbers - self.block_id = self.wire_id = self.comment_id = 0 + self.wire_id = 0 # Initialize Viewer mode to Selection mode self.Mode = MODE_SELECTION @@ -414,6 +526,12 @@ self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheelWindow) self.Bind(wx.EVT_SIZE, self.OnMoveWindow) + def SetCurrentCursor(self, cursor): + global CURSORS + if self.CurrentCursor != cursor: + self.CurrentCursor = cursor + self.SetCursor(CURSORS[cursor]) + def GetScrolledRect(self, rect): rect.x, rect.y = self.CalcScrolledPosition(int(rect.x * self.ViewScale[0]), int(rect.y * self.ViewScale[1])) @@ -483,47 +601,53 @@ #------------------------------------------------------------------------------- def AddBlock(self, block): - self.block_id += 1 - self.Blocks[block] = self.block_id + self.Blocks[block.GetId()] = block def AddWire(self, wire): self.wire_id += 1 self.Wires[wire] = self.wire_id def AddComment(self, comment): - self.comment_id += 1 - self.Comments[comment] = self.comment_id + self.Comments[comment.GetId()] = comment def IsBlock(self, block): - return self.Blocks.get(block, False) + return self.Blocks.get(block.GetId(), False) def IsWire(self, wire): return self.Wires.get(wire, False) def IsComment(self, comment): - return self.Comments.get(comment, False) + return self.Comments.get(comment.GetId(), False) def RemoveBlock(self, block): - self.Blocks.pop(block) + self.Blocks.pop(block.GetId()) def RemoveWire(self, wire): self.Wires.pop(wire) def RemoveComment(self, comment): - self.Comments.pop(comment) + self.Comments.pop(comment.GetId()) def GetElements(self, sort_blocks=False, sort_wires=False, sort_comments=False): - blocks = self.Blocks.keys() + blocks = self.Blocks.values() wires = self.Wires.keys() - comments = self.Comments.keys() + comments = self.Comments.values() if sort_blocks: - blocks.sort(lambda x, y: cmp(self.Blocks[x], self.Blocks[y])) + blocks.sort(lambda x, y: cmp(x.GetId(), y.GetId())) if sort_wires: wires.sort(lambda x, y: cmp(self.Wires[x], self.Wires[y])) if sort_comments: - comments.sort(lambda x, y: cmp(self.Comments[x], self.Comments[y])) + comments.sort(lambda x, y: cmp(x.GetId(), y.GetId())) return blocks + wires + comments + def GetConnectorByName(self, name): + for block in self.Blocks.itervalues(): + if isinstance(block, FBD_Connector) and\ + block.GetType() == CONNECTOR and\ + block.GetName() == name: + return block + return None + def RefreshVisibleElements(self, xp = None, yp = None): x, y = self.CalcUnscrolledPosition(0, 0) if xp is not None: @@ -533,11 +657,11 @@ width, height = self.GetClientSize() screen = wx.Rect(int(x / self.ViewScale[0]), int(y / self.ViewScale[1]), int(width / self.ViewScale[0]), int(height / self.ViewScale[1])) - for comment in self.Comments: + for comment in self.Comments.itervalues(): comment.TestVisible(screen) - for wire in self.Wires: + for wire in self.Wires.iterkeys(): wire.TestVisible(screen) - for block in self.Blocks: + for block in self.Blocks.itervalues(): block.TestVisible(screen) def GetElementIECPath(self, element): @@ -556,6 +680,12 @@ iec_path = "%s.%s%d_%s"%(self.InstancePath, block.GetType(), block.GetId(), connectorname) elif isinstance(block, FBD_Variable): iec_path = "%s.%s"%(self.InstancePath, block.GetName()) + elif isinstance(block, FBD_Connector): + connection = self.GetConnectorByName(block.GetName()) + if connection is not None: + connector = connection.GetConnector() + if len(connector.Wires) == 1: + iec_path = self.GetElementIECPath(connector.Wires[0][0]) elif isinstance(element, LD_Contact): iec_path = "%s.%s"%(self.InstancePath, element.GetName()) elif isinstance(element, SFC_Step): @@ -582,12 +712,12 @@ def Flush(self): self.DeleteDataConsumers() - for block in self.Blocks: + for block in self.Blocks.itervalues(): block.Flush() # Remove all elements def CleanView(self): - for block in self.Blocks.keys(): + for block in self.Blocks.itervalues(): block.Clean() self.ResetView() @@ -617,7 +747,7 @@ def RefreshScaling(self, refresh=True): properties = self.Controler.GetProjectProperties(self.Debug) scaling = properties["scaling"][self.CurrentLanguage] - if scaling != (0, 0): + if scaling[0] != 0 and scaling[1] != 0: self.Scaling = scaling if self.DrawGrid: width = max(2, int(scaling[0] * self.ViewScale[0])) @@ -667,7 +797,7 @@ pass # Refresh Viewer elements - def RefreshView(self): + def RefreshView(self, selection=None): self.Inhibit(True) self.current_id = 0 # Start by reseting Viewer @@ -680,37 +810,19 @@ while instance is not None: instance = self.Controler.GetEditedElementInstanceInfos(self.TagName, exclude = ids, debug = self.Debug) if instance is not None: - self.loadInstance(instance, ids) + self.loadInstance(instance, ids, selection) self.RefreshScrollBars() for wire in self.Wires: if not wire.IsConnectedCompatible(): wire.SetValid(False) if self.Debug: - block = wire.EndConnected.GetParentBlock() - if isinstance(block, LD_PowerRail): - wire.SetValue(True) - if isinstance(block, FBD_Block): - blockname = block.GetName() - connectorname = wire.EndConnected.GetName() - if blockname != "": - iec_path = "%s.%s.%s"%(self.InstancePath, blockname, connectorname) - else: - if connectorname == "": - iec_path = "%s.%s%d"%(self.InstancePath, block.GetType(), block.GetId()) - else: - iec_path = "%s.%s%d_%s"%(self.InstancePath, block.GetType(), block.GetId(), connectorname) - if self.AddDataConsumer(iec_path.upper(), wire) is None: - wire.SetValue("undefined") - elif isinstance(block, FBD_Variable): - iec_path = "%s.%s"%(self.InstancePath, block.GetName()) - if self.AddDataConsumer(iec_path.upper(), wire) is None: - wire.SetValue("undefined") - elif isinstance(block, FBD_Connector): + iec_path = self.GetElementIECPath(wire) + if self.AddDataConsumer(iec_path.upper(), wire) is None: wire.SetValue("undefined") if self.Debug: - for block in self.Blocks.keys(): + for block in self.Blocks.itervalues(): block.SpreadCurrent() iec_path = self.GetElementIECPath(block) if iec_path is not None: @@ -770,229 +882,46 @@ self.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, round(maxx / SCROLLBAR_UNIT) + width_incr, round(maxy / SCROLLBAR_UNIT) + height_incr, xstart, ystart, True) + + def SelectInGroup(self, element): + element.SetSelected(True) + if self.SelectedElement is None: + self.SelectedElement = element + elif isinstance(self.SelectedElement, Graphic_Group): + self.SelectedElement.SelectElement(element) + else: + group = Graphic_Group(self) + group.SelectElement(self.SelectedElement) + group.SelectElement(element) + self.SelectedElement = group # Load instance from given informations - def loadInstance(self, instance, ids): + def loadInstance(self, instance, ids, selection): ids.append(instance["id"]) - self.current_id = max(self.current_id, instance["id"]) - if instance["type"] == "input": - variable = FBD_Variable(self, INPUT, instance["name"], instance["value_type"], instance["id"], instance["executionOrder"]) - variable.SetPosition(instance["x"], instance["y"]) - variable.SetSize(instance["width"], instance["height"]) - self.AddBlock(variable) - connectors = variable.GetConnectors() - connectors["output"].SetPosition(wx.Point(*instance["connector"]["position"])) - if instance["connector"]["negated"]: - connectors["output"].SetNegated(True) - if instance["connector"]["edge"]: - connectors["output"].SetEdge(instance["connector"]["edge"]) - elif instance["type"] == "output": - variable = FBD_Variable(self, OUTPUT, instance["name"], instance["value_type"], instance["id"], instance["executionOrder"]) - variable.SetPosition(instance["x"], instance["y"]) - variable.SetSize(instance["width"], instance["height"]) - self.AddBlock(variable) - connectors = variable.GetConnectors() - connectors["input"].SetPosition(wx.Point(*instance["connector"]["position"])) - if instance["connector"]["negated"]: - connectors["input"].SetNegated(True) - if instance["connector"]["edge"]: - connectors["input"].SetEdge(instance["connector"]["edge"]) - self.CreateWires(connectors["input"], instance["connector"]["links"], ids) - elif instance["type"] == "inout": - variable = FBD_Variable(self, INOUT, instance["name"], instance["value_type"], instance["id"], instance["executionOrder"]) - variable.SetPosition(instance["x"], instance["y"]) - variable.SetSize(instance["width"], instance["height"]) - self.AddBlock(variable) - connectors = variable.GetConnectors() - connectors["output"].SetPosition(wx.Point(*instance["connectors"]["output"]["position"])) - connectors["input"].SetPosition(wx.Point(*instance["connectors"]["input"]["position"])) - if instance["connectors"]["output"]["negated"]: - connectors["output"].SetNegated(True) - if instance["connectors"]["output"]["edge"]: - connectors["output"].SetEdge(instance["connectors"]["output"]["edge"]) - if instance["connectors"]["input"]["negated"]: - connectors["input"].SetNegated(True) - if instance["connectors"]["input"]["edge"]: - connectors["input"].SetEdge(instance["connectors"]["input"]["edge"]) - self.CreateWires(connectors["input"], instance["connectors"]["input"]["links"], ids) - elif instance["type"] == "continuation": - connection = FBD_Connector(self, CONTINUATION, instance["name"], instance["id"]) - connection.SetPosition(instance["x"], instance["y"]) - connection.SetSize(instance["width"], instance["height"]) - self.AddBlock(connection) - connector = connection.GetConnector() - connector.SetPosition(wx.Point(*instance["connector"]["position"])) - elif instance["type"] == "connection": - connection = FBD_Connector(self, CONNECTOR, instance["name"], instance["id"]) - connection.SetPosition(instance["x"], instance["y"]) - connection.SetSize(instance["width"], instance["height"]) - self.AddBlock(connection) - connector = connection.GetConnector() - connector.SetPosition(wx.Point(*instance["connector"]["position"])) - self.CreateWires(connector, instance["connector"]["links"], ids) - elif instance["type"] == "comment": - comment = Comment(self, instance["content"], instance["id"]) - comment.SetPosition(instance["x"], instance["y"]) - comment.SetSize(instance["width"], instance["height"]) - self.AddComment(comment) - elif instance["type"] == "leftPowerRail": - leftpowerrail = LD_PowerRail(self, LEFTRAIL, instance["id"], [True for i in range(len(instance["connectors"]))]) - leftpowerrail.SetPosition(instance["x"], instance["y"]) - leftpowerrail.SetSize(instance["width"], instance["height"]) - self.AddBlock(leftpowerrail) - connectors = leftpowerrail.GetConnectors() - for i, connector in enumerate(instance["connectors"]): - connectors[i].SetPosition(wx.Point(*connector["position"])) - elif instance["type"] == "rightPowerRail": - rightpowerrail = LD_PowerRail(self, RIGHTRAIL, instance["id"], [True for i in range(len(instance["connectors"]))]) - rightpowerrail.SetPosition(instance["x"], instance["y"]) - rightpowerrail.SetSize(instance["width"], instance["height"]) - self.AddBlock(rightpowerrail) - connectors = rightpowerrail.GetConnectors() - for i, connector in enumerate(instance["connectors"]): - connectors[i].SetPosition(wx.Point(*connector["position"])) - self.CreateWires(connectors[i], connector["links"], ids) - elif instance["type"] == "contact": - if instance["negated"]: - negated = instance["negated"] - else: - negated = False - if instance["edge"]: - edge = instance["edge"] - else: - edge = "none" - if negated and edge == "none": - contact_type = CONTACT_REVERSE - elif not negated and edge == "rising": - contact_type = CONTACT_RISING - elif not negated and edge == "falling": - contact_type = CONTACT_FALLING - else: - contact_type = CONTACT_NORMAL - contact = LD_Contact(self, contact_type, instance["name"], instance["id"]) - contact.SetPosition(instance["x"], instance["y"]) - contact.SetSize(instance["width"], instance["height"]) - self.AddBlock(contact) - connectors = contact.GetConnectors() - connectors["input"].SetPosition(wx.Point(*instance["connectors"]["input"]["position"])) - self.CreateWires(connectors["input"], instance["connectors"]["input"]["links"], ids) - connectors["output"].SetPosition(wx.Point(*instance["connectors"]["output"]["position"])) - elif instance["type"] == "coil": - if instance["negated"]: - negated = instance["negated"] - else: - negated = False - if instance["storage"]: - storage = instance["storage"] - else: - storage = "none" - if instance["edge"]: - edge = instance["edge"] - else: - edge = "none" - if negated and storage == "none" and edge == "none": - coil_type = COIL_REVERSE - elif not negated and edge == "none" and storage == "set": - coil_type = COIL_SET - elif not negated and edge == "none" and storage == "reset": - coil_type = COIL_RESET - elif not negated and storage == "none" and edge == "rising": - coil_type = COIL_RISING - elif not negated and storage == "none" and edge == "falling": - coil_type = COIL_FALLING - else: - coil_type = COIL_NORMAL - coil = LD_Coil(self, coil_type, instance["name"], instance["id"]) - coil.SetPosition(instance["x"], instance["y"]) - coil.SetSize(instance["width"], instance["height"]) - self.AddBlock(coil) - connectors = coil.GetConnectors() - connectors["input"].SetPosition(wx.Point(*instance["connectors"]["input"]["position"])) - self.CreateWires(connectors["input"], instance["connectors"]["input"]["links"], ids) - connectors["output"].SetPosition(wx.Point(*instance["connectors"]["output"]["position"])) - elif instance["type"] == "step": - if instance["initial"]: - initial = instance["initial"] - else: - initial = False - step = SFC_Step(self, instance["name"], initial, instance["id"]) - step.SetPosition(instance["x"], instance["y"]) - step.SetSize(instance["width"], instance["height"]) - self.AddBlock(step) - if "output" in instance["connectors"]: - step.AddOutput() - if "action" in instance["connectors"]: - step.AddAction() - connectors = step.GetConnectors() - if connectors["input"]: - connectors["input"].SetPosition(wx.Point(*instance["connectors"]["input"]["position"])) - self.CreateWires(connectors["input"], instance["connectors"]["input"]["links"], ids) - if connectors["output"]: - connectors["output"].SetPosition(wx.Point(*instance["connectors"]["output"]["position"])) - if connectors["action"]: - connectors["action"].SetPosition(wx.Point(*instance["connectors"]["action"]["position"])) - elif instance["type"] == "transition": - transition = SFC_Transition(self, instance["condition_type"], instance["condition"], instance["priority"], instance["id"]) - transition.SetPosition(instance["x"], instance["y"]) - transition.SetSize(instance["width"], instance["height"]) - self.AddBlock(transition) - connectors = transition.GetConnectors() - connectors["input"].SetPosition(wx.Point(*instance["connectors"]["input"]["position"])) - self.CreateWires(connectors["input"], instance["connectors"]["input"]["links"], ids) - connectors["output"].SetPosition(wx.Point(*instance["connectors"]["output"]["position"])) - if instance["condition_type"] == "connection": - self.CreateWires(connectors["connection"], instance["connectors"]["connection"]["links"], ids) - elif instance["type"] in ["selectionDivergence", "selectionConvergence", "simultaneousDivergence", "simultaneousConvergence"]: - if instance["type"] == "selectionDivergence": - divergence = SFC_Divergence(self, SELECTION_DIVERGENCE, - len(instance["connectors"]["outputs"]), instance["id"]) - elif instance["type"] == "selectionConvergence": - divergence = SFC_Divergence(self, SELECTION_CONVERGENCE, - len(instance["connectors"]["inputs"]), instance["id"]) - elif instance["type"] == "simultaneousDivergence": - divergence = SFC_Divergence(self, SIMULTANEOUS_DIVERGENCE, - len(instance["connectors"]["outputs"]), instance["id"]) - else: - divergence = SFC_Divergence(self, SIMULTANEOUS_CONVERGENCE, - len(instance["connectors"]["inputs"]), instance["id"]) - divergence.SetPosition(instance["x"], instance["y"]) - divergence.SetSize(instance["width"], instance["height"]) - self.AddBlock(divergence) - connectors = divergence.GetConnectors() - for i, input_connector in enumerate(instance["connectors"]["inputs"]): - connector = connectors["inputs"][i] - connector.SetPosition(wx.Point(*input_connector["position"])) - self.CreateWires(connector, input_connector["links"], ids) - for i, output_connector in enumerate(instance["connectors"]["outputs"]): - connector = connectors["outputs"][i] - connector.SetPosition(wx.Point(*output_connector["position"])) - elif instance["type"] == "jump": - jump = SFC_Jump(self, instance["target"], instance["id"]) - jump.SetPosition(instance["x"], instance["y"]) - jump.SetSize(instance["width"], instance["height"]) - self.AddBlock(jump) - connector = jump.GetConnector() - connector.SetPosition(wx.Point(*instance["connector"]["position"])) - self.CreateWires(connector, instance["connector"]["links"], ids) - elif instance["type"] == "actionBlock": - actionBlock = SFC_ActionBlock(self, instance["actions"], instance["id"]) - actionBlock.SetPosition(instance["x"], instance["y"]) - actionBlock.SetSize(instance["width"], instance["height"]) - self.AddBlock(actionBlock) - connector = actionBlock.GetConnector() - connector.SetPosition(wx.Point(*instance["connector"]["position"])) - self.CreateWires(connector, instance["connector"]["links"], ids) + self.current_id = max(self.current_id, instance["id"]) + creation_function = ElementCreationFunctions.get(instance["type"], None) + connectors = {"inputs" : [], "outputs" : []} + specific_values = instance["specific_values"] + if creation_function is not None: + element = creation_function(self, instance["id"], specific_values) + if isinstance(element, SFC_Step): + if len(instance["inputs"]) > 0: + element.AddInput() + if len(instance["outputs"]) > 0: + element.AddOutput() + if isinstance(element, SFC_Transition) and specific_values["condition_type"] == "connection": + connector = element.GetConditionConnector() + self.CreateWires(connector, id, specific_values["connection"]["links"], ids, selection) else: - connectors = {"inputs" : [], "outputs" : []} executionControl = False - for input in instance["connectors"]["inputs"]: + for input in instance["inputs"]: if input["negated"]: connectors["inputs"].append((input["name"], None, "negated")) elif input["edge"]: connectors["inputs"].append((input["name"], None, input["edge"])) else: connectors["inputs"].append((input["name"], None, "none")) - for output in instance["connectors"]["outputs"]: + for output in instance["outputs"]: if output["negated"]: connectors["outputs"].append((output["name"], None, "negated")) elif output["edge"]: @@ -1000,47 +929,52 @@ else: connectors["outputs"].append((output["name"], None, "none")) if len(connectors["inputs"]) > 0 and connectors["inputs"][0][0] == "EN": - connectors["inputs"].pop(0) - executionControl = True + connectors["inputs"].pop(0) + executionControl = True if len(connectors["outputs"]) > 0 and connectors["outputs"][0][0] == "ENO": connectors["outputs"].pop(0) executionControl = True - if instance["name"] is None: - instance["name"] = "" - block = FBD_Block(self, instance["type"], instance["name"], - instance["id"], len(connectors["inputs"]), - connectors=connectors, executionControl=executionControl, - executionOrder=instance["executionOrder"]) - block.SetPosition(instance["x"], instance["y"]) - block.SetSize(instance["width"], instance["height"]) - self.AddBlock(block) - connectors = block.GetConnectors() - for i, input_connector in enumerate(instance["connectors"]["inputs"]): - if i < len(connectors["inputs"]): - connector = connectors["inputs"][i] - connector.SetPosition(wx.Point(*input_connector["position"])) - if input_connector["negated"]: - connector.SetNegated(True) - if input_connector["edge"] != "none": - connector.SetEdge(input_connector["edge"]) - self.CreateWires(connector, input_connector["links"], ids) - for i, output_connector in enumerate(instance["connectors"]["outputs"]): - if i < len(connectors["outputs"]): - connector = connectors["outputs"][i] - if output_connector["negated"]: - connector.SetNegated(True) - if output_connector["edge"] != "none": - connector.SetEdge(output_connector["edge"]) - connector.SetPosition(wx.Point(*output_connector["position"])) - - def CreateWires(self, start_connector, links, ids): + if specific_values["name"] is None: + specific_values["name"] = "" + element = FBD_Block(self, instance["type"], specific_values["name"], + instance["id"], len(connectors["inputs"]), + connectors=connectors, executionControl=executionControl, + executionOrder=specific_values["executionOrder"]) + element.SetPosition(instance["x"], instance["y"]) + element.SetSize(instance["width"], instance["height"]) + if isinstance(element, Comment): + self.AddComment(element) + else: + self.AddBlock(element) + connectors = element.GetConnectors() + for i, input_connector in enumerate(instance["inputs"]): + if i < len(connectors["inputs"]): + connector = connectors["inputs"][i] + connector.SetPosition(wx.Point(*input_connector["position"])) + if input_connector.get("negated", False): + connector.SetNegated(True) + if input_connector.get("edge", "none") != "none": + connector.SetEdge(input_connector["edge"]) + self.CreateWires(connector, instance["id"], input_connector["links"], ids, selection) + for i, output_connector in enumerate(instance["outputs"]): + if i < len(connectors["outputs"]): + connector = connectors["outputs"][i] + if output_connector.get("negated", False): + connector.SetNegated(True) + if output_connector.get("edge", "none") != "none": + connector.SetEdge(output_connector["edge"]) + connector.SetPosition(wx.Point(*output_connector["position"])) + if selection is not None and selection[0].get(instance["id"], False): + self.SelectInGroup(element) + + def CreateWires(self, start_connector, id, links, ids, selection=None): for link in links: refLocalId = link["refLocalId"] if refLocalId is not None: if refLocalId not in ids: new_instance = self.Controler.GetEditedElementInstanceInfos(self.TagName, refLocalId, debug = self.Debug) if new_instance is not None: - self.loadInstance(new_instance, ids) + self.loadInstance(new_instance, ids, selection) connected = self.FindElementById(refLocalId) if connected is not None: points = link["points"] @@ -1053,6 +987,10 @@ wire.ConnectStartPoint(None, start_connector) wire.ConnectEndPoint(None, end_connector) self.AddWire(wire) + if selection is not None and (\ + selection[1].get((id, refLocalId), False) or \ + selection[1].get((refLocalId, id), False)): + self.SelectInGroup(wire) def IsOfType(self, type, reference): return self.Controler.IsOfType(type, reference, self.Debug) @@ -1068,7 +1006,7 @@ #------------------------------------------------------------------------------- def FindBlock(self, pos): - for block in self.Blocks: + for block in self.Blocks.itervalues(): if block.HitTest(pos) or block.TestHandle(pos) != (0, 0): return block return None @@ -1089,19 +1027,19 @@ return None def FindBlockConnector(self, pos, direction = None, exclude = None): - for block in self.Blocks: + for block in self.Blocks.itervalues(): result = block.TestConnector(pos, direction, exclude) if result: return result return None def FindElementById(self, id): - for element in self.Blocks: - if element.GetId() == id: - return element - for element in self.Comments: - if element.GetId() == id: - return element + block = self.Blocks.get(id, None) + if block is not None: + return block + comment = self.Comments.get(id, None) + if comment is not None: + return comment return None def SearchElements(self, bbox): @@ -1492,7 +1430,7 @@ Graphic_Element.OnLeftUp(self.SelectedElement, event, dc, self.Scaling) else: self.SelectedElement.OnLeftUp(event, dc, self.Scaling) - wx.CallAfter(self.SetCursor, wx.NullCursor) + wx.CallAfter(self.SetCurrentCursor, 0) if self.Mode != MODE_SELECTION and not self.SavedMode: wx.CallAfter(self.ParentWindow.ResetCurrentMode) event.Skip() @@ -1531,7 +1469,7 @@ Graphic_Element.OnRightUp(self.SelectedElement, event, dc, self.Scaling) else: self.SelectedElement.OnRightUp(event, dc, self.Scaling) - wx.CallAfter(self.SetCursor, wx.NullCursor) + wx.CallAfter(self.SetCurrentCursor, 0) elif not self.Debug: self.PopupDefaultMenu(False) event.Skip() @@ -1683,7 +1621,7 @@ self.SelectedElement = None self.RefreshBuffer() self.RefreshScrollBars() - self.SetCursor(wx.NullCursor) + wx.CallAfter(self.SetCurrentCursor, 0) self.RefreshRect(self.GetScrolledRect(rect), False) elif not self.Debug and keycode == wx.WXK_RETURN and self.SelectedElement is not None: self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling) @@ -1855,9 +1793,9 @@ def AddNewComment(self, bbox): if wx.VERSION >= (2, 5, 0): - dialog = wx.TextEntryDialog(self.ParentWindow, "Edit comment", "Please enter comment text", "", wx.OK|wx.CANCEL|wx.TE_MULTILINE) + dialog = wx.TextEntryDialog(self.ParentWindow, _("Edit comment"), _("Please enter comment text"), "", wx.OK|wx.CANCEL|wx.TE_MULTILINE) else: - dialog = wx.TextEntryDialog(self.ParentWindow, "Edit comment", "Please enter comment text", "", wx.OK|wx.CANCEL) + dialog = wx.TextEntryDialog(self.ParentWindow, _("Edit comment"), _("Please enter comment text"), "", wx.OK|wx.CANCEL) if dialog.ShowModal() == wx.ID_OK: value = dialog.GetValue() id = self.GetNewId() @@ -1955,7 +1893,7 @@ dialog.SetPreviewFont(self.GetFont()) dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug)) dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)) - dialog.SetStepNames([block.GetName() for block in self.Blocks if isinstance(block, SFC_Step)]) + dialog.SetStepNames([block.GetName() for block in self.Blocks.itervalues() if isinstance(block, SFC_Step)]) dialog.SetMinStepSize((bbox.width, bbox.height)) if dialog.ShowModal() == wx.ID_OK: id = self.GetNewId() @@ -2027,10 +1965,10 @@ def AddNewJump(self, bbox): choices = [] - for block in self.Blocks: + for block in self.Blocks.itervalues(): if isinstance(block, SFC_Step): choices.append(block.GetName()) - dialog = wx.SingleChoiceDialog(self.ParentWindow, "Add a new jump", "Please choose a target", choices, wx.OK|wx.CANCEL) + dialog = wx.SingleChoiceDialog(self.ParentWindow, _("Add a new jump"), _("Please choose a target"), choices, wx.OK|wx.CANCEL) if dialog.ShowModal() == wx.ID_OK: id = self.GetNewId() value = dialog.GetStringSelection() @@ -2265,13 +2203,13 @@ dialog.SetPreviewFont(self.GetFont()) dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug)) dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)) - dialog.SetStepNames([block.GetName() for block in self.Blocks if isinstance(block, SFC_Step) and block.GetName() != step.GetName()]) + dialog.SetStepNames([block.GetName() for block in self.Blocks.itervalues() if isinstance(block, SFC_Step) and block.GetName() != step.GetName()]) dialog.SetMinStepSize(step.GetSize()) values = {"name" : step.GetName()} connectors = step.GetConnectors() - values["input"] = connectors["input"] != None - values["output"] = connectors["output"] != None - values["action"] = connectors["action"] != None + values["input"] = len(connectors["inputs"]) > 0 + values["output"] = len(connectors["outputs"]) > 0 + values["action"] = step.GetActionConnector() != None dialog.SetValues(values) if dialog.ShowModal() == wx.ID_OK: values = dialog.GetValues() @@ -2318,10 +2256,10 @@ def EditJumpContent(self, jump): choices = [] - for block in self.Blocks: + for block in self.Blocks.itervalues(): if isinstance(block, SFC_Step): choices.append(block.GetName()) - dialog = wx.SingleChoiceDialog(self.ParentWindow, "Edit jump target", "Please choose a target", choices, wx.OK|wx.CANCEL) + dialog = wx.SingleChoiceDialog(self.ParentWindow, _("Edit jump target"), _("Please choose a target"), choices, wx.OK|wx.CANCEL) dialog.SetSelection(choices.index(jump.GetTarget())) if dialog.ShowModal() == wx.ID_OK: value = dialog.GetStringSelection() @@ -2356,9 +2294,9 @@ def EditCommentContent(self, comment): if wx.VERSION >= (2, 5, 0): - dialog = wx.TextEntryDialog(self.ParentWindow, "Edit comment", "Please enter comment text", comment.GetContent(), wx.OK|wx.CANCEL|wx.TE_MULTILINE) + dialog = wx.TextEntryDialog(self.ParentWindow, _("Edit comment"), _("Please enter comment text"), comment.GetContent(), wx.OK|wx.CANCEL|wx.TE_MULTILINE) else: - dialog = wx.TextEntryDialog(self.ParentWindow, "Edit comment", "Please enter comment text", comment.GetContent(), wx.OK|wx.CANCEL) + dialog = wx.TextEntryDialog(self.ParentWindow, _("Edit comment"), _("Please enter comment text"), comment.GetContent(), wx.OK|wx.CANCEL) if dialog.ShowModal() == wx.ID_OK: value = dialog.GetValue() rect = comment.GetRedrawRect(1, 1) @@ -2452,6 +2390,7 @@ infos["x"], infos["y"] = step.GetPosition() infos["width"], infos["height"] = step.GetSize() infos["connectors"] = step.GetConnectors() + infos["action"] = step.GetActionConnector() self.Controler.SetEditedElementStepInfos(self.TagName, stepid, infos) def RefreshTransitionModel(self, transition): @@ -2463,6 +2402,7 @@ infos["x"], infos["y"] = transition.GetPosition() infos["width"], infos["height"] = transition.GetSize() infos["connectors"] = transition.GetConnectors() + infos["connection"] = transition.GetConditionConnector() self.Controler.SetEditedElementTransitionInfos(self.TagName, transitionid, infos) def RefreshDivergenceModel(self, divergence): @@ -2513,8 +2453,8 @@ def DeleteVariable(self, variable): connectors = variable.GetConnectors() - if connectors["output"]: - elements = connectors["output"].GetConnectedBlocks() + if len(connectors["outputs"]) > 0: + elements = connectors["outputs"][0].GetConnectedBlocks() else: elements = [] variable.Clean() @@ -2548,7 +2488,7 @@ def DeleteContact(self, contact): connectors = contact.GetConnectors() - elements = connectors["output"].GetConnectedBlocks() + elements = connectors["outputs"][0].GetConnectedBlocks() contact.Clean() self.RemoveBlock(contact) self.Controler.RemoveEditedElementInstance(self.TagName, contact.GetId()) @@ -2557,7 +2497,7 @@ def DeleteCoil(self, coil): connectors = coil.GetConnectors() - elements = connectors["output"].GetConnectedBlocks() + elements = connectors["outputs"][0].GetConnectedBlocks() coil.Clean() self.RemoveBlock(coil) self.Controler.RemoveEditedElementInstance(self.TagName, coil.GetId()) @@ -2567,7 +2507,8 @@ def DeletePowerRail(self, powerrail): elements = [] if powerrail.GetType() == LEFTRAIL: - for connector in powerrail.GetConnectors(): + connectors = powerrail.GetConnectors() + for connector in connectors["outputs"]: for element in connector.GetConnectedBlocks(): if element not in elements: elements.append(element) @@ -2580,12 +2521,13 @@ def DeleteStep(self, step): elements = [] connectors = step.GetConnectors() - if connectors["output"]: - for element in connectors["output"].GetConnectedBlocks(): + action_connector = step.GetActionConnector() + if len(connectors["outputs"]) > 0: + for element in connectors["outputs"][0].GetConnectedBlocks(): if element not in elements: elements.append(element) - if connectors["action"]: - for element in connectors["action"].GetConnectedBlocks(): + if action_connector is not None: + for element in action_connector.GetConnectedBlocks(): if element not in elements: elements.append(element) step.Clean() @@ -2597,10 +2539,9 @@ def DeleteTransition(self, transition): elements = [] connectors = transition.GetConnectors() - if connectors["output"]: - for element in connectors["output"].GetConnectedBlocks(): - if element not in elements: - elements.append(element) + for element in connectors["outputs"][0].GetConnectedBlocks(): + if element not in elements: + elements.append(element) transition.Clean() self.RemoveBlock(transition) self.Controler.RemoveEditedElementInstance(self.TagName, transition.GetId()) @@ -2637,7 +2578,9 @@ def Cut(self): if not self.Debug and (self.IsBlock(self.SelectedElement) or self.IsComment(self.SelectedElement) or isinstance(self.SelectedElement, Graphic_Group)): - self.ParentWindow.SetCopyBuffer(self.SelectedElement.Clone(self)) + blocks, wires = self.SelectedElement.GetDefinition() + text = self.Controler.GetEditedElementInstancesCopy(self.TagName, blocks, wires, self.Debug) + self.ParentWindow.SetCopyBuffer(text) rect = self.SelectedElement.GetRedrawRect(1, 1) self.SelectedElement.Delete() self.SelectedElement = None @@ -2649,42 +2592,30 @@ def Copy(self): if not self.Debug and (self.IsBlock(self.SelectedElement) or self.IsComment(self.SelectedElement) or isinstance(self.SelectedElement, Graphic_Group)): - self.ParentWindow.SetCopyBuffer(self.SelectedElement.Clone(self)) + blocks, wires = self.SelectedElement.GetDefinition() + text = self.Controler.GetEditedElementInstancesCopy(self.TagName, blocks, wires, self.Debug) + self.ParentWindow.SetCopyBuffer(text) def Paste(self): - element = self.ParentWindow.GetCopyBuffer() - if not self.Debug and element is not None and self.CanAddElement(element): + if not self.Debug: + element = self.ParentWindow.GetCopyBuffer() mouse_pos = self.ScreenToClient(wx.GetMousePosition()) - if wx.Rect(0, 0, *self.GetClientSize()).InsideXY(mouse_pos.x, mouse_pos.y): + middle = wx.Rect(0, 0, *self.GetClientSize()).InsideXY(mouse_pos.x, mouse_pos.y) + if middle: x, y = self.CalcUnscrolledPosition(mouse_pos.x, mouse_pos.y) - block_size = element.GetSize() - x = int(float(x) / self.ViewScale[0]) - block_size[0] / 2 - y = int(float(y) / self.ViewScale[1]) - block_size[1] / 2 else: x, y = self.CalcUnscrolledPosition(0, 0) - x = int(x / self.ViewScale[0]) + 30 - y = int(y / self.ViewScale[1]) + 30 - if self.Scaling is not None: - new_pos = wx.Point(max(round_scaling(30, self.Scaling[0], 1), - round_scaling(x, self.Scaling[0])), - max(round_scaling(30, self.Scaling[1], 1), - round_scaling(y, self.Scaling[1]))) + new_pos = [int(x / self.ViewScale[0]), int(y / self.ViewScale[1])] + result = self.Controler.PasteEditedElementInstances(self.TagName, element, new_pos, middle, self.Debug) + if not isinstance(result, (StringType, UnicodeType)): + self.RefreshBuffer() + self.RefreshView(result) + self.ParentWindow.RefreshVariablePanel(self.TagName) + self.ParentWindow.RefreshInstancesTree() else: - new_pos = wx.Point(max(30, x), max(30, y)) - block = self.CopyBlock(element, new_pos) - self.RefreshVisibleElements() - if self.SelectedElement is not None: - self.SelectedElement.SetSelected(False) - self.SelectedElement = block - self.SelectedElement.SetSelected(True) - self.RefreshBuffer() - self.RefreshScrollBars() - self.ParentWindow.RefreshVariablePanel(self.TagName) - self.ParentWindow.RefreshInstancesTree() - else: - message = wx.MessageDialog(self, "You can't paste the element in buffer here!", "Error", wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() + message = wx.MessageDialog(self, result, "Error", wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() def CanAddElement(self, block): if isinstance(block, Graphic_Group): @@ -2698,17 +2629,11 @@ return False def GenerateNewName(self, element, exclude={}): - names = exclude.copy() - if isinstance(element, FBD_Block): - names.update(dict([(varname.upper(), True) for varname in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)])) - format = "Block%d" - elif isinstance(element, SFC_Step): - names.update(dict([(block.GetName().upper(), True) for block in self.Blocks if isinstance(block, SFC_Step)])) + if isinstance(element, SFC_Step): format = "Step%d" - i = 1 - while names.get((format%i).upper(), False): - i += 1 - return format%i + else: + format = "Block%d" + return self.Controler.GenerateNewName(self.TagName, element.GetName(), format, exclude, self.Debug) def IsNamedElement(self, element): return isinstance(element, FBD_Block) and element.GetName() != "" or isinstance(element, SFC_Step) @@ -2875,18 +2800,18 @@ int((xstart * SCROLLBAR_UNIT + window_size[0]) / self.ViewScale[1]), ystart * SCROLLBAR_UNIT + y + 1) # Draw all elements - for comment in self.Comments: + for comment in self.Comments.itervalues(): if comment != self.SelectedElement and (comment.IsVisible() or printing): comment.Draw(dc) - for wire in self.Wires: + for wire in self.Wires.iterkeys(): if wire != self.SelectedElement and (wire.IsVisible() or printing): if not self.Debug or wire.GetValue() != True: wire.Draw(dc) if self.Debug: - for wire in self.Wires: + for wire in self.Wires.iterkeys(): if wire != self.SelectedElement and (wire.IsVisible() or printing) and wire.GetValue() == True: wire.Draw(dc) - for block in self.Blocks: + for block in self.Blocks.itervalues(): if block != self.SelectedElement and (block.IsVisible() or printing): block.Draw(dc) diff -r d07815f10ca8 -r 323c8d76f6f2 examples/example.xml --- a/examples/example.xml Mon Jul 27 12:01:43 2009 +0200 +++ b/examples/example.xml Fri Aug 07 15:49:10 2009 +0200 @@ -2,17 +2,17 @@ + xsi:schemaLocation="http://www.plcopen.org/xml/tc6.xsd"> @@ -99,6 +99,22 @@ + + + + + + + + + + + + + + + + @@ -203,13 +219,6 @@ - - - - - - IN3 - @@ -227,11 +236,9 @@ - + - - - + @@ -286,6 +293,29 @@ + + + + + + IN3 + + + + + + + + + + + + + + + + + @@ -884,7 +914,7 @@ - + @@ -893,7 +923,8 @@ - + + @@ -967,7 +998,7 @@ - + @@ -976,13 +1007,16 @@ - + + - + + - + + @@ -1116,7 +1150,7 @@ - + diff -r d07815f10ca8 -r 323c8d76f6f2 graphics/FBD_Objects.py --- a/graphics/FBD_Objects.py Mon Jul 27 12:01:43 2009 +0200 +++ b/graphics/FBD_Objects.py Fri Aug 07 15:49:10 2009 +0200 @@ -240,14 +240,8 @@ inputs.append(("IN%d"%start, inputs[-1][1], inputs[-1][2])) else: self.Colour = wx.RED - if "inputs" in connectors: - inputs = connectors["inputs"] - else: - inputs = [] - if "outputs" in connectors: - outputs = connectors["outputs"] - else: - outputs = [] + inputs = connectors.get("inputs", []) + outputs = connectors.get("outputs", []) if self.ExecutionControl: inputs.insert(0, ("EN","BOOL","none")) outputs.insert(0, ("ENO","BOOL","none")) @@ -421,9 +415,9 @@ # Draw block execution order dc.DrawText(str(self.ExecutionOrder), self.Pos.x + self.Size[0] - executionorder_size[0], self.Pos.y + self.Size[1] + 2) - if "name" in self.Errors: + if self.Errors.has_key("name"): HighlightErrorZone(dc, name_pos[0], name_pos[1], name_size[0], name_size[1]) - if "type" in self.Errors: + if self.Errors.has_key("type"): HighlightErrorZone(dc, type_pos[0], type_pos[1], type_size[0], type_size[1]) dc.SetTextForeground(wx.BLACK) @@ -578,7 +572,12 @@ # Returns all the block connectors def GetConnectors(self): - return {"input" : self.Input, "output" : self.Output} + connectors = {"inputs": [], "outputs": []} + if self.Input: + connectors["inputs"].append(self.Input) + if self.Output: + connectors["outputs"].append(self.Output) + return connectors # Changes the negated property of the variable connector if handled def SetConnectorNegated(self, negated): @@ -791,6 +790,15 @@ def GetConnector(self, position = None, name = None): return self.Connector + # Returns all the block connectors + def GetConnectors(self): + connectors = {"inputs": [], "outputs": []} + if self.Type == CONNECTOR: + connectors["inputs"].append(self.Connector) + else: + connectors["outputs"].append(self.Connector) + return connectors + # Changes the variable type def SetType(self, type): if type != self.Type: @@ -808,6 +816,10 @@ return self.Type def GetConnectionResultType(self, connector, connectortype): + if self.Type == CONTINUATION: + connector = self.Parent.GetConnectorByName(self.Name) + if connector is not None: + return connector.Connector.GetConnectedType() return connectortype # Changes the connection name @@ -856,7 +868,7 @@ else: name_size = self.NameSize - # Draw a rectangle with the connection size with arrows in + # Draw a rectangle with the connection size with arrows inside dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1) arrowsize = min(self.Size[1] / 2, (self.Size[0] - name_size[0] - 10) / 2) dc.DrawLine(self.Pos.x, self.Pos.y, self.Pos.x + arrowsize, diff -r d07815f10ca8 -r 323c8d76f6f2 graphics/GraphicCommons.py --- a/graphics/GraphicCommons.py Mon Jul 27 12:01:43 2009 +0200 +++ b/graphics/GraphicCommons.py Fri Aug 07 15:49:10 2009 +0200 @@ -92,18 +92,6 @@ # Color for Highlighting HIGHLIGHTCOLOR = wx.CYAN - -CURSORS = None - -def ResetCursors(): - global CURSORS - if CURSORS == None: - CURSORS = [wx.NullCursor, - wx.StockCursor(wx.CURSOR_HAND), - wx.StockCursor(wx.CURSOR_SIZENWSE), - wx.StockCursor(wx.CURSOR_SIZENESW), - wx.StockCursor(wx.CURSOR_SIZEWE), - wx.StockCursor(wx.CURSOR_SIZENS)] HANDLE_CURSORS = { (1, 1) : 2, @@ -470,8 +458,9 @@ self.Size = wx.Size(0, 0) self.BoundingBox = wx.Rect(0, 0, 0, 0) self.Visible = False - self.CurrentCursor = 0 - ResetCursors() + + def GetDefinition(self): + return [self.Id], [] def TestVisible(self, screen): self.Visible = self.GetRedrawRect().Intersects(screen) @@ -630,9 +619,7 @@ # Find which type of handle have been clicked, # Save a resize event and change the cursor cursor = HANDLE_CURSORS.get(handle, 1) - if cursor != self.CurrentCursor: - self.Parent.SetCursor(CURSORS[cursor]) - self.CurrentCursor = cursor + wx.CallAfter(self.Parent.SetCurrentCursor, cursor) if cursor > 1: self.Handle = (HANDLE_RESIZE, handle) else: @@ -649,9 +636,7 @@ if self.Dragging and self.oldPos: self.RefreshModel() self.Parent.RefreshBuffer() - if self.CurrentCursor != 0: - self.Parent.SetCursor(CURSORS[0]) - self.CurrentCursor = 0 + wx.CallAfter(self.Parent.SetCurrentCursor, 0) self.SetSelected(True) self.oldPos = None @@ -664,9 +649,7 @@ if self.Dragging and self.oldPos: self.RefreshModel() self.Parent.RefreshBuffer() - if self.CurrentCursor != 0: - self.Parent.SetCursor(CURSORS[0]) - self.CurrentCursor = 0 + wx.CallAfter(self.Parent.SetCurrentCursor, 0) self.SetSelected(True) self.oldPos = None @@ -703,9 +686,7 @@ # Find which type of handle have been clicked, # Save a resize event and change the cursor cursor = HANDLE_CURSORS.get(handle, 0) - if cursor != self.CurrentCursor: - self.Parent.SetCursor(CURSORS[cursor]) - self.CurrentCursor = cursor + wx.CallAfter(self.Parent.SetCurrentCursor, cursor) return 0, 0 # Moves the element @@ -872,6 +853,15 @@ def __del__(self): self.Elements = [] + def GetDefinition(self): + blocks = [] + wires = [] + for element in self.Elements: + block, wire = element.GetDefinition() + blocks.extend(block) + wires.extend(wire) + return blocks, wires + # Make a clone of this element def Clone(self, parent, pos = None): group = Graphic_Group(parent) @@ -1560,7 +1550,15 @@ self.OverEnd = False self.ComputingType = False self.ToolTip = None - + self.Font = parent.GetMiniFont() + + def GetDefinition(self): + if self.StartConnected is not None and self.EndConnected is not None: + startblock = self.StartConnected.GetParentBlock() + endblock = self.EndConnected.GetParentBlock() + return [], [(startblock.GetId(), endblock.GetId())] + return [], [] + def Flush(self): self.StartConnected = None self.EndConnected = None @@ -2374,15 +2372,15 @@ #result = self.TestPoint(pos) #if result != None: # self.Handle = (HANDLE_POINT, result) - # self.Parent.SetCursor(wx.StockCursor(wx.CURSOR_HAND)) + # wx.CallAfter(self.Parent.SetCurrentCursor, 1) #else: # Test if a segment have been handled result = self.TestSegment(pos) if result != None: if result[1] in (NORTH, SOUTH): - self.Parent.SetCursor(wx.StockCursor(wx.CURSOR_SIZEWE)) + wx.CallAfter(self.Parent.SetCurrentCursor, 4) elif result[1] in (EAST, WEST): - self.Parent.SetCursor(wx.StockCursor(wx.CURSOR_SIZENS)) + wx.CallAfter(self.Parent.SetCurrentCursor, 5) self.Handle = (HANDLE_SEGMENT, result) # Execute the default method for a graphic element else: @@ -2461,13 +2459,9 @@ result = self.TestSegment(pos) if result: if result[1] in (NORTH, SOUTH): - if self.CurrentCursor != 4: - self.CurrentCursor = 4 - wx.CallAfter(self.Parent.SetCursor, CURSORS[4]) + wx.CallAfter(self.Parent.SetCurrentCursor, 4) elif result[1] in (EAST, WEST): - if self.CurrentCursor != 5: - self.CurrentCursor = 5 - wx.CallAfter(self.Parent.SetCursor, CURSORS[5]) + wx.CallAfter(self.Parent.SetCurrentCursor, 5) return 0, 0 else: # Test if a point has been handled @@ -2783,21 +2777,22 @@ wordwidth, wordheight = dc.GetTextExtent(test) if y + wordheight > self.Pos.y + self.Size[1] - 10: break - if wordwidth < self.Size[0] - 20 and i < len(words) - 1: - linetext = test - first = False + if wordwidth < self.Size[0] - 20: + if i < len(words) - 1: + linetext = test + first = False + else: + dc.DrawText(test, self.Pos.x + 10, y) + y += wordheight + 5 else: - if wordwidth < self.Size[0] - 20 and i == len(words) - 1: - dc.DrawText(test, self.Pos.x + 10, y) + dc.DrawText(linetext, self.Pos.x + 10, y) + if i == len(words) - 1: + y += wordheight + 5 + if y + wordheight > self.Pos.y + self.Size[1] - 10: + break + dc.DrawText(word, self.Pos.x + 10, y) else: - dc.DrawText(linetext, self.Pos.x + 10, y) - if i == len(words) - 1: - y += wordheight + 5 - if y + wordheight > self.Pos.y + self.Size[1] - 10: - break - dc.DrawText(word, self.Pos.x + 10, y) - else: - linetext = word + linetext = word y += wordheight + 5 if y + wordheight > self.Pos.y + self.Size[1] - 10: break diff -r d07815f10ca8 -r 323c8d76f6f2 graphics/LD_Objects.py --- a/graphics/LD_Objects.py Mon Jul 27 12:01:43 2009 +0200 +++ b/graphics/LD_Objects.py Fri Aug 07 15:49:10 2009 +0200 @@ -246,7 +246,11 @@ # Returns all the power rail connectors def GetConnectors(self): - return [connector for connector in self.Connectors if connector] + connectors = [connector for connector in self.Connectors if connector] + if self.Type == LEFTRAIL: + return {"inputs": [], "outputs": connectors} + else: + return {"inputs": connectors, "outputs": []} # Test if point given is on one of the power rail connectors def TestConnector(self, pt, direction = None, exclude = True): @@ -297,7 +301,7 @@ connector = self.TestConnector(pos, exclude=False) if connector: self.Handle = (HANDLE_CONNECTOR, connector) - self.Parent.SetCursor(wx.StockCursor(wx.CURSOR_HAND)) + wx.CallAfter(self.Parent.SetCurrentCursor, 1) self.Selected = False # Initializes the last position self.oldPos = GetScaledEventPosition(event, dc, scaling) @@ -548,7 +552,7 @@ # Returns input and output contact connectors def GetConnectors(self): - return {"input":self.Input,"output":self.Output} + return {"inputs": [self.Input], "outputs": [self.Output]} # Test if point given is on contact input or output connector def TestConnector(self, pt, direction = None, exclude=True): @@ -669,9 +673,9 @@ # Draw input and output connectors self.Input.Draw(dc) self.Output.Draw(dc) - if "reference" in self.Errors: + if self.Errors.has_key("reference"): HighlightErrorZone(dc, name_pos[0], name_pos[1], name_size[0], name_size[1]) - if typetext != "" and ("negated" in self.Errors or "rising" in self.Errors or "falling" in self.Errors): + if typetext != "" and (self.Errors.has_key("negated") or self.Errors.has_key("rising") or self.Errors.has_key("falling")): HighlightErrorZone(dc, type_pos[0], type_pos[1], type_size[0], type_size[1]) @@ -837,7 +841,7 @@ # Returns input and output coil connectors def GetConnectors(self): - return {"input":self.Input,"output":self.Output} + return {"inputs": [self.Input], "outputs": [self.Output]} # Test if point given is on coil input or output connector def TestConnector(self, pt, direction = None, exclude=True): @@ -967,9 +971,9 @@ # Draw input and output connectors self.Input.Draw(dc) self.Output.Draw(dc) - if "reference" in self.Errors: + if self.Errors.has_key("reference"): HighlightErrorZone(dc, name_pos[0], name_pos[1], name_size[0], name_size[1]) - if typetext != "" and ("negated" in self.Errors or "rising" in self.Errors or "falling" in self.Errors): + if typetext != "" and (self.Errors.has_key("negated") or self.Errors.has_key("rising") or self.Errors.has_key("falling")): HighlightErrorZone(dc, type_pos[0], type_pos[1], type_size[0], type_size[1]) diff -r d07815f10ca8 -r 323c8d76f6f2 graphics/SFC_Objects.py --- a/graphics/SFC_Objects.py Mon Jul 27 12:01:43 2009 +0200 +++ b/graphics/SFC_Objects.py Fri Aug 07 15:49:10 2009 +0200 @@ -272,9 +272,18 @@ return self.Action return None + # Returns action step connector + def GetActionConnector(self): + return self.Action + # Returns input and output step connectors def GetConnectors(self): - return {"input":self.Input,"output":self.Output,"action":self.Action} + connectors = {"inputs": [], "outputs": []} + if self.Input: + connectors["inputs"].append(self.Input) + if self.Output: + connectors["outputs"].append(self.Output) + return connectors # Test if point given is on step input or output connector def TestConnector(self, pt, direction = None, exclude=True): @@ -319,7 +328,7 @@ return None # Returns the connector connected to action - def GetActionConnector(self): + def GetActionConnected(self): if self.Action: wires = self.Action.GetWires() if len(wires) == 1: @@ -491,7 +500,7 @@ def RefreshModel(self, move=True): self.Parent.RefreshStepModel(self) if self.Action: - action = self.GetActionConnector() + action = self.GetActionConnected() if action: action_block = action.GetParentBlock() action_block.RefreshModel(False) @@ -748,13 +757,16 @@ return self.Condition return None + # Returns the transition condition connector + def GetConditionConnector(self): + if self.Type == "connection": + return self.Condition + return None + # Returns input and output transition connectors def GetConnectors(self): - connectors = {"input":self.Input,"output":self.Output} - if self.Type == "connection": - connectors["connection"] = self.Condition - return connectors - + return {"inputs": [self.Input], "outputs": [self.Output]} + # Test if point given is on transition input or output connector def TestConnector(self, pt, direction = None, exclude=True): # Test input connector @@ -913,7 +925,7 @@ if infos[0] == "priority" and start[0] == 0 and start[1] == 0: self.Errors[infos[0]] = (start[1], end[1]) elif infos[0] == "inline": - if infos[0] not in self.Errors: + if not self.Errors.has_key(infos[0]): self.Errors[infos[0]] = [] self.Errors[infos[0]].append((start[1], end[1])) else: @@ -965,9 +977,9 @@ self.Output.Draw(dc) if self.Type == "connection": self.Condition.Draw(dc) - if "priority" in self.Errors: + if self.Errors.has_key("priority"): HighlightErrorZone(dc, priority_pos[0], priority_pos[1], priority_size[0], priority_size[1]) - if "inline" in self.Errors: + if self.Errors.has_key("inline"): for start, end in self.Errors["inline"]: offset = dc.GetTextExtent(self.Condition[:start]) size = dc.GetTextExtent(self.Condition[start:end + 1]) @@ -1206,7 +1218,7 @@ # Returns input and output divergence connectors def GetConnectors(self): - return {"inputs":self.Inputs,"outputs":self.Outputs} + return {"inputs": self.Inputs, "outputs": self.Outputs} # Test if point given is on divergence input or output connector def TestConnector(self, pt, direction = None, exclude=True): @@ -1332,7 +1344,7 @@ connector = self.TestConnector(pos, exclude=False) if connector: self.Handle = (HANDLE_CONNECTOR, connector) - self.Parent.SetCursor(wx.StockCursor(wx.CURSOR_HAND)) + wx.CallAfter(self.Parent.SetCurrentCursor, 1) self.Selected = False # Initializes the last position self.oldPos = GetScaledEventPosition(event, dc, scaling) @@ -1553,6 +1565,10 @@ def GetConnector(self, position = None, name = None): return self.Input + # Returns all the jump connectors + def GetConnectors(self): + return {"inputs": [self.Input], "outputs": []} + # Test if point given is on jump input connector def TestConnector(self, pt, direction = None, exclude = True): # Test input connector @@ -1681,7 +1697,7 @@ # Draw input connector if self.Input: self.Input.Draw(dc) - if "target" in self.Errors: + if self.Errors.has_key("target"): HighlightErrorZone(dc, target_pos[0], target_pos[1], target_size[0], target_size[1]) @@ -1782,6 +1798,10 @@ def GetConnector(self, position = None, name = None): return self.Input + # Returns all the action block connectors + def GetConnectors(self): + return {"inputs": [self.Input], "outputs": []} + # Test if point given is on action block input connector def TestConnector(self, pt, direction = None, exclude = True): # Test input connector @@ -1807,14 +1827,14 @@ width, height = self.Parent.GetTextExtent(action["qualifier"]) self.ColSize[0] = max(self.ColSize[0], width + 10) row_height = height - if "duration" in action: + if action.has_key("duration"): width, height = self.Parent.GetTextExtent(action["duration"]) row_height = max(row_height, height) self.ColSize[0] = max(self.ColSize[0], width + 10) width, height = self.Parent.GetTextExtent(action["value"]) row_height = max(row_height, height) self.ColSize[1] = max(self.ColSize[1], width + 10) - if "indicator" in action and action["indicator"] != "": + if action.get("indicator", "") != "": width, height = self.Parent.GetTextExtent(action["indicator"]) row_height = max(row_height, height) self.ColSize[2] = max(self.ColSize[2], width + 10) @@ -1882,10 +1902,10 @@ def AddError(self, infos, start, end): if infos[0] == "action" and infos[1] < len(self.Actions): - if infos[1] not in self.Errors: + if not self.Errors.has_key(infos[1]): self.Errors[infos[1]] = {} if infos[2] == "inline": - if infos[2] not in self.Errors[infos[1]]: + if not self.Errors[infos[1]].has_key(infos[2]): self.Errors[infos[1]][infos[2]] = [] self.Errors[infos[1]][infos[2]].append((start[1], end[1])) else: @@ -1912,7 +1932,7 @@ dc.DrawLine(self.Pos.x, self.Pos.y + i * line_size, self.Pos.x + self.Size[0], self.Pos.y + i * line_size) qualifier_size = dc.GetTextExtent(action["qualifier"]) - if "duration" in action: + if action.has_key("duration"): qualifier_pos = (self.Pos.x + (colsize[0] - qualifier_size[0]) / 2, self.Pos.y + i * line_size + line_size / 2 - qualifier_size[1]) duration_size = dc.GetTextExtent(action["duration"]) @@ -1927,24 +1947,24 @@ content_pos = (self.Pos.x + colsize[0] + (colsize[1] - content_size[0]) / 2, self.Pos.y + i * line_size + (line_size - content_size[1]) / 2) dc.DrawText(action["value"], content_pos[0], content_pos[1]) - if "indicator" in action: + if action.has_key("indicator"): indicator_size = dc.GetTextExtent(action["indicator"]) indicator_pos = (self.Pos.x + colsize[0] + colsize[1] + (colsize[2] - indicator_size[0]) / 2, self.Pos.y + i * line_size + (line_size - indicator_size[1]) / 2) dc.DrawText(action["indicator"], indicator_pos[0], indicator_pos[1]) if i in self.Errors: - if "duration" in self.Errors[i] and "duration" in action: + if self.Errors[i].has_key("duration") and action.has_key("duration"): HighlightErrorZone(dc, duration_pos[0], duration_pos[1], duration_size[0], duration_size[1]) - if "qualifier" in self.Errors[i]: + if self.Errors[i].has_key("qualifier"): HighlightErrorZone(dc, qualifier_pos[0], qualifier_pos[1], qualifier_size[0], qualifier_size[1]) - if "reference" in self.Errors[i]: + if self.Errors[i].has_key("reference"): HighlightErrorZone(dc, content_pos[0], content_pos[1], content_size[0], content_size[1]) - elif "inline" in self.Errors[i]: + elif self.Errors[i].has_key("inline"): for start, end in self.Errors[i]["inline"]: offset = dc.GetTextExtent(action["value"][:start]) size = dc.GetTextExtent(action["value"][start:end + 1]) HighlightErrorZone(dc, content_pos[0] + offset[0], content_pos[1], size[0], size[1]) - if "indicator" in self.Errors[i]: + if self.Errors[i].has_key("indicator"): HighlightErrorZone(dc, indicator_pos[0], indicator_pos[1], indicator_size[0], indicator_size[1]) # Draw input connector self.Input.Draw(dc) diff -r d07815f10ca8 -r 323c8d76f6f2 i18n/PLCOpenEditor_fr_FR.po --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i18n/PLCOpenEditor_fr_FR.po Fri Aug 07 15:49:10 2009 +0200 @@ -0,0 +1,2302 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-07-24 16:55+0200\n" +"PO-Revision-Date: 2009-07-24 17:02+0100\n" +"Last-Translator: \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../PLCOpenEditor.py:5044 +msgid "" +"\n" +"An error happens.\n" +"\n" +"Click on OK for saving an error report.\n" +"\n" +"Please contact LOLITech at:\n" +"+33 (0)3 29 57 60 42\n" +"bugs_PLCOpenEditor@lolitech.fr\n" +"\n" +"\n" +"Error:\n" +msgstr "" +"\n" +"Une erreur est apparue.\n" +"\n" +"Appuyer sur 'Valider' pour enregistrer un rapport d'erreur.\n" +"\n" +"Veuillez contacter LOLITech au :\n" +"+33 (0)3 29 57 60 42\n" +"bugs_PLCOpenEditor@lolitech.fr\n" +"\n" +"\n" +"Erreur:\n" + +#: ../PLCOpenEditor.py:3860 +msgid " External" +msgstr " Externe" + +#: ../PLCOpenEditor.py:3859 +msgid " InOut" +msgstr " Entrée-Sortie" + +#: ../PLCOpenEditor.py:3859 +msgid " Input" +msgstr " Entrée" + +#: ../PLCOpenEditor.py:3860 +msgid " Local" +msgstr " Locale" + +#: ../PLCOpenEditor.py:3859 +msgid " Output" +msgstr " Sortie" + +#: ../PLCOpenEditor.py:3861 +msgid " Temp" +msgstr " Temporaire" + +#: ../PLCOpenEditor.py:840 +msgid " (Debug)" +msgstr " (Debug)" + +#: ../PLCOpenEditor.py:5056 +msgid " : " +msgstr " : " + +#: ../PLCOpenEditor.py:3283 +#: ../PLCOpenEditor.py:3446 +#: ../PLCOpenEditor.py:3590 +#: ../Dialogs.py:1800 +#, python-format +msgid " and %s" +msgstr " et %s" + +#: ../plcopen/plcopen.py:782 +#, python-format +msgid "\"%s\" Data Type doesn't exist !!!" +msgstr "Le type de donnée \"%s\" n'existe pas !!!" + +#: ../plcopen/plcopen.py:800 +#, python-format +msgid "\"%s\" POU already exists !!!" +msgstr "Le POU \"%s\" existe déjà !!!" + +#: ../plcopen/plcopen.py:821 +#, python-format +msgid "\"%s\" POU doesn't exist !!!" +msgstr "Le POU \"%s\" n'existe pas !!!" + +#: ../Viewer.py:225 +#, python-format +msgid "\"%s\" can't use itself!" +msgstr "\"%s\" ne peut pas s'utiliser lui-même !" + +#: ../PLCOpenEditor.py:1617 +#: ../PLCOpenEditor.py:1637 +#, python-format +msgid "\"%s\" config already exists!" +msgstr "La configuration \"%s\" existe déjà !" + +#: ../plcopen/plcopen.py:256 +#, python-format +msgid "\"%s\" configuration already exists !!!" +msgstr "La configuration \"%s\" existe déjà !!!" + +#: ../PLCOpenEditor.py:1571 +#: ../PLCOpenEditor.py:3145 +#, python-format +msgid "\"%s\" data type already exists!" +msgstr "Le type de données \"%s\" existe déjà !" + +#: ../PLCControler.py:1663 +#, python-format +msgid "\"%s\" element can't be paste here!!!" +msgstr "L'élément \"%s\" ne peut être collé ici !!!" + +#: ../PLCOpenEditor.py:3465 +#: ../PLCOpenEditor.py:3609 +#: ../Viewer.py:248 +#: ../Dialogs.py:261 +#: ../Dialogs.py:898 +#, python-format +msgid "\"%s\" element for this pou already exists!" +msgstr "Un élément \"%s\" existe déjà dans ce POU !" + +#: ../plcopen/structures.py:97 +#, python-format +msgid "\"%s\" function cancelled in \"%s\" POU: No input connected" +msgstr "L'appel à la fonction \"%s\" dans le POU \"%s\" a été abandonné : aucune entrée connectée" + +#: ../PLCOpenEditor.py:1562 +#: ../PLCOpenEditor.py:3141 +#: ../PLCOpenEditor.py:3294 +#: ../PLCOpenEditor.py:3457 +#: ../PLCOpenEditor.py:3601 +#: ../PLCOpenEditor.py:3672 +#: ../PLCOpenEditor.py:3735 +#: ../PLCOpenEditor.py:4449 +#: ../Dialogs.py:253 +#: ../Dialogs.py:652 +#: ../Dialogs.py:890 +#: ../Dialogs.py:1533 +#: ../Dialogs.py:2516 +#: ../Dialogs.py:2583 +#: ../DataTypeEditor.py:702 +#: ../DataTypeEditor.py:762 +#, python-format +msgid "\"%s\" is a keyword. It can't be used!" +msgstr "\"%s\" est un mot réservé. Il ne peut être utilisé !" + +#: ../Viewer.py:231 +#, python-format +msgid "\"%s\" is already used by \"%s\"!" +msgstr "\"%s\" est déjà utilisé par \"%s\" !" + +#: ../plcopen/plcopen.py:2120 +#, python-format +msgid "\"%s\" is an invalid value!" +msgstr "\"%s\" n'est pas une valeur valide !" + +#: ../PLCOpenEditor.py:1097 +#: ../PLCOpenEditor.py:1126 +#, python-format +msgid "\"%s\" is not a valid folder!" +msgstr "\"%s\" n'est pas un répertoire valide !" + +#: ../PLCOpenEditor.py:1560 +#: ../PLCOpenEditor.py:3137 +#: ../PLCOpenEditor.py:3290 +#: ../PLCOpenEditor.py:3453 +#: ../PLCOpenEditor.py:3597 +#: ../PLCOpenEditor.py:3668 +#: ../PLCOpenEditor.py:3731 +#: ../PLCOpenEditor.py:4444 +#: ../Dialogs.py:249 +#: ../Dialogs.py:886 +#: ../Dialogs.py:1529 +#: ../Dialogs.py:2512 +#: ../Dialogs.py:2579 +#: ../DataTypeEditor.py:757 +#, python-format +msgid "\"%s\" is not a valid identifier!" +msgstr "\"%s\" n'est pas un identifiant valide !" + +#: ../PLCOpenEditor.py:283 +#: ../PLCOpenEditor.py:2491 +#: ../PLCOpenEditor.py:2520 +#, python-format +msgid "\"%s\" is used by one or more POUs. It can't be removed!" +msgstr "Le POU \"%s\" est utilisé par un ou plusieurs POUs. Il ne peut être supprimé !" + +#: ../PLCOpenEditor.py:1580 +#: ../PLCOpenEditor.py:3298 +#: ../Viewer.py:246 +#: ../Dialogs.py:257 +#: ../Dialogs.py:894 +#, python-format +msgid "\"%s\" pou already exists!" +msgstr "Le POU \"%s\" existe déjà !" + +#: ../plcopen/plcopen.py:287 +#, python-format +msgid "\"%s\" resource already exists in \"%s\" configuration !!!" +msgstr "La ressource \"%s\" existe déjà dans la configuration \"%\" !!!" + +#: ../plcopen/plcopen.py:303 +#, python-format +msgid "\"%s\" resource doesn't exist in \"%s\" configuration !!!" +msgstr "La ressource \"%s\" n'existe pas dans la configuration \"%s\" !!!" + +#: ../Dialogs.py:1545 +#: ../Dialogs.py:2528 +#, python-format +msgid "\"%s\" step already exists!" +msgstr "L'étape \"%s\" existe déjà !" + +#: ../DataTypeEditor.py:697 +#, python-format +msgid "\"%s\" value already defined!" +msgstr "La valeur \"%s\" est déjà définie !" + +#: ../DataTypeEditor.py:899 +#, python-format +msgid "\"%s\" value isn't a valid array dimension!" +msgstr "\"%s\" n'est pas une dimension de tableau valide !" + +#: ../DataTypeEditor.py:906 +#, python-format +msgid "" +"\"%s\" value isn't a valid array dimension!\n" +"Right value must be greater than left value." +msgstr "" +"\"%s\" n'est pas une dimension de tableau valide !\n" +"La valeur de droite doit être supérieur à celle de gauche." + +#: ../GraphicViewer.py:181 +#, python-format +msgid "%s Graphics" +msgstr "Graphique %s" + +#: ../plcopen/plcopen.py:1276 +#: ../plcopen/plcopen.py:1286 +#: ../plcopen/plcopen.py:1296 +#: ../plcopen/plcopen.py:1306 +#: ../plcopen/plcopen.py:1315 +#, python-format +msgid "%s body don't have instances!" +msgstr "Le code d'un %s n'a pas d'instances !" + +#: ../plcopen/plcopen.py:1338 +#: ../plcopen/plcopen.py:1345 +#, python-format +msgid "%s body don't have text!" +msgstr "Le code d'un %s n'a pas de texte !" + +#: ../PLCOpenEditor.py:5032 +#: ../PLCOpenEditor.py:5034 +#: ../PLCOpenEditor.py:5035 +msgid ", " +msgstr ", " + +#: ../PLCOpenEditor.py:3285 +#: ../PLCOpenEditor.py:3448 +#: ../PLCOpenEditor.py:3592 +#: ../Dialogs.py:1802 +#, python-format +msgid ", %s" +msgstr ", %s" + +#: ../PLCOpenEditor.py:5030 +msgid ". " +msgstr ". " + +#: ../DataTypeEditor.py:772 +#, python-format +msgid "A element with \"%s\" as name exists in this structure!" +msgstr "Un élément nommé \"%s\" existe déjà dans la structure !" + +#: ../PLCOpenEditor.py:1583 +#: ../PLCOpenEditor.py:1625 +#: ../PLCOpenEditor.py:1645 +#: ../PLCOpenEditor.py:3302 +#: ../PLCOpenEditor.py:3680 +#: ../PLCOpenEditor.py:3743 +#, python-format +msgid "A pou has an element with \"%s\" as name. It can generate a conflict. Do you wish to continue?" +msgstr "Un POU a un élément nommé \"%s\". Cela peut générer des conflits. Voulez-vous continuer ?" + +#: ../PLCOpenEditor.py:1620 +#: ../PLCOpenEditor.py:1640 +#, python-format +msgid "A pou is defined with \"%s\" as name. It can generate a conflict. Do you wish to continue?" +msgstr "Un POU a pour nom \"%s\". Cela peut générer des conflits. Voulez-vous continuer ?" + +#: ../PLCOpenEditor.py:1596 +#: ../PLCOpenEditor.py:1607 +#: ../PLCOpenEditor.py:3461 +#: ../PLCOpenEditor.py:3605 +#: ../PLCOpenEditor.py:3676 +#: ../PLCOpenEditor.py:3739 +#: ../PLCOpenEditor.py:4454 +#: ../Dialogs.py:1537 +#: ../Dialogs.py:2520 +#: ../Dialogs.py:2587 +#, python-format +msgid "A pou with \"%s\" as name exists!" +msgstr "Un POU nommé \"%s\" existe déjà !" + +#: ../PLCOpenEditor.py:1598 +#: ../PLCOpenEditor.py:1609 +#: ../PLCOpenEditor.py:4459 +#: ../Dialogs.py:1541 +#: ../Dialogs.py:2524 +#, python-format +msgid "A variable with \"%s\" as name already exists in this pou!" +msgstr "Une variable nommée \"%s\" existe déjà dans ce POU !" + +#: ../PLCOpenEditor.py:445 +msgid "About" +msgstr "A propos" + +#: ../PLCOpenEditor.py:2614 +msgid "About PLCOpenEditor" +msgstr "A propos de PLCOpenEditor" + +#: ../plcopen/iec_std.csv:22 +msgid "Absolute number" +msgstr "Nombre absolu" + +#: ../Dialogs.py:1482 +#: ../Dialogs.py:2109 +msgid "Action" +msgstr "Action" + +#: ../PLCOpenEditor.py:3581 +msgid "Action Name" +msgstr "Nom de l'action" + +#: ../PLCOpenEditor.py:3548 +msgid "Action Name:" +msgstr "Nom de l'action :" + +#: ../plcopen/plcopen.py:1073 +#, python-format +msgid "Action with name %s doesn't exists!" +msgstr "L'action nommée %s n'existe pas !" + +#: ../PLCControler.py:83 +msgid "Actions" +msgstr "Actions" + +#: ../Dialogs.py:2332 +msgid "Actions:" +msgstr "Actions :" + +#: ../PLCOpenEditor.py:4244 +#: ../Dialogs.py:2346 +#: ../DataTypeEditor.py:539 +msgid "Add" +msgstr "Ajouter" + +#: ../PLCOpenEditor.py:1800 +#: ../PLCOpenEditor.py:1873 +msgid "Add Action" +msgstr "Ajouter une action" + +#: ../PLCOpenEditor.py:1856 +msgid "Add Configuration" +msgstr "Ajouter une configuration" + +#: ../PLCOpenEditor.py:1844 +msgid "Add DataType" +msgstr "Ajouter un type de donnée" + +#: ../Viewer.py:402 +msgid "Add Divergence Branch" +msgstr "Ajouter une branche à la divergence" + +#: ../PLCOpenEditor.py:384 +msgid "Add Element" +msgstr "Ajouter un élément" + +#: ../RessourceEditor.py:409 +msgid "Add Instance" +msgstr "Ajouter une instance" + +#: ../PLCOpenEditor.py:1850 +msgid "Add Pou" +msgstr "Ajouter un POU" + +#: ../PLCOpenEditor.py:1827 +#: ../PLCOpenEditor.py:1884 +msgid "Add Resource" +msgstr "Ajouter une resource" + +#: ../RessourceEditor.py:373 +msgid "Add Task" +msgstr "Ajouter une tâche" + +#: ../PLCOpenEditor.py:1797 +#: ../PLCOpenEditor.py:1862 +msgid "Add Transition" +msgstr "Ajouter une transition" + +#: ../Viewer.py:397 +msgid "Add Wire Segment" +msgstr "Ajouter un segment au fil" + +#: ../PLCOpenEditor.py:2359 +msgid "Add a new data type" +msgstr "Ajouter un nouveau type de données" + +#: ../SFCViewer.py:362 +msgid "Add a new initial step" +msgstr "Ajouter une nouvelle étape initiale" + +#: ../Viewer.py:1971 +#: ../SFCViewer.py:698 +msgid "Add a new jump" +msgstr "Ajouter un nouveau renvoi" + +#: ../SFCViewer.py:384 +msgid "Add a new step" +msgstr "Ajouter une nouvelle étape" + +#: ../PLCOpenEditor.py:2416 +msgid "Add new configuration" +msgstr "Ajouter une nouvelle configuration" + +#: ../PLCOpenEditor.py:2431 +msgid "Add new resource" +msgstr "Ajouter une nouvelle resource" + +#: ../plcopen/iec_std.csv:33 +msgid "Addition" +msgstr "Addition" + +#: ../plcopen/structures.py:222 +msgid "Additionnal function blocks" +msgstr "Blocs fonctionnels additionnels" + +#: ../Viewer.py:411 +msgid "Alignment" +msgstr "Alignement" + +#: ../PLCOpenEditor.py:3858 +msgid "All" +msgstr "Toutes" + +#: ../plcopen/iec_std.csv:31 +msgid "Arc cosine" +msgstr "Arc cosinus" + +#: ../plcopen/iec_std.csv:30 +msgid "Arc sine" +msgstr "Arc sinus" + +#: ../plcopen/iec_std.csv:32 +msgid "Arc tangent" +msgstr "Arc tangente" + +#: ../plcopen/iec_std.csv:33 +msgid "Arithmetic" +msgstr "Arithmétique" + +#: ../DataTypeEditor.py:236 +msgid "Array" +msgstr "Tableau" + +#: ../plcopen/iec_std.csv:50 +msgid "Assignment" +msgstr "Assignation" + +#: ../Dialogs.py:648 +msgid "At least a variable or an expression must be selected!" +msgstr "Au moins une variable ou une expression doit être sélectionné !" + +#: ../PLCOpenEditor.py:2941 +msgid "Author" +msgstr "Auteur" + +#: ../PLCOpenEditor.py:2926 +msgid "Author Name (optional):" +msgstr "Nom de l'auteur (optionel) :" + +#: ../DataTypeEditor.py:379 +#: ../DataTypeEditor.py:403 +#: ../DataTypeEditor.py:478 +msgid "Base Type:" +msgstr "Type de base :" + +#: ../PLCOpenEditor.py:4491 +#: ../DataTypeEditor.py:798 +msgid "Base Types" +msgstr "Types de base" + +#: ../plcopen/iec_std.csv:59 +msgid "Binary selection (1 of 2)" +msgstr "Selection binaire (sélectionne 1 sur 2)" + +#: ../plcopen/iec_std.csv:51 +msgid "Bit-shift" +msgstr "Décalage de bit" + +#: ../plcopen/iec_std.csv:55 +msgid "Bitwise" +msgstr "Bit à bit" + +#: ../plcopen/iec_std.csv:55 +msgid "Bitwise AND" +msgstr "ET bit à bit" + +#: ../plcopen/iec_std.csv:56 +msgid "Bitwise OR" +msgstr "OU bit à bit" + +#: ../plcopen/iec_std.csv:57 +msgid "Bitwise XOR" +msgstr "OU exclusif bit à bit" + +#: ../plcopen/iec_std.csv:58 +msgid "Bitwise inverting" +msgstr "Inversion bit à bit" + +#: ../Dialogs.py:114 +msgid "Block Properties" +msgstr "Propriétés du bloc" + +#: ../PLCOpenEditor.py:2077 +#: ../Dialogs.py:269 +msgid "Block Types" +msgstr "Types de blocs" + +#: ../Viewer.py:369 +msgid "Bottom" +msgstr "Bas" + +#: ../PLCOpenEditor.py:2031 +msgid "CSV Log" +msgstr "Log CVS" + +#: ../PLCOpenEditor.py:4072 +msgid "Can affect a location only to local or global variables" +msgstr "Une adresse ne peut être affecté qu'à des variables locales ou globales" + +#: ../plcopen/plcopen.py:1218 +#: ../plcopen/plcopen.py:1232 +#: ../plcopen/plcopen.py:1253 +#: ../plcopen/plcopen.py:1269 +msgid "Can only generate execution order on FBD networks!" +msgstr "L'ordre d'exécution ne peut être généré que dans les FBD !" + +#: ../PLCOpenEditor.py:4070 +msgid "Can't affect a location to a function block instance" +msgstr "Une adresse ne peut être affectée une instance de Function Block" + +#: ../PLCOpenEditor.py:1092 +#, python-format +msgid "Can't generate program to file %s!" +msgstr "Le programme n'a pu être généré dans le fichier \"%s\" !" + +#: ../PLCOpenEditor.py:1124 +#, python-format +msgid "Can't save project to file %s!" +msgstr "Le projet n'a pu être sauvé dans le fichier \"%s\" !" + +#: ../Viewer.py:360 +msgid "Center" +msgstr "Centre" + +#: ../PLCOpenEditor.py:1816 +msgid "Change POU Type To" +msgstr "Changer le type du POU pour" + +#: ../plcopen/iec_std.csv:70 +msgid "Character string" +msgstr "Chaîne de caractères" + +#: ../PLCOpenEditor.py:1031 +#: ../PLCOpenEditor.py:1082 +#: ../PLCOpenEditor.py:1118 +msgid "Choose a file" +msgstr "Choisissez un fichier" + +#: ../PLCOpenEditor.py:3848 +#: ../PLCOpenEditor.py:3849 +msgid "Class" +msgstr "Classe" + +#: ../PLCOpenEditor.py:4236 +msgid "Class Filter:" +msgstr "Filtre de classe :" + +#: ../Dialogs.py:508 +msgid "Class:" +msgstr "Classe :" + +#: ../PLCOpenEditor.py:423 +msgid "Clear Errors\tCTRL+K" +msgstr "Effacer les erreurs\tCTRL+K" + +#: ../Viewer.py:407 +msgid "Clear Execution Order" +msgstr "Effacer l'ordre d'exécution" + +#: ../PLCOpenEditor.py:346 +msgid "Close\tCTRL+Q" +msgstr "Fermer\tCTRL+Q" + +#: ../PLCOpenEditor.py:961 +msgid "Close Application" +msgstr "Fermer l'application" + +#: ../PLCOpenEditor.py:319 +msgid "Close Project" +msgstr "Fermer le projet" + +#: ../PLCOpenEditor.py:316 +msgid "Close Tab\tCTRL+W" +msgstr "Fermer l'onglet\tCTRL+W" + +#: ../LDViewer.py:478 +msgid "Comment" +msgstr "Commentaire" + +#: ../PLCOpenEditor.py:2910 +msgid "Company Name (required):" +msgstr "Nom de l'entreprise (obligatoire) :" + +#: ../PLCOpenEditor.py:2918 +msgid "Company URL (optional):" +msgstr "URL de l'entreprise (optionel) :" + +#: ../plcopen/iec_std.csv:64 +msgid "Comparison" +msgstr "Comparaison" + +#: ../plcopen/iec_std.csv:74 +msgid "Concatenation" +msgstr "Concaténation" + +#: ../PLCOpenEditor.py:394 +msgid "Configuration" +msgstr "Configuration" + +#: ../PLCControler.py:84 +msgid "Configurations" +msgstr "Configurations" + +#: ../Dialogs.py:1737 +msgid "Connection" +msgstr "Connexion" + +#: ../Dialogs.py:784 +msgid "Connection Properties" +msgstr "Propriétés de la connexion" + +#: ../Dialogs.py:800 +msgid "Connector" +msgstr "Connecteur" + +#: ../Dialogs.py:1459 +msgid "Connectors:" +msgstr "Connecteurs :" + +#: ../PLCOpenEditor.py:3848 +#: ../PLCOpenEditor.py:3849 +msgid "Constant" +msgstr "Constante" + +#: ../PLCOpenEditor.py:3000 +msgid "Content Description (optional):" +msgstr "Description du contenu (optionel) :" + +#: ../Dialogs.py:806 +msgid "Continuation" +msgstr "Prolongement" + +#: ../plcopen/iec_std.csv:18 +msgid "Conversion from BCD" +msgstr "Conversion d'un BCD" + +#: ../plcopen/iec_std.csv:19 +msgid "Conversion to BCD" +msgstr "Conversion en BCD" + +#: ../plcopen/iec_std.csv:21 +msgid "Conversion to date" +msgstr "Conversion en date" + +#: ../plcopen/iec_std.csv:20 +msgid "Conversion to time-of-day" +msgstr "Conversion en heure de la journée" + +#: ../PLCOpenEditor.py:379 +msgid "Copy\tCTRL+C" +msgstr "Copier\tCtrl+C" + +#: ../plcopen/iec_std.csv:28 +msgid "Cosine" +msgstr "Cosinus" + +#: ../PLCOpenEditor.py:3223 +msgid "Create a new POU" +msgstr "Créer un nouveau POU" + +#: ../PLCOpenEditor.py:1804 +#: ../PLCOpenEditor.py:2461 +msgid "Create a new POU from" +msgstr "Créer un nouveau POU à partir de" + +#: ../PLCOpenEditor.py:3544 +msgid "Create a new action" +msgstr "Créer une nouvelle action" + +#: ../PLCOpenEditor.py:214 +msgid "Create a new action block" +msgstr "Créer un nouveau bloc d'actions" + +#: ../PLCOpenEditor.py:169 +#: ../PLCOpenEditor.py:196 +#: ../PLCOpenEditor.py:226 +msgid "Create a new block" +msgstr "Créer un nouveau bloc" + +#: ../PLCOpenEditor.py:190 +msgid "Create a new branch" +msgstr "Créer une nouvelle branche" + +#: ../PLCOpenEditor.py:184 +msgid "Create a new coil" +msgstr "Créer un nouveau relai" + +#: ../PLCOpenEditor.py:163 +#: ../PLCOpenEditor.py:175 +#: ../PLCOpenEditor.py:202 +msgid "Create a new comment" +msgstr "Créer un nouveau copmmentaire" + +#: ../PLCOpenEditor.py:172 +#: ../PLCOpenEditor.py:199 +#: ../PLCOpenEditor.py:229 +msgid "Create a new connection" +msgstr "Créer une nouvelle connexion" + +#: ../PLCOpenEditor.py:187 +#: ../PLCOpenEditor.py:235 +msgid "Create a new contact" +msgstr "Créer un nouveau contact" + +#: ../PLCOpenEditor.py:217 +msgid "Create a new divergence" +msgstr "Créer une nouvelle divergence" + +#: ../Dialogs.py:1976 +msgid "Create a new divergence or convergence" +msgstr "Créer une nouvelle divergence ou convergence" + +#: ../PLCOpenEditor.py:205 +msgid "Create a new initial step" +msgstr "Créer une nouvelle étape initiale" + +#: ../PLCOpenEditor.py:220 +msgid "Create a new jump" +msgstr "Créer un nouveau renvoi" + +#: ../PLCOpenEditor.py:178 +#: ../PLCOpenEditor.py:232 +msgid "Create a new power rail" +msgstr "Créer une nouvelle barre d'alimentation" + +#: ../PLCOpenEditor.py:181 +msgid "Create a new rung" +msgstr "Créer un nouvel échelon" + +#: ../PLCOpenEditor.py:208 +msgid "Create a new step" +msgstr "Créer une nouvelle étape" + +#: ../PLCOpenEditor.py:211 +#: ../PLCOpenEditor.py:3400 +msgid "Create a new transition" +msgstr "Créer une nouvelle transition" + +#: ../PLCOpenEditor.py:166 +#: ../PLCOpenEditor.py:193 +#: ../PLCOpenEditor.py:223 +msgid "Create a new variable" +msgstr "Créer une nouvelle variable" + +#: ../PLCOpenEditor.py:377 +msgid "Cut\tCTRL+X" +msgstr "Couper\tCTRL+X" + +#: ../PLCOpenEditor.py:386 +msgid "Data Type" +msgstr "Type de donnée" + +#: ../PLCControler.py:83 +msgid "Data Types" +msgstr "Types de données" + +#: ../plcopen/iec_std.csv:16 +msgid "Data type conversion" +msgstr "Conversion entre types de donnée" + +#: ../plcopen/iec_std.csv:36 +msgid "Date addition" +msgstr "Addition de dates" + +#: ../plcopen/iec_std.csv:44 +#: ../plcopen/iec_std.csv:45 +msgid "Date and time subtraction" +msgstr "Soustraction entre horodatage" + +#: ../plcopen/iec_std.csv:41 +msgid "Date subtraction" +msgstr "Soustraction de date" + +#: ../PLCOpenEditor.py:398 +#: ../PLCOpenEditor.py:1821 +#: ../PLCOpenEditor.py:1830 +#: ../PLCOpenEditor.py:1836 +#: ../PLCOpenEditor.py:4249 +#: ../PLCOpenEditor.py:4862 +#: ../Viewer.py:416 +#: ../Dialogs.py:2351 +#: ../DataTypeEditor.py:544 +msgid "Delete" +msgstr "Supprimer" + +#: ../Viewer.py:404 +msgid "Delete Divergence Branch" +msgstr "Supprimer une branche de divergence" + +#: ../RessourceEditor.py:414 +msgid "Delete Instance" +msgstr "Supprimer une instance" + +#: ../RessourceEditor.py:378 +msgid "Delete Task" +msgstr "Supprimer une tâche" + +#: ../Viewer.py:399 +msgid "Delete Wire Segment" +msgstr "Supprimer un segment de fil" + +#: ../DataTypeEditor.py:453 +#: ../DataTypeEditor.py:495 +msgid "Delete item" +msgstr "Supprimer un élément" + +#: ../plcopen/iec_std.csv:77 +msgid "Deletion (within)" +msgstr "Suppression (au milieu)" + +#: ../DataTypeEditor.py:364 +msgid "Derivation Type:" +msgstr "Type de dérivation :" + +#: ../plcopen/structures.py:236 +msgid "" +"Derivative\n" +"The derivative function block produces an output XOUT proportional to the rate of change of the input XIN." +msgstr "" +"Dérivée\n" +"Le Function Block derivative produit une sortie XOUT proportionnelle au rapport de changement de l'entrée XIN." + +#: ../DataTypeEditor.py:487 +msgid "Dimensions:" +msgstr "Dimensions :" + +#: ../DataTypeEditor.py:236 +msgid "Directly" +msgstr "Direct" + +#: ../PLCOpenEditor.py:306 +msgid "Display" +msgstr "Affichage" + +#: ../plcopen/iec_std.csv:46 +msgid "Division" +msgstr "Division" + +#: ../PLCOpenEditor.py:1086 +msgid "Done" +msgstr "Terminé" + +#: ../plcopen/structures.py:199 +msgid "" +"Down-counter\n" +"The down-counter can be used to signal when a count has reached zero, on counting down from a preset value." +msgstr "" +"Compteur décrémental\n" +"Le compteur décrémental peut être utilisé pour signaler lorsque le compteur atteint zéro en partant d'une valeur prédéfinie." + +#: ../Dialogs.py:2105 +msgid "Duration" +msgstr "Durée" + +#: ../PLCOpenEditor.py:305 +msgid "Edit" +msgstr "Editer" + +#: ../Viewer.py:414 +msgid "Edit Block" +msgstr "Editer le block" + +#: ../Dialogs.py:1098 +msgid "Edit Coil Values" +msgstr "Editer les valeurs du relai" + +#: ../Dialogs.py:1093 +msgid "Edit Contact Values" +msgstr "Editer les valeurs du contact" + +#: ../Dialogs.py:1451 +msgid "Edit Step" +msgstr "Editer l'étape" + +#: ../Dialogs.py:2328 +msgid "Edit action block properties" +msgstr "Editer les propriétés du block d'actions" + +#: ../Viewer.py:1796 +#: ../Viewer.py:1798 +#: ../Viewer.py:2297 +#: ../Viewer.py:2299 +msgid "Edit comment" +msgstr "Editer le commentaire" + +#: ../DataTypeEditor.py:448 +#: ../DataTypeEditor.py:490 +msgid "Edit item" +msgstr "Editer l'élément" + +#: ../Viewer.py:2262 +msgid "Edit jump target" +msgstr "Editer la cible du renvoi" + +#: ../SFCViewer.py:726 +msgid "Edit step name" +msgstr "Editer le nom de l'étape" + +#: ../Dialogs.py:1698 +msgid "Edit transition" +msgstr "Editer la transition" + +#: ../DataTypeEditor.py:520 +msgid "Elements :" +msgstr "Eléments :" + +#: ../DataTypeEditor.py:236 +msgid "Enumerated" +msgstr "Enumération" + +#: ../plcopen/iec_std.csv:66 +msgid "Equal to" +msgstr "Egal à" + +#: ../PLCOpenEditor.py:953 +#: ../PLCOpenEditor.py:1093 +#: ../PLCOpenEditor.py:1098 +#: ../PLCOpenEditor.py:1583 +#: ../PLCOpenEditor.py:1620 +#: ../PLCOpenEditor.py:1625 +#: ../PLCOpenEditor.py:1640 +#: ../PLCOpenEditor.py:1645 +#: ../PLCOpenEditor.py:2491 +#: ../PLCOpenEditor.py:2520 +#: ../PLCOpenEditor.py:3041 +#: ../PLCOpenEditor.py:3133 +#: ../PLCOpenEditor.py:3137 +#: ../PLCOpenEditor.py:3141 +#: ../PLCOpenEditor.py:3145 +#: ../PLCOpenEditor.py:3286 +#: ../PLCOpenEditor.py:3290 +#: ../PLCOpenEditor.py:3294 +#: ../PLCOpenEditor.py:3298 +#: ../PLCOpenEditor.py:3449 +#: ../PLCOpenEditor.py:3453 +#: ../PLCOpenEditor.py:3457 +#: ../PLCOpenEditor.py:3461 +#: ../PLCOpenEditor.py:3465 +#: ../PLCOpenEditor.py:3593 +#: ../PLCOpenEditor.py:3597 +#: ../PLCOpenEditor.py:3601 +#: ../PLCOpenEditor.py:3605 +#: ../PLCOpenEditor.py:3609 +#: ../PLCOpenEditor.py:3664 +#: ../PLCOpenEditor.py:3668 +#: ../PLCOpenEditor.py:3672 +#: ../PLCOpenEditor.py:3676 +#: ../PLCOpenEditor.py:3727 +#: ../PLCOpenEditor.py:3731 +#: ../PLCOpenEditor.py:3735 +#: ../PLCOpenEditor.py:3739 +#: ../PLCOpenEditor.py:4119 +#: ../PLCOpenEditor.py:4444 +#: ../PLCOpenEditor.py:4449 +#: ../PLCOpenEditor.py:4454 +#: ../PLCOpenEditor.py:4459 +#: ../PLCOpenEditor.py:4795 +#: ../PLCOpenEditor.py:5057 +#: ../PLCOpenEditor.py:5067 +#: ../Viewer.py:335 +#: ../TextViewer.py:224 +#: ../LDViewer.py:628 +#: ../LDViewer.py:850 +#: ../LDViewer.py:854 +#: ../Dialogs.py:241 +#: ../Dialogs.py:245 +#: ../Dialogs.py:249 +#: ../Dialogs.py:253 +#: ../Dialogs.py:257 +#: ../Dialogs.py:261 +#: ../Dialogs.py:648 +#: ../Dialogs.py:652 +#: ../Dialogs.py:882 +#: ../Dialogs.py:886 +#: ../Dialogs.py:890 +#: ../Dialogs.py:894 +#: ../Dialogs.py:898 +#: ../Dialogs.py:1525 +#: ../Dialogs.py:1529 +#: ../Dialogs.py:1533 +#: ../Dialogs.py:1537 +#: ../Dialogs.py:1541 +#: ../Dialogs.py:1545 +#: ../Dialogs.py:1803 +#: ../Dialogs.py:2508 +#: ../Dialogs.py:2512 +#: ../Dialogs.py:2516 +#: ../Dialogs.py:2520 +#: ../Dialogs.py:2524 +#: ../Dialogs.py:2528 +#: ../Dialogs.py:2575 +#: ../Dialogs.py:2579 +#: ../Dialogs.py:2583 +#: ../Dialogs.py:2587 +#: ../DataTypeEditor.py:697 +#: ../DataTypeEditor.py:702 +#: ../DataTypeEditor.py:757 +#: ../DataTypeEditor.py:762 +#: ../DataTypeEditor.py:772 +#: ../DataTypeEditor.py:899 +#: ../DataTypeEditor.py:906 +msgid "Error" +msgstr "Erreur" + +#: ../Dialogs.py:134 +msgid "Execution Control:" +msgstr "Contrôle d'exécution :" + +#: ../Dialogs.py:130 +#: ../Dialogs.py:516 +msgid "Execution Order:" +msgstr "Ordre d'exécution :" + +#: ../plcopen/iec_std.csv:49 +msgid "Exponent" +msgstr "Exposant" + +#: ../plcopen/iec_std.csv:26 +msgid "Exponentiation" +msgstr "Exponentiel" + +#: ../Dialogs.py:512 +msgid "Expression:" +msgstr "Expression :" + +#: ../PLCOpenEditor.py:3860 +msgid "External" +msgstr "Externe" + +#: ../PLCOpenEditor.py:2978 +#: ../PLCOpenEditor.py:3168 +#: ../PLCOpenEditor.py:3178 +#: ../PLCOpenEditor.py:3357 +#: ../PLCOpenEditor.py:3501 +msgid "FBD" +msgstr "FBD" + +#: ../Viewer.py:394 +#: ../Dialogs.py:1060 +msgid "Falling Edge" +msgstr "Front descendant" + +#: ../plcopen/structures.py:189 +msgid "" +"Falling edge detector\n" +"The output produces a single pulse when a falling edge is detected." +msgstr "" +"Détecteur de front descendant\n" +"La sortie produit une impulsion unique lorsqu'un front descendant est détecté." + +#: ../PLCOpenEditor.py:303 +msgid "File" +msgstr "Fichier" + +#: ../plcopen/iec_std.csv:79 +msgid "Find position" +msgstr "Trouver la position" + +#: ../PLCOpenEditor.py:3041 +#: ../PLCOpenEditor.py:3286 +#: ../PLCOpenEditor.py:3449 +#: ../PLCOpenEditor.py:3593 +#: ../Dialogs.py:1803 +#, python-format +msgid "Form isn't complete. %s must be filled!" +msgstr "Le formulaire est incomplet. %s doit être complété !" + +#: ../Dialogs.py:245 +#: ../Dialogs.py:882 +msgid "Form isn't complete. Name must be filled!" +msgstr "Le formulaire est incomplet. Le nom doit être complété !" + +#: ../Dialogs.py:241 +msgid "Form isn't complete. Valid block type must be selected!" +msgstr "Le formulaire est incomplet. Un type de bloc valide doit être sélectionné !" + +#: ../PLCOpenEditor.py:388 +msgid "Function" +msgstr "Fonction" + +#: ../PLCOpenEditor.py:390 +#: ../PLCOpenEditor.py:1811 +msgid "Function Block" +msgstr "Bloc fonctionnel" + +#: ../PLCOpenEditor.py:4506 +msgid "Function Block Types" +msgstr "Types de blocs fonctionnels" + +#: ../PLCControler.py:82 +msgid "Function Blocks" +msgstr "Blocs fonctionnels" + +#: ../Viewer.py:227 +msgid "Function Blocks can't be used in Functions!" +msgstr "Les blocs fonctionnels ne peuvent être utilisés dans des functions !" + +#: ../Viewer.py:229 +msgid "Function Blocks can't be used in Transitions!" +msgstr "Les blocs fonctionnels ne peuvent être utilisés dans des transitions" + +#: ../PLCControler.py:1673 +#, python-format +msgid "FunctionBlock \"%s\" can't be paste in a Function!!!" +msgstr "Le bloc fonctionnel \"%s\" ne peuvent être collés dans une function !" + +#: ../PLCControler.py:82 +msgid "Functions" +msgstr "Fonctions" + +#: ../PLCOpenEditor.py:328 +msgid "Generate Program\tCTRL+G" +msgstr "Générer le program\tCTRL+G" + +#: ../PLCOpenEditor.py:3861 +msgid "Global" +msgstr "Globale" + +#: ../PLCOpenEditor.py:2028 +msgid "Graphic Panel" +msgstr "Graphique" + +#: ../PLCOpenEditor.py:2983 +msgid "Graphics" +msgstr "Graphiques" + +#: ../plcopen/iec_std.csv:64 +msgid "Greater than" +msgstr "Supérieur à" + +#: ../plcopen/iec_std.csv:65 +msgid "Greater than or equal to" +msgstr "Supérieur ou égal à" + +#: ../PLCOpenEditor.py:2962 +msgid "Height:" +msgstr "Hauteur :" + +#: ../PLCOpenEditor.py:307 +msgid "Help" +msgstr "Aide" + +#: ../plcopen/structures.py:251 +msgid "" +"Hysteresis\n" +"The hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2." +msgstr "" + +#: ../PLCOpenEditor.py:3168 +#: ../PLCOpenEditor.py:3178 +#: ../PLCOpenEditor.py:3357 +#: ../PLCOpenEditor.py:3501 +msgid "IL" +msgstr "IL" + +#: ../PLCOpenEditor.py:3859 +#: ../Dialogs.py:426 +msgid "InOut" +msgstr "Entrée-Sortie" + +#: ../PLCOpenEditor.py:4089 +#, python-format +msgid "Incompatible data types between \"%s\" and \"%s\"" +msgstr "Types de donnée imcompatible entre \"%s\" et \"%s\"" + +#: ../PLCOpenEditor.py:4100 +#, python-format +msgid "Incompatible size of data between \"%s\" and \"%s\"" +msgstr "Taille de donnée incompatible entre \"%s\" et \"%s\"" + +#: ../PLCOpenEditor.py:4096 +#, python-format +msgid "Incompatible size of data between \"%s\" and \"BOOL\"" +msgstr "Taille de donnée incompatible entre \"%s\" et \"BOOL\"" + +#: ../Dialogs.py:2105 +msgid "Indicator" +msgstr "Indicateur" + +#: ../PLCOpenEditor.py:3848 +#: ../PLCOpenEditor.py:3849 +#: ../DataTypeEditor.py:46 +msgid "Initial Value" +msgstr "Valeur initiale" + +#: ../DataTypeEditor.py:388 +#: ../DataTypeEditor.py:412 +#: ../DataTypeEditor.py:463 +#: ../DataTypeEditor.py:505 +msgid "Initial Value:" +msgstr "Valeur initiale :" + +#: ../Dialogs.py:1725 +#: ../Dialogs.py:1793 +#: ../Dialogs.py:2109 +msgid "Inline" +msgstr "Inline" + +#: ../PLCOpenEditor.py:3859 +#: ../Dialogs.py:425 +#: ../Dialogs.py:1472 +msgid "Input" +msgstr "Entrée" + +#: ../Dialogs.py:126 +msgid "Inputs:" +msgstr "Entrées :" + +#: ../plcopen/iec_std.csv:76 +msgid "Insertion (into)" +msgstr "Insertion (au milieu)" + +#: ../plcopen/plcopen.py:1329 +#, python-format +msgid "Instance with id %d doesn't exists!" +msgstr "L'instance dont l'id est %d n'existe pas !" + +#: ../PLCOpenEditor.py:559 +#: ../PLCOpenEditor.py:597 +msgid "Instances" +msgstr "Instances" + +#: ../RessourceEditor.py:394 +msgid "Instances:" +msgstr "Instances :" + +#: ../plcopen/structures.py:231 +msgid "" +"Integral\n" +"The integral function block integrates the value of input XIN over time." +msgstr "" +"Intégrale\n" +"Le bloc fonctionnel INTEGRAL intègre les valeurs de l'entrée XIN en fonction du temps." + +#: ../PLCOpenEditor.py:3858 +msgid "Interface" +msgstr "Interface" + +#: ../RessourceEditor.py:79 +msgid "Interval" +msgstr "Interval" + +#: ../PLCControler.py:1654 +#: ../PLCControler.py:1688 +msgid "Invalid plcopen element(s)!!!" +msgstr "Les éléments plcopen ne sont pas valides !!! " + +#: ../PLCOpenEditor.py:4784 +#: ../PLCOpenEditor.py:4787 +#, python-format +msgid "Invalid value \"%s\" for debug variable" +msgstr "Chemin de variable à déboguer \"%s\" invalide" + +#: ../PLCOpenEditor.py:4077 +#: ../PLCOpenEditor.py:4080 +#, python-format +msgid "Invalid value \"%s\" for location" +msgstr "Adresse \"%s\" invalide " + +#: ../Viewer.py:211 +#: ../Viewer.py:214 +#, python-format +msgid "Invalid value \"%s\" for viewer block" +msgstr "Valeur \"%s\" invalide pour un élément graphique" + +#: ../PLCOpenEditor.py:2978 +#: ../PLCOpenEditor.py:3168 +#: ../PLCOpenEditor.py:3178 +#: ../PLCOpenEditor.py:3357 +#: ../PLCOpenEditor.py:3501 +msgid "LD" +msgstr "LD" + +#: ../LDViewer.py:213 +#: ../LDViewer.py:228 +#, python-format +msgid "Ladder element with id %d is on more than one rung." +msgstr "L'élément de LD dont l'id est %d apparait dans plusieurs échelons. " + +#: ../PLCOpenEditor.py:3276 +#: ../PLCOpenEditor.py:3439 +#: ../PLCOpenEditor.py:3583 +msgid "Language" +msgstr "Langue" + +#: ../PLCOpenEditor.py:2992 +msgid "Language (optional):" +msgstr "Langue (optionnel) :" + +#: ../PLCOpenEditor.py:3244 +#: ../PLCOpenEditor.py:3412 +#: ../PLCOpenEditor.py:3556 +msgid "Language:" +msgstr "Langue :" + +#: ../Viewer.py:358 +msgid "Left" +msgstr "Gauche" + +#: ../Dialogs.py:1287 +msgid "Left PowerRail" +msgstr "Barre d'alimentation à gauche" + +#: ../plcopen/iec_std.csv:70 +msgid "Length of string" +msgstr "Longueur de la chaîne" + +#: ../plcopen/iec_std.csv:67 +msgid "Less than" +msgstr "Inférieur à" + +#: ../plcopen/iec_std.csv:68 +msgid "Less than or equal to" +msgstr "Inférieur ou égal à" + +#: ../PLCOpenEditor.py:638 +msgid "Library" +msgstr "Librairie" + +#: ../plcopen/iec_std.csv:62 +msgid "Limitation" +msgstr "Limitation" + +#: ../PLCOpenEditor.py:3860 +msgid "Local" +msgstr "Locale" + +#: ../PLCOpenEditor.py:3848 +msgid "Location" +msgstr "Adresse" + +#: ../plcopen/iec_std.csv:25 +msgid "Logarithm to base 10" +msgstr "Logarithme de base 10" + +#: ../plcopen/iec_std.csv:60 +msgid "Maximum" +msgstr "Maximum" + +#: ../DataTypeEditor.py:430 +msgid "Maximum:" +msgstr "Maximum :" + +#: ../Viewer.py:367 +msgid "Middle" +msgstr "Milieu" + +#: ../plcopen/iec_std.csv:61 +msgid "Minimum" +msgstr "Minimum" + +#: ../DataTypeEditor.py:421 +msgid "Minimum:" +msgstr "Minimum :" + +#: ../PLCOpenEditor.py:3007 +msgid "Miscellaneous" +msgstr "Divers" + +#: ../Dialogs.py:1022 +msgid "Modifier:" +msgstr "Modificateur :" + +#: ../PLCGenerator.py:672 +#: ../PLCGenerator.py:876 +#, python-format +msgid "More than one connector found corresponding to \"%s\" continuation in \"%s\" POU" +msgstr "Plusieurs connecteurs trouvés pour le prolongement \"%s\" dans le POU \"%s\"" + +#: ../DataTypeEditor.py:459 +#: ../DataTypeEditor.py:501 +msgid "Move down" +msgstr "Déplcer vers le haut" + +#: ../DataTypeEditor.py:456 +#: ../DataTypeEditor.py:498 +msgid "Move up" +msgstr "Déplacer vers le bas" + +#: ../plcopen/iec_std.csv:63 +msgid "Multiplexer (select 1 of N)" +msgstr "Multipléxeur (sélection 1 sur N)" + +#: ../plcopen/iec_std.csv:37 +msgid "Multiplication" +msgstr "Multiplication" + +#: ../PLCOpenEditor.py:3848 +#: ../PLCOpenEditor.py:3849 +#: ../RessourceEditor.py:79 +#: ../RessourceEditor.py:83 +#: ../DataTypeEditor.py:46 +msgid "Name" +msgstr "Nom" + +#: ../Dialogs.py:122 +#: ../Dialogs.py:520 +#: ../Dialogs.py:792 +#: ../Dialogs.py:1026 +#: ../Dialogs.py:1455 +msgid "Name:" +msgstr "Nom :" + +#: ../plcopen/iec_std.csv:24 +msgid "Natural logarithm" +msgstr "Logarithme népérien" + +#: ../Viewer.py:390 +#: ../Dialogs.py:1040 +msgid "Negated" +msgstr "Inversé" + +#: ../PLCOpenEditor.py:312 +msgid "New\tCTRL+N" +msgstr "Nouveau\tCTRL+N" + +#: ../DataTypeEditor.py:450 +#: ../DataTypeEditor.py:492 +msgid "New item" +msgstr "Nouvel élément" + +#: ../PLCOpenEditor.py:3853 +msgid "No" +msgstr "Non" + +#: ../Viewer.py:388 +msgid "No Modifier" +msgstr "Pas de modificateur" + +#: ../PLCControler.py:2535 +msgid "No PLC project found" +msgstr "Pas de projet d'automate trouvé" + +#: ../PLCGenerator.py:1257 +#, python-format +msgid "No body defined in \"%s\" POU" +msgstr "Pas de code défini dans le POU \"%s\"" + +#: ../PLCGenerator.py:691 +#: ../PLCGenerator.py:885 +#, python-format +msgid "No connector found corresponding to \"%s\" continuation in \"%s\" POU" +msgstr "Pas de connecteur trouvé pour le prolongement \"%s\" dans le POU \"%s\"" + +#: ../PLCOpenEditor.py:2606 +msgid "" +"No documentation available.\n" +"Coming soon." +msgstr "" +"Pas de documentation.\n" +"Bientôt disponible." + +#: ../PLCGenerator.py:743 +#, python-format +msgid "No informations found for \"%s\" block" +msgstr "" + +#: ../plcopen/structures.py:139 +msgid "No output variable found" +msgstr "Pas de variable de sortie trouvée." + +#: ../PLCGenerator.py:1255 +#, python-format +msgid "No variable defined in \"%s\" POU" +msgstr "Pas de varaibles définies dans le POU \"%s\"" + +#: ../Dialogs.py:1034 +msgid "Normal" +msgstr "Normal" + +#: ../plcopen/iec_std.csv:69 +msgid "Not equal to" +msgstr "Non égal à" + +#: ../Dialogs.py:2008 +msgid "Number of sequences:" +msgstr "Nombre de branches :" + +#: ../plcopen/iec_std.csv:22 +msgid "Numerical" +msgstr "Numérique" + +#: ../plcopen/structures.py:219 +msgid "" +"Off-delay timer\n" +"The off-delay timer can be used to delay setting an output false, for fixed period after input goes false." +msgstr "" + +#: ../plcopen/structures.py:214 +msgid "" +"On-delay timer\n" +"The on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true." +msgstr "" + +#: ../PLCOpenEditor.py:314 +msgid "Open\tCTRL+O" +msgstr "Ouvrir\tCTRL+O" + +#: ../PLCOpenEditor.py:2934 +msgid "Organization (optional):" +msgstr "Groupe (optionnel) :" + +#: ../PLCOpenEditor.py:3859 +#: ../Dialogs.py:427 +#: ../Dialogs.py:1477 +msgid "Output" +msgstr "Sortie" + +#: ../plcopen/structures.py:241 +msgid "" +"PID\n" +"The PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control." +msgstr "" +"PID\n" +"Le bloc fonctionnel PID (Proportionnel, Intégrale, Dérivée) fournit un controller de boucle fermé classique à trois paramètres." + +#: ../PLCOpenEditor.py:1031 +#: ../PLCOpenEditor.py:1118 +msgid "PLCOpen files (*.xml)|*.xml|All files|*.*" +msgstr "Fichiers PLCOpen (*.xml)|*.xml|Tous les fichiers|*.*" + +#: ../PLCOpenEditor.py:485 +#: ../PLCOpenEditor.py:838 +msgid "PLCOpenEditor" +msgstr "PLCOpenEditor" + +#: ../PLCOpenEditor.py:438 +msgid "PLCOpenEditor\tF1" +msgstr "PLCOpenEditor\tF1" + +#: ../PLCOpenEditor.py:3272 +msgid "POU Name" +msgstr "Nom du POU" + +#: ../PLCOpenEditor.py:3227 +msgid "POU Name:" +msgstr "Nom du POU :" + +#: ../PLCOpenEditor.py:3274 +msgid "POU Type" +msgstr "Type du POU" + +#: ../PLCOpenEditor.py:3235 +msgid "POU Type:" +msgstr "Type du POU :" + +#: ../PLCOpenEditor.py:331 +msgid "Page Setup" +msgstr "Mise en page..." + +#: ../PLCOpenEditor.py:2950 +msgid "Page Size (optional):" +msgstr "Taille de la page (optionnel) :" + +#: ../PLCOpenEditor.py:5000 +#, python-format +msgid "Page: %d" +msgstr "Page: %d" + +#: ../PLCOpenEditor.py:381 +msgid "Paste\tCTRL+V" +msgstr "Coller\tCTRL+V" + +#: ../Dialogs.py:1279 +msgid "Pin number:" +msgstr "Nombre de pattes :" + +#: ../Viewer.py:1971 +#: ../Viewer.py:2262 +#: ../SFCViewer.py:698 +msgid "Please choose a target" +msgstr "Choisissez une cible" + +#: ../PLCOpenEditor.py:2461 +msgid "Please enter POU name" +msgstr "Saisissez le nom du POU" + +#: ../Viewer.py:1796 +#: ../Viewer.py:1798 +#: ../Viewer.py:2297 +#: ../Viewer.py:2299 +msgid "Please enter comment text" +msgstr "Saisissez le texte du commentaire" + +#: ../PLCOpenEditor.py:2416 +#: ../PLCOpenEditor.py:3647 +msgid "Please enter configuration name" +msgstr "Saisissez le nom de la configuration" + +#: ../PLCOpenEditor.py:2359 +msgid "Please enter data type name" +msgstr "Saisissez le nom du type de donnée" + +#: ../PLCOpenEditor.py:2431 +#: ../PLCOpenEditor.py:3710 +msgid "Please enter resource name" +msgstr "Saisissez le nom de la ressource" + +#: ../SFCViewer.py:362 +#: ../SFCViewer.py:384 +#: ../SFCViewer.py:726 +msgid "Please enter step name" +msgstr "Saisissez le nom de l'étape" + +#: ../PLCOpenEditor.py:3118 +msgid "Please enter text" +msgstr "Saisissez le texte" + +#: ../GraphicViewer.py:117 +msgid "Position:" +msgstr "Position :" + +#: ../Dialogs.py:1271 +msgid "Power Rail Properties" +msgstr "Propriétés de la barre d'alimentation" + +#: ../PLCOpenEditor.py:333 +msgid "Preview" +msgstr "Aperçu avant impression" + +#: ../Dialogs.py:138 +#: ../Dialogs.py:524 +#: ../Dialogs.py:796 +#: ../Dialogs.py:1030 +#: ../Dialogs.py:1283 +#: ../Dialogs.py:1463 +#: ../Dialogs.py:1706 +#: ../Dialogs.py:2017 +msgid "Preview:" +msgstr "Aperçu :" + +#: ../PLCOpenEditor.py:335 +msgid "Print" +msgstr "Imprimer" + +#: ../PLCOpenEditor.py:1150 +msgid "Print preview" +msgstr "Aperçu avant impression" + +#: ../RessourceEditor.py:79 +msgid "Priority" +msgstr "Priorité" + +#: ../Dialogs.py:1710 +msgid "Priority:" +msgstr "Priorité :" + +#: ../PLCOpenEditor.py:2878 +msgid "Product Name (required):" +msgstr "Nom du produit (obligatoire) :" + +#: ../PLCOpenEditor.py:2894 +msgid "Product Release (optional):" +msgstr "Publication du produit (optionnel) :" + +#: ../PLCOpenEditor.py:2886 +msgid "Product Version (required):" +msgstr "Version du produit (obligatoire) :" + +#: ../PLCOpenEditor.py:392 +#: ../PLCOpenEditor.py:1814 +msgid "Program" +msgstr "Programme" + +#: ../PLCOpenEditor.py:1095 +msgid "Program was successfully generated!" +msgstr "Le programme a été généré avec succès !" + +#: ../PLCControler.py:83 +msgid "Programs" +msgstr "Programmes" + +#: ../Viewer.py:220 +msgid "Programs can't be used by other POUs!" +msgstr "Les programmes ne peuvent être utilisés par les autres POUs !" + +#: ../PLCOpenEditor.py:497 +#: ../PLCOpenEditor.py:2901 +msgid "Project" +msgstr "Projet" + +#: ../PLCOpenEditor.py:2862 +msgid "Project Name (required):" +msgstr "Nom du projet (obligatoire) :" + +#: ../PLCOpenEditor.py:2870 +msgid "Project Version (optional):" +msgstr "Version du projet (optionnel) :" + +#: ../PLCOpenEditor.py:2848 +msgid "Project properties" +msgstr "Propriétés du projet" + +#: ../PLCOpenEditor.py:339 +#: ../PLCControler.py:84 +msgid "Properties" +msgstr "Propriétés" + +#: ../plcopen/structures.py:209 +msgid "" +"Pulse timer\n" +"The pulse timer can be used to generate output pulses of a given time duration." +msgstr "" + +#: ../Dialogs.py:2105 +msgid "Qualifier" +msgstr "Qualificatif" + +#: ../PLCOpenEditor.py:343 +msgid "Quit\tCTRL+Q" +msgstr "Quitter\tCTRL+Q" + +#: ../plcopen/structures.py:174 +msgid "" +"RS bistable\n" +"The RS bistable is a latch where the Reset dominates." +msgstr "" +"Bascule RS\n" +"La bascule RS est une bascule où le Reset est dominant." + +#: ../plcopen/structures.py:246 +msgid "" +"Ramp\n" +"The RAMP function block is modelled on example given in the standard but with the addition of a 'Holdback' feature." +msgstr "" +"Rampe\n" +"Le bloc fonctionnel RAMP est basé sur l'exemple du standard mais avec en supplément un paramètre 'Holdback'." + +#: ../GraphicViewer.py:106 +msgid "Range:" +msgstr "Echelle :" + +#: ../PLCOpenEditor.py:374 +msgid "Redo\tCTRL+Y" +msgstr "Refaire\tCTRL+Y" + +#: ../Dialogs.py:1714 +#: ../Dialogs.py:1791 +msgid "Reference" +msgstr "Référence" + +#: ../PLCOpenEditor.py:420 +msgid "Refresh\tF5" +msgstr "Actualiser\tF5" + +#: ../plcopen/iec_std.csv:48 +msgid "Remainder (modulo)" +msgstr "Modulo" + +#: ../PLCOpenEditor.py:1818 +msgid "Rename" +msgstr "Renommer" + +#: ../plcopen/iec_std.csv:78 +msgid "Replacement (within)" +msgstr "Remplacement (au milieu)" + +#: ../Dialogs.py:1050 +msgid "Reset" +msgstr "Mise à zéro" + +#: ../Viewer.py:409 +msgid "Reset Execution Order" +msgstr "Réinitialiser l'order d'exécution" + +#: ../PLCControler.py:84 +msgid "Resources" +msgstr "Ressources" + +#: ../PLCOpenEditor.py:3848 +#: ../PLCOpenEditor.py:3849 +msgid "Retain" +msgstr "Persistante" + +#: ../PLCOpenEditor.py:4227 +msgid "Return Type:" +msgstr "Type de retour :" + +#: ../Viewer.py:362 +msgid "Right" +msgstr "Droite" + +#: ../Dialogs.py:1293 +msgid "Right PowerRail" +msgstr "Barre d'alimentation à droite" + +#: ../Viewer.py:392 +#: ../Dialogs.py:1055 +msgid "Rising Edge" +msgstr "Front montant" + +#: ../plcopen/structures.py:184 +msgid "" +"Rising edge detector\n" +"The output produces a single pulse when a rising edge is detected." +msgstr "" +"Détecteur de front montant\n" +"La sortie produit une impulsion unique lorsqu'un front montant est détecté." + +#: ../plcopen/iec_std.csv:54 +msgid "Rotate left" +msgstr "Rotation à gauche" + +#: ../plcopen/iec_std.csv:53 +msgid "Rotate right" +msgstr "Rotation à droite" + +#: ../plcopen/iec_std.csv:17 +msgid "Rounding up/down" +msgstr "Arrondi" + +#: ../PLCOpenEditor.py:2978 +#: ../PLCOpenEditor.py:3178 +msgid "SFC" +msgstr "SFC" + +#: ../plcopen/structures.py:169 +msgid "" +"SR bistable\n" +"The SR bistable is a latch where the Set dominates." +msgstr "" +"Bascule SR\n" +"La bascule SR est une bascule où le Set est dominant." + +#: ../PLCOpenEditor.py:3168 +#: ../PLCOpenEditor.py:3178 +#: ../PLCOpenEditor.py:3357 +#: ../PLCOpenEditor.py:3501 +msgid "ST" +msgstr "ST" + +#: ../PLCOpenEditor.py:1082 +msgid "ST files (*.st)|*.st|All files|*.*" +msgstr "Fichiers ST (*.st)|*.st|Tous les fichiers|*.*" + +#: ../PLCOpenEditor.py:323 +msgid "Save\tCTRL+S" +msgstr "Enregistrer\tCTRL+S" + +#: ../PLCOpenEditor.py:326 +msgid "Save As...\tCTRL+SHIFT+S" +msgstr "Enregistrer sous...\tCTRL+SHIFT+S" + +#: ../PLCOpenEditor.py:2970 +msgid "Scaling:" +msgstr "Echelle :" + +#: ../PLCOpenEditor.py:396 +msgid "Select All\tCTRL+A" +msgstr "Tout sélectionner\tCTRL+A" + +#: ../PLCOpenEditor.py:4102 +msgid "Select a variable class:" +msgstr "Sélectionner une direction pour la variable :" + +#: ../PLCOpenEditor.py:604 +#: ../PLCOpenEditor.py:616 +msgid "Select an object" +msgstr "Sélectionner un objet" + +#: ../plcopen/iec_std.csv:59 +msgid "Selection" +msgstr "Sélection" + +#: ../Dialogs.py:1990 +msgid "Selection Convergence" +msgstr "Convergence simple" + +#: ../Dialogs.py:1984 +msgid "Selection Divergence" +msgstr "Divergence simple" + +#: ../plcopen/structures.py:179 +msgid "" +"Semaphore\n" +"The semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources." +msgstr "" +"Sémaphore\n" +"La sémaphore fournit un mécanisme permettant à des éléments du programme d'accéder de façon exclusive à certaines resources." + +#: ../Dialogs.py:1045 +msgid "Set" +msgstr "Mise à 1" + +#: ../plcopen/iec_std.csv:51 +msgid "Shift left" +msgstr "Décalage à gauche" + +#: ../plcopen/iec_std.csv:52 +msgid "Shift right" +msgstr "Décalage à droite" + +#: ../Dialogs.py:2002 +msgid "Simultaneous Convergence" +msgstr "Convergence double" + +#: ../Dialogs.py:1996 +msgid "Simultaneous Divergence" +msgstr "Divergence double" + +#: ../plcopen/iec_std.csv:27 +msgid "Sine" +msgstr "Sinus" + +#: ../RessourceEditor.py:79 +msgid "Single" +msgstr "Evènement" + +#: ../plcopen/iec_std.csv:23 +msgid "Square root (base 2)" +msgstr "Racine carré (base 2)" + +#: ../plcopen/structures.py:165 +msgid "Standard function blocks" +msgstr "Blocs fonctionnels standards" + +#: ../DataTypeEditor.py:236 +msgid "Structure" +msgstr "Structure" + +#: ../DataTypeEditor.py:236 +msgid "Subrange" +msgstr "Sous-ensemble" + +#: ../plcopen/iec_std.csv:39 +msgid "Subtraction" +msgstr "Soustraction" + +#: ../plcopen/iec_std.csv:29 +msgid "Tangent" +msgstr "Tangente" + +#: ../RessourceEditor.py:83 +msgid "Task" +msgstr "Tâche" + +#: ../RessourceEditor.py:358 +msgid "Tasks:" +msgstr "Tâches :" + +#: ../PLCOpenEditor.py:3861 +msgid "Temp" +msgstr "Temporaire" + +#: ../LDViewer.py:850 +msgid "The group of block must be coherent!" +msgstr "Le groupe de blocs doit être cohérent !" + +#: ../PLCOpenEditor.py:961 +msgid "There are changes, do you want to save?" +msgstr "Le projet a été modifié. Voulez-vous l'enregistrer ?" + +#: ../PLCOpenEditor.py:1169 +msgid "" +"There was a problem printing.\n" +"Perhaps your current printer is not set correctly?" +msgstr "" +"Un problème est apparu lors de l'impression.\n" +"Peut-être que votre imprimante n'est pas correctement configurée ?" + +#: ../LDViewer.py:859 +msgid "This option isn't available yet!" +msgstr "Cette option n'a pas encore disponible" + +#: ../GraphicViewer.py:181 +msgid "Tick" +msgstr "Tick" + +#: ../plcopen/iec_std.csv:34 +msgid "Time addition" +msgstr "Addition de durée" + +#: ../plcopen/iec_std.csv:75 +msgid "Time concatenation" +msgstr "Concaténation de date et de durée" + +#: ../plcopen/iec_std.csv:47 +msgid "Time division" +msgstr "Division de durée" + +#: ../plcopen/iec_std.csv:38 +msgid "Time multiplication" +msgstr "Multiplication de durée" + +#: ../plcopen/iec_std.csv:40 +msgid "Time subtraction" +msgstr "Soustraction de durée" + +#: ../plcopen/iec_std.csv:35 +msgid "Time-of-day addition" +msgstr "Addition d'horodatage" + +#: ../plcopen/iec_std.csv:42 +#: ../plcopen/iec_std.csv:43 +msgid "Time-of-day subtraction" +msgstr "Soustraction d'horodatage" + +#: ../PLCOpenEditor.py:608 +msgid "Toolbar" +msgstr "Barre d'outils" + +#: ../Viewer.py:365 +msgid "Top" +msgstr "Haut" + +#: ../PLCOpenEditor.py:3437 +msgid "Transition Name" +msgstr "Nom de la transition" + +#: ../PLCOpenEditor.py:3404 +msgid "Transition Name:" +msgstr "Nom de la transition :" + +#: ../PLCGenerator.py:1237 +#, python-format +msgid "Transition with content \"%s\" not connected to a next step in \"%s\" POU" +msgstr "La transition contenant \"%s\" n'est pas connectée à une étape en sortie dans le POU \"%s\" !" + +#: ../PLCGenerator.py:1228 +#, python-format +msgid "Transition with content \"%s\" not connected to a previous step in \"%s\" POU" +msgstr "La transition contenant \"%s\" n'est pas connectée à une étape en entrée dans le POU \"%s\" !" + +#: ../plcopen/plcopen.py:1035 +#, python-format +msgid "Transition with name %s doesn't exists!" +msgstr "La transition nommée %s n'existe pas !" + +#: ../PLCControler.py:83 +msgid "Transitions" +msgstr "Transitions" + +#: ../PLCOpenEditor.py:3848 +#: ../PLCOpenEditor.py:3849 +#: ../RessourceEditor.py:83 +#: ../Dialogs.py:2105 +#: ../DataTypeEditor.py:46 +msgid "Type" +msgstr "Type" + +#: ../plcopen/iec_std.csv:16 +msgid "Type conversion" +msgstr "Conversion de type" + +#: ../DataTypeEditor.py:360 +msgid "Type infos:" +msgstr "Propriétés du type :" + +#: ../Dialogs.py:118 +#: ../Dialogs.py:788 +#: ../Dialogs.py:1275 +#: ../Dialogs.py:1702 +#: ../Dialogs.py:1980 +msgid "Type:" +msgstr "Type :" + +#: ../PLCOpenEditor.py:560 +#: ../PLCOpenEditor.py:596 +msgid "Types" +msgstr "Types" + +#: ../PLCGenerator.py:232 +#, python-format +msgid "Undefined pou type \"%s\"" +msgstr "Type de POU \"%s\" indéterminé !" + +#: ../PLCOpenEditor.py:372 +msgid "Undo\tCTRL+Z" +msgstr "Défaire\tCTRL+Z" + +#: ../Viewer.py:286 +#, python-format +msgid "Unknown variable \"%s\" for this POU!" +msgstr "Variable \"%s\" inconnue dans ce POU !" + +#: ../PLCControler.py:293 +#, python-format +msgid "Unnamed%d" +msgstr "Sansnom%d" + +#: ../PLCOpenEditor.py:4098 +#, python-format +msgid "Unrecognized data size \"%s\"" +msgstr "Taille de donnée \"%s\" non identifié !" + +#: ../plcopen/structures.py:194 +msgid "" +"Up-counter\n" +"The up-counter can be used to signal when a count has reached a maximum value." +msgstr "" +"Compteur incrémental\n" +"Le compteur incrémental peut être utilisé pour signaler lorsque le compteur a atteint la valeur maximale." + +#: ../plcopen/structures.py:204 +msgid "" +"Up-down counter\n" +"The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other." +msgstr "" +"Compteur bidirectionnel\n" +"Le compteur bidirectionnel a deux entrées CU et CD. Il peut être utilisé pour compter de façon incrémentale ou décrémentale sur l'une ou l'autre des entrées." + +#: ../PLCOpenEditor.py:4497 +#: ../DataTypeEditor.py:804 +msgid "User Data Types" +msgstr "Types de donnée du projet" + +#: ../PLCControler.py:82 +msgid "User-defined POUs" +msgstr "POUs du projet" + +#: ../PLCOpenEditor.py:4614 +#: ../Dialogs.py:2105 +msgid "Value" +msgstr "Valeur" + +#: ../GraphicViewer.py:181 +msgid "Values" +msgstr "Valeurs" + +#: ../DataTypeEditor.py:445 +msgid "Values:" +msgstr "Valeurs" + +#: ../PLCOpenEditor.py:4614 +#: ../Dialogs.py:2109 +msgid "Variable" +msgstr "Variable" + +#: ../Dialogs.py:504 +msgid "Variable Properties" +msgstr "Propriétés de la variable" + +#: ../PLCOpenEditor.py:4102 +msgid "Variable class" +msgstr "Direction de la variable" + +#: ../Viewer.py:288 +#: ../TextViewer.py:224 +msgid "Variable don't belong to this POU!" +msgstr "La variable n'appartient pas à ce POU !" + +#: ../PLCOpenEditor.py:573 +#: ../PLCOpenEditor.py:624 +#: ../PLCOpenEditor.py:3860 +msgid "Variables" +msgstr "Variables" + +#: ../PLCOpenEditor.py:3302 +#: ../PLCOpenEditor.py:3680 +#: ../PLCOpenEditor.py:3743 +#: ../LDViewer.py:859 +msgid "Warning" +msgstr "Attention" + +#: ../PLCOpenEditor.py:2954 +msgid "Width:" +msgstr "Longueur :" + +#: ../PLCOpenEditor.py:2697 +msgid "X Scale:" +msgstr "Echelle X :" + +#: ../PLCOpenEditor.py:2705 +msgid "Y Scale:" +msgstr "Echelle Y :" + +#: ../PLCOpenEditor.py:3853 +msgid "Yes" +msgstr "Oui" + +#: ../LDViewer.py:854 +msgid "You must select the block or group of blocks around which a branch should be added!" +msgstr "Vous devez sélectionné le bloc ou le group autour duquel un ebranche doit être ajoutée !" + +#: ../LDViewer.py:628 +msgid "You must select the wire where a contact should be added!" +msgstr "Vous devez sélectionner le fil sur lequel le contact doit être ajouté !" + +#: ../PLCOpenEditor.py:3133 +#: ../PLCOpenEditor.py:3664 +#: ../PLCOpenEditor.py:3727 +#: ../Dialogs.py:1525 +#: ../Dialogs.py:2508 +#: ../Dialogs.py:2575 +msgid "You must type a name!" +msgstr "Vous devez saisir un nom !" + +#: ../PLCOpenEditor.py:426 +msgid "Zoom" +msgstr "Zoom" + +#: ../PLCOpenEditor.py:1091 +#, python-format +msgid "error: %s\n" +msgstr "erreur: %s\n" + +#: ../PLCOpenEditor.py:5032 +#: ../PLCOpenEditor.py:5034 +msgid "file : " +msgstr "fichier :" + +#: ../PLCOpenEditor.py:3173 +msgid "function" +msgstr "fonction" + +#: ../PLCOpenEditor.py:5035 +msgid "function : " +msgstr "fonction :" + +#: ../PLCOpenEditor.py:3173 +msgid "functionBlock" +msgstr "Bloc fonctionnel" + +#: ../PLCOpenEditor.py:5035 +msgid "line : " +msgstr "ligne :" + +#: ../PLCOpenEditor.py:3173 +msgid "program" +msgstr "programme" + +#: ../plcopen/iec_std.csv:73 +msgid "string from the middle" +msgstr "Caractères du milieu" + +#: ../plcopen/iec_std.csv:71 +msgid "string left of" +msgstr "Caractères à gauche de" + +#: ../plcopen/iec_std.csv:72 +msgid "string right of" +msgstr "Caractères à droite de" + +#: ../PLCOpenEditor.py:1089 +#, python-format +msgid "warning: %s\n" +msgstr "attention: %s\n" + +#~ msgid "" +#~ "A variable is defined with \"%s\" as name. It can generate a conflict. Do " +#~ "you wish to continue?" +#~ msgstr "Une variable" +#~ msgid "A pou with \"%s\" for name exists!" +#~ msgstr "Un POU nommé \"%s\" existe déjà !" +#~ msgid "Create A New POU From" +#~ msgstr "Créer un nouveau POU à partir de" + diff -r d07815f10ca8 -r 323c8d76f6f2 i18n/PLCOpenEditor_zh_CN.po --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i18n/PLCOpenEditor_zh_CN.po Fri Aug 07 15:49:10 2009 +0200 @@ -0,0 +1,2334 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-06-24 18:43+0200\n" +"PO-Revision-Date: 2009-06-25 11:55+0100\n" +"Last-Translator: \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: PLCOpenEditor.py:5108 +msgid "" +"\n" +"An error happens.\n" +"\n" +"Click on OK for saving an error report.\n" +"\n" +"Please contact LOLITech at:\n" +"+33 (0)3 29 57 60 42\n" +"bugs_PLCOpenEditor@lolitech.fr\n" +"\n" +"\n" +"Error:\n" +msgstr "" +"\n" +"一个错误发生了。\n" +"\n" +"点击确定以保存一个错误报告。\n" +"\n" +"请用以下方式联系LOLITech:\n" +"+33 (0)3 29 57 60 42\n" +"bugs_PLCOpenEditor@lolitech.fr\n" +"\n" +"\n" +"错误:\n" + +#: PLCOpenEditor.py:3923 +msgid " External" +msgstr " 外部" + +#: PLCOpenEditor.py:3922 +msgid " InOut" +msgstr " 输入" + +#: PLCOpenEditor.py:3922 +msgid " Input" +msgstr " 输入" + +#: PLCOpenEditor.py:3923 +msgid " Local" +msgstr " 本地" + +#: PLCOpenEditor.py:3922 +msgid " Output" +msgstr " 输出" + +#: PLCOpenEditor.py:3924 +msgid " Temp" +msgstr " 缓冲" + +#: PLCOpenEditor.py:841 +msgid " (Debug)" +msgstr " (调试)" + +#: PLCOpenEditor.py:5120 +msgid " : " +msgstr ":" + +#: PLCOpenEditor.py:3346 +#: PLCOpenEditor.py:3509 +#: PLCOpenEditor.py:3653 +#: Dialogs.py:1796 +#, python-format +msgid " and %s" +msgstr "和 %s" + +#: plcopen/plcopen.py:754 +#, python-format +msgid "\"%s\" Data Type doesn't exist !!!" +msgstr "\"%s\" 数据类型尚不存在!!!" + +#: plcopen/plcopen.py:772 +#, python-format +msgid "\"%s\" POU already exists !!!" +msgstr "\"%s\"编程组织单元已经存在!!!" + +#: plcopen/plcopen.py:793 +#, python-format +msgid "\"%s\" POU doesn't exist !!!" +msgstr "\"%s\" POU不存在!!!" + +#: Viewer.py:228 +#, python-format +msgid "\"%s\" can't use itself!" +msgstr "\"%s\" 不能自己使用!" + +#: PLCOpenEditor.py:1644 +#: PLCOpenEditor.py:1669 +#, python-format +msgid "\"%s\" config already exists!" +msgstr "\"%s\" 配置已存在!" + +#: plcopen/plcopen.py:257 +#, python-format +msgid "\"%s\" configuration already exists !!!" +msgstr "\"%s\" 配置已存在!!!" + +#: PLCOpenEditor.py:1588 +#: PLCOpenEditor.py:3207 +#, python-format +msgid "\"%s\" data type already exists!" +msgstr "\"%s\" 数据类型已存在!" + +#: PLCControler.py:1648 +#, python-format +msgid "\"%s\" element can't be paste here!!!" +msgstr "\"%s\" 元素不能粘贴在这里!!!" + +#: PLCOpenEditor.py:3528 +#: PLCOpenEditor.py:3672 +#: Viewer.py:251 +#: Dialogs.py:257 +#: Dialogs.py:894 +#, python-format +msgid "\"%s\" element for this pou already exists!" +msgstr "\"%s\" " + +#: plcopen/structures.py:97 +#, python-format +msgid "\"%s\" function cancelled in \"%s\" POU: No input connected" +msgstr "\"%s\" 功能被取消 \"%s\" 在POU中:没有输入连接" + +#: PLCOpenEditor.py:1579 +#: PLCOpenEditor.py:3203 +#: PLCOpenEditor.py:3357 +#: PLCOpenEditor.py:3520 +#: PLCOpenEditor.py:3664 +#: PLCOpenEditor.py:3735 +#: PLCOpenEditor.py:3798 +#: PLCOpenEditor.py:4513 +#: Dialogs.py:249 +#: Dialogs.py:648 +#: Dialogs.py:886 +#: Dialogs.py:1529 +#: Dialogs.py:2513 +#: Dialogs.py:2580 +#: DataTypeEditor.py:698 +#: DataTypeEditor.py:758 +#, python-format +msgid "\"%s\" is a keyword. It can't be used!" +msgstr "\"%s\" 是一个关键词。它不能被使用!" + +#: Viewer.py:234 +#, python-format +msgid "\"%s\" is already used by \"%s\"!" +msgstr "\"%s\" 已被 \"%s\" 使用!" + +#: plcopen/plcopen.py:2056 +#, python-format +msgid "\"%s\" is an invalid value!" +msgstr "\"%s\"不是有效值!" + +#: PLCOpenEditor.py:1098 +#: PLCOpenEditor.py:1127 +#, python-format +msgid "\"%s\" is not a valid folder!" +msgstr "\"%s\"不是有效文件夹!" + +#: PLCOpenEditor.py:1577 +#: PLCOpenEditor.py:3199 +#: PLCOpenEditor.py:3353 +#: PLCOpenEditor.py:3516 +#: PLCOpenEditor.py:3660 +#: PLCOpenEditor.py:3731 +#: PLCOpenEditor.py:3794 +#: PLCOpenEditor.py:4508 +#: Dialogs.py:245 +#: Dialogs.py:882 +#: Dialogs.py:1525 +#: Dialogs.py:2509 +#: Dialogs.py:2576 +#: DataTypeEditor.py:753 +#, python-format +msgid "\"%s\" is not a valid identifier!" +msgstr "\"%s\"不是有效标识符!" + +#: PLCOpenEditor.py:283 +#: PLCOpenEditor.py:2553 +#: PLCOpenEditor.py:2582 +#, python-format +msgid "\"%s\" is used by one or more POUs. It can't be removed!" +msgstr "%s 正在被一个或多个POU使用。不能被删除!" + +#: PLCOpenEditor.py:1597 +#: PLCOpenEditor.py:3361 +#: Viewer.py:249 +#: Dialogs.py:253 +#: Dialogs.py:890 +#, python-format +msgid "\"%s\" pou already exists!" +msgstr "\"%s\"编程组织单元已经存在!" + +#: plcopen/plcopen.py:288 +#, python-format +msgid "\"%s\" resource already exists in \"%s\" configuration !!!" +msgstr "\"%s\" 资源已经存在于 \"%s\" 配置中!!!" + +#: plcopen/plcopen.py:304 +#, python-format +msgid "\"%s\" resource doesn't exist in \"%s\" configuration !!!" +msgstr "\"%s\" 资源不存在于 \"%s\" 配置之内!!!" + +#: Dialogs.py:1541 +#: Dialogs.py:2525 +#, python-format +msgid "\"%s\" step already exists!" +msgstr "\"%s\"步骤已经存在!" + +#: DataTypeEditor.py:693 +#, python-format +msgid "\"%s\" value already defined!" +msgstr "\"%s\" 值已经被定义!" + +#: DataTypeEditor.py:895 +#, python-format +msgid "\"%s\" value isn't a valid array dimension!" +msgstr "\"%s\" 值不是有效数组维数!" + +#: DataTypeEditor.py:902 +#, python-format +msgid "" +"\"%s\" value isn't a valid array dimension!\n" +"Right value must be greater than left value." +msgstr "" +"\"%s\" 不是一个有效的数组维数值!\n" +"右边的数值必须大于左边的数值。" + +#: GraphicViewer.py:181 +#, python-format +msgid "%s Graphics" +msgstr "%s 图形" + +#: plcopen/plcopen.py:1181 +#: plcopen/plcopen.py:1191 +#: plcopen/plcopen.py:1201 +#: plcopen/plcopen.py:1211 +#: plcopen/plcopen.py:1220 +#, python-format +msgid "%s body don't have instances!" +msgstr "%s 未包含实例!" + +#: plcopen/plcopen.py:1243 +#: plcopen/plcopen.py:1250 +#, python-format +msgid "%s body don't have text!" +msgstr "%s 未包含文本!" + +#: PLCOpenEditor.py:5096 +#: PLCOpenEditor.py:5098 +#: PLCOpenEditor.py:5099 +msgid ", " +msgstr "," + +#: PLCOpenEditor.py:3348 +#: PLCOpenEditor.py:3511 +#: PLCOpenEditor.py:3655 +#: Dialogs.py:1798 +#, python-format +msgid ", %s" +msgstr ", %s" + +#: PLCOpenEditor.py:5094 +msgid ". " +msgstr "。" + +#: DataTypeEditor.py:768 +#, python-format +msgid "A element with \"%s\" as name exists in this structure!" +msgstr "一个以\"%s\"命名的元素已经在这个结构中存在!" + +#: PLCOpenEditor.py:1600 +#: PLCOpenEditor.py:1652 +#: PLCOpenEditor.py:1677 +#: PLCOpenEditor.py:3365 +#: PLCOpenEditor.py:3743 +#: PLCOpenEditor.py:3806 +#, python-format +msgid "A pou has an element with \"%s\" as name. It can generate a conflict. Do you wish to continue?" +msgstr "一个编程组织单元的成员被命名为\"%s\"。这可能会产生冲突。你希望继续吗?" + +#: PLCOpenEditor.py:1647 +#: PLCOpenEditor.py:1672 +#, python-format +msgid "A pou is defined with \"%s\" as name. It can generate a conflict. Do you wish to continue?" +msgstr "一个编程组织单元被命名为\"%s\"。这可能会产生冲突。你希望继续吗?" + +#: PLCOpenEditor.py:1618 +#: PLCOpenEditor.py:1634 +#: PLCOpenEditor.py:3524 +#: PLCOpenEditor.py:3668 +#: PLCOpenEditor.py:3739 +#: PLCOpenEditor.py:3802 +#: PLCOpenEditor.py:4518 +#: Dialogs.py:1533 +#: Dialogs.py:2517 +#: Dialogs.py:2584 +#, python-format +msgid "A pou with \"%s\" as name exists!" +msgstr "一个以\"%s\"命名的的编程组织单元已经存在!" + +#: PLCOpenEditor.py:1620 +#: PLCOpenEditor.py:1636 +#: PLCOpenEditor.py:4523 +#: Dialogs.py:1537 +#: Dialogs.py:2521 +#, python-format +msgid "A variable with \"%s\" as name already exists in this pou!" +msgstr "一个以\"%s\"命名的变量在这个编程组织单元中已经存在!" + +#: PLCOpenEditor.py:445 +msgid "About" +msgstr "关于" + +#: PLCOpenEditor.py:2676 +msgid "About PLCOpenEditor" +msgstr "关于PLCOpen编辑器" + +#: plcopen/iec_std.csv:22 +msgid "Absolute number" +msgstr "绝对值" + +#: Dialogs.py:1478 +#: Dialogs.py:2105 +msgid "Action" +msgstr "行动" + +#: PLCOpenEditor.py:3644 +msgid "Action Name" +msgstr "行动名字" + +#: PLCOpenEditor.py:3611 +msgid "Action Name:" +msgstr "行动名字:" + +#: plcopen/plcopen.py:1028 +#, python-format +msgid "Action with name %s doesn't exists!" +msgstr "一个以\"%s\"命名的的行动不存在!" + +#: PLCControler.py:83 +msgid "Actions" +msgstr "行动" + +#: Dialogs.py:2336 +msgid "Actions:" +msgstr "行动:" + +#: PLCOpenEditor.py:4309 +#: Dialogs.py:2350 +#: DataTypeEditor.py:536 +msgid "Add" +msgstr "添加" + +#: PLCOpenEditor.py:1860 +#: PLCOpenEditor.py:1933 +msgid "Add Action" +msgstr "添加行动" + +#: PLCOpenEditor.py:1916 +msgid "Add Configuration" +msgstr "添加配置" + +#: PLCOpenEditor.py:1904 +msgid "Add DataType" +msgstr "添加数据类型" + +#: Viewer.py:405 +msgid "Add Divergence Branch" +msgstr "添加发散分支" + +#: PLCOpenEditor.py:384 +msgid "Add Element" +msgstr "插入" + +#: RessourceEditor.py:409 +msgid "Add Instance" +msgstr "添加实例" + +#: PLCOpenEditor.py:1910 +msgid "Add Pou" +msgstr "添加Pou" + +#: PLCOpenEditor.py:1887 +#: PLCOpenEditor.py:1944 +msgid "Add Resource" +msgstr "添加源" + +#: RessourceEditor.py:373 +msgid "Add Task" +msgstr "添加任务" + +#: PLCOpenEditor.py:1857 +#: PLCOpenEditor.py:1922 +msgid "Add Transition" +msgstr "添加跃迁" + +#: Viewer.py:400 +msgid "Add Wire Segment" +msgstr "添加布线段" + +#: PLCOpenEditor.py:2421 +msgid "Add a new data type" +msgstr "添加一个新的数据类型" + +#: SFCViewer.py:362 +msgid "Add a new initial step" +msgstr "新建一个初始步骤" + +#: Viewer.py:1977 +#: SFCViewer.py:698 +msgid "Add a new jump" +msgstr "新建一个跳跃" + +#: SFCViewer.py:384 +msgid "Add a new step" +msgstr "添加一个新步骤" + +#: PLCOpenEditor.py:2478 +msgid "Add new configuration" +msgstr "添加新配置" + +#: PLCOpenEditor.py:2493 +msgid "Add new resource" +msgstr "添加新源" + +#: plcopen/iec_std.csv:33 +msgid "Addition" +msgstr "加法" + +#: plcopen/structures.py:222 +msgid "Additionnal function blocks" +msgstr "附加功能类型" + +#: Viewer.py:414 +msgid "Alignment" +msgstr "对准" + +#: PLCOpenEditor.py:3921 +msgid "All" +msgstr "所有" + +#: plcopen/iec_std.csv:31 +msgid "Arc cosine" +msgstr "反余弦" + +#: plcopen/iec_std.csv:30 +msgid "Arc sine" +msgstr "反正弦" + +#: plcopen/iec_std.csv:32 +msgid "Arc tangent" +msgstr "反正切" + +#: plcopen/iec_std.csv:33 +msgid "Arithmetic" +msgstr "运算" + +#: DataTypeEditor.py:238 +msgid "Array" +msgstr "阵列的" + +#: plcopen/iec_std.csv:50 +msgid "Assignment" +msgstr "分配" + +#: Dialogs.py:644 +msgid "At least a variable or an expression must be selected!" +msgstr "至少选择一个变量或者表达式!" + +#: PLCOpenEditor.py:3003 +msgid "Author" +msgstr "作者" + +#: PLCOpenEditor.py:2988 +msgid "Author Name (optional):" +msgstr "作者姓名(选填):" + +#: DataTypeEditor.py:376 +#: DataTypeEditor.py:400 +#: DataTypeEditor.py:475 +msgid "Base Type:" +msgstr "基类型:" + +#: PLCOpenEditor.py:4555 +#: DataTypeEditor.py:794 +msgid "Base Types" +msgstr "基类型" + +#: plcopen/iec_std.csv:59 +msgid "Binary selection (1 of 2)" +msgstr "二进制选取(二选一)" + +#: plcopen/iec_std.csv:51 +msgid "Bit-shift" +msgstr "位移" + +#: plcopen/iec_std.csv:55 +msgid "Bitwise" +msgstr "位操作" + +#: plcopen/iec_std.csv:55 +msgid "Bitwise AND" +msgstr "按位”与“" + +#: plcopen/iec_std.csv:56 +msgid "Bitwise OR" +msgstr "按位”或“" + +#: plcopen/iec_std.csv:57 +msgid "Bitwise XOR" +msgstr "按位”异或“" + +#: plcopen/iec_std.csv:58 +msgid "Bitwise inverting" +msgstr "按位“反向”" + +#: Dialogs.py:110 +msgid "Block Properties" +msgstr "块属性" + +#: PLCOpenEditor.py:2139 +#: Dialogs.py:265 +msgid "Block Types" +msgstr "块类型" + +#: Viewer.py:372 +msgid "Bottom" +msgstr "底部" + +#: PLCOpenEditor.py:2093 +msgid "CSV Log" +msgstr "逗号分隔值文件日志" + +#: PLCOpenEditor.py:4137 +msgid "Can affect a location only to local or global variables" +msgstr "只能影响本地或全局变量的位置" + +#: plcopen/plcopen.py:1123 +#: plcopen/plcopen.py:1137 +#: plcopen/plcopen.py:1158 +#: plcopen/plcopen.py:1174 +msgid "Can only generate execution order on FBD networks!" +msgstr "在功能块网络,只能生成执行命令!" + +#: PLCOpenEditor.py:4135 +msgid "Can't affect a location to a function block instance" +msgstr "不能影响功能块实例的位置" + +#: PLCOpenEditor.py:1093 +#, python-format +msgid "Can't generate program to file %s!" +msgstr "这个编程生成文件失败 %s!" + +#: PLCOpenEditor.py:1125 +#, python-format +msgid "Can't save project to file %s!" +msgstr "这个项目保存为文件失败 %s!" + +#: Viewer.py:363 +msgid "Center" +msgstr "中" + +#: PLCOpenEditor.py:1876 +msgid "Change POU Type To" +msgstr "将POU类型转换为" + +#: plcopen/iec_std.csv:70 +msgid "Character string" +msgstr "字符串" + +#: PLCOpenEditor.py:1032 +#: PLCOpenEditor.py:1083 +#: PLCOpenEditor.py:1119 +msgid "Choose a file" +msgstr "选择一个文件" + +#: PLCOpenEditor.py:3911 +#: PLCOpenEditor.py:3912 +msgid "Class" +msgstr "分类" + +#: PLCOpenEditor.py:4301 +msgid "Class Filter:" +msgstr "类过滤器:" + +#: Dialogs.py:504 +msgid "Class:" +msgstr "分类:" + +#: PLCOpenEditor.py:423 +msgid "Clear Errors\tCTRL+K" +msgstr "清除错误\tCTRL+K" + +#: Viewer.py:410 +msgid "Clear Execution Order" +msgstr "清空执行命令" + +#: PLCOpenEditor.py:346 +msgid "Close\tCTRL+Q" +msgstr "关闭\tCTRL+Q" + +#: PLCOpenEditor.py:962 +msgid "Close Application" +msgstr "关闭应用程序" + +#: PLCOpenEditor.py:319 +msgid "Close Project" +msgstr "关闭程序" + +#: PLCOpenEditor.py:316 +msgid "Close Tab\tCTRL+W" +msgstr "关闭当前" + +#: LDViewer.py:478 +msgid "Comment" +msgstr "注释" + +#: PLCOpenEditor.py:2972 +msgid "Company Name (required):" +msgstr "公司名字(必须):" + +#: PLCOpenEditor.py:2980 +msgid "Company URL (optional):" +msgstr "公司网址(选填):" + +#: plcopen/iec_std.csv:64 +msgid "Comparison" +msgstr "比较" + +#: plcopen/iec_std.csv:74 +msgid "Concatenation" +msgstr "级联" + +#: PLCOpenEditor.py:394 +msgid "Configuration" +msgstr "配置" + +#: PLCControler.py:84 +msgid "Configurations" +msgstr "配置" + +#: Dialogs.py:1733 +msgid "Connection" +msgstr "连接" + +#: Dialogs.py:780 +msgid "Connection Properties" +msgstr "连接属性" + +#: Dialogs.py:796 +msgid "Connector" +msgstr "连接" + +#: Dialogs.py:1455 +msgid "Connectors:" +msgstr "连接:" + +#: PLCOpenEditor.py:3911 +#: PLCOpenEditor.py:3912 +msgid "Constant" +msgstr "常量" + +#: PLCOpenEditor.py:3062 +msgid "Content Description (optional):" +msgstr "内容描述(选填):" + +#: Dialogs.py:802 +msgid "Continuation" +msgstr "连续" + +#: plcopen/iec_std.csv:18 +msgid "Conversion from BCD" +msgstr "由BCD码转换" + +#: plcopen/iec_std.csv:19 +msgid "Conversion to BCD" +msgstr "转换为BCD码" + +#: plcopen/iec_std.csv:21 +msgid "Conversion to date" +msgstr "转换为日期" + +#: plcopen/iec_std.csv:20 +msgid "Conversion to time-of-day" +msgstr "转换为日期时间" + +#: PLCOpenEditor.py:379 +msgid "Copy\tCTRL+C" +msgstr "复制\tCTRL+C" + +#: plcopen/iec_std.csv:28 +msgid "Cosine" +msgstr "余弦" + +#: PLCOpenEditor.py:3286 +msgid "Create a new POU" +msgstr "新建一个POU" + +#: PLCOpenEditor.py:1864 +#: PLCOpenEditor.py:2523 +msgid "Create a new POU from" +msgstr "新建一个POU从" + +#: PLCOpenEditor.py:3607 +msgid "Create a new action" +msgstr "新建一个行动" + +#: PLCOpenEditor.py:214 +msgid "Create a new action block" +msgstr "新建一个作用块" + +#: PLCOpenEditor.py:169 +#: PLCOpenEditor.py:196 +#: PLCOpenEditor.py:226 +msgid "Create a new block" +msgstr "新建一个块" + +#: PLCOpenEditor.py:190 +msgid "Create a new branch" +msgstr "新建一个支流" + +#: PLCOpenEditor.py:184 +msgid "Create a new coil" +msgstr "新建一个线圈" + +#: PLCOpenEditor.py:163 +#: PLCOpenEditor.py:175 +#: PLCOpenEditor.py:202 +msgid "Create a new comment" +msgstr "新建一个备注" + +#: PLCOpenEditor.py:172 +#: PLCOpenEditor.py:199 +#: PLCOpenEditor.py:229 +msgid "Create a new connection" +msgstr "新建一个连接" + +#: PLCOpenEditor.py:187 +#: PLCOpenEditor.py:235 +msgid "Create a new contact" +msgstr "新建一个接触点" + +#: PLCOpenEditor.py:217 +msgid "Create a new divergence" +msgstr "新建一个发散" + +#: Dialogs.py:1972 +msgid "Create a new divergence or convergence" +msgstr "新建一个发散或者收敛" + +#: PLCOpenEditor.py:205 +msgid "Create a new initial step" +msgstr "新建一个初始步骤" + +#: PLCOpenEditor.py:220 +msgid "Create a new jump" +msgstr "新建一个跳跃" + +#: PLCOpenEditor.py:178 +#: PLCOpenEditor.py:232 +msgid "Create a new power rail" +msgstr "新建一个电源导轨" + +#: PLCOpenEditor.py:181 +msgid "Create a new rung" +msgstr "新建一个梯级" + +#: PLCOpenEditor.py:208 +msgid "Create a new step" +msgstr "新建一个步骤" + +#: PLCOpenEditor.py:211 +#: PLCOpenEditor.py:3463 +msgid "Create a new transition" +msgstr "新建一个跃迁" + +#: PLCOpenEditor.py:166 +#: PLCOpenEditor.py:193 +#: PLCOpenEditor.py:223 +msgid "Create a new variable" +msgstr "新建一个变量" + +#: PLCOpenEditor.py:377 +msgid "Cut\tCTRL+X" +msgstr "剪切\tCTRL+X" + +#: PLCOpenEditor.py:386 +msgid "Data Type" +msgstr "数据类型" + +#: PLCControler.py:83 +msgid "Data Types" +msgstr "数据类型 " + +#: plcopen/iec_std.csv:16 +msgid "Data type conversion" +msgstr "日期类型转换" + +#: plcopen/iec_std.csv:36 +msgid "Date addition" +msgstr "日期加法" + +#: plcopen/iec_std.csv:44 +#: plcopen/iec_std.csv:45 +msgid "Date and time subtraction" +msgstr "日期和时间减法" + +#: plcopen/iec_std.csv:41 +msgid "Date subtraction" +msgstr "日期减法" + +#: PLCOpenEditor.py:398 +#: PLCOpenEditor.py:1881 +#: PLCOpenEditor.py:1890 +#: PLCOpenEditor.py:1896 +#: PLCOpenEditor.py:4314 +#: PLCOpenEditor.py:4926 +#: Viewer.py:419 +#: Dialogs.py:2355 +#: DataTypeEditor.py:541 +msgid "Delete" +msgstr "删除" + +#: Viewer.py:407 +msgid "Delete Divergence Branch" +msgstr "删除发散分支" + +#: RessourceEditor.py:414 +msgid "Delete Instance" +msgstr "删除实例" + +#: RessourceEditor.py:378 +msgid "Delete Task" +msgstr "删除任务" + +#: Viewer.py:402 +msgid "Delete Wire Segment" +msgstr "删除布线段" + +#: DataTypeEditor.py:450 +#: DataTypeEditor.py:492 +msgid "Delete item" +msgstr "删除项目" + +#: plcopen/iec_std.csv:77 +msgid "Deletion (within)" +msgstr "删除" + +#: DataTypeEditor.py:361 +msgid "Derivation Type:" +msgstr "推导类型:" + +#: plcopen/structures.py:236 +msgid "" +"Derivative\n" +"The derivative function block produces an output XOUT proportional to the rate of change of the input XIN." +msgstr "" +"导数\n" +"导数功能块根据输入XIN的速率的变化而按比例的生产输出XOUT。" + +#: DataTypeEditor.py:484 +msgid "Dimensions:" +msgstr "维数:" + +#: DataTypeEditor.py:238 +msgid "Directly" +msgstr "直接的" + +#: PLCOpenEditor.py:306 +msgid "Display" +msgstr "显示" + +#: plcopen/iec_std.csv:46 +msgid "Division" +msgstr "除法" + +#: PLCOpenEditor.py:1087 +msgid "Done" +msgstr "完成" + +#: plcopen/structures.py:199 +msgid "" +"Down-counter\n" +"The down-counter can be used to signal when a count has reached zero, on counting down from a preset value." +msgstr "" +"倒计时器\n" +"倒计时器用于当计数到达 0的时候,从当前值开始倒计时。" + +#: Dialogs.py:2101 +msgid "Duration" +msgstr "时间" + +#: PLCOpenEditor.py:305 +msgid "Edit" +msgstr "编辑" + +#: Viewer.py:417 +msgid "Edit Block" +msgstr "编辑块" + +#: Dialogs.py:1094 +msgid "Edit Coil Values" +msgstr "编辑线圈值" + +#: Dialogs.py:1089 +msgid "Edit Contact Values" +msgstr "编辑接触点值" + +#: Dialogs.py:1447 +msgid "Edit Step" +msgstr "编辑步骤" + +#: Dialogs.py:2332 +msgid "Edit action block properties" +msgstr "编辑行动块属性" + +#: Viewer.py:1802 +#: Viewer.py:1804 +#: Viewer.py:2303 +#: Viewer.py:2305 +msgid "Edit comment" +msgstr "编辑注释" + +#: DataTypeEditor.py:445 +#: DataTypeEditor.py:487 +msgid "Edit item" +msgstr "编辑项目" + +#: Viewer.py:2268 +msgid "Edit jump target" +msgstr "编辑跳跃目标" + +#: SFCViewer.py:726 +msgid "Edit step name" +msgstr "编辑步骤名称" + +#: Dialogs.py:1694 +msgid "Edit transition" +msgstr "编辑跃迁" + +#: DataTypeEditor.py:517 +msgid "Elements :" +msgstr "元素:" + +#: DataTypeEditor.py:238 +msgid "Enumerated" +msgstr "列举的" + +#: plcopen/iec_std.csv:66 +msgid "Equal to" +msgstr "等于" + +#: PLCOpenEditor.py:954 +#: PLCOpenEditor.py:1094 +#: PLCOpenEditor.py:1099 +#: PLCOpenEditor.py:1600 +#: PLCOpenEditor.py:1647 +#: PLCOpenEditor.py:1652 +#: PLCOpenEditor.py:1672 +#: PLCOpenEditor.py:1677 +#: PLCOpenEditor.py:2553 +#: PLCOpenEditor.py:2582 +#: PLCOpenEditor.py:3103 +#: PLCOpenEditor.py:3195 +#: PLCOpenEditor.py:3199 +#: PLCOpenEditor.py:3203 +#: PLCOpenEditor.py:3207 +#: PLCOpenEditor.py:3349 +#: PLCOpenEditor.py:3353 +#: PLCOpenEditor.py:3357 +#: PLCOpenEditor.py:3361 +#: PLCOpenEditor.py:3512 +#: PLCOpenEditor.py:3516 +#: PLCOpenEditor.py:3520 +#: PLCOpenEditor.py:3524 +#: PLCOpenEditor.py:3528 +#: PLCOpenEditor.py:3656 +#: PLCOpenEditor.py:3660 +#: PLCOpenEditor.py:3664 +#: PLCOpenEditor.py:3668 +#: PLCOpenEditor.py:3672 +#: PLCOpenEditor.py:3727 +#: PLCOpenEditor.py:3731 +#: PLCOpenEditor.py:3735 +#: PLCOpenEditor.py:3739 +#: PLCOpenEditor.py:3790 +#: PLCOpenEditor.py:3794 +#: PLCOpenEditor.py:3798 +#: PLCOpenEditor.py:3802 +#: PLCOpenEditor.py:4184 +#: PLCOpenEditor.py:4508 +#: PLCOpenEditor.py:4513 +#: PLCOpenEditor.py:4518 +#: PLCOpenEditor.py:4523 +#: PLCOpenEditor.py:4859 +#: PLCOpenEditor.py:5121 +#: PLCOpenEditor.py:5131 +#: Viewer.py:338 +#: TextViewer.py:224 +#: LDViewer.py:628 +#: LDViewer.py:850 +#: LDViewer.py:854 +#: Dialogs.py:237 +#: Dialogs.py:241 +#: Dialogs.py:245 +#: Dialogs.py:249 +#: Dialogs.py:253 +#: Dialogs.py:257 +#: Dialogs.py:644 +#: Dialogs.py:648 +#: Dialogs.py:878 +#: Dialogs.py:882 +#: Dialogs.py:886 +#: Dialogs.py:890 +#: Dialogs.py:894 +#: Dialogs.py:1521 +#: Dialogs.py:1525 +#: Dialogs.py:1529 +#: Dialogs.py:1533 +#: Dialogs.py:1537 +#: Dialogs.py:1541 +#: Dialogs.py:1799 +#: Dialogs.py:2505 +#: Dialogs.py:2509 +#: Dialogs.py:2513 +#: Dialogs.py:2517 +#: Dialogs.py:2521 +#: Dialogs.py:2525 +#: Dialogs.py:2572 +#: Dialogs.py:2576 +#: Dialogs.py:2580 +#: Dialogs.py:2584 +#: DataTypeEditor.py:693 +#: DataTypeEditor.py:698 +#: DataTypeEditor.py:753 +#: DataTypeEditor.py:758 +#: DataTypeEditor.py:768 +#: DataTypeEditor.py:895 +#: DataTypeEditor.py:902 +msgid "Error" +msgstr "错误" + +#: Dialogs.py:130 +msgid "Execution Control:" +msgstr "执行控制:" + +#: Dialogs.py:126 +#: Dialogs.py:512 +msgid "Execution Order:" +msgstr "执行命令:" + +#: plcopen/iec_std.csv:49 +msgid "Exponent" +msgstr "指数" + +#: plcopen/iec_std.csv:26 +msgid "Exponentiation" +msgstr "幂" + +#: Dialogs.py:508 +msgid "Expression:" +msgstr "表达式:" + +#: PLCOpenEditor.py:3923 +msgid "External" +msgstr "外部的" + +#: PLCOpenEditor.py:3040 +#: PLCOpenEditor.py:3230 +#: PLCOpenEditor.py:3241 +#: PLCOpenEditor.py:3420 +#: PLCOpenEditor.py:3564 +msgid "FBD" +msgstr "功能区块图" + +#: Viewer.py:397 +#: Dialogs.py:1056 +msgid "Falling Edge" +msgstr "下降沿" + +#: plcopen/structures.py:189 +msgid "" +"Falling edge detector\n" +"The output produces a single pulse when a falling edge is detected." +msgstr "" +"下降沿检测\n" +"当下降沿被检测到时,输出便产生一个单脉冲。" + +#: PLCOpenEditor.py:303 +msgid "File" +msgstr "文件" + +#: plcopen/iec_std.csv:79 +msgid "Find position" +msgstr "定位" + +#: PLCOpenEditor.py:3103 +#: PLCOpenEditor.py:3349 +#: PLCOpenEditor.py:3512 +#: PLCOpenEditor.py:3656 +#: Dialogs.py:1799 +#, python-format +msgid "Form isn't complete. %s must be filled!" +msgstr "形式不完整。%s 必须被填补完整!" + +#: Dialogs.py:241 +#: Dialogs.py:878 +msgid "Form isn't complete. Name must be filled!" +msgstr "形式不完整。%s 名字必须填!" + +#: Dialogs.py:237 +msgid "Form isn't complete. Valid block type must be selected!" +msgstr "形式不完整。%s 有效的块类型必须被选择!" + +#: PLCOpenEditor.py:388 +msgid "Function" +msgstr "功能" + +#: PLCOpenEditor.py:390 +#: PLCOpenEditor.py:1871 +msgid "Function Block" +msgstr "功能块" + +#: PLCOpenEditor.py:4570 +msgid "Function Block Types" +msgstr "功能块类型" + +#: PLCControler.py:82 +msgid "Function Blocks" +msgstr "功能块" + +#: Viewer.py:230 +msgid "Function Blocks can't be used in Functions!" +msgstr "功能块不能用于功能中!" + +#: Viewer.py:232 +msgid "Function Blocks can't be used in Transitions!" +msgstr "功能块不能用于跃迁中" + +#: PLCControler.py:1658 +#, python-format +msgid "FunctionBlock \"%s\" can't be paste in a Function!!!" +msgstr "功能块 \"%s\" 不能用于功能中!" + +#: PLCControler.py:82 +msgid "Functions" +msgstr "功能" + +#: PLCOpenEditor.py:328 +msgid "Generate Program\tCTRL+G" +msgstr "生成程序\tCTRL+G" + +#: PLCOpenEditor.py:3924 +msgid "Global" +msgstr "全球的" + +#: PLCOpenEditor.py:2090 +msgid "Graphic Panel" +msgstr "图形面板" + +#: PLCOpenEditor.py:3045 +msgid "Graphics" +msgstr "图形" + +#: plcopen/iec_std.csv:64 +msgid "Greater than" +msgstr "大于" + +#: plcopen/iec_std.csv:65 +msgid "Greater than or equal to" +msgstr "大于或等于" + +#: PLCOpenEditor.py:3024 +msgid "Height:" +msgstr "高度:" + +#: PLCOpenEditor.py:307 +msgid "Help" +msgstr "帮助" + +#: plcopen/structures.py:251 +msgid "" +"Hysteresis\n" +"The hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2." +msgstr "" +"滞后\n" +"滞后功能块提供一个被2个浮点(REAL)的差异所驱动的布尔型滞后输出,2个浮点即输入的XIN1和XIN2。" + +#: PLCOpenEditor.py:3230 +#: PLCOpenEditor.py:3241 +#: PLCOpenEditor.py:3420 +#: PLCOpenEditor.py:3564 +msgid "IL" +msgstr "指令集" + +#: PLCOpenEditor.py:3922 +#: Dialogs.py:422 +msgid "InOut" +msgstr "输入输出" + +#: PLCOpenEditor.py:4154 +#, python-format +msgid "Incompatible data types between \"%s\" and \"%s\"" +msgstr " \"%s\" 和 \"%s\" 数据类型不相容" + +#: PLCOpenEditor.py:4165 +#, python-format +msgid "Incompatible size of data between \"%s\" and \"%s\"" +msgstr " \"%s\" 和 \"%s\" 数据大小不相容" + +#: PLCOpenEditor.py:4161 +#, python-format +msgid "Incompatible size of data between \"%s\" and \"BOOL\"" +msgstr " \"%s\" 和 \"BOOL\" 数据类型不相容" + +#: Dialogs.py:2101 +msgid "Indicator" +msgstr "指示器" + +#: PLCOpenEditor.py:3911 +#: PLCOpenEditor.py:3912 +#: DataTypeEditor.py:46 +msgid "Initial Value" +msgstr "初始值" + +#: DataTypeEditor.py:385 +#: DataTypeEditor.py:409 +#: DataTypeEditor.py:460 +#: DataTypeEditor.py:502 +msgid "Initial Value:" +msgstr "初始值:" + +#: Dialogs.py:1721 +#: Dialogs.py:1789 +#: Dialogs.py:2105 +msgid "Inline" +msgstr "在线" + +#: PLCOpenEditor.py:3922 +#: Dialogs.py:421 +#: Dialogs.py:1468 +msgid "Input" +msgstr "输入" + +#: Dialogs.py:122 +msgid "Inputs:" +msgstr "输入:" + +#: plcopen/iec_std.csv:76 +msgid "Insertion (into)" +msgstr "插入" + +#: plcopen/plcopen.py:1234 +#, python-format +msgid "Instance with id %d doesn't exists!" +msgstr "有id的实例 %d 尚不存在!" + +#: PLCOpenEditor.py:559 +#: PLCOpenEditor.py:597 +msgid "Instances" +msgstr "实例" + +#: RessourceEditor.py:394 +msgid "Instances:" +msgstr "实例:" + +#: plcopen/structures.py:231 +msgid "" +"Integral\n" +"The integral function block integrates the value of input XIN over time." +msgstr "" +"积分\n" +"积分功能随着时间推移而集成输入的XIN的值。" + +#: PLCOpenEditor.py:3921 +msgid "Interface" +msgstr "界面" + +#: RessourceEditor.py:79 +msgid "Interval" +msgstr "区间" + +#: PLCControler.py:1640 +msgid "Invalid plcopen element(s)!!!" +msgstr "无效的plcopen元素!!!" + +#: PLCOpenEditor.py:4848 +#: PLCOpenEditor.py:4851 +#, python-format +msgid "Invalid value \"%s\" for debug variable" +msgstr "无效值 \"%s\" 为调试变量" + +#: PLCOpenEditor.py:4142 +#: PLCOpenEditor.py:4145 +#, python-format +msgid "Invalid value \"%s\" for location" +msgstr "因地点而无效\"%s\"" + +#: Viewer.py:214 +#: Viewer.py:217 +#, python-format +msgid "Invalid value \"%s\" for viewer block" +msgstr "无效值 \"%s\" 在视窗块" + +#: PLCOpenEditor.py:3040 +#: PLCOpenEditor.py:3230 +#: PLCOpenEditor.py:3241 +#: PLCOpenEditor.py:3420 +#: PLCOpenEditor.py:3564 +msgid "LD" +msgstr "梯级图" + +#: LDViewer.py:213 +#: LDViewer.py:228 +#, python-format +msgid "Ladder element with id %d is on more than one rung." +msgstr "有id的梯形元素 %d 不止在一个梯级上。" + +#: PLCOpenEditor.py:3339 +#: PLCOpenEditor.py:3502 +#: PLCOpenEditor.py:3646 +msgid "Language" +msgstr "语言" + +#: PLCOpenEditor.py:3054 +msgid "Language (optional):" +msgstr "语言(选填):" + +#: PLCOpenEditor.py:3307 +#: PLCOpenEditor.py:3475 +#: PLCOpenEditor.py:3619 +msgid "Language:" +msgstr "语言:" + +#: Viewer.py:361 +msgid "Left" +msgstr "左" + +#: Dialogs.py:1283 +msgid "Left PowerRail" +msgstr "左电源导轨" + +#: plcopen/iec_std.csv:70 +msgid "Length of string" +msgstr "字符串长度" + +#: plcopen/iec_std.csv:67 +msgid "Less than" +msgstr "小于" + +#: plcopen/iec_std.csv:68 +msgid "Less than or equal to" +msgstr "小于或等于" + +#: PLCOpenEditor.py:638 +msgid "Library" +msgstr "图书馆" + +#: plcopen/iec_std.csv:62 +msgid "Limitation" +msgstr "限制" + +#: PLCOpenEditor.py:3923 +msgid "Local" +msgstr "位置" + +#: PLCOpenEditor.py:3911 +msgid "Location" +msgstr "位置" + +#: plcopen/iec_std.csv:25 +msgid "Logarithm to base 10" +msgstr "底数10的对数" + +#: plcopen/iec_std.csv:60 +msgid "Maximum" +msgstr "最大值" + +#: DataTypeEditor.py:427 +msgid "Maximum:" +msgstr "最大值:" + +#: Viewer.py:370 +msgid "Middle" +msgstr "中间" + +#: plcopen/iec_std.csv:61 +msgid "Minimum" +msgstr "最小值" + +#: DataTypeEditor.py:418 +msgid "Minimum:" +msgstr "最小值:" + +#: PLCOpenEditor.py:3069 +msgid "Miscellaneous" +msgstr "其他" + +#: Dialogs.py:1018 +msgid "Modifier:" +msgstr "改动:" + +#: PLCGenerator.py:665 +#: PLCGenerator.py:864 +#, python-format +msgid "More than one connector found corresponding to \"%s\" continuation in \"%s\" POU" +msgstr "发现不止一个连接器符合 \"%s\" 延续在 \"%s\" POU中" + +#: DataTypeEditor.py:456 +#: DataTypeEditor.py:498 +msgid "Move down" +msgstr "下移" + +#: DataTypeEditor.py:453 +#: DataTypeEditor.py:495 +msgid "Move up" +msgstr "上移" + +#: plcopen/iec_std.csv:63 +msgid "Multiplexer (select 1 of N)" +msgstr "多路器(多选一)" + +#: plcopen/iec_std.csv:37 +msgid "Multiplication" +msgstr "乘法" + +#: PLCOpenEditor.py:3911 +#: PLCOpenEditor.py:3912 +#: RessourceEditor.py:79 +#: RessourceEditor.py:83 +#: DataTypeEditor.py:46 +msgid "Name" +msgstr "名字" + +#: Dialogs.py:118 +#: Dialogs.py:516 +#: Dialogs.py:788 +#: Dialogs.py:1022 +#: Dialogs.py:1451 +msgid "Name:" +msgstr "名字:" + +#: plcopen/iec_std.csv:24 +msgid "Natural logarithm" +msgstr "自然对数" + +#: Viewer.py:393 +#: Dialogs.py:1036 +msgid "Negated" +msgstr "否定" + +#: PLCOpenEditor.py:312 +msgid "New\tCTRL+N" +msgstr "新建\tCTRL+N" + +#: DataTypeEditor.py:447 +#: DataTypeEditor.py:489 +msgid "New item" +msgstr "建立项目" + +#: PLCOpenEditor.py:3916 +msgid "No" +msgstr "否" + +#: Viewer.py:391 +msgid "No Modifier" +msgstr "无改动" + +#: PLCControler.py:2507 +msgid "No PLC project found" +msgstr "未找到PLC项目" + +#: PLCGenerator.py:1225 +#, python-format +msgid "No body defined in \"%s\" POU" +msgstr "在 \"%s\" POU 中没有任何东西被定义" + +#: PLCGenerator.py:684 +#: PLCGenerator.py:873 +#, python-format +msgid "No connector found corresponding to \"%s\" continuation in \"%s\" POU" +msgstr "未发现连接器符合 \"%s\" 连续在 \"%s\" POU中" + +#: PLCOpenEditor.py:2668 +msgid "" +"No documentation available.\n" +"Coming soon." +msgstr "" +"没有文件可用。\n" +"稍候" + +#: plcopen/structures.py:139 +msgid "No output variable found" +msgstr "未找到输出值" + +#: PLCGenerator.py:1223 +#, python-format +msgid "No variable defined in \"%s\" POU" +msgstr "无变量被定义在 \"%s\" POU" + +#: Dialogs.py:1030 +msgid "Normal" +msgstr "正常" + +#: plcopen/iec_std.csv:69 +msgid "Not equal to" +msgstr "不等于" + +#: Dialogs.py:2004 +msgid "Number of sequences:" +msgstr "序列号:" + +#: plcopen/iec_std.csv:22 +msgid "Numerical" +msgstr "数学式" + +#: plcopen/structures.py:219 +msgid "" +"Off-delay timer\n" +"The off-delay timer can be used to delay setting an output false, for fixed period after input goes false." +msgstr "" +"关闭延迟计时器\n" +"关闭延迟计时器可用于延迟设置一个假性输出,固定期限后一个输入变成假。" + +#: plcopen/structures.py:214 +msgid "" +"On-delay timer\n" +"The on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true." +msgstr "" +"开启延迟计时器\n" +"开启延时计时器可用于延迟设置一个真性输出,固定期限后一个输入成为真。" + +#: PLCOpenEditor.py:314 +msgid "Open\tCTRL+O" +msgstr "打开\tCTRL+O" + +#: PLCOpenEditor.py:2996 +msgid "Organization (optional):" +msgstr "组织(选填):" + +#: PLCOpenEditor.py:3922 +#: Dialogs.py:423 +#: Dialogs.py:1473 +msgid "Output" +msgstr "输出" + +#: plcopen/structures.py:241 +msgid "" +"PID\n" +"The PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control." +msgstr "" +"PID\n" +"PID(比例,积分,导数)功能块为闭循环控制提供经典的三阶段控制器。" + +#: PLCOpenEditor.py:1032 +#: PLCOpenEditor.py:1119 +msgid "PLCOpen files (*.xml)|*.xml|All files|*.*" +msgstr "PLCOpen 文件 (*.xml)|*.xml|所有文件|*.*" + +#: PLCOpenEditor.py:485 +#: PLCOpenEditor.py:839 +msgid "PLCOpenEditor" +msgstr "PLCOpen编辑器" + +#: PLCOpenEditor.py:438 +msgid "PLCOpenEditor\tF1" +msgstr "PLCOpen编辑器\tF1" + +#: PLCOpenEditor.py:3335 +msgid "POU Name" +msgstr "POU 名字" + +#: PLCOpenEditor.py:3290 +msgid "POU Name:" +msgstr "POU 名字:" + +#: PLCOpenEditor.py:3337 +msgid "POU Type" +msgstr "POU类型" + +#: PLCOpenEditor.py:3298 +msgid "POU Type:" +msgstr "POU 类型:" + +#: PLCOpenEditor.py:331 +msgid "Page Setup" +msgstr "页面设置" + +#: PLCOpenEditor.py:3012 +msgid "Page Size (optional):" +msgstr "页面大小(选填):" + +#: PLCOpenEditor.py:5064 +#, python-format +msgid "Page: %d" +msgstr "页:%d" + +#: PLCOpenEditor.py:381 +msgid "Paste\tCTRL+V" +msgstr "粘贴\tCTRL+V" + +#: Dialogs.py:1275 +msgid "Pin number:" +msgstr "插脚数:" + +#: Viewer.py:1977 +#: Viewer.py:2268 +#: SFCViewer.py:698 +msgid "Please choose a target" +msgstr "请选择一个目标" + +#: PLCOpenEditor.py:2523 +msgid "Please enter POU name" +msgstr "请输入POU名" + +#: Viewer.py:1802 +#: Viewer.py:1804 +#: Viewer.py:2303 +#: Viewer.py:2305 +msgid "Please enter comment text" +msgstr "请输入注释文本" + +#: PLCOpenEditor.py:2478 +#: PLCOpenEditor.py:3710 +msgid "Please enter configuration name" +msgstr "请输入配置名" + +#: PLCOpenEditor.py:2421 +msgid "Please enter data type name" +msgstr "请输入数据类型名" + +#: PLCOpenEditor.py:2493 +#: PLCOpenEditor.py:3773 +msgid "Please enter resource name" +msgstr "请输入源名" + +#: SFCViewer.py:362 +#: SFCViewer.py:384 +#: SFCViewer.py:726 +msgid "Please enter step name" +msgstr "请输入步骤名称" + +#: PLCOpenEditor.py:3180 +msgid "Please enter text" +msgstr "请输入文本" + +#: GraphicViewer.py:117 +msgid "Position:" +msgstr "定位:" + +#: Dialogs.py:1267 +msgid "Power Rail Properties" +msgstr "电源导轨属性" + +#: PLCOpenEditor.py:333 +msgid "Preview" +msgstr "打印预览" + +#: Dialogs.py:134 +#: Dialogs.py:520 +#: Dialogs.py:792 +#: Dialogs.py:1026 +#: Dialogs.py:1279 +#: Dialogs.py:1459 +#: Dialogs.py:1702 +#: Dialogs.py:2013 +msgid "Preview:" +msgstr "预览:" + +#: PLCOpenEditor.py:335 +msgid "Print" +msgstr "打印" + +#: PLCOpenEditor.py:1151 +msgid "Print preview" +msgstr "打印预览" + +#: RessourceEditor.py:79 +msgid "Priority" +msgstr "优先" + +#: Dialogs.py:1706 +msgid "Priority:" +msgstr "优先:" + +#: PLCOpenEditor.py:2940 +msgid "Product Name (required):" +msgstr "产品名字(必填):" + +#: PLCOpenEditor.py:2956 +msgid "Product Release (optional):" +msgstr "产品发布(选填):" + +#: PLCOpenEditor.py:2948 +msgid "Product Version (required):" +msgstr "产品版本(必填):" + +#: PLCOpenEditor.py:392 +#: PLCOpenEditor.py:1874 +msgid "Program" +msgstr "程序" + +#: PLCOpenEditor.py:1096 +msgid "Program was successfully generated!" +msgstr "该编程成功生成文件!" + +#: PLCControler.py:83 +msgid "Programs" +msgstr "程序" + +#: Viewer.py:223 +msgid "Programs can't be used by other POUs!" +msgstr "程序不能被其它POU使用!" + +#: PLCOpenEditor.py:497 +#: PLCOpenEditor.py:2963 +msgid "Project" +msgstr "项目" + +#: PLCOpenEditor.py:2924 +msgid "Project Name (required):" +msgstr "项目名称(必填):" + +#: PLCOpenEditor.py:2932 +msgid "Project Version (optional):" +msgstr "项目版本(选填):" + +#: PLCOpenEditor.py:2910 +msgid "Project properties" +msgstr "项目属性" + +#: PLCOpenEditor.py:339 +#: PLCControler.py:84 +msgid "Properties" +msgstr "属性" + +#: plcopen/structures.py:209 +msgid "" +"Pulse timer\n" +"The pulse timer can be used to generate output pulses of a given time duration." +msgstr "" +"脉冲计时器\n" +"脉冲计时器可用于产生给定时间限制的输出的脉冲。" + +#: Dialogs.py:2101 +msgid "Qualifier" +msgstr "合格验证" + +#: PLCOpenEditor.py:343 +msgid "Quit\tCTRL+Q" +msgstr "退出\tCTRL+Q" + +#: plcopen/structures.py:174 +msgid "" +"RS bistable\n" +"The RS bistable is a latch where the Reset dominates." +msgstr "" +"RS双稳\n" +"RS双稳是一个重置支配的锁存器。" + +#: plcopen/structures.py:246 +msgid "" +"Ramp\n" +"The RAMP function block is modelled on example given in the standard but with the addition of a 'Holdback' feature." +msgstr "" +"匝道\n" +"匝道功能块模拟给定标准的例子,但增加了一个' 阻碍 '功能。" + +#: GraphicViewer.py:106 +msgid "Range:" +msgstr "范围:" + +#: PLCOpenEditor.py:374 +msgid "Redo\tCTRL+Y" +msgstr "重做\tCTRL+Y" + +#: Dialogs.py:1710 +#: Dialogs.py:1787 +msgid "Reference" +msgstr "参照" + +#: PLCOpenEditor.py:420 +msgid "Refresh\tF5" +msgstr "重新载入\tF5" + +#: plcopen/iec_std.csv:48 +msgid "Remainder (modulo)" +msgstr "余数(模)" + +#: PLCOpenEditor.py:1878 +msgid "Rename" +msgstr "重命名" + +#: plcopen/iec_std.csv:78 +msgid "Replacement (within)" +msgstr "替换" + +#: Dialogs.py:1046 +msgid "Reset" +msgstr "重置" + +#: Viewer.py:412 +msgid "Reset Execution Order" +msgstr "重置执行命令" + +#: PLCControler.py:84 +msgid "Resources" +msgstr "资源" + +#: PLCOpenEditor.py:3911 +#: PLCOpenEditor.py:3912 +msgid "Retain" +msgstr "保持" + +#: PLCOpenEditor.py:4292 +msgid "Return Type:" +msgstr "返回类型:" + +#: Viewer.py:365 +msgid "Right" +msgstr "右" + +#: Dialogs.py:1289 +msgid "Right PowerRail" +msgstr "右电源导轨" + +#: Viewer.py:395 +#: Dialogs.py:1051 +msgid "Rising Edge" +msgstr "上升沿" + +#: plcopen/structures.py:184 +msgid "" +"Rising edge detector\n" +"The output produces a single pulse when a rising edge is detected." +msgstr "" +"上升沿检测\n" +"当上升沿被检测到时,输出便产生一个单脉冲。" + +#: plcopen/iec_std.csv:54 +msgid "Rotate left" +msgstr "循环左移" + +#: plcopen/iec_std.csv:53 +msgid "Rotate right" +msgstr "循环右移" + +#: plcopen/iec_std.csv:17 +msgid "Rounding up/down" +msgstr "四舍五入" + +#: PLCOpenEditor.py:3040 +#: PLCOpenEditor.py:3241 +msgid "SFC" +msgstr "顺序功能流程图" + +#: plcopen/structures.py:169 +msgid "" +"SR bistable\n" +"The SR bistable is a latch where the Set dominates." +msgstr "" +"SR双稳态\n" +"SR双稳态是一个设置支配的锁存器。" + +#: PLCOpenEditor.py:3230 +#: PLCOpenEditor.py:3241 +#: PLCOpenEditor.py:3420 +#: PLCOpenEditor.py:3564 +msgid "ST" +msgstr "结构化文字" + +#: PLCOpenEditor.py:1083 +msgid "ST files (*.st)|*.st|All files|*.*" +msgstr "ST 文件 (*.st)|*.st|所有文件|*.*" + +#: PLCOpenEditor.py:323 +msgid "Save\tCTRL+S" +msgstr "保存\tCTRL+S" + +#: PLCOpenEditor.py:326 +msgid "Save As...\tCTRL+SHIFT+S" +msgstr "另存为...\tCTRL+SHIFT+S" + +#: PLCOpenEditor.py:3032 +msgid "Scaling:" +msgstr "比例:" + +#: PLCOpenEditor.py:396 +msgid "Select All\tCTRL+A" +msgstr "全部选中\tCTRL+A" + +#: PLCOpenEditor.py:4167 +msgid "Select a variable class:" +msgstr "选择一个变量种类:" + +#: PLCOpenEditor.py:604 +#: PLCOpenEditor.py:616 +msgid "Select an object" +msgstr "选择一个对象" + +#: plcopen/iec_std.csv:59 +msgid "Selection" +msgstr "选择" + +#: Dialogs.py:1986 +msgid "Selection Convergence" +msgstr "选择收敛" + +#: Dialogs.py:1980 +msgid "Selection Divergence" +msgstr "选择发散" + +#: plcopen/structures.py:179 +msgid "" +"Semaphore\n" +"The semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources." +msgstr "" +"信号\n" +"信号提供一个机制,使软件元素相互排斥的进入一定资源。" + +#: Dialogs.py:1041 +msgid "Set" +msgstr "设置" + +#: plcopen/iec_std.csv:51 +msgid "Shift left" +msgstr "左移" + +#: plcopen/iec_std.csv:52 +msgid "Shift right" +msgstr "右移" + +#: Dialogs.py:1998 +msgid "Simultaneous Convergence" +msgstr "同步收敛" + +#: Dialogs.py:1992 +msgid "Simultaneous Divergence" +msgstr "同步发散" + +#: plcopen/iec_std.csv:27 +msgid "Sine" +msgstr "正弦" + +#: RessourceEditor.py:79 +msgid "Single" +msgstr "单" + +#: plcopen/iec_std.csv:23 +msgid "Square root (base 2)" +msgstr "平方根(底数2)" + +#: plcopen/structures.py:165 +msgid "Standard function blocks" +msgstr "标准功能类型" + +#: DataTypeEditor.py:238 +msgid "Structure" +msgstr "结构的" + +#: DataTypeEditor.py:238 +msgid "Subrange" +msgstr "子集的" + +#: plcopen/iec_std.csv:39 +msgid "Subtraction" +msgstr "减法" + +#: plcopen/iec_std.csv:29 +msgid "Tangent" +msgstr "正切" + +#: RessourceEditor.py:83 +msgid "Task" +msgstr "任务 " + +#: RessourceEditor.py:358 +msgid "Tasks:" +msgstr "任务:" + +#: PLCOpenEditor.py:3924 +msgid "Temp" +msgstr "缓冲" + +#: LDViewer.py:850 +msgid "The group of block must be coherent!" +msgstr "块的组必须是连贯的!" + +#: PLCOpenEditor.py:962 +msgid "There are changes, do you want to save?" +msgstr "文件已被改动。你希望保存吗?" + +#: PLCOpenEditor.py:1170 +msgid "" +"There was a problem printing.\n" +"Perhaps your current printer is not set correctly?" +msgstr "" +"打印出现问题。\n" +"请检查你当前打印机设置。" + +#: LDViewer.py:859 +msgid "This option isn't available yet!" +msgstr "该选项尚未可用!" + +#: GraphicViewer.py:181 +msgid "Tick" +msgstr "" + +#: plcopen/iec_std.csv:34 +msgid "Time addition" +msgstr "时间加法" + +#: plcopen/iec_std.csv:75 +msgid "Time concatenation" +msgstr "时间级联" + +#: plcopen/iec_std.csv:47 +msgid "Time division" +msgstr "时间除法" + +#: plcopen/iec_std.csv:38 +msgid "Time multiplication" +msgstr "时间乘法" + +#: plcopen/iec_std.csv:40 +msgid "Time subtraction" +msgstr "时间减法" + +#: plcopen/iec_std.csv:35 +msgid "Time-of-day addition" +msgstr "日期时间加法" + +#: plcopen/iec_std.csv:42 +#: plcopen/iec_std.csv:43 +msgid "Time-of-day subtraction" +msgstr "日期时间减法" + +#: PLCOpenEditor.py:608 +msgid "Toolbar" +msgstr "工具条" + +#: Viewer.py:368 +msgid "Top" +msgstr "顶部" + +#: PLCOpenEditor.py:3500 +msgid "Transition Name" +msgstr "跃迁名字" + +#: PLCOpenEditor.py:3467 +msgid "Transition Name:" +msgstr "跃迁名字:" + +#: PLCGenerator.py:1205 +#, python-format +msgid "Transition with content \"%s\" not connected to a next step in \"%s\" POU" +msgstr "跃迁的内容 \"%s\" 与后一步骤没有关联在 \"%s\" 中" + +#: PLCGenerator.py:1196 +#, python-format +msgid "Transition with content \"%s\" not connected to a previous step in \"%s\" POU" +msgstr "跃迁的内容 \"%s\" 与前一步骤没有关联在 \"%s\" 中" + +#: plcopen/plcopen.py:990 +#, python-format +msgid "Transition with name %s doesn't exists!" +msgstr "已命名的跃迁 %s 尚不存在!" + +#: PLCControler.py:83 +msgid "Transitions" +msgstr "跃迁" + +#: PLCOpenEditor.py:3911 +#: PLCOpenEditor.py:3912 +#: RessourceEditor.py:83 +#: Dialogs.py:2101 +#: DataTypeEditor.py:46 +msgid "Type" +msgstr "类型" + +#: plcopen/iec_std.csv:16 +msgid "Type conversion" +msgstr "类型转换" + +#: DataTypeEditor.py:357 +msgid "Type infos:" +msgstr "类型信息:" + +#: Dialogs.py:114 +#: Dialogs.py:784 +#: Dialogs.py:1271 +#: Dialogs.py:1698 +#: Dialogs.py:1976 +msgid "Type:" +msgstr "类型:" + +#: PLCOpenEditor.py:560 +#: PLCOpenEditor.py:596 +msgid "Types" +msgstr "类型" + +#: PLCGenerator.py:232 +#, python-format +msgid "Undefined pou type \"%s\"" +msgstr "未定义的pou类型" + +#: PLCOpenEditor.py:372 +msgid "Undo\tCTRL+Z" +msgstr "撤消\tCTRL+Z" + +#: Viewer.py:289 +#, python-format +msgid "Unknown variable \"%s\" for this POU!" +msgstr "未知的变量 \"%s\" 这个POU!" + +#: PLCControler.py:293 +#, python-format +msgid "Unnamed%d" +msgstr "未命名%d" + +#: PLCOpenEditor.py:4163 +#, python-format +msgid "Unrecognized data size \"%s\"" +msgstr "无法识别数据大小 \"%s\"" + +#: plcopen/structures.py:194 +msgid "" +"Up-counter\n" +"The up-counter can be used to signal when a count has reached a maximum value." +msgstr "" +"顺计时器\n" +"当计数到达最大值时,顺计时器给出信号。" + +#: plcopen/structures.py:204 +msgid "" +"Up-down counter\n" +"The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other." +msgstr "" +"顺逆计数器\n" +"顺逆计数器有两个输入:CU和CD。可用于顺计时和倒计时的输入。" + +#: PLCOpenEditor.py:4561 +#: DataTypeEditor.py:800 +msgid "User Data Types" +msgstr "用户数据类型" + +#: PLCControler.py:82 +msgid "User-defined POUs" +msgstr "用户 - 定义POUs" + +#: PLCOpenEditor.py:4678 +#: Dialogs.py:2101 +msgid "Value" +msgstr "值" + +#: GraphicViewer.py:181 +msgid "Values" +msgstr "值" + +#: DataTypeEditor.py:442 +msgid "Values:" +msgstr "值:" + +#: PLCOpenEditor.py:4678 +#: Dialogs.py:2105 +msgid "Variable" +msgstr "变量" + +#: Dialogs.py:500 +msgid "Variable Properties" +msgstr "变量属性" + +#: PLCOpenEditor.py:4167 +msgid "Variable class" +msgstr "变量种类" + +#: Viewer.py:291 +#: TextViewer.py:224 +msgid "Variable don't belong to this POU!" +msgstr "变量不属于这个POU!" + +#: PLCOpenEditor.py:573 +#: PLCOpenEditor.py:624 +#: PLCOpenEditor.py:3923 +msgid "Variables" +msgstr "变量" + +#: PLCOpenEditor.py:3365 +#: PLCOpenEditor.py:3743 +#: PLCOpenEditor.py:3806 +#: LDViewer.py:859 +msgid "Warning" +msgstr "警告" + +#: PLCOpenEditor.py:3016 +msgid "Width:" +msgstr "宽度:" + +#: PLCOpenEditor.py:2759 +msgid "X Scale:" +msgstr "X 坐标:" + +#: PLCOpenEditor.py:2767 +msgid "Y Scale:" +msgstr "Y 坐标:" + +#: PLCOpenEditor.py:3916 +msgid "Yes" +msgstr "是" + +#: LDViewer.py:854 +msgid "You must select the block or group of blocks around which a branch should be added!" +msgstr "你必须选择一个块或块的组围绕着需被添加的分支!" + +#: LDViewer.py:628 +msgid "You must select the wire where a contact should be added!" +msgstr "你必须选择一条线连接需被添加的接触点!" + +#: PLCOpenEditor.py:3195 +#: PLCOpenEditor.py:3727 +#: PLCOpenEditor.py:3790 +#: Dialogs.py:1521 +#: Dialogs.py:2505 +#: Dialogs.py:2572 +msgid "You must type a name!" +msgstr "你必须输入一个名字!" + +#: PLCOpenEditor.py:426 +msgid "Zoom" +msgstr "显示比例" + +#: PLCOpenEditor.py:1092 +#, python-format +msgid "error: %s\n" +msgstr "错误:%s\n" + +#: PLCOpenEditor.py:5096 +#: PLCOpenEditor.py:5098 +msgid "file : " +msgstr "文件:" + +#: PLCOpenEditor.py:3236 +msgid "function" +msgstr "功能" + +#: PLCOpenEditor.py:5099 +msgid "function : " +msgstr "功能:" + +#: PLCOpenEditor.py:3236 +msgid "functionBlock" +msgstr "功能块" + +#: PLCOpenEditor.py:5099 +msgid "line : " +msgstr "在线:" + +#: PLCOpenEditor.py:3236 +msgid "program" +msgstr "程序" + +#: plcopen/iec_std.csv:73 +msgid "string from the middle" +msgstr "从中间取字符串" + +#: plcopen/iec_std.csv:71 +msgid "string left of" +msgstr "从左取字符串" + +#: plcopen/iec_std.csv:72 +msgid "string right of" +msgstr "从右取字符串" + +#: PLCOpenEditor.py:1090 +#, python-format +msgid "warning: %s\n" +msgstr "警告:%s\n" + +#~ msgid "\n" +#~ msgstr "\n" +#~ msgid "A pou with \"%s\" for name exists!" +#~ msgstr "一个以\"%s\"命名的的编程组织单元已经存在!" +#~ msgid "" +#~ "A variable is defined with \"%s\" as name. It can generate a conflict. Do " +#~ "you wish to continue?" +#~ msgstr "一个变量被定义 \"%s\" 为名称。它会导致冲突。你希望继续吗?" +#~ msgid "A variable with \"%s\" as name exists in this pou!" +#~ msgstr "一个以\"%s\"命名的变量在这个编程组织单元中已经存在!" +#~ msgid "A variable with \"%s\" as name exists!" +#~ msgstr "一个以\"%s\"命名的变量已经存在!" +#~ msgid "Create A New POU From" +#~ msgstr "新建一个POU从" +#~ msgid "Create a new project" +#~ msgstr "新建一个项目" +#~ msgid "Printing" +#~ msgstr "打印" +#~ msgid "" +#~ "Ratio monitor\n" +#~ "The ratio_monitor function block checks that one process value PV1 is " +#~ "always a given ratio (defined by input RATIO) of a second process value " +#~ "PV2." +#~ msgstr "" +#~ "比监视器\n" +#~ "比监视器功能块检查一个步骤值PV1总是被比较于(被输入的比定义)第二个步骤" +#~ "值。" +#~ msgid "" +#~ "Real time clock\n" +#~ "The real time clock has many uses including time stamping, setting dates " +#~ "and times of day in batch reports, in alarm messages and so on." +#~ msgstr "" +#~ "实时时钟\n" +#~ "实时时钟有很多用途,包括时间冲压,设置日期和批量报告日期时间,报警信息等。" +#~ msgid "ValueError" +#~ msgstr "值错误" +#~ msgid "You can't paste the element in buffer here!" +#~ msgstr "你不能在这缓冲区中粘贴元素!" + diff -r d07815f10ca8 -r 323c8d76f6f2 i18n/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i18n/README Fri Aug 07 15:49:10 2009 +0200 @@ -0,0 +1,8 @@ +To generate message.pot file: + + python mki18n.py -p --domain=PLCOpenEditor + +To generate .mo files for all languages: + + python mki18n.py -m --moTarget=../locale --domain=PLCOpenEditor + \ No newline at end of file diff -r d07815f10ca8 -r 323c8d76f6f2 i18n/app.fil --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i18n/app.fil Fri Aug 07 15:49:10 2009 +0200 @@ -0,0 +1,14 @@ +../PLCOpenEditor.py +../PLCGenerator.py +../PLCControler.py +../RessourceEditor.py +../Viewer.py +../TextViewer.py +../SFCViewer.py +../LDViewer.py +../GraphicViewer.py +../Dialogs.py +../DataTypeEditor.py +../plcopen/iec_std.csv +../plcopen/plcopen.py +../plcopen/structures.py diff -r d07815f10ca8 -r 323c8d76f6f2 i18n/messages.pot --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i18n/messages.pot Fri Aug 07 15:49:10 2009 +0200 @@ -0,0 +1,2000 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-07-24 16:55+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../PLCOpenEditor.py:5044 +msgid "" +"\n" +"An error happens.\n" +"\n" +"Click on OK for saving an error report.\n" +"\n" +"Please contact LOLITech at:\n" +"+33 (0)3 29 57 60 42\n" +"bugs_PLCOpenEditor@lolitech.fr\n" +"\n" +"\n" +"Error:\n" +msgstr "" + +#: ../PLCOpenEditor.py:3860 +msgid " External" +msgstr "" + +#: ../PLCOpenEditor.py:3859 +msgid " InOut" +msgstr "" + +#: ../PLCOpenEditor.py:3859 +msgid " Input" +msgstr "" + +#: ../PLCOpenEditor.py:3860 +msgid " Local" +msgstr "" + +#: ../PLCOpenEditor.py:3859 +msgid " Output" +msgstr "" + +#: ../PLCOpenEditor.py:3861 +msgid " Temp" +msgstr "" + +#: ../PLCOpenEditor.py:840 +msgid " (Debug)" +msgstr "" + +#: ../PLCOpenEditor.py:5056 +msgid " : " +msgstr "" + +#: ../PLCOpenEditor.py:3283 ../PLCOpenEditor.py:3446 ../PLCOpenEditor.py:3590 +#: ../Dialogs.py:1800 +#, python-format +msgid " and %s" +msgstr "" + +#: ../plcopen/plcopen.py:782 +#, python-format +msgid "\"%s\" Data Type doesn't exist !!!" +msgstr "" + +#: ../plcopen/plcopen.py:800 +#, python-format +msgid "\"%s\" POU already exists !!!" +msgstr "" + +#: ../plcopen/plcopen.py:821 +#, python-format +msgid "\"%s\" POU doesn't exist !!!" +msgstr "" + +#: ../Viewer.py:225 +#, python-format +msgid "\"%s\" can't use itself!" +msgstr "" + +#: ../PLCOpenEditor.py:1617 ../PLCOpenEditor.py:1637 +#, python-format +msgid "\"%s\" config already exists!" +msgstr "" + +#: ../plcopen/plcopen.py:256 +#, python-format +msgid "\"%s\" configuration already exists !!!" +msgstr "" + +#: ../PLCOpenEditor.py:1571 ../PLCOpenEditor.py:3145 +#, python-format +msgid "\"%s\" data type already exists!" +msgstr "" + +#: ../PLCControler.py:1663 +#, python-format +msgid "\"%s\" element can't be paste here!!!" +msgstr "" + +#: ../PLCOpenEditor.py:3465 ../PLCOpenEditor.py:3609 ../Viewer.py:248 +#: ../Dialogs.py:261 ../Dialogs.py:898 +#, python-format +msgid "\"%s\" element for this pou already exists!" +msgstr "" + +#: ../plcopen/structures.py:97 +#, python-format +msgid "\"%s\" function cancelled in \"%s\" POU: No input connected" +msgstr "" + +#: ../PLCOpenEditor.py:1562 ../PLCOpenEditor.py:3141 ../PLCOpenEditor.py:3294 +#: ../PLCOpenEditor.py:3457 ../PLCOpenEditor.py:3601 ../PLCOpenEditor.py:3672 +#: ../PLCOpenEditor.py:3735 ../PLCOpenEditor.py:4449 ../Dialogs.py:253 +#: ../Dialogs.py:652 ../Dialogs.py:890 ../Dialogs.py:1533 ../Dialogs.py:2516 +#: ../Dialogs.py:2583 ../DataTypeEditor.py:702 ../DataTypeEditor.py:762 +#, python-format +msgid "\"%s\" is a keyword. It can't be used!" +msgstr "" + +#: ../Viewer.py:231 +#, python-format +msgid "\"%s\" is already used by \"%s\"!" +msgstr "" + +#: ../plcopen/plcopen.py:2120 +#, python-format +msgid "\"%s\" is an invalid value!" +msgstr "" + +#: ../PLCOpenEditor.py:1097 ../PLCOpenEditor.py:1126 +#, python-format +msgid "\"%s\" is not a valid folder!" +msgstr "" + +#: ../PLCOpenEditor.py:1560 ../PLCOpenEditor.py:3137 ../PLCOpenEditor.py:3290 +#: ../PLCOpenEditor.py:3453 ../PLCOpenEditor.py:3597 ../PLCOpenEditor.py:3668 +#: ../PLCOpenEditor.py:3731 ../PLCOpenEditor.py:4444 ../Dialogs.py:249 +#: ../Dialogs.py:886 ../Dialogs.py:1529 ../Dialogs.py:2512 ../Dialogs.py:2579 +#: ../DataTypeEditor.py:757 +#, python-format +msgid "\"%s\" is not a valid identifier!" +msgstr "" + +#: ../PLCOpenEditor.py:283 ../PLCOpenEditor.py:2491 ../PLCOpenEditor.py:2520 +#, python-format +msgid "\"%s\" is used by one or more POUs. It can't be removed!" +msgstr "" + +#: ../PLCOpenEditor.py:1580 ../PLCOpenEditor.py:3298 ../Viewer.py:246 +#: ../Dialogs.py:257 ../Dialogs.py:894 +#, python-format +msgid "\"%s\" pou already exists!" +msgstr "" + +#: ../plcopen/plcopen.py:287 +#, python-format +msgid "\"%s\" resource already exists in \"%s\" configuration !!!" +msgstr "" + +#: ../plcopen/plcopen.py:303 +#, python-format +msgid "\"%s\" resource doesn't exist in \"%s\" configuration !!!" +msgstr "" + +#: ../Dialogs.py:1545 ../Dialogs.py:2528 +#, python-format +msgid "\"%s\" step already exists!" +msgstr "" + +#: ../DataTypeEditor.py:697 +#, python-format +msgid "\"%s\" value already defined!" +msgstr "" + +#: ../DataTypeEditor.py:899 +#, python-format +msgid "\"%s\" value isn't a valid array dimension!" +msgstr "" + +#: ../DataTypeEditor.py:906 +#, python-format +msgid "" +"\"%s\" value isn't a valid array dimension!\n" +"Right value must be greater than left value." +msgstr "" + +#: ../GraphicViewer.py:181 +#, python-format +msgid "%s Graphics" +msgstr "" + +#: ../plcopen/plcopen.py:1276 ../plcopen/plcopen.py:1286 +#: ../plcopen/plcopen.py:1296 ../plcopen/plcopen.py:1306 +#: ../plcopen/plcopen.py:1315 +#, python-format +msgid "%s body don't have instances!" +msgstr "" + +#: ../plcopen/plcopen.py:1338 ../plcopen/plcopen.py:1345 +#, python-format +msgid "%s body don't have text!" +msgstr "" + +#: ../PLCOpenEditor.py:5032 ../PLCOpenEditor.py:5034 ../PLCOpenEditor.py:5035 +msgid ", " +msgstr "" + +#: ../PLCOpenEditor.py:3285 ../PLCOpenEditor.py:3448 ../PLCOpenEditor.py:3592 +#: ../Dialogs.py:1802 +#, python-format +msgid ", %s" +msgstr "" + +#: ../PLCOpenEditor.py:5030 +msgid ". " +msgstr "" + +#: ../DataTypeEditor.py:772 +#, python-format +msgid "A element with \"%s\" as name exists in this structure!" +msgstr "" + +#: ../PLCOpenEditor.py:1583 ../PLCOpenEditor.py:1625 ../PLCOpenEditor.py:1645 +#: ../PLCOpenEditor.py:3302 ../PLCOpenEditor.py:3680 ../PLCOpenEditor.py:3743 +#, python-format +msgid "A pou has an element with \"%s\" as name. It can generate a conflict. Do you wish to continue?" +msgstr "" + +#: ../PLCOpenEditor.py:1620 ../PLCOpenEditor.py:1640 +#, python-format +msgid "A pou is defined with \"%s\" as name. It can generate a conflict. Do you wish to continue?" +msgstr "" + +#: ../PLCOpenEditor.py:1596 ../PLCOpenEditor.py:1607 ../PLCOpenEditor.py:3461 +#: ../PLCOpenEditor.py:3605 ../PLCOpenEditor.py:3676 ../PLCOpenEditor.py:3739 +#: ../PLCOpenEditor.py:4454 ../Dialogs.py:1537 ../Dialogs.py:2520 +#: ../Dialogs.py:2587 +#, python-format +msgid "A pou with \"%s\" as name exists!" +msgstr "" + +#: ../PLCOpenEditor.py:1598 ../PLCOpenEditor.py:1609 ../PLCOpenEditor.py:4459 +#: ../Dialogs.py:1541 ../Dialogs.py:2524 +#, python-format +msgid "A variable with \"%s\" as name already exists in this pou!" +msgstr "" + +#: ../PLCOpenEditor.py:445 +msgid "About" +msgstr "" + +#: ../PLCOpenEditor.py:2614 +msgid "About PLCOpenEditor" +msgstr "" + +#: ../plcopen/iec_std.csv:22 +msgid "Absolute number" +msgstr "" + +#: ../Dialogs.py:1482 ../Dialogs.py:2109 +msgid "Action" +msgstr "" + +#: ../PLCOpenEditor.py:3581 +msgid "Action Name" +msgstr "" + +#: ../PLCOpenEditor.py:3548 +msgid "Action Name:" +msgstr "" + +#: ../plcopen/plcopen.py:1073 +#, python-format +msgid "Action with name %s doesn't exists!" +msgstr "" + +#: ../PLCControler.py:83 +msgid "Actions" +msgstr "" + +#: ../Dialogs.py:2332 +msgid "Actions:" +msgstr "" + +#: ../PLCOpenEditor.py:4244 ../Dialogs.py:2346 ../DataTypeEditor.py:539 +msgid "Add" +msgstr "" + +#: ../PLCOpenEditor.py:1800 ../PLCOpenEditor.py:1873 +msgid "Add Action" +msgstr "" + +#: ../PLCOpenEditor.py:1856 +msgid "Add Configuration" +msgstr "" + +#: ../PLCOpenEditor.py:1844 +msgid "Add DataType" +msgstr "" + +#: ../Viewer.py:402 +msgid "Add Divergence Branch" +msgstr "" + +#: ../PLCOpenEditor.py:384 +msgid "Add Element" +msgstr "" + +#: ../RessourceEditor.py:409 +msgid "Add Instance" +msgstr "" + +#: ../PLCOpenEditor.py:1850 +msgid "Add Pou" +msgstr "" + +#: ../PLCOpenEditor.py:1827 ../PLCOpenEditor.py:1884 +msgid "Add Resource" +msgstr "" + +#: ../RessourceEditor.py:373 +msgid "Add Task" +msgstr "" + +#: ../PLCOpenEditor.py:1797 ../PLCOpenEditor.py:1862 +msgid "Add Transition" +msgstr "" + +#: ../Viewer.py:397 +msgid "Add Wire Segment" +msgstr "" + +#: ../PLCOpenEditor.py:2359 +msgid "Add a new data type" +msgstr "" + +#: ../SFCViewer.py:362 +msgid "Add a new initial step" +msgstr "" + +#: ../Viewer.py:1971 ../SFCViewer.py:698 +msgid "Add a new jump" +msgstr "" + +#: ../SFCViewer.py:384 +msgid "Add a new step" +msgstr "" + +#: ../PLCOpenEditor.py:2416 +msgid "Add new configuration" +msgstr "" + +#: ../PLCOpenEditor.py:2431 +msgid "Add new resource" +msgstr "" + +#: ../plcopen/iec_std.csv:33 +msgid "Addition" +msgstr "" + +#: ../plcopen/structures.py:222 +msgid "Additionnal function blocks" +msgstr "" + +#: ../Viewer.py:411 +msgid "Alignment" +msgstr "" + +#: ../PLCOpenEditor.py:3858 +msgid "All" +msgstr "" + +#: ../plcopen/iec_std.csv:31 +msgid "Arc cosine" +msgstr "" + +#: ../plcopen/iec_std.csv:30 +msgid "Arc sine" +msgstr "" + +#: ../plcopen/iec_std.csv:32 +msgid "Arc tangent" +msgstr "" + +#: ../plcopen/iec_std.csv:33 +msgid "Arithmetic" +msgstr "" + +#: ../DataTypeEditor.py:236 +msgid "Array" +msgstr "" + +#: ../plcopen/iec_std.csv:50 +msgid "Assignment" +msgstr "" + +#: ../Dialogs.py:648 +msgid "At least a variable or an expression must be selected!" +msgstr "" + +#: ../PLCOpenEditor.py:2941 +msgid "Author" +msgstr "" + +#: ../PLCOpenEditor.py:2926 +msgid "Author Name (optional):" +msgstr "" + +#: ../DataTypeEditor.py:379 ../DataTypeEditor.py:403 ../DataTypeEditor.py:478 +msgid "Base Type:" +msgstr "" + +#: ../PLCOpenEditor.py:4491 ../DataTypeEditor.py:798 +msgid "Base Types" +msgstr "" + +#: ../plcopen/iec_std.csv:59 +msgid "Binary selection (1 of 2)" +msgstr "" + +#: ../plcopen/iec_std.csv:51 +msgid "Bit-shift" +msgstr "" + +#: ../plcopen/iec_std.csv:55 +msgid "Bitwise" +msgstr "" + +#: ../plcopen/iec_std.csv:55 +msgid "Bitwise AND" +msgstr "" + +#: ../plcopen/iec_std.csv:56 +msgid "Bitwise OR" +msgstr "" + +#: ../plcopen/iec_std.csv:57 +msgid "Bitwise XOR" +msgstr "" + +#: ../plcopen/iec_std.csv:58 +msgid "Bitwise inverting" +msgstr "" + +#: ../Dialogs.py:114 +msgid "Block Properties" +msgstr "" + +#: ../PLCOpenEditor.py:2077 ../Dialogs.py:269 +msgid "Block Types" +msgstr "" + +#: ../Viewer.py:369 +msgid "Bottom" +msgstr "" + +#: ../PLCOpenEditor.py:2031 +msgid "CSV Log" +msgstr "" + +#: ../PLCOpenEditor.py:4072 +msgid "Can affect a location only to local or global variables" +msgstr "" + +#: ../plcopen/plcopen.py:1218 ../plcopen/plcopen.py:1232 +#: ../plcopen/plcopen.py:1253 ../plcopen/plcopen.py:1269 +msgid "Can only generate execution order on FBD networks!" +msgstr "" + +#: ../PLCOpenEditor.py:4070 +msgid "Can't affect a location to a function block instance" +msgstr "" + +#: ../PLCOpenEditor.py:1092 +#, python-format +msgid "Can't generate program to file %s!" +msgstr "" + +#: ../PLCOpenEditor.py:1124 +#, python-format +msgid "Can't save project to file %s!" +msgstr "" + +#: ../Viewer.py:360 +msgid "Center" +msgstr "" + +#: ../PLCOpenEditor.py:1816 +msgid "Change POU Type To" +msgstr "" + +#: ../plcopen/iec_std.csv:70 +msgid "Character string" +msgstr "" + +#: ../PLCOpenEditor.py:1031 ../PLCOpenEditor.py:1082 ../PLCOpenEditor.py:1118 +msgid "Choose a file" +msgstr "" + +#: ../PLCOpenEditor.py:3848 ../PLCOpenEditor.py:3849 +msgid "Class" +msgstr "" + +#: ../PLCOpenEditor.py:4236 +msgid "Class Filter:" +msgstr "" + +#: ../Dialogs.py:508 +msgid "Class:" +msgstr "" + +#: ../PLCOpenEditor.py:423 +msgid "Clear Errors\tCTRL+K" +msgstr "" + +#: ../Viewer.py:407 +msgid "Clear Execution Order" +msgstr "" + +#: ../PLCOpenEditor.py:346 +msgid "Close\tCTRL+Q" +msgstr "" + +#: ../PLCOpenEditor.py:961 +msgid "Close Application" +msgstr "" + +#: ../PLCOpenEditor.py:319 +msgid "Close Project" +msgstr "" + +#: ../PLCOpenEditor.py:316 +msgid "Close Tab\tCTRL+W" +msgstr "" + +#: ../LDViewer.py:478 +msgid "Comment" +msgstr "" + +#: ../PLCOpenEditor.py:2910 +msgid "Company Name (required):" +msgstr "" + +#: ../PLCOpenEditor.py:2918 +msgid "Company URL (optional):" +msgstr "" + +#: ../plcopen/iec_std.csv:64 +msgid "Comparison" +msgstr "" + +#: ../plcopen/iec_std.csv:74 +msgid "Concatenation" +msgstr "" + +#: ../PLCOpenEditor.py:394 +msgid "Configuration" +msgstr "" + +#: ../PLCControler.py:84 +msgid "Configurations" +msgstr "" + +#: ../Dialogs.py:1737 +msgid "Connection" +msgstr "" + +#: ../Dialogs.py:784 +msgid "Connection Properties" +msgstr "" + +#: ../Dialogs.py:800 +msgid "Connector" +msgstr "" + +#: ../Dialogs.py:1459 +msgid "Connectors:" +msgstr "" + +#: ../PLCOpenEditor.py:3848 ../PLCOpenEditor.py:3849 +msgid "Constant" +msgstr "" + +#: ../PLCOpenEditor.py:3000 +msgid "Content Description (optional):" +msgstr "" + +#: ../Dialogs.py:806 +msgid "Continuation" +msgstr "" + +#: ../plcopen/iec_std.csv:18 +msgid "Conversion from BCD" +msgstr "" + +#: ../plcopen/iec_std.csv:19 +msgid "Conversion to BCD" +msgstr "" + +#: ../plcopen/iec_std.csv:21 +msgid "Conversion to date" +msgstr "" + +#: ../plcopen/iec_std.csv:20 +msgid "Conversion to time-of-day" +msgstr "" + +#: ../PLCOpenEditor.py:379 +msgid "Copy\tCTRL+C" +msgstr "" + +#: ../plcopen/iec_std.csv:28 +msgid "Cosine" +msgstr "" + +#: ../PLCOpenEditor.py:3223 +msgid "Create a new POU" +msgstr "" + +#: ../PLCOpenEditor.py:1804 ../PLCOpenEditor.py:2461 +msgid "Create a new POU from" +msgstr "" + +#: ../PLCOpenEditor.py:3544 +msgid "Create a new action" +msgstr "" + +#: ../PLCOpenEditor.py:214 +msgid "Create a new action block" +msgstr "" + +#: ../PLCOpenEditor.py:169 ../PLCOpenEditor.py:196 ../PLCOpenEditor.py:226 +msgid "Create a new block" +msgstr "" + +#: ../PLCOpenEditor.py:190 +msgid "Create a new branch" +msgstr "" + +#: ../PLCOpenEditor.py:184 +msgid "Create a new coil" +msgstr "" + +#: ../PLCOpenEditor.py:163 ../PLCOpenEditor.py:175 ../PLCOpenEditor.py:202 +msgid "Create a new comment" +msgstr "" + +#: ../PLCOpenEditor.py:172 ../PLCOpenEditor.py:199 ../PLCOpenEditor.py:229 +msgid "Create a new connection" +msgstr "" + +#: ../PLCOpenEditor.py:187 ../PLCOpenEditor.py:235 +msgid "Create a new contact" +msgstr "" + +#: ../PLCOpenEditor.py:217 +msgid "Create a new divergence" +msgstr "" + +#: ../Dialogs.py:1976 +msgid "Create a new divergence or convergence" +msgstr "" + +#: ../PLCOpenEditor.py:205 +msgid "Create a new initial step" +msgstr "" + +#: ../PLCOpenEditor.py:220 +msgid "Create a new jump" +msgstr "" + +#: ../PLCOpenEditor.py:178 ../PLCOpenEditor.py:232 +msgid "Create a new power rail" +msgstr "" + +#: ../PLCOpenEditor.py:181 +msgid "Create a new rung" +msgstr "" + +#: ../PLCOpenEditor.py:208 +msgid "Create a new step" +msgstr "" + +#: ../PLCOpenEditor.py:211 ../PLCOpenEditor.py:3400 +msgid "Create a new transition" +msgstr "" + +#: ../PLCOpenEditor.py:166 ../PLCOpenEditor.py:193 ../PLCOpenEditor.py:223 +msgid "Create a new variable" +msgstr "" + +#: ../PLCOpenEditor.py:377 +msgid "Cut\tCTRL+X" +msgstr "" + +#: ../PLCOpenEditor.py:386 +msgid "Data Type" +msgstr "" + +#: ../PLCControler.py:83 +msgid "Data Types" +msgstr "" + +#: ../plcopen/iec_std.csv:16 +msgid "Data type conversion" +msgstr "" + +#: ../plcopen/iec_std.csv:36 +msgid "Date addition" +msgstr "" + +#: ../plcopen/iec_std.csv:44 ../plcopen/iec_std.csv:45 +msgid "Date and time subtraction" +msgstr "" + +#: ../plcopen/iec_std.csv:41 +msgid "Date subtraction" +msgstr "" + +#: ../PLCOpenEditor.py:398 ../PLCOpenEditor.py:1821 ../PLCOpenEditor.py:1830 +#: ../PLCOpenEditor.py:1836 ../PLCOpenEditor.py:4249 ../PLCOpenEditor.py:4862 +#: ../Viewer.py:416 ../Dialogs.py:2351 ../DataTypeEditor.py:544 +msgid "Delete" +msgstr "" + +#: ../Viewer.py:404 +msgid "Delete Divergence Branch" +msgstr "" + +#: ../RessourceEditor.py:414 +msgid "Delete Instance" +msgstr "" + +#: ../RessourceEditor.py:378 +msgid "Delete Task" +msgstr "" + +#: ../Viewer.py:399 +msgid "Delete Wire Segment" +msgstr "" + +#: ../DataTypeEditor.py:453 ../DataTypeEditor.py:495 +msgid "Delete item" +msgstr "" + +#: ../plcopen/iec_std.csv:77 +msgid "Deletion (within)" +msgstr "" + +#: ../DataTypeEditor.py:364 +msgid "Derivation Type:" +msgstr "" + +#: ../plcopen/structures.py:236 +msgid "" +"Derivative\n" +"The derivative function block produces an output XOUT proportional to the rate of change of the input XIN." +msgstr "" + +#: ../DataTypeEditor.py:487 +msgid "Dimensions:" +msgstr "" + +#: ../DataTypeEditor.py:236 +msgid "Directly" +msgstr "" + +#: ../PLCOpenEditor.py:306 +msgid "Display" +msgstr "" + +#: ../plcopen/iec_std.csv:46 +msgid "Division" +msgstr "" + +#: ../PLCOpenEditor.py:1086 +msgid "Done" +msgstr "" + +#: ../plcopen/structures.py:199 +msgid "" +"Down-counter\n" +"The down-counter can be used to signal when a count has reached zero, on counting down from a preset value." +msgstr "" + +#: ../Dialogs.py:2105 +msgid "Duration" +msgstr "" + +#: ../PLCOpenEditor.py:305 +msgid "Edit" +msgstr "" + +#: ../Viewer.py:414 +msgid "Edit Block" +msgstr "" + +#: ../Dialogs.py:1098 +msgid "Edit Coil Values" +msgstr "" + +#: ../Dialogs.py:1093 +msgid "Edit Contact Values" +msgstr "" + +#: ../Dialogs.py:1451 +msgid "Edit Step" +msgstr "" + +#: ../Dialogs.py:2328 +msgid "Edit action block properties" +msgstr "" + +#: ../Viewer.py:1796 ../Viewer.py:1798 ../Viewer.py:2297 ../Viewer.py:2299 +msgid "Edit comment" +msgstr "" + +#: ../DataTypeEditor.py:448 ../DataTypeEditor.py:490 +msgid "Edit item" +msgstr "" + +#: ../Viewer.py:2262 +msgid "Edit jump target" +msgstr "" + +#: ../SFCViewer.py:726 +msgid "Edit step name" +msgstr "" + +#: ../Dialogs.py:1698 +msgid "Edit transition" +msgstr "" + +#: ../DataTypeEditor.py:520 +msgid "Elements :" +msgstr "" + +#: ../DataTypeEditor.py:236 +msgid "Enumerated" +msgstr "" + +#: ../plcopen/iec_std.csv:66 +msgid "Equal to" +msgstr "" + +#: ../PLCOpenEditor.py:953 ../PLCOpenEditor.py:1093 ../PLCOpenEditor.py:1098 +#: ../PLCOpenEditor.py:1583 ../PLCOpenEditor.py:1620 ../PLCOpenEditor.py:1625 +#: ../PLCOpenEditor.py:1640 ../PLCOpenEditor.py:1645 ../PLCOpenEditor.py:2491 +#: ../PLCOpenEditor.py:2520 ../PLCOpenEditor.py:3041 ../PLCOpenEditor.py:3133 +#: ../PLCOpenEditor.py:3137 ../PLCOpenEditor.py:3141 ../PLCOpenEditor.py:3145 +#: ../PLCOpenEditor.py:3286 ../PLCOpenEditor.py:3290 ../PLCOpenEditor.py:3294 +#: ../PLCOpenEditor.py:3298 ../PLCOpenEditor.py:3449 ../PLCOpenEditor.py:3453 +#: ../PLCOpenEditor.py:3457 ../PLCOpenEditor.py:3461 ../PLCOpenEditor.py:3465 +#: ../PLCOpenEditor.py:3593 ../PLCOpenEditor.py:3597 ../PLCOpenEditor.py:3601 +#: ../PLCOpenEditor.py:3605 ../PLCOpenEditor.py:3609 ../PLCOpenEditor.py:3664 +#: ../PLCOpenEditor.py:3668 ../PLCOpenEditor.py:3672 ../PLCOpenEditor.py:3676 +#: ../PLCOpenEditor.py:3727 ../PLCOpenEditor.py:3731 ../PLCOpenEditor.py:3735 +#: ../PLCOpenEditor.py:3739 ../PLCOpenEditor.py:4119 ../PLCOpenEditor.py:4444 +#: ../PLCOpenEditor.py:4449 ../PLCOpenEditor.py:4454 ../PLCOpenEditor.py:4459 +#: ../PLCOpenEditor.py:4795 ../PLCOpenEditor.py:5057 ../PLCOpenEditor.py:5067 +#: ../Viewer.py:335 ../TextViewer.py:224 ../LDViewer.py:628 ../LDViewer.py:850 +#: ../LDViewer.py:854 ../Dialogs.py:241 ../Dialogs.py:245 ../Dialogs.py:249 +#: ../Dialogs.py:253 ../Dialogs.py:257 ../Dialogs.py:261 ../Dialogs.py:648 +#: ../Dialogs.py:652 ../Dialogs.py:882 ../Dialogs.py:886 ../Dialogs.py:890 +#: ../Dialogs.py:894 ../Dialogs.py:898 ../Dialogs.py:1525 ../Dialogs.py:1529 +#: ../Dialogs.py:1533 ../Dialogs.py:1537 ../Dialogs.py:1541 ../Dialogs.py:1545 +#: ../Dialogs.py:1803 ../Dialogs.py:2508 ../Dialogs.py:2512 ../Dialogs.py:2516 +#: ../Dialogs.py:2520 ../Dialogs.py:2524 ../Dialogs.py:2528 ../Dialogs.py:2575 +#: ../Dialogs.py:2579 ../Dialogs.py:2583 ../Dialogs.py:2587 +#: ../DataTypeEditor.py:697 ../DataTypeEditor.py:702 ../DataTypeEditor.py:757 +#: ../DataTypeEditor.py:762 ../DataTypeEditor.py:772 ../DataTypeEditor.py:899 +#: ../DataTypeEditor.py:906 +msgid "Error" +msgstr "" + +#: ../Dialogs.py:134 +msgid "Execution Control:" +msgstr "" + +#: ../Dialogs.py:130 ../Dialogs.py:516 +msgid "Execution Order:" +msgstr "" + +#: ../plcopen/iec_std.csv:49 +msgid "Exponent" +msgstr "" + +#: ../plcopen/iec_std.csv:26 +msgid "Exponentiation" +msgstr "" + +#: ../Dialogs.py:512 +msgid "Expression:" +msgstr "" + +#: ../PLCOpenEditor.py:3860 +msgid "External" +msgstr "" + +#: ../PLCOpenEditor.py:2978 ../PLCOpenEditor.py:3168 ../PLCOpenEditor.py:3178 +#: ../PLCOpenEditor.py:3357 ../PLCOpenEditor.py:3501 +msgid "FBD" +msgstr "" + +#: ../Viewer.py:394 ../Dialogs.py:1060 +msgid "Falling Edge" +msgstr "" + +#: ../plcopen/structures.py:189 +msgid "" +"Falling edge detector\n" +"The output produces a single pulse when a falling edge is detected." +msgstr "" + +#: ../PLCOpenEditor.py:303 +msgid "File" +msgstr "" + +#: ../plcopen/iec_std.csv:79 +msgid "Find position" +msgstr "" + +#: ../PLCOpenEditor.py:3041 ../PLCOpenEditor.py:3286 ../PLCOpenEditor.py:3449 +#: ../PLCOpenEditor.py:3593 ../Dialogs.py:1803 +#, python-format +msgid "Form isn't complete. %s must be filled!" +msgstr "" + +#: ../Dialogs.py:245 ../Dialogs.py:882 +msgid "Form isn't complete. Name must be filled!" +msgstr "" + +#: ../Dialogs.py:241 +msgid "Form isn't complete. Valid block type must be selected!" +msgstr "" + +#: ../PLCOpenEditor.py:388 +msgid "Function" +msgstr "" + +#: ../PLCOpenEditor.py:390 ../PLCOpenEditor.py:1811 +msgid "Function Block" +msgstr "" + +#: ../PLCOpenEditor.py:4506 +msgid "Function Block Types" +msgstr "" + +#: ../PLCControler.py:82 +msgid "Function Blocks" +msgstr "" + +#: ../Viewer.py:227 +msgid "Function Blocks can't be used in Functions!" +msgstr "" + +#: ../Viewer.py:229 +msgid "Function Blocks can't be used in Transitions!" +msgstr "" + +#: ../PLCControler.py:1673 +#, python-format +msgid "FunctionBlock \"%s\" can't be paste in a Function!!!" +msgstr "" + +#: ../PLCControler.py:82 +msgid "Functions" +msgstr "" + +#: ../PLCOpenEditor.py:328 +msgid "Generate Program\tCTRL+G" +msgstr "" + +#: ../PLCOpenEditor.py:3861 +msgid "Global" +msgstr "" + +#: ../PLCOpenEditor.py:2028 +msgid "Graphic Panel" +msgstr "" + +#: ../PLCOpenEditor.py:2983 +msgid "Graphics" +msgstr "" + +#: ../plcopen/iec_std.csv:64 +msgid "Greater than" +msgstr "" + +#: ../plcopen/iec_std.csv:65 +msgid "Greater than or equal to" +msgstr "" + +#: ../PLCOpenEditor.py:2962 +msgid "Height:" +msgstr "" + +#: ../PLCOpenEditor.py:307 +msgid "Help" +msgstr "" + +#: ../plcopen/structures.py:251 +msgid "" +"Hysteresis\n" +"The hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2." +msgstr "" + +#: ../PLCOpenEditor.py:3168 ../PLCOpenEditor.py:3178 ../PLCOpenEditor.py:3357 +#: ../PLCOpenEditor.py:3501 +msgid "IL" +msgstr "" + +#: ../PLCOpenEditor.py:3859 ../Dialogs.py:426 +msgid "InOut" +msgstr "" + +#: ../PLCOpenEditor.py:4089 +#, python-format +msgid "Incompatible data types between \"%s\" and \"%s\"" +msgstr "" + +#: ../PLCOpenEditor.py:4100 +#, python-format +msgid "Incompatible size of data between \"%s\" and \"%s\"" +msgstr "" + +#: ../PLCOpenEditor.py:4096 +#, python-format +msgid "Incompatible size of data between \"%s\" and \"BOOL\"" +msgstr "" + +#: ../Dialogs.py:2105 +msgid "Indicator" +msgstr "" + +#: ../PLCOpenEditor.py:3848 ../PLCOpenEditor.py:3849 ../DataTypeEditor.py:46 +msgid "Initial Value" +msgstr "" + +#: ../DataTypeEditor.py:388 ../DataTypeEditor.py:412 ../DataTypeEditor.py:463 +#: ../DataTypeEditor.py:505 +msgid "Initial Value:" +msgstr "" + +#: ../Dialogs.py:1725 ../Dialogs.py:1793 ../Dialogs.py:2109 +msgid "Inline" +msgstr "" + +#: ../PLCOpenEditor.py:3859 ../Dialogs.py:425 ../Dialogs.py:1472 +msgid "Input" +msgstr "" + +#: ../Dialogs.py:126 +msgid "Inputs:" +msgstr "" + +#: ../plcopen/iec_std.csv:76 +msgid "Insertion (into)" +msgstr "" + +#: ../plcopen/plcopen.py:1329 +#, python-format +msgid "Instance with id %d doesn't exists!" +msgstr "" + +#: ../PLCOpenEditor.py:559 ../PLCOpenEditor.py:597 +msgid "Instances" +msgstr "" + +#: ../RessourceEditor.py:394 +msgid "Instances:" +msgstr "" + +#: ../plcopen/structures.py:231 +msgid "" +"Integral\n" +"The integral function block integrates the value of input XIN over time." +msgstr "" + +#: ../PLCOpenEditor.py:3858 +msgid "Interface" +msgstr "" + +#: ../RessourceEditor.py:79 +msgid "Interval" +msgstr "" + +#: ../PLCControler.py:1654 ../PLCControler.py:1688 +msgid "Invalid plcopen element(s)!!!" +msgstr "" + +#: ../PLCOpenEditor.py:4784 ../PLCOpenEditor.py:4787 +#, python-format +msgid "Invalid value \"%s\" for debug variable" +msgstr "" + +#: ../PLCOpenEditor.py:4077 ../PLCOpenEditor.py:4080 +#, python-format +msgid "Invalid value \"%s\" for location" +msgstr "" + +#: ../Viewer.py:211 ../Viewer.py:214 +#, python-format +msgid "Invalid value \"%s\" for viewer block" +msgstr "" + +#: ../PLCOpenEditor.py:2978 ../PLCOpenEditor.py:3168 ../PLCOpenEditor.py:3178 +#: ../PLCOpenEditor.py:3357 ../PLCOpenEditor.py:3501 +msgid "LD" +msgstr "" + +#: ../LDViewer.py:213 ../LDViewer.py:228 +#, python-format +msgid "Ladder element with id %d is on more than one rung." +msgstr "" + +#: ../PLCOpenEditor.py:3276 ../PLCOpenEditor.py:3439 ../PLCOpenEditor.py:3583 +msgid "Language" +msgstr "" + +#: ../PLCOpenEditor.py:2992 +msgid "Language (optional):" +msgstr "" + +#: ../PLCOpenEditor.py:3244 ../PLCOpenEditor.py:3412 ../PLCOpenEditor.py:3556 +msgid "Language:" +msgstr "" + +#: ../Viewer.py:358 +msgid "Left" +msgstr "" + +#: ../Dialogs.py:1287 +msgid "Left PowerRail" +msgstr "" + +#: ../plcopen/iec_std.csv:70 +msgid "Length of string" +msgstr "" + +#: ../plcopen/iec_std.csv:67 +msgid "Less than" +msgstr "" + +#: ../plcopen/iec_std.csv:68 +msgid "Less than or equal to" +msgstr "" + +#: ../PLCOpenEditor.py:638 +msgid "Library" +msgstr "" + +#: ../plcopen/iec_std.csv:62 +msgid "Limitation" +msgstr "" + +#: ../PLCOpenEditor.py:3860 +msgid "Local" +msgstr "" + +#: ../PLCOpenEditor.py:3848 +msgid "Location" +msgstr "" + +#: ../plcopen/iec_std.csv:25 +msgid "Logarithm to base 10" +msgstr "" + +#: ../plcopen/iec_std.csv:60 +msgid "Maximum" +msgstr "" + +#: ../DataTypeEditor.py:430 +msgid "Maximum:" +msgstr "" + +#: ../Viewer.py:367 +msgid "Middle" +msgstr "" + +#: ../plcopen/iec_std.csv:61 +msgid "Minimum" +msgstr "" + +#: ../DataTypeEditor.py:421 +msgid "Minimum:" +msgstr "" + +#: ../PLCOpenEditor.py:3007 +msgid "Miscellaneous" +msgstr "" + +#: ../Dialogs.py:1022 +msgid "Modifier:" +msgstr "" + +#: ../PLCGenerator.py:672 ../PLCGenerator.py:876 +#, python-format +msgid "More than one connector found corresponding to \"%s\" continuation in \"%s\" POU" +msgstr "" + +#: ../DataTypeEditor.py:459 ../DataTypeEditor.py:501 +msgid "Move down" +msgstr "" + +#: ../DataTypeEditor.py:456 ../DataTypeEditor.py:498 +msgid "Move up" +msgstr "" + +#: ../plcopen/iec_std.csv:63 +msgid "Multiplexer (select 1 of N)" +msgstr "" + +#: ../plcopen/iec_std.csv:37 +msgid "Multiplication" +msgstr "" + +#: ../PLCOpenEditor.py:3848 ../PLCOpenEditor.py:3849 ../RessourceEditor.py:79 +#: ../RessourceEditor.py:83 ../DataTypeEditor.py:46 +msgid "Name" +msgstr "" + +#: ../Dialogs.py:122 ../Dialogs.py:520 ../Dialogs.py:792 ../Dialogs.py:1026 +#: ../Dialogs.py:1455 +msgid "Name:" +msgstr "" + +#: ../plcopen/iec_std.csv:24 +msgid "Natural logarithm" +msgstr "" + +#: ../Viewer.py:390 ../Dialogs.py:1040 +msgid "Negated" +msgstr "" + +#: ../PLCOpenEditor.py:312 +msgid "New\tCTRL+N" +msgstr "" + +#: ../DataTypeEditor.py:450 ../DataTypeEditor.py:492 +msgid "New item" +msgstr "" + +#: ../PLCOpenEditor.py:3853 +msgid "No" +msgstr "" + +#: ../Viewer.py:388 +msgid "No Modifier" +msgstr "" + +#: ../PLCControler.py:2535 +msgid "No PLC project found" +msgstr "" + +#: ../PLCGenerator.py:1257 +#, python-format +msgid "No body defined in \"%s\" POU" +msgstr "" + +#: ../PLCGenerator.py:691 ../PLCGenerator.py:885 +#, python-format +msgid "No connector found corresponding to \"%s\" continuation in \"%s\" POU" +msgstr "" + +#: ../PLCOpenEditor.py:2606 +msgid "" +"No documentation available.\n" +"Coming soon." +msgstr "" + +#: ../PLCGenerator.py:743 +#, python-format +msgid "No informations found for \"%s\" block" +msgstr "" + +#: ../plcopen/structures.py:139 +msgid "No output variable found" +msgstr "" + +#: ../PLCGenerator.py:1255 +#, python-format +msgid "No variable defined in \"%s\" POU" +msgstr "" + +#: ../Dialogs.py:1034 +msgid "Normal" +msgstr "" + +#: ../plcopen/iec_std.csv:69 +msgid "Not equal to" +msgstr "" + +#: ../Dialogs.py:2008 +msgid "Number of sequences:" +msgstr "" + +#: ../plcopen/iec_std.csv:22 +msgid "Numerical" +msgstr "" + +#: ../plcopen/structures.py:219 +msgid "" +"Off-delay timer\n" +"The off-delay timer can be used to delay setting an output false, for fixed period after input goes false." +msgstr "" + +#: ../plcopen/structures.py:214 +msgid "" +"On-delay timer\n" +"The on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true." +msgstr "" + +#: ../PLCOpenEditor.py:314 +msgid "Open\tCTRL+O" +msgstr "" + +#: ../PLCOpenEditor.py:2934 +msgid "Organization (optional):" +msgstr "" + +#: ../PLCOpenEditor.py:3859 ../Dialogs.py:427 ../Dialogs.py:1477 +msgid "Output" +msgstr "" + +#: ../plcopen/structures.py:241 +msgid "" +"PID\n" +"The PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control." +msgstr "" + +#: ../PLCOpenEditor.py:1031 ../PLCOpenEditor.py:1118 +msgid "PLCOpen files (*.xml)|*.xml|All files|*.*" +msgstr "" + +#: ../PLCOpenEditor.py:485 ../PLCOpenEditor.py:838 +msgid "PLCOpenEditor" +msgstr "" + +#: ../PLCOpenEditor.py:438 +msgid "PLCOpenEditor\tF1" +msgstr "" + +#: ../PLCOpenEditor.py:3272 +msgid "POU Name" +msgstr "" + +#: ../PLCOpenEditor.py:3227 +msgid "POU Name:" +msgstr "" + +#: ../PLCOpenEditor.py:3274 +msgid "POU Type" +msgstr "" + +#: ../PLCOpenEditor.py:3235 +msgid "POU Type:" +msgstr "" + +#: ../PLCOpenEditor.py:331 +msgid "Page Setup" +msgstr "" + +#: ../PLCOpenEditor.py:2950 +msgid "Page Size (optional):" +msgstr "" + +#: ../PLCOpenEditor.py:5000 +#, python-format +msgid "Page: %d" +msgstr "" + +#: ../PLCOpenEditor.py:381 +msgid "Paste\tCTRL+V" +msgstr "" + +#: ../Dialogs.py:1279 +msgid "Pin number:" +msgstr "" + +#: ../Viewer.py:1971 ../Viewer.py:2262 ../SFCViewer.py:698 +msgid "Please choose a target" +msgstr "" + +#: ../PLCOpenEditor.py:2461 +msgid "Please enter POU name" +msgstr "" + +#: ../Viewer.py:1796 ../Viewer.py:1798 ../Viewer.py:2297 ../Viewer.py:2299 +msgid "Please enter comment text" +msgstr "" + +#: ../PLCOpenEditor.py:2416 ../PLCOpenEditor.py:3647 +msgid "Please enter configuration name" +msgstr "" + +#: ../PLCOpenEditor.py:2359 +msgid "Please enter data type name" +msgstr "" + +#: ../PLCOpenEditor.py:2431 ../PLCOpenEditor.py:3710 +msgid "Please enter resource name" +msgstr "" + +#: ../SFCViewer.py:362 ../SFCViewer.py:384 ../SFCViewer.py:726 +msgid "Please enter step name" +msgstr "" + +#: ../PLCOpenEditor.py:3118 +msgid "Please enter text" +msgstr "" + +#: ../GraphicViewer.py:117 +msgid "Position:" +msgstr "" + +#: ../Dialogs.py:1271 +msgid "Power Rail Properties" +msgstr "" + +#: ../PLCOpenEditor.py:333 +msgid "Preview" +msgstr "" + +#: ../Dialogs.py:138 ../Dialogs.py:524 ../Dialogs.py:796 ../Dialogs.py:1030 +#: ../Dialogs.py:1283 ../Dialogs.py:1463 ../Dialogs.py:1706 ../Dialogs.py:2017 +msgid "Preview:" +msgstr "" + +#: ../PLCOpenEditor.py:335 +msgid "Print" +msgstr "" + +#: ../PLCOpenEditor.py:1150 +msgid "Print preview" +msgstr "" + +#: ../RessourceEditor.py:79 +msgid "Priority" +msgstr "" + +#: ../Dialogs.py:1710 +msgid "Priority:" +msgstr "" + +#: ../PLCOpenEditor.py:2878 +msgid "Product Name (required):" +msgstr "" + +#: ../PLCOpenEditor.py:2894 +msgid "Product Release (optional):" +msgstr "" + +#: ../PLCOpenEditor.py:2886 +msgid "Product Version (required):" +msgstr "" + +#: ../PLCOpenEditor.py:392 ../PLCOpenEditor.py:1814 +msgid "Program" +msgstr "" + +#: ../PLCOpenEditor.py:1095 +msgid "Program was successfully generated!" +msgstr "" + +#: ../PLCControler.py:83 +msgid "Programs" +msgstr "" + +#: ../Viewer.py:220 +msgid "Programs can't be used by other POUs!" +msgstr "" + +#: ../PLCOpenEditor.py:497 ../PLCOpenEditor.py:2901 +msgid "Project" +msgstr "" + +#: ../PLCOpenEditor.py:2862 +msgid "Project Name (required):" +msgstr "" + +#: ../PLCOpenEditor.py:2870 +msgid "Project Version (optional):" +msgstr "" + +#: ../PLCOpenEditor.py:2848 +msgid "Project properties" +msgstr "" + +#: ../PLCOpenEditor.py:339 ../PLCControler.py:84 +msgid "Properties" +msgstr "" + +#: ../plcopen/structures.py:209 +msgid "" +"Pulse timer\n" +"The pulse timer can be used to generate output pulses of a given time duration." +msgstr "" + +#: ../Dialogs.py:2105 +msgid "Qualifier" +msgstr "" + +#: ../PLCOpenEditor.py:343 +msgid "Quit\tCTRL+Q" +msgstr "" + +#: ../plcopen/structures.py:174 +msgid "" +"RS bistable\n" +"The RS bistable is a latch where the Reset dominates." +msgstr "" + +#: ../plcopen/structures.py:246 +msgid "" +"Ramp\n" +"The RAMP function block is modelled on example given in the standard but with the addition of a 'Holdback' feature." +msgstr "" + +#: ../GraphicViewer.py:106 +msgid "Range:" +msgstr "" + +#: ../PLCOpenEditor.py:374 +msgid "Redo\tCTRL+Y" +msgstr "" + +#: ../Dialogs.py:1714 ../Dialogs.py:1791 +msgid "Reference" +msgstr "" + +#: ../PLCOpenEditor.py:420 +msgid "Refresh\tF5" +msgstr "" + +#: ../plcopen/iec_std.csv:48 +msgid "Remainder (modulo)" +msgstr "" + +#: ../PLCOpenEditor.py:1818 +msgid "Rename" +msgstr "" + +#: ../plcopen/iec_std.csv:78 +msgid "Replacement (within)" +msgstr "" + +#: ../Dialogs.py:1050 +msgid "Reset" +msgstr "" + +#: ../Viewer.py:409 +msgid "Reset Execution Order" +msgstr "" + +#: ../PLCControler.py:84 +msgid "Resources" +msgstr "" + +#: ../PLCOpenEditor.py:3848 ../PLCOpenEditor.py:3849 +msgid "Retain" +msgstr "" + +#: ../PLCOpenEditor.py:4227 +msgid "Return Type:" +msgstr "" + +#: ../Viewer.py:362 +msgid "Right" +msgstr "" + +#: ../Dialogs.py:1293 +msgid "Right PowerRail" +msgstr "" + +#: ../Viewer.py:392 ../Dialogs.py:1055 +msgid "Rising Edge" +msgstr "" + +#: ../plcopen/structures.py:184 +msgid "" +"Rising edge detector\n" +"The output produces a single pulse when a rising edge is detected." +msgstr "" + +#: ../plcopen/iec_std.csv:54 +msgid "Rotate left" +msgstr "" + +#: ../plcopen/iec_std.csv:53 +msgid "Rotate right" +msgstr "" + +#: ../plcopen/iec_std.csv:17 +msgid "Rounding up/down" +msgstr "" + +#: ../PLCOpenEditor.py:2978 ../PLCOpenEditor.py:3178 +msgid "SFC" +msgstr "" + +#: ../plcopen/structures.py:169 +msgid "" +"SR bistable\n" +"The SR bistable is a latch where the Set dominates." +msgstr "" + +#: ../PLCOpenEditor.py:3168 ../PLCOpenEditor.py:3178 ../PLCOpenEditor.py:3357 +#: ../PLCOpenEditor.py:3501 +msgid "ST" +msgstr "" + +#: ../PLCOpenEditor.py:1082 +msgid "ST files (*.st)|*.st|All files|*.*" +msgstr "" + +#: ../PLCOpenEditor.py:323 +msgid "Save\tCTRL+S" +msgstr "" + +#: ../PLCOpenEditor.py:326 +msgid "Save As...\tCTRL+SHIFT+S" +msgstr "" + +#: ../PLCOpenEditor.py:2970 +msgid "Scaling:" +msgstr "" + +#: ../PLCOpenEditor.py:396 +msgid "Select All\tCTRL+A" +msgstr "" + +#: ../PLCOpenEditor.py:4102 +msgid "Select a variable class:" +msgstr "" + +#: ../PLCOpenEditor.py:604 ../PLCOpenEditor.py:616 +msgid "Select an object" +msgstr "" + +#: ../plcopen/iec_std.csv:59 +msgid "Selection" +msgstr "" + +#: ../Dialogs.py:1990 +msgid "Selection Convergence" +msgstr "" + +#: ../Dialogs.py:1984 +msgid "Selection Divergence" +msgstr "" + +#: ../plcopen/structures.py:179 +msgid "" +"Semaphore\n" +"The semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources." +msgstr "" + +#: ../Dialogs.py:1045 +msgid "Set" +msgstr "" + +#: ../plcopen/iec_std.csv:51 +msgid "Shift left" +msgstr "" + +#: ../plcopen/iec_std.csv:52 +msgid "Shift right" +msgstr "" + +#: ../Dialogs.py:2002 +msgid "Simultaneous Convergence" +msgstr "" + +#: ../Dialogs.py:1996 +msgid "Simultaneous Divergence" +msgstr "" + +#: ../plcopen/iec_std.csv:27 +msgid "Sine" +msgstr "" + +#: ../RessourceEditor.py:79 +msgid "Single" +msgstr "" + +#: ../plcopen/iec_std.csv:23 +msgid "Square root (base 2)" +msgstr "" + +#: ../plcopen/structures.py:165 +msgid "Standard function blocks" +msgstr "" + +#: ../DataTypeEditor.py:236 +msgid "Structure" +msgstr "" + +#: ../DataTypeEditor.py:236 +msgid "Subrange" +msgstr "" + +#: ../plcopen/iec_std.csv:39 +msgid "Subtraction" +msgstr "" + +#: ../plcopen/iec_std.csv:29 +msgid "Tangent" +msgstr "" + +#: ../RessourceEditor.py:83 +msgid "Task" +msgstr "" + +#: ../RessourceEditor.py:358 +msgid "Tasks:" +msgstr "" + +#: ../PLCOpenEditor.py:3861 +msgid "Temp" +msgstr "" + +#: ../LDViewer.py:850 +msgid "The group of block must be coherent!" +msgstr "" + +#: ../PLCOpenEditor.py:961 +msgid "There are changes, do you want to save?" +msgstr "" + +#: ../PLCOpenEditor.py:1169 +msgid "" +"There was a problem printing.\n" +"Perhaps your current printer is not set correctly?" +msgstr "" + +#: ../LDViewer.py:859 +msgid "This option isn't available yet!" +msgstr "" + +#: ../GraphicViewer.py:181 +msgid "Tick" +msgstr "" + +#: ../plcopen/iec_std.csv:34 +msgid "Time addition" +msgstr "" + +#: ../plcopen/iec_std.csv:75 +msgid "Time concatenation" +msgstr "" + +#: ../plcopen/iec_std.csv:47 +msgid "Time division" +msgstr "" + +#: ../plcopen/iec_std.csv:38 +msgid "Time multiplication" +msgstr "" + +#: ../plcopen/iec_std.csv:40 +msgid "Time subtraction" +msgstr "" + +#: ../plcopen/iec_std.csv:35 +msgid "Time-of-day addition" +msgstr "" + +#: ../plcopen/iec_std.csv:42 ../plcopen/iec_std.csv:43 +msgid "Time-of-day subtraction" +msgstr "" + +#: ../PLCOpenEditor.py:608 +msgid "Toolbar" +msgstr "" + +#: ../Viewer.py:365 +msgid "Top" +msgstr "" + +#: ../PLCOpenEditor.py:3437 +msgid "Transition Name" +msgstr "" + +#: ../PLCOpenEditor.py:3404 +msgid "Transition Name:" +msgstr "" + +#: ../PLCGenerator.py:1237 +#, python-format +msgid "Transition with content \"%s\" not connected to a next step in \"%s\" POU" +msgstr "" + +#: ../PLCGenerator.py:1228 +#, python-format +msgid "Transition with content \"%s\" not connected to a previous step in \"%s\" POU" +msgstr "" + +#: ../plcopen/plcopen.py:1035 +#, python-format +msgid "Transition with name %s doesn't exists!" +msgstr "" + +#: ../PLCControler.py:83 +msgid "Transitions" +msgstr "" + +#: ../PLCOpenEditor.py:3848 ../PLCOpenEditor.py:3849 ../RessourceEditor.py:83 +#: ../Dialogs.py:2105 ../DataTypeEditor.py:46 +msgid "Type" +msgstr "" + +#: ../plcopen/iec_std.csv:16 +msgid "Type conversion" +msgstr "" + +#: ../DataTypeEditor.py:360 +msgid "Type infos:" +msgstr "" + +#: ../Dialogs.py:118 ../Dialogs.py:788 ../Dialogs.py:1275 ../Dialogs.py:1702 +#: ../Dialogs.py:1980 +msgid "Type:" +msgstr "" + +#: ../PLCOpenEditor.py:560 ../PLCOpenEditor.py:596 +msgid "Types" +msgstr "" + +#: ../PLCGenerator.py:232 +#, python-format +msgid "Undefined pou type \"%s\"" +msgstr "" + +#: ../PLCOpenEditor.py:372 +msgid "Undo\tCTRL+Z" +msgstr "" + +#: ../Viewer.py:286 +#, python-format +msgid "Unknown variable \"%s\" for this POU!" +msgstr "" + +#: ../PLCControler.py:293 +#, python-format +msgid "Unnamed%d" +msgstr "" + +#: ../PLCOpenEditor.py:4098 +#, python-format +msgid "Unrecognized data size \"%s\"" +msgstr "" + +#: ../plcopen/structures.py:194 +msgid "" +"Up-counter\n" +"The up-counter can be used to signal when a count has reached a maximum value." +msgstr "" + +#: ../plcopen/structures.py:204 +msgid "" +"Up-down counter\n" +"The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other." +msgstr "" + +#: ../PLCOpenEditor.py:4497 ../DataTypeEditor.py:804 +msgid "User Data Types" +msgstr "" + +#: ../PLCControler.py:82 +msgid "User-defined POUs" +msgstr "" + +#: ../PLCOpenEditor.py:4614 ../Dialogs.py:2105 +msgid "Value" +msgstr "" + +#: ../GraphicViewer.py:181 +msgid "Values" +msgstr "" + +#: ../DataTypeEditor.py:445 +msgid "Values:" +msgstr "" + +#: ../PLCOpenEditor.py:4614 ../Dialogs.py:2109 +msgid "Variable" +msgstr "" + +#: ../Dialogs.py:504 +msgid "Variable Properties" +msgstr "" + +#: ../PLCOpenEditor.py:4102 +msgid "Variable class" +msgstr "" + +#: ../Viewer.py:288 ../TextViewer.py:224 +msgid "Variable don't belong to this POU!" +msgstr "" + +#: ../PLCOpenEditor.py:573 ../PLCOpenEditor.py:624 ../PLCOpenEditor.py:3860 +msgid "Variables" +msgstr "" + +#: ../PLCOpenEditor.py:3302 ../PLCOpenEditor.py:3680 ../PLCOpenEditor.py:3743 +#: ../LDViewer.py:859 +msgid "Warning" +msgstr "" + +#: ../PLCOpenEditor.py:2954 +msgid "Width:" +msgstr "" + +#: ../PLCOpenEditor.py:2697 +msgid "X Scale:" +msgstr "" + +#: ../PLCOpenEditor.py:2705 +msgid "Y Scale:" +msgstr "" + +#: ../PLCOpenEditor.py:3853 +msgid "Yes" +msgstr "" + +#: ../LDViewer.py:854 +msgid "You must select the block or group of blocks around which a branch should be added!" +msgstr "" + +#: ../LDViewer.py:628 +msgid "You must select the wire where a contact should be added!" +msgstr "" + +#: ../PLCOpenEditor.py:3133 ../PLCOpenEditor.py:3664 ../PLCOpenEditor.py:3727 +#: ../Dialogs.py:1525 ../Dialogs.py:2508 ../Dialogs.py:2575 +msgid "You must type a name!" +msgstr "" + +#: ../PLCOpenEditor.py:426 +msgid "Zoom" +msgstr "" + +#: ../PLCOpenEditor.py:1091 +#, python-format +msgid "error: %s\n" +msgstr "" + +#: ../PLCOpenEditor.py:5032 ../PLCOpenEditor.py:5034 +msgid "file : " +msgstr "" + +#: ../PLCOpenEditor.py:3173 +msgid "function" +msgstr "" + +#: ../PLCOpenEditor.py:5035 +msgid "function : " +msgstr "" + +#: ../PLCOpenEditor.py:3173 +msgid "functionBlock" +msgstr "" + +#: ../PLCOpenEditor.py:5035 +msgid "line : " +msgstr "" + +#: ../PLCOpenEditor.py:3173 +msgid "program" +msgstr "" + +#: ../plcopen/iec_std.csv:73 +msgid "string from the middle" +msgstr "" + +#: ../plcopen/iec_std.csv:71 +msgid "string left of" +msgstr "" + +#: ../plcopen/iec_std.csv:72 +msgid "string right of" +msgstr "" + +#: ../PLCOpenEditor.py:1089 +#, python-format +msgid "warning: %s\n" +msgstr "" diff -r d07815f10ca8 -r 323c8d76f6f2 i18n/mki18n.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i18n/mki18n.py Fri Aug 07 15:49:10 2009 +0200 @@ -0,0 +1,455 @@ +#! /usr/bin/env python +# -*- coding: iso-8859-1 -*- +# +# PYTHON MODULE: MKI18N.PY +# ========= +# +# Abstract: Make Internationalization (i18n) files for an application. +# +# Copyright Pierre Rouleau. 2003. Released to public domain. +# +# Last update: Saturday, November 8, 2003. @ 15:55:18. +# +# File: ROUP2003N01::C:/dev/python/mki18n.py +# +# RCS $Header: //software/official/MKS/MKS_SI/TV_NT/dev/Python/rcs/mki18n.py 1.5 2003/11/05 19:40:04 PRouleau Exp $ +# +# Update history: +# +# - File created: Saturday, June 7, 2003. by Pierre Rouleau +# - 10/06/03 rcs : RCS Revision 1.1 2003/06/10 10:06:12 PRouleau +# - 10/06/03 rcs : RCS Initial revision +# - 23/08/03 rcs : RCS Revision 1.2 2003/06/10 10:54:27 PRouleau +# - 23/08/03 P.R.: [code:fix] : The strings encoded in this file are encode in iso-8859-1 format. Added the encoding +# notification to Python to comply with Python's 2.3 PEP 263. +# - 23/08/03 P.R.: [feature:new] : Added the '-e' switch which is used to force the creation of the empty English .mo file. +# - 22/10/03 P.R.: [code] : incorporated utility functions in here to make script self sufficient. +# - 05/11/03 rcs : RCS Revision 1.4 2003/10/22 06:39:31 PRouleau +# - 05/11/03 P.R.: [code:fix] : included the unixpath() in this file. +# - 08/11/03 rcs : RCS Revision 1.5 2003/11/05 19:40:04 PRouleau +# +# RCS $Log: $ +# +# +# ----------------------------------------------------------------------------- +""" +mki18n allows you to internationalize your software. You can use it to +create the GNU .po files (Portable Object) and the compiled .mo files +(Machine Object). + +mki18n module can be used from the command line or from within a script (see +the Usage at the end of this page). + + Table of Contents + ----------------- + + makePO() -- Build the Portable Object file for the application -- + catPO() -- Concatenate one or several PO files with the application domain files. -- + makeMO() -- Compile the Portable Object files into the Machine Object stored in the right location. -- + printUsage -- Displays how to use this script from the command line -- + + Scriptexecution -- Runs when invoked from the command line -- + + +NOTE: this module uses GNU gettext utilities. + +You can get the gettext tools from the following sites: + + - `GNU FTP site for gettetx`_ where several versions (0.10.40, 0.11.2, 0.11.5 and 0.12.1) are available. + Note that you need to use `GNU libiconv`_ to use this. Get it from the `GNU + libiconv ftp site`_ and get version 1.9.1 or later. Get the Windows .ZIP + files and install the packages inside c:/gnu. All binaries will be stored + inside c:/gnu/bin. Just put c:/gnu/bin inside your PATH. You will need + the following files: + + - `gettext-runtime-0.12.1.bin.woe32.zip`_ + - `gettext-tools-0.12.1.bin.woe32.zip`_ + - `libiconv-1.9.1.bin.woe32.zip`_ + + +.. _GNU libiconv: http://www.gnu.org/software/libiconv/ +.. _GNU libiconv ftp site: http://www.ibiblio.org/pub/gnu/libiconv/ +.. _gettext-runtime-0.12.1.bin.woe32.zip: ftp://ftp.gnu.org/gnu/gettext/gettext-runtime-0.12.1.bin.woe32.zip +.. _gettext-tools-0.12.1.bin.woe32.zip: ftp://ftp.gnu.org/gnu/gettext/gettext-tools-0.12.1.bin.woe32.zip +.. _libiconv-1.9.1.bin.woe32.zip: http://www.ibiblio.org/pub/gnu/libiconv/libiconv-1.9.1.bin.woe32.zip + +""" +# ----------------------------------------------------------------------------- +# Module Import +# ------------- +# +import os +import sys +import wx +# ----------------------------------------------------------------------------- +# Global variables +# ---------------- +# + +__author__ = "Pierre Rouleau" +__version__= "$Revision: 1.5 $" + +# ----------------------------------------------------------------------------- + +def getlanguageDict(): + languageDict = {} + + for lang in [x for x in dir(wx) if x.startswith("LANGUAGE")]: + i = wx.Locale(wx.LANGUAGE_DEFAULT).GetLanguageInfo(getattr(wx, lang)) + if i: + languageDict[i.CanonicalName] = i.Description + + return languageDict + +# ----------------------------------------------------------------------------- +# m a k e P O ( ) -- Build the Portable Object file for the application -- +# ^^^^^^^^^^^^^^^ +# +def makePO(applicationDirectoryPath, applicationDomain=None, verbose=0) : + """Build the Portable Object Template file for the application. + + makePO builds the .pot file for the application stored inside + a specified directory by running xgettext for all application source + files. It finds the name of all files by looking for a file called 'app.fil'. + If this file does not exists, makePo raises an IOError exception. + By default the application domain (the application + name) is the same as the directory name but it can be overridden by the + 'applicationDomain' argument. + + makePO always creates a new file called messages.pot. If it finds files + of the form app_xx.po where 'app' is the application name and 'xx' is one + of the ISO 639 two-letter language codes, makePO resynchronizes those + files with the latest extracted strings (now contained in messages.pot). + This process updates all line location number in the language-specific + .po files and may also create new entries for translation (or comment out + some). The .po file is not changed, instead a new file is created with + the .new extension appended to the name of the .po file. + + By default the function does not display what it is doing. Set the + verbose argument to 1 to force it to print its commands. + """ + + if applicationDomain is None: + applicationName = fileBaseOf(applicationDirectoryPath,withPath=0) + else: + applicationName = applicationDomain + currentDir = os.getcwd() + os.chdir(applicationDirectoryPath) + if not os.path.exists('app.fil'): + raise IOError(2,'No module file: app.fil') + + # Steps: + # Use xgettext to parse all application modules + # The following switches are used: + # + # -s : sort output by string content (easier to use when we need to merge several .po files) + # --files-from=app.fil : The list of files is taken from the file: app.fil + # --output= : specifies the name of the output file (using a .pot extension) + cmd = 'xgettext -s --no-wrap --language=Python --files-from=app.fil --output=messages.pot' + if verbose: print cmd + os.system(cmd) + + languageDict = getlanguageDict() + + for langCode in languageDict.keys(): + if langCode == 'en': + pass + else: + langPOfileName = "%s_%s.po" % (applicationName , langCode) + if os.path.exists(langPOfileName): + cmd = 'msgmerge -s --no-wrap "%s" messages.pot > "%s.new"' % (langPOfileName, langPOfileName) + if verbose: print cmd + os.system(cmd) + os.chdir(currentDir) + +# ----------------------------------------------------------------------------- +# c a t P O ( ) -- Concatenate one or several PO files with the application domain files. -- +# ^^^^^^^^^^^^^ +# +def catPO(applicationDirectoryPath, listOf_extraPo, applicationDomain=None, targetDir=None, verbose=0) : + """Concatenate one or several PO files with the application domain files. + """ + + if applicationDomain is None: + applicationName = fileBaseOf(applicationDirectoryPath,withPath=0) + else: + applicationName = applicationDomain + currentDir = os.getcwd() + os.chdir(applicationDirectoryPath) + + languageDict = getlanguageDict() + + for langCode in languageDict.keys(): + if langCode == 'en': + pass + else: + langPOfileName = "%s_%s.po" % (applicationName , langCode) + if os.path.exists(langPOfileName): + fileList = '' + for fileName in listOf_extraPo: + fileList += ("%s_%s.po " % (fileName,langCode)) + cmd = "msgcat -s --no-wrap %s %s > %s.cat" % (langPOfileName, fileList, langPOfileName) + if verbose: print cmd + os.system(cmd) + if targetDir is None: + pass + else: + mo_targetDir = "%s/%s/LC_MESSAGES" % (targetDir,langCode) + cmd = "msgfmt --output-file=%s/%s.mo %s_%s.po.cat" % (mo_targetDir,applicationName,applicationName,langCode) + if verbose: print cmd + os.system(cmd) + os.chdir(currentDir) + +# ----------------------------------------------------------------------------- +# m a k e M O ( ) -- Compile the Portable Object files into the Machine Object stored in the right location. -- +# ^^^^^^^^^^^^^^^ +# +def makeMO(applicationDirectoryPath,targetDir='./locale',applicationDomain=None, verbose=0, forceEnglish=0) : + """Compile the Portable Object files into the Machine Object stored in the right location. + + makeMO converts all translated language-specific PO files located inside + the application directory into the binary .MO files stored inside the + LC_MESSAGES sub-directory for the found locale files. + + makeMO searches for all files that have a name of the form 'app_xx.po' + inside the application directory specified by the first argument. The + 'app' is the application domain name (that can be specified by the + applicationDomain argument or is taken from the directory name). The 'xx' + corresponds to one of the ISO 639 two-letter language codes. + + makeMo stores the resulting files inside a sub-directory of `targetDir` + called xx/LC_MESSAGES where 'xx' corresponds to the 2-letter language + code. + """ + if targetDir is None: + targetDir = './locale' + if verbose: + print "Target directory for .mo files is: %s" % targetDir + + if applicationDomain is None: + applicationName = fileBaseOf(applicationDirectoryPath,withPath=0) + else: + applicationName = applicationDomain + currentDir = os.getcwd() + os.chdir(applicationDirectoryPath) + + languageDict = getlanguageDict() + + for langCode in languageDict.keys(): + if (langCode == 'en') and (forceEnglish==0): + pass + else: + langPOfileName = "%s_%s.po" % (applicationName , langCode) + if os.path.exists(langPOfileName): + mo_targetDir = "%s/%s/LC_MESSAGES" % (targetDir,langCode) + if not os.path.exists(mo_targetDir): + mkdir(mo_targetDir) + cmd = 'msgfmt --output-file="%s/%s.mo" "%s_%s.po"' % (mo_targetDir,applicationName,applicationName,langCode) + if verbose: print cmd + os.system(cmd) + os.chdir(currentDir) + +# ----------------------------------------------------------------------------- +# p r i n t U s a g e -- Displays how to use this script from the command line -- +# ^^^^^^^^^^^^^^^^^^^ +# +def printUsage(errorMsg=None) : + """Displays how to use this script from the command line.""" + print """ + ################################################################################## + # mki18n : Make internationalization files. # + # Uses the GNU gettext system to create PO (Portable Object) files # + # from source code, coimpile PO into MO (Machine Object) files. # + # Supports C,C++,Python source files. # + # # + # Usage: mki18n {OPTION} [appDirPath] # + # # + # Options: # + # -e : When -m is used, forces English .mo file creation # + # -h : prints this help # + # -m : make MO from existing PO files # + # -p : make PO, update PO files: Creates a new messages.pot # + # file. Creates a dom_xx.po.new for every existing # + # language specific .po file. ('xx' stands for the ISO639 # + # two-letter language code and 'dom' stands for the # + # application domain name). mki18n requires that you # + # write a 'app.fil' file which contains the list of all # + # source code to parse. # + # -v : verbose (prints comments while running) # + # --domain=appName : specifies the application domain name. By default # + # the directory name is used. # + # --moTarget=dir : specifies the directory where .mo files are stored. # + # If not specified, the target is './locale' # + # # + # You must specify one of the -p or -m option to perform the work. You can # + # specify the path of the target application. If you leave it out mki18n # + # will use the current directory as the application main directory. # + # # + ##################################################################################""" + if errorMsg: + print "\n ERROR: %s" % errorMsg + +# ----------------------------------------------------------------------------- +# f i l e B a s e O f ( ) -- Return base name of filename -- +# ^^^^^^^^^^^^^^^^^^^^^^^ +# +def fileBaseOf(filename,withPath=0) : + """fileBaseOf(filename,withPath) ---> string + + Return base name of filename. The returned string never includes the extension. + Use os.path.basename() to return the basename with the extension. The + second argument is optional. If specified and if set to 'true' (non zero) + the string returned contains the full path of the file name. Otherwise the + path is excluded. + + [Example] + >>> fn = 'd:/dev/telepath/tvapp/code/test.html' + >>> fileBaseOf(fn) + 'test' + >>> fileBaseOf(fn) + 'test' + >>> fileBaseOf(fn,1) + 'd:/dev/telepath/tvapp/code/test' + >>> fileBaseOf(fn,0) + 'test' + >>> fn = 'abcdef' + >>> fileBaseOf(fn) + 'abcdef' + >>> fileBaseOf(fn,1) + 'abcdef' + >>> fn = "abcdef." + >>> fileBaseOf(fn) + 'abcdef' + >>> fileBaseOf(fn,1) + 'abcdef' + """ + pos = filename.rfind('.') + if pos > 0: + filename = filename[:pos] + if withPath: + return filename + else: + return os.path.basename(filename) +# ----------------------------------------------------------------------------- +# m k d i r ( ) -- Create a directory (and possibly the entire tree) -- +# ^^^^^^^^^^^^^ +# +def mkdir(directory) : + """Create a directory (and possibly the entire tree). + + The os.mkdir() will fail to create a directory if one of the + directory in the specified path does not exist. mkdir() + solves this problem. It creates every intermediate directory + required to create the final path. Under Unix, the function + only supports forward slash separator, but under Windows and MacOS + the function supports the forward slash and the OS separator (backslash + under windows). + """ + + # translate the path separators + directory = unixpath(directory) + # build a list of all directory elements + aList = filter(lambda x: len(x)>0, directory.split('/')) + theLen = len(aList) + # if the first element is a Windows-style disk drive + # concatenate it with the first directory + if aList[0].endswith(':'): + if theLen > 1: + aList[1] = aList[0] + '/' + aList[1] + del aList[0] + theLen -= 1 + # if the original directory starts at root, + # make sure the first element of the list + # starts at root too + if directory[0] == '/': + aList[0] = '/' + aList[0] + # Now iterate through the list, check if the + # directory exists and if not create it + theDir = '' + for i in range(theLen): + theDir += aList[i] + if not os.path.exists(theDir): + os.mkdir(theDir) + theDir += '/' + +# ----------------------------------------------------------------------------- +# u n i x p a t h ( ) -- Return a path name that contains Unix separator. -- +# ^^^^^^^^^^^^^^^^^^^ +# +def unixpath(thePath) : + r"""Return a path name that contains Unix separator. + + [Example] + >>> unixpath(r"d:\test") + 'd:/test' + >>> unixpath("d:/test/file.txt") + 'd:/test/file.txt' + >>> + """ + thePath = os.path.normpath(thePath) + if os.sep == '/': + return thePath + else: + return thePath.replace(os.sep,'/') + +# ----------------------------------------------------------------------------- + +# S c r i p t e x e c u t i o n -- Runs when invoked from the command line -- +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +if __name__ == "__main__": + import getopt # command line parsing + argc = len(sys.argv) + if argc == 1: + printUsage('Missing argument: specify at least one of -m or -p (or both).') + sys.exit(1) + # If there is some arguments, parse the command line + validOptions = "ehmpv" + validLongOptions = ['domain=', 'moTarget='] + option = {} + option['forceEnglish'] = 0 + option['mo'] = 0 + option['po'] = 0 + option['verbose'] = 0 + option['domain'] = None + option['moTarget'] = None + try: + optionList,pargs = getopt.getopt(sys.argv[1:],validOptions,validLongOptions) + except getopt.GetoptError, e: + printUsage(e[0]) + sys.exit(1) + for (opt,val) in optionList: + if (opt == '-h'): + printUsage() + sys.exit(0) + elif (opt == '-e'): option['forceEnglish'] = 1 + elif (opt == '-m'): option['mo'] = 1 + elif (opt == '-p'): option['po'] = 1 + elif (opt == '-v'): option['verbose'] = 1 + elif (opt == '--domain'): option['domain'] = val + elif (opt == '--moTarget'): option['moTarget'] = val + if len(pargs) == 0: + appDirPath = os.getcwd() + if option['verbose']: + print "No project directory given. Using current one: %s" % appDirPath + elif len(pargs) == 1: + appDirPath = pargs[0] + else: + printUsage('Too many arguments (%u). Use double quotes if you have space in directory name' % len(pargs)) + sys.exit(1) + if option['domain'] is None: + # If no domain specified, use the name of the target directory + option['domain'] = fileBaseOf(appDirPath) + if option['verbose']: + print "Application domain used is: '%s'" % option['domain'] + if option['po']: + try: + makePO(appDirPath,option['domain'],option['verbose']) + except IOError, e: + printUsage(e[1] + '\n You must write a file app.fil that contains the list of all files to parse.') + if option['mo']: + makeMO(appDirPath,option['moTarget'],option['domain'],option['verbose'],option['forceEnglish']) + sys.exit(1) + + +# ----------------------------------------------------------------------------- diff -r d07815f10ca8 -r 323c8d76f6f2 locale/fr_FR/LC_MESSAGES/PLCOpenEditor.mo Binary file locale/fr_FR/LC_MESSAGES/PLCOpenEditor.mo has changed diff -r d07815f10ca8 -r 323c8d76f6f2 locale/zh_CN/LC_MESSAGES/PLCOpenEditor.mo Binary file locale/zh_CN/LC_MESSAGES/PLCOpenEditor.mo has changed diff -r d07815f10ca8 -r 323c8d76f6f2 plcopen/__init__.py --- a/plcopen/__init__.py Mon Jul 27 12:01:43 2009 +0200 +++ b/plcopen/__init__.py Fri Aug 07 15:49:10 2009 +0200 @@ -28,6 +28,6 @@ import plcopen for classname, cls in plcopen.PLCOpenClasses.items(): plcopen.__dict__[classname] = cls -from plcopen import VarOrder +from plcopen import VarOrder, ElementNameToClass, rect from structures import * diff -r d07815f10ca8 -r 323c8d76f6f2 plcopen/iec_std.csv --- a/plcopen/iec_std.csv Mon Jul 27 12:01:43 2009 +0200 +++ b/plcopen/iec_std.csv Fri Aug 07 15:49:10 2009 +0200 @@ -13,67 +13,67 @@ ;;;;;;;; ;;;;;;;; Standard_functions_type;name;baseinputnumber;inputs;outputs;comment;extensible;python_eval_c_code_format;return_type_rule -Type conversion;*_TO_**;1;(ANY);ANY;Data type conversion;no;ANY_TO_ANY_FORMAT_GEN(ANY_TO_ANY_LIST,fdecl);defined -;TRUNC;1;(ANY_REAL);ANY_INT;Rounding up/down;no;("int", None, None);&search_constant_type_c::constant_int_type_name -;BCD_TO_**;1;(ANY_BIT);ANY_INT;Conversion from BCD;no;ANY_TO_ANY_FORMAT_GEN(BCD_TO_ANY_LIST,fdecl);defined -;*_TO_BCD;1;(ANY_INT);ANY_BIT;Conversion to BCD;no;ANY_TO_ANY_FORMAT_GEN(ANY_TO_BCD_LIST,fdecl);&search_constant_type_c::constant_int_type_name -;DATE_AND_TIME_TO_TIME_OF_DAY;1;(DT);TOD;Conversion to time-of-day;no;(None, "__date_and_time_to_time_of_day", None);defined -;DATE_AND_TIME_TO_DATE;1;(DT);DATE;Conversion to date;no;(None, "__date_and_time_to_date", None);defined -Numerical;ABS;1;(ANY_NUM);ANY_NUM;Absolute number;no;(None, "__abs_", "IN_type");IN_type_symbol -;SQRT;1;(ANY_REAL);ANY_REAL;Square root (base 2);no;(None, "__sqrt_", "IN_type");IN_type_symbol -;LN;1;(ANY_REAL);ANY_REAL;Natural logarithm;no;(None, "__ln_", "IN_type");IN_type_symbol -;LOG;1;(ANY_REAL);ANY_REAL;Logarithm to base 10;no;(None, "__log_", "IN_type");IN_type_symbol -;EXP;1;(ANY_REAL);ANY_REAL;Exponentiation;no;(None, "__exp_", "IN_type");IN_type_symbol -;SIN;1;(ANY_REAL);ANY_REAL;Sine;no;(None, "__sin_", "IN_type");IN_type_symbol -;COS;1;(ANY_REAL);ANY_REAL;Cosine;no;(None, "__cos_", "IN_type");IN_type_symbol -;TAN;1;(ANY_REAL);ANY_REAL;Tangent;no;(None, "__tan_", "IN_type");IN_type_symbol -;ASIN;1;(ANY_REAL);ANY_REAL;Arc sine;no;(None, "__asin_", "IN_type");IN_type_symbol -;ACOS;1;(ANY_REAL);ANY_REAL;Arc cosine;no;(None, "__acos_", "IN_type");IN_type_symbol -;ATAN;1;(ANY_REAL);ANY_REAL;Arc tangent;no;(None, "__atan_", "IN_type");IN_type_symbol -Arithmetic;ADD;1;(ANY_NUM, ANY_NUM);ANY_NUM;Addition;yes;(None, "__add_", "return_type");copy_input -;ADD;1;(TIME, TIME);TIME;Time addition;no;(None, "__time_add", None);defined -;ADD;1;(TOD, TIME);TOD;Time-of-day addition;no;(None, "__time_add", None);defined -;ADD;1;(DT, TIME);DT;Date addition;no;(None, "__time_add", None);defined -;MUL;1;(ANY_NUM, ANY_NUM);ANY_NUM;Multiplication;yes;(None, "__mul_", "return_type");copy_input -;MUL;1;(TIME, ANY_NUM);TIME;Time multiplication;no;(None, "__time_mul", None);defined -;SUB;1;(ANY_NUM, ANY_NUM);ANY_NUM;Subtraction;no;(None, "__sub_", "return_type");copy_input -;SUB;1;(TIME, TIME);TIME;Time subtraction;no;(None, "__time_sub", None);defined -;SUB;1;(DATE, DATE);TIME;Date subtraction;no;(None, "__time_sub", None);defined -;SUB;1;(TOD, TIME);TOD;Time-of-day subtraction;no;(None, "__time_sub", None);defined -;SUB;1;(TOD, TOD);TIME;Time-of-day subtraction;no;(None, "__time_sub", None);defined -;SUB;1;(DT, TIME);DT;Date and time subtraction;no;(None, "__time_sub", None);defined -;SUB;1;(DT, DT);TIME;Date and time subtraction;no;(None, "__time_sub", None);defined -;DIV;1;(ANY_NUM, ANY_NUM);ANY_NUM;Division;no;(None, "__div_", "return_type");copy_input -;DIV;1;(TIME, ANY_NUM);TIME;Time division;no;(None, "__time_div", None);defined -;MOD;1;(ANY_NUM, ANY_NUM);ANY_NUM;Remainder (modulo);no;(None, "__mod_", "return_type");copy_input -;EXPT;1;(ANY_REAL, ANY_NUM);ANY_REAL;Exponent;no;(None, "__expt_", "IN1_type");copy_input -;MOVE;1;(ANY);ANY;Assignment;no;(None, "__move_", "return_type");copy_input -Bit-shift;SHL;1;(ANY_BIT, N);ANY_BIT;Shift left;no;(None, "__shl_", "IN_type");IN_type_symbol -;SHR;1;(ANY_BIT, N);ANY_BIT;Shift right;no;(None, "__shr_", "IN_type");IN_type_symbol -;ROR;1;(ANY_NBIT, N);ANY_NBIT;Rotate right;no;(None, "__ror_", "IN_type");IN_type_symbol -;ROL;1;(ANY_NBIT, N);ANY_NBIT;Rotate left;no;(None, "__rol_", "IN_type");IN_type_symbol -Bitwise;AND;1;(ANY_BIT, ANY_BIT);ANY_BIT;Bitwise AND;yes;(None, "__and_", "return_type");copy_input -;OR;1;(ANY_BIT, ANY_BIT);ANY_BIT;Bitwise OR;yes;(None, "__or_", "return_type");copy_input -;XOR;1;(ANY_BIT, ANY_BIT);ANY_BIT;Bitwise EXOR;yes;(None, "__xor_", "return_type");copy_input -;NOT;1;(ANY_BIT);ANY_BIT;Bitwise inverting;no;(None, "__not_", "return_type");IN_type_symbol -Selection;SEL;0;(G, ANY, ANY);ANY;Binary selection (1 of 2);no;(None, "__sel_", "IN0_type");copy_input -;MAX;1;(ANY, ANY);ANY;Maximum;yes;(None, "__max_", "return_type");copy_input -;MIN;1;(ANY, ANY);ANY;Minimum;yes;(None, "__min_", "return_type");copy_input -;LIMIT;1;(MN, ANY, MX);ANY;Limitation;no;(None, "__limit_", "IN_type");IN_type_symbol -;MUX;0;(K, ANY, ANY);ANY;Multiplexer (select 1 of N);yes;(None, "__mux_", "return_type");copy_input -Comparison;GT;1;(ANY, ANY);BOOL;Greater than;yes;(None, "__gt_", "common_type");defined -;GE;1;(ANY, ANY);BOOL;Greater than or equal to;yes;(None, "__ge_", "common_type");defined -;EQ;1;(ANY, ANY);BOOL;Equal to;yes;(None, "__eq_", "common_type");defined -;LT;1;(ANY, ANY);BOOL;Less than;yes;(None, "__lt_", "common_type");defined -;LE;1;(ANY, ANY);BOOL;Less than or equal to;yes;(None, "__le_", "common_type");defined -;NE;1;(ANY, ANY);BOOL;Not equal to;yes;(None, "__ne_", "common_type");defined -Character string;LEN;1;(STRING);INT;Length of string;no;(None, "__len", None);defined -;LEFT;1;(STRING, L);STRING;string left of;no;(None, "__left", None);defined -;RIGHT;1;(STRING, L);STRING;string right of;no;(None, "__right", None);defined -;MID;1;(STRING, L, P);STRING;string from the middle;no;(None, "__mid", None);defined -;CONCAT;1;(STRING, STRING);STRING;Concatenation;yes;(None, "__concat", None);defined -;CONCAT;1;(DATE, TOD);DT;Time concatenation;no;(None, "__time_add", None);defined -;INSERT;1;(STRING, STRING, P);STRING;Insertion (into);no;(None, "__insert", None);defined -;DELETE;1;(STRING, L, P);STRING;Deletion (within);no;(None, "__delete", None);defined -;REPLACE;1;(STRING, STRING, L, P);STRING;Replacement (within);no;(None, "__replace", None);defined -;FIND;1;(STRING, STRING);INT;Find position;no;(None, "__find", None);defined +_("Type conversion");*_TO_**;1;(ANY);ANY;_("Data type conversion");no;ANY_TO_ANY_FORMAT_GEN(ANY_TO_ANY_LIST,fdecl);defined +;TRUNC;1;(ANY_REAL);ANY_INT;_("Rounding up/down");no;("int", None, None);&search_constant_type_c::constant_int_type_name +;BCD_TO_**;1;(ANY_BIT);ANY_INT;_("Conversion from BCD");no;ANY_TO_ANY_FORMAT_GEN(BCD_TO_ANY_LIST,fdecl);defined +;*_TO_BCD;1;(ANY_INT);ANY_BIT;_("Conversion to BCD");no;ANY_TO_ANY_FORMAT_GEN(ANY_TO_BCD_LIST,fdecl);&search_constant_type_c::constant_int_type_name +;DATE_AND_TIME_TO_TIME_OF_DAY;1;(DT);TOD;_("Conversion to time-of-day");no;(None, "__date_and_time_to_time_of_day", None);defined +;DATE_AND_TIME_TO_DATE;1;(DT);DATE;_("Conversion to date");no;(None, "__date_and_time_to_date", None);defined +_("Numerical");ABS;1;(ANY_NUM);ANY_NUM;_("Absolute number");no;(None, "__abs_", "IN_type");IN_type_symbol +;SQRT;1;(ANY_REAL);ANY_REAL;_("Square root (base 2)");no;(None, "__sqrt_", "IN_type");IN_type_symbol +;LN;1;(ANY_REAL);ANY_REAL;_("Natural logarithm");no;(None, "__ln_", "IN_type");IN_type_symbol +;LOG;1;(ANY_REAL);ANY_REAL;_("Logarithm to base 10");no;(None, "__log_", "IN_type");IN_type_symbol +;EXP;1;(ANY_REAL);ANY_REAL;_("Exponentiation");no;(None, "__exp_", "IN_type");IN_type_symbol +;SIN;1;(ANY_REAL);ANY_REAL;_("Sine");no;(None, "__sin_", "IN_type");IN_type_symbol +;COS;1;(ANY_REAL);ANY_REAL;_("Cosine");no;(None, "__cos_", "IN_type");IN_type_symbol +;TAN;1;(ANY_REAL);ANY_REAL;_("Tangent");no;(None, "__tan_", "IN_type");IN_type_symbol +;ASIN;1;(ANY_REAL);ANY_REAL;_("Arc sine");no;(None, "__asin_", "IN_type");IN_type_symbol +;ACOS;1;(ANY_REAL);ANY_REAL;_("Arc cosine");no;(None, "__acos_", "IN_type");IN_type_symbol +;ATAN;1;(ANY_REAL);ANY_REAL;_("Arc tangent");no;(None, "__atan_", "IN_type");IN_type_symbol +_("Arithmetic");ADD;1;(ANY_NUM, ANY_NUM);ANY_NUM;_("Addition");yes;(None, "__add_", "return_type");copy_input +;ADD;1;(TIME, TIME);TIME;_("Time addition");no;(None, "__time_add", None);defined +;ADD;1;(TOD, TIME);TOD;_("Time-of-day addition");no;(None, "__time_add", None);defined +;ADD;1;(DT, TIME);DT;_("Date addition");no;(None, "__time_add", None);defined +;MUL;1;(ANY_NUM, ANY_NUM);ANY_NUM;_("Multiplication");yes;(None, "__mul_", "return_type");copy_input +;MUL;1;(TIME, ANY_NUM);TIME;_("Time multiplication");no;(None, "__time_mul", None);defined +;SUB;1;(ANY_NUM, ANY_NUM);ANY_NUM;_("Subtraction");no;(None, "__sub_", "return_type");copy_input +;SUB;1;(TIME, TIME);TIME;_("Time subtraction");no;(None, "__time_sub", None);defined +;SUB;1;(DATE, DATE);TIME;_("Date subtraction");no;(None, "__time_sub", None);defined +;SUB;1;(TOD, TIME);TOD;_("Time-of-day subtraction");no;(None, "__time_sub", None);defined +;SUB;1;(TOD, TOD);TIME;_("Time-of-day subtraction");no;(None, "__time_sub", None);defined +;SUB;1;(DT, TIME);DT;_("Date and time subtraction");no;(None, "__time_sub", None);defined +;SUB;1;(DT, DT);TIME;_("Date and time subtraction");no;(None, "__time_sub", None);defined +;DIV;1;(ANY_NUM, ANY_NUM);ANY_NUM;_("Division");no;(None, "__div_", "return_type");copy_input +;DIV;1;(TIME, ANY_NUM);TIME;_("Time division");no;(None, "__time_div", None);defined +;MOD;1;(ANY_NUM, ANY_NUM);ANY_NUM;_("Remainder (modulo)");no;(None, "__mod_", "return_type");copy_input +;EXPT;1;(ANY_REAL, ANY_NUM);ANY_REAL;_("Exponent");no;(None, "__expt_", "IN1_type");copy_input +;MOVE;1;(ANY);ANY;_("Assignment");no;(None, "__move_", "return_type");copy_input +_("Bit-shift");SHL;1;(ANY_BIT, N);ANY_BIT;_("Shift left");no;(None, "__shl_", "IN_type");IN_type_symbol +;SHR;1;(ANY_BIT, N);ANY_BIT;_("Shift right");no;(None, "__shr_", "IN_type");IN_type_symbol +;ROR;1;(ANY_NBIT, N);ANY_NBIT;_("Rotate right");no;(None, "__ror_", "IN_type");IN_type_symbol +;ROL;1;(ANY_NBIT, N);ANY_NBIT;_("Rotate left");no;(None, "__rol_", "IN_type");IN_type_symbol +_("Bitwise");AND;1;(ANY_BIT, ANY_BIT);ANY_BIT;_("Bitwise AND");yes;(None, "__and_", "return_type");copy_input +;OR;1;(ANY_BIT, ANY_BIT);ANY_BIT;_("Bitwise OR");yes;(None, "__or_", "return_type");copy_input +;XOR;1;(ANY_BIT, ANY_BIT);ANY_BIT;_("Bitwise XOR");yes;(None, "__xor_", "return_type");copy_input +;NOT;1;(ANY_BIT);ANY_BIT;_("Bitwise inverting");no;(None, "__not_", "return_type");IN_type_symbol +_("Selection");SEL;0;(G, ANY, ANY);ANY;_("Binary selection (1 of 2)");no;(None, "__sel_", "IN0_type");copy_input +;MAX;1;(ANY, ANY);ANY;_("Maximum");yes;(None, "__max_", "return_type");copy_input +;MIN;1;(ANY, ANY);ANY;_("Minimum");yes;(None, "__min_", "return_type");copy_input +;LIMIT;1;(MN, ANY, MX);ANY;_("Limitation");no;(None, "__limit_", "IN_type");IN_type_symbol +;MUX;0;(K, ANY, ANY);ANY;_("Multiplexer (select 1 of N)");yes;(None, "__mux_", "return_type");copy_input +_("Comparison");GT;1;(ANY, ANY);BOOL;_("Greater than");yes;(None, "__gt_", "common_type");defined +;GE;1;(ANY, ANY);BOOL;_("Greater than or equal to");yes;(None, "__ge_", "common_type");defined +;EQ;1;(ANY, ANY);BOOL;_("Equal to");yes;(None, "__eq_", "common_type");defined +;LT;1;(ANY, ANY);BOOL;_("Less than");yes;(None, "__lt_", "common_type");defined +;LE;1;(ANY, ANY);BOOL;_("Less than or equal to");yes;(None, "__le_", "common_type");defined +;NE;1;(ANY, ANY);BOOL;_("Not equal to");yes;(None, "__ne_", "common_type");defined +_("Character string");LEN;1;(STRING);INT;_("Length of string");no;(None, "__len", None);defined +;LEFT;1;(STRING, L);STRING;_("string left of");no;(None, "__left", None);defined +;RIGHT;1;(STRING, L);STRING;_("string right of");no;(None, "__right", None);defined +;MID;1;(STRING, L, P);STRING;_("string from the middle");no;(None, "__mid", None);defined +;CONCAT;1;(STRING, STRING);STRING;_("Concatenation");yes;(None, "__concat", None);defined +;CONCAT;1;(DATE, TOD);DT;_("Time concatenation");no;(None, "__time_add", None);defined +;INSERT;1;(STRING, STRING, P);STRING;_("Insertion (into)");no;(None, "__insert", None);defined +;DELETE;1;(STRING, L, P);STRING;_("Deletion (within)");no;(None, "__delete", None);defined +;REPLACE;1;(STRING, STRING, L, P);STRING;_("Replacement (within)");no;(None, "__replace", None);defined +;FIND;1;(STRING, STRING);INT;_("Find position");no;(None, "__find", None);defined diff -r d07815f10ca8 -r 323c8d76f6f2 plcopen/plcopen.py --- a/plcopen/plcopen.py Mon Jul 27 12:01:43 2009 +0200 +++ b/plcopen/plcopen.py Fri Aug 07 15:49:10 2009 +0200 @@ -45,7 +45,53 @@ QualifierList = {"N" : False, "R" : False, "S" : False, "L" : True, "D" : True, "P" : False, "P0" : False, "P1" : False, "SD" : True, "DS" : True, "SL" : True} -PLCOpenClasses = GenerateClassesFromXSD(os.path.join(os.path.split(__file__)[0], "TC6_XML_V10_B.xsd")) + +def _init_and_compare(function, v1, v2): + if v1 is None: + return v2 + if v2 is not None: + return function(v1, v2) + return v1 + +""" +Helper class for bounding_box calculation +""" +class rect: + + def __init__(self, x=None, y=None, width=None, height=None): + self.x_min = x + self.x_max = None + self.y_min = y + self.y_max = None + if width is not None and x is not None: + self.x_max = x + width + if height is not None and y is not None: + self.y_max = y + height + + def update(self, x, y): + self.x_min = _init_and_compare(min, self.x_min, x) + self.x_max = _init_and_compare(max, self.x_max, x) + self.y_min = _init_and_compare(min, self.y_min, y) + self.y_max = _init_and_compare(max, self.y_max, y) + + def union(self, rect): + self.x_min = _init_and_compare(min, self.x_min, rect.x_min) + self.x_max = _init_and_compare(max, self.x_max, rect.x_max) + self.y_min = _init_and_compare(min, self.y_min, rect.y_min) + self.y_max = _init_and_compare(max, self.y_max, rect.y_max) + + def bounding_box(self): + width = height = None + if self.x_min is not None and self.x_max is not None: + width = self.x_max - self.x_min + if self.y_min is not None and self.y_max is not None: + height = self.y_max - self.y_min + return self.x_min, self.y_min, width, height + + +PLCOpenClasses = GenerateClassesFromXSD(os.path.join(os.path.split(__file__)[0], "tc6_xml_v201.xsd")) + +ElementNameToClass = {} cls = PLCOpenClasses.get("formattedText", None) if cls: @@ -95,14 +141,14 @@ def setfileHeader(self, fileheader): self.fileHeader.setcompanyName(fileheader["companyName"]) - if "companyURL" in fileheader: + if fileheader.has_key("companyURL"): self.fileHeader.setcompanyURL(fileheader["companyURL"]) self.fileHeader.setproductName(fileheader["productName"]) self.fileHeader.setproductVersion(fileheader["productVersion"]) - if "productRelease" in fileheader: + if fileheader.has_key("productRelease"): self.fileHeader.setproductRelease(fileheader["productRelease"]) self.fileHeader.setcreationDateTime(fileheader["creationDateTime"]) - if "contentDescription" in fileheader: + if fileheader.has_key("contentDescription"): self.fileHeader.setcontentDescription(fileheader["contentDescription"]) setattr(cls, "setfileHeader", setfileHeader) @@ -126,15 +172,15 @@ def setcontentHeader(self, contentheader): self.contentHeader.setname(contentheader["projectName"]) - if "projectVersion" in contentheader: + if contentheader.has_key("projectVersion"): self.contentHeader.setversion(contentheader["projectVersion"]) - if "modificationDateTime" in contentheader: + if contentheader.has_key("modificationDateTime"): self.contentHeader.setmodificationDateTime(contentheader["modificationDateTime"]) - if "organization" in contentheader: + if contentheader.has_key("organization"): self.contentHeader.setorganization(contentheader["organization"]) - if "authorName" in contentheader: + if contentheader.has_key("authorName"): self.contentHeader.setauthor(contentheader["authorName"]) - if "language" in contentheader: + if contentheader.has_key("language"): self.contentHeader.setlanguage(contentheader["language"]) self.contentHeader.setpageSize(*contentheader["pageSize"]) self.contentHeader.setscaling(contentheader["scaling"]) @@ -149,7 +195,7 @@ setattr(cls, "getdataType", getdataType) def appenddataType(self, name): - if name in self.CustomTypeHierarchy: + if self.CustomTypeHierarchy.has_key(name): raise ValueError, "\"%s\" Data Type already exists !!!"%name self.types.appenddataTypeElement(name) self.AddCustomDataType(self.getdataType(name)) @@ -207,7 +253,7 @@ def addconfiguration(self, name): for configuration in self.instances.configurations.getconfiguration(): if configuration.getname() == name: - raise ValueError, "\"%s\" configuration already exists !!!"%name + raise ValueError, _("\"%s\" configuration already exists !!!")%name new_configuration = PLCOpenClasses["configurations_configuration"]() new_configuration.setname(name) self.instances.configurations.appendconfiguration(new_configuration) @@ -221,7 +267,7 @@ found = True break if not found: - raise ValueError, "\"%s\" configuration doesn't exist !!!"%name + raise ValueError, ("\"%s\" configuration doesn't exist !!!")%name setattr(cls, "removeconfiguration", removeconfiguration) def getconfigurationResource(self, config_name, name): @@ -238,7 +284,7 @@ if configuration: for resource in configuration.getresource(): if resource.getname() == name: - raise ValueError, "\"%s\" resource already exists in \"%s\" configuration !!!"%(name, config_name) + raise ValueError, _("\"%s\" resource already exists in \"%s\" configuration !!!")%(name, config_name) new_resource = PLCOpenClasses["configuration_resource"]() new_resource.setname(name) configuration.appendresource(new_resource) @@ -254,7 +300,7 @@ found = True break if not found: - raise ValueError, "\"%s\" resource doesn't exist in \"%s\" configuration !!!"%(name, config_name) + raise ValueError, _("\"%s\" resource doesn't exist in \"%s\" configuration !!!")%(name, config_name) setattr(cls, "removeconfigurationResource", removeconfigurationResource) def updateElementName(self, old_name, new_name): @@ -391,20 +437,20 @@ basetype_content = datatype.baseType.getcontent() if basetype_content["name"] == "derived": typename = basetype_content["value"].getname() - if typename in elementnames and name not in self.ElementUsingTree[typename]: + if name in self.ElementUsingTree[typename]: self.ElementUsingTree[typename].append(name) elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned", "array"]: base_type = basetype_content["value"].baseType.getcontent() if base_type["name"] == "derived": typename = base_type["value"].getname() - if typename in elementnames and name not in self.ElementUsingTree[typename]: + if self.ElementUsingTree.has_key(typename) and name not in self.ElementUsingTree[typename]: self.ElementUsingTree[typename].append(name) elif basetype_content["name"] == "struct": for element in basetype_content["value"].getvariable(): type_content = element.type.getcontent() if type_content["name"] == "derived": typename = type_content["value"].getname() - if typename in elementnames and name not in self.ElementUsingTree[typename]: + if self.ElementUsingTree.has_key(typename) and name not in self.ElementUsingTree[typename]: self.ElementUsingTree[typename].append(name) # Analyze each pou for pou in pous: @@ -416,14 +462,14 @@ vartype_content = var.gettype().getcontent() if vartype_content["name"] == "derived": typename = vartype_content["value"].getname() - if typename in elementnames and name not in self.ElementUsingTree[typename]: + if self.ElementUsingTree.has_key(typename) and name not in self.ElementUsingTree[typename]: self.ElementUsingTree[typename].append(name) setattr(cls, "RefreshElementUsingTree", RefreshElementUsingTree) def GetParentType(self, type): - if type in self.CustomTypeHierarchy: + if self.CustomTypeHierarchy.has_key(type): return self.CustomTypeHierarchy[type] - elif type in TypeHierarchy: + elif TypeHierarchy.has_key(type): return TypeHierarchy[type] return None setattr(cls, "GetParentType", GetParentType) @@ -465,7 +511,7 @@ # Return if pou given by name is used by another pou def ElementIsUsed(self, name): - if name in self.ElementUsingTree: + if self.ElementUsingTree.has_key(name): return len(self.ElementUsingTree[name]) > 0 return False setattr(cls, "ElementIsUsed", ElementIsUsed) @@ -476,7 +522,7 @@ # Return if pou given by name is directly or undirectly used by the reference pou def ElementIsUsedBy(self, name, reference): - if name in self.ElementUsingTree: + if self.ElementUsingTree.has_key(name): list = self.ElementUsingTree[name] # Test if pou is directly used by reference if reference in list: @@ -492,9 +538,9 @@ setattr(cls, "ElementIsUsedBy", ElementIsUsedBy) def GetDataTypeRange(self, type): - if type in self.CustomDataTypeRange: + if self.CustomDataTypeRange.has_key(type): return self.CustomDataTypeRange[type] - elif type in DataTypeRange: + elif DataTypeRange.has_key(type): return DataTypeRange[type] else: parent_type = self.GetParentType(type) @@ -509,8 +555,8 @@ for values in self.EnumeratedDataTypeValues.values(): all_values.extend(values) return all_values - elif type in self.EnumeratedDataTypeValues: - return self.EnumeratedDataTypeValues(type) + elif self.EnumeratedDataTypeValues.has_key(type): + return self.EnumeratedDataTypeValues[type] return [] setattr(cls, "GetEnumeratedDataTypeValues", GetEnumeratedDataTypeValues) @@ -657,6 +703,30 @@ cls = PLCOpenClasses.get("resource_task", None) if cls: + def compatibility(self, tree): + if tree.hasAttribute("interval"): + interval = GetAttributeValue(tree._attrs["interval"]) + result = time_model.match(interval) + if result is not None: + values = result.groups() + time_values = [int(v) for v in values[:2]] + seconds = float(values[2]) + time_values.extend([int(seconds), int((seconds % 1) * 1000000)]) + text = "t#" + if time_values[0] != 0: + text += "%dh"%time_values[0] + if time_values[1] != 0: + text += "%dm"%time_values[1] + if time_values[2] != 0: + text += "%ds"%time_values[2] + if time_values[3] != 0: + if time_values[3] % 1000 != 0: + text += "%.3fms"%(float(time_values[3]) / 1000) + else: + text += "%dms"%(time_values[3] / 1000) + NodeSetAttr(tree, "interval", text) + setattr(cls, "compatibility", compatibility) + def updateElementName(self, old_name, new_name): if self.single == old_name: self.single = new_name @@ -666,6 +736,11 @@ cls = PLCOpenClasses.get("pouInstance", None) if cls: + def compatibility(self, tree): + if tree.hasAttribute("type"): + NodeRenameAttr(tree, "type", "typeName") + setattr(cls, "compatibility", compatibility) + def updateElementName(self, old_name, new_name): if self.type == old_name: self.type = new_name @@ -704,7 +779,7 @@ found = True break if not found: - raise ValueError, "\"%s\" Data Type doesn't exist !!!"%name + raise ValueError, _("\"%s\" Data Type doesn't exist !!!")%name setattr(cls, "removedataTypeElement", removedataTypeElement) def getpouElements(self): @@ -722,11 +797,11 @@ def appendpouElement(self, name, pou_type, body_type): for element in self.pous.getpou(): if element.getname() == name: - raise ValueError, "\"%s\" POU already exists !!!"%name + raise ValueError, _("\"%s\" POU already exists !!!")%name new_pou = PLCOpenClasses["pous_pou"]() new_pou.setname(name) new_pou.setpouType(pou_type) - new_pou.setbody(PLCOpenClasses["body"]()) + new_pou.appendbody(PLCOpenClasses["body"]()) new_pou.setbodyType(body_type) self.pous.appendpou(new_pou) setattr(cls, "appendpouElement", appendpouElement) @@ -743,74 +818,91 @@ found = True break if not found: - raise ValueError, "\"%s\" POU doesn't exist !!!"%name + raise ValueError, _("\"%s\" POU doesn't exist !!!")%name setattr(cls, "removepouElement", removepouElement) -def setbodyType(self, type): - if type == "IL": - self.body.setcontent({"name" : "IL", "value" : PLCOpenClasses["formattedText"]()}) - elif type == "ST": - self.body.setcontent({"name" : "ST", "value" : PLCOpenClasses["formattedText"]()}) - elif type == "LD": - self.body.setcontent({"name" : "LD", "value" : PLCOpenClasses["body_LD"]()}) - elif type == "FBD": - self.body.setcontent({"name" : "FBD", "value" : PLCOpenClasses["body_FBD"]()}) - elif type == "SFC": - self.body.setcontent({"name" : "SFC", "value" : PLCOpenClasses["body_SFC"]()}) - else: - raise ValueError, "%s isn't a valid body type!"%type - -def getbodyType(self): - return self.body.getcontent()["name"] - -def resetexecutionOrder(self): - self.body.resetexecutionOrder() - -def compileexecutionOrder(self): - self.body.compileexecutionOrder() - -def setelementExecutionOrder(self, instance, new_executionOrder): - self.body.setelementExecutionOrder(instance, new_executionOrder) - -def addinstance(self, name, instance): - self.body.appendcontentInstance(name, instance) - -def getinstances(self): - return self.body.getcontentInstances() - -def getinstance(self, id): - return self.body.getcontentInstance(id) - -def getrandomInstance(self, exclude): - return self.body.getcontentRandomInstance(exclude) - -def getinstanceByName(self, name): - return self.body.getcontentInstanceByName(name) - -def removeinstance(self, id): - self.body.removecontentInstance(id) - -def settext(self, text): - self.body.settext(text) - -def gettext(self): - return self.body.gettext() -setattr(cls, "gettext", gettext) - cls = PLCOpenClasses.get("pous_pou", None) if cls: + + def setbodyType(self, type): + if len(self.body) > 0: + if type == "IL": + self.body[0].setcontent({"name" : "IL", "value" : PLCOpenClasses["formattedText"]()}) + elif type == "ST": + self.body[0].setcontent({"name" : "ST", "value" : PLCOpenClasses["formattedText"]()}) + elif type == "LD": + self.body[0].setcontent({"name" : "LD", "value" : PLCOpenClasses["body_LD"]()}) + elif type == "FBD": + self.body[0].setcontent({"name" : "FBD", "value" : PLCOpenClasses["body_FBD"]()}) + elif type == "SFC": + self.body[0].setcontent({"name" : "SFC", "value" : PLCOpenClasses["body_SFC"]()}) + else: + raise ValueError, "%s isn't a valid body type!"%type setattr(cls, "setbodyType", setbodyType) + + def getbodyType(self): + if len(self.body) > 0: + return self.body[0].getcontent()["name"] setattr(cls, "getbodyType", getbodyType) + + def resetexecutionOrder(self): + if len(self.body) > 0: + self.body[0].resetexecutionOrder() setattr(cls, "resetexecutionOrder", resetexecutionOrder) + + def compileexecutionOrder(self): + if len(self.body) > 0: + self.body[0].compileexecutionOrder() setattr(cls, "compileexecutionOrder", compileexecutionOrder) + + def setelementExecutionOrder(self, instance, new_executionOrder): + if len(self.body) > 0: + self.body[0].setelementExecutionOrder(instance, new_executionOrder) setattr(cls, "setelementExecutionOrder", setelementExecutionOrder) + + def addinstance(self, name, instance): + if len(self.body) > 0: + self.body[0].appendcontentInstance(name, instance) setattr(cls, "addinstance", addinstance) + + def getinstances(self): + if len(self.body) > 0: + return self.body[0].getcontentInstances() + return [] setattr(cls, "getinstances", getinstances) + + def getinstance(self, id): + if len(self.body) > 0: + return self.body[0].getcontentInstance(id) + return None setattr(cls, "getinstance", getinstance) + + def getrandomInstance(self, exclude): + if len(self.body) > 0: + return self.body[0].getcontentRandomInstance(exclude) + return None setattr(cls, "getrandomInstance", getrandomInstance) + + def getinstanceByName(self, name): + if len(self.body) > 0: + return self.body[0].getcontentInstanceByName(name) + return None setattr(cls, "getinstanceByName", getinstanceByName) + + def removeinstance(self, id): + if len(self.body) > 0: + self.body[0].removecontentInstance(id) setattr(cls, "removeinstance", removeinstance) + + def settext(self, text): + if len(self.body) > 0: + self.body[0].settext(text) setattr(cls, "settext", settext) + + def gettext(self): + if len(self.body) > 0: + return self.body[0].gettext() + return "" setattr(cls, "gettext", gettext) def getvars(self): @@ -940,7 +1032,7 @@ removed = True i += 1 if not removed: - raise ValueError, "Transition with name %s doesn't exists!"%name + raise ValueError, _("Transition with name %s doesn't exists!")%name setattr(cls, "removetransition", removetransition) def addaction(self, name, type): @@ -978,7 +1070,7 @@ removed = True i += 1 if not removed: - raise ValueError, "Action with name %s doesn't exists!"%name + raise ValueError, _("Action with name %s doesn't exists!")%name setattr(cls, "removeaction", removeaction) def updateElementName(self, old_name, new_name): @@ -996,6 +1088,56 @@ transition.updateElementName(old_name, new_name) setattr(cls, "updateElementName", updateElementName) +def setbodyType(self, type): + if type == "IL": + self.body.setcontent({"name" : "IL", "value" : PLCOpenClasses["formattedText"]()}) + elif type == "ST": + self.body.setcontent({"name" : "ST", "value" : PLCOpenClasses["formattedText"]()}) + elif type == "LD": + self.body.setcontent({"name" : "LD", "value" : PLCOpenClasses["body_LD"]()}) + elif type == "FBD": + self.body.setcontent({"name" : "FBD", "value" : PLCOpenClasses["body_FBD"]()}) + elif type == "SFC": + self.body.setcontent({"name" : "SFC", "value" : PLCOpenClasses["body_SFC"]()}) + else: + raise ValueError, "%s isn't a valid body type!"%type + +def getbodyType(self): + return self.body.getcontent()["name"] + +def resetexecutionOrder(self): + self.body.resetexecutionOrder() + +def compileexecutionOrder(self): + self.body.compileexecutionOrder() + +def setelementExecutionOrder(self, instance, new_executionOrder): + self.body.setelementExecutionOrder(instance, new_executionOrder) + +def addinstance(self, name, instance): + self.body.appendcontentInstance(name, instance) + +def getinstances(self): + return self.body.getcontentInstances() + +def getinstance(self, id): + return self.body.getcontentInstance(id) + +def getrandomInstance(self, exclude): + return self.body.getcontentRandomInstance(exclude) + +def getinstanceByName(self, name): + return self.body.getcontentInstanceByName(name) + +def removeinstance(self, id): + self.body.removecontentInstance(id) + +def settext(self, text): + self.body.settext(text) + +def gettext(self): + return self.body.gettext() + cls = PLCOpenClasses.get("transitions_transition", None) if cls: setattr(cls, "setbodyType", setbodyType) @@ -1073,7 +1215,7 @@ PLCOpenClasses.get("commonObjects_continuation", None))): element["value"].setexecutionOrderId(0) else: - raise TypeError, "Can only generate execution order on FBD networks!" + raise TypeError, _("Can only generate execution order on FBD networks!") setattr(cls, "resetexecutionOrder", resetexecutionOrder) def compileexecutionOrder(self): @@ -1087,7 +1229,7 @@ self.compileelementExecutionOrder(connections[0]) element["value"].setexecutionOrderId(self.getnewExecutionOrderId()) else: - raise TypeError, "Can only generate execution order on FBD networks!" + raise TypeError, _("Can only generate execution order on FBD networks!") setattr(cls, "compileexecutionOrder", compileexecutionOrder) def compileelementExecutionOrder(self, link): @@ -1108,7 +1250,7 @@ if connections and len(connections) == 1: self.compileelementExecutionOrder(connections[0]) else: - raise TypeError, "Can only generate execution order on FBD networks!" + raise TypeError, _("Can only generate execution order on FBD networks!") setattr(cls, "compileelementExecutionOrder", compileelementExecutionOrder) def setelementExecutionOrder(self, instance, new_executionOrder): @@ -1124,14 +1266,14 @@ element["value"].setexecutionOrderId(element_executionOrder + 1) instance.setexecutionOrderId(new_executionOrder) else: - raise TypeError, "Can only generate execution order on FBD networks!" + raise TypeError, _("Can only generate execution order on FBD networks!") setattr(cls, "setelementExecutionOrder", setelementExecutionOrder) def appendcontentInstance(self, name, instance): if self.content["name"] in ["LD","FBD","SFC"]: self.content["value"].appendcontent({"name" : name, "value" : instance}) else: - raise TypeError, "%s body don't have instances!"%self.content["name"] + raise TypeError, _("%s body don't have instances!")%self.content["name"] setattr(cls, "appendcontentInstance", appendcontentInstance) def getcontentInstances(self): @@ -1141,7 +1283,7 @@ instances.append(element["value"]) return instances else: - raise TypeError, "%s body don't have instances!"%self.content["name"] + raise TypeError, _("%s body don't have instances!")%self.content["name"] setattr(cls, "getcontentInstances", getcontentInstances) def getcontentInstance(self, id): @@ -1151,7 +1293,7 @@ return element["value"] return None else: - raise TypeError, "%s body don't have instances!"%self.content["name"] + raise TypeError, _("%s body don't have instances!")%self.content["name"] setattr(cls, "getcontentInstance", getcontentInstance) def getcontentRandomInstance(self, exclude): @@ -1161,7 +1303,7 @@ return element["value"] return None else: - raise TypeError, "%s body don't have instances!"%self.content["name"] + raise TypeError, _("%s body don't have instances!")%self.content["name"] setattr(cls, "getcontentRandomInstance", getcontentRandomInstance) def getcontentInstanceByName(self, name): @@ -1170,7 +1312,7 @@ if isinstance(element["value"], PLCOpenClasses.get("fbdObjects_block", None)) and element["value"].getinstanceName() == name: return element["value"] else: - raise TypeError, "%s body don't have instances!"%self.content["name"] + raise TypeError, _("%s body don't have instances!")%self.content["name"] setattr(cls, "getcontentInstanceByName", getcontentInstanceByName) def removecontentInstance(self, id): @@ -1184,7 +1326,7 @@ removed = True i += 1 if not removed: - raise ValueError, "Instance with id %d doesn't exists!"%id + raise ValueError, _("Instance with id %d doesn't exists!")%id else: raise TypeError, "%s body don't have instances!"%self.content["name"] setattr(cls, "removecontentInstance", removecontentInstance) @@ -1193,14 +1335,14 @@ if self.content["name"] in ["IL","ST"]: self.content["value"].settext(text) else: - raise TypeError, "%s body don't have text!"%self.content["name"] + raise TypeError, _("%s body don't have text!")%self.content["name"] setattr(cls, "settext", settext) def gettext(self): if self.content["name"] in ["IL","ST"]: return self.content["value"].gettext() else: - raise TypeError, "%s body don't have text!"%self.content["name"] + raise TypeError, _("%s body don't have text!")%self.content["name"] setattr(cls, "gettext", gettext) def updateElementName(self, old_name, new_name): @@ -1223,13 +1365,272 @@ def sety(self, y): self.position.sety(y) -cls = PLCOpenClasses.get("commonObjects_comment", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - +def _getBoundingBox(self): + return rect(self.getx(), self.gety(), self.getwidth(), self.getheight()) + +def _getConnectionsBoundingBox(connectionPointIn): + bbox = rect() + connections = connectionPointIn.getconnections() + if connections is not None: + for connection in connections: + for x, y in connection.getpoints(): + bbox.update(x, y) + return bbox + +def _getBoundingBoxSingle(self): + bbox = _getBoundingBox(self) + if self.connectionPointIn is not None: + bbox.union(_getConnectionsBoundingBox(self.connectionPointIn)) + return bbox + +def _getBoundingBoxMultiple(self): + bbox = _getBoundingBox(self) + for connectionPointIn in self.getconnectionPointIn(): + bbox.union(_getConnectionsBoundingBox(connectionPointIn)) + return bbox + +def _filterConnections(connectionPointIn, localId, connections): + in_connections = connectionPointIn.getconnections() + if in_connections is not None: + to_delete = [] + for i, connection in enumerate(in_connections): + connected = connection.getrefLocalId() + if not connections.has_key((localId, connected)) and \ + not connections.has_key((connected, localId)): + to_delete.append(i) + to_delete.reverse() + for i in to_delete: + connectionPointIn.removeconnection(i) + +def _filterConnectionsSingle(self, connections): + if self.connectionPointIn is not None: + _filterConnections(self.connectionPointIn, self.localId, connections) + +def _filterConnectionsMultiple(self, connections): + for connectionPointIn in self.getconnectionPointIn(): + _filterConnections(connectionPointIn, self.localId, connections) + +def _getconnectionsdefinition(instance, connections_end): + id = instance.getlocalId() + return dict([((id, end), True) for end in connections_end]) + +def _updateConnectionsId(connectionPointIn, translation): + connections_end = [] + connections = connectionPointIn.getconnections() + if connections is not None: + for connection in connections: + refLocalId = connection.getrefLocalId() + new_reflocalId = translation.get(refLocalId, refLocalId) + connection.setrefLocalId(new_reflocalId) + connections_end.append(new_reflocalId) + return connections_end + +def _updateConnectionsIdSingle(self, translation): + connections_end = [] + if self.connectionPointIn is not None: + connections_end = _updateConnectionsId(self.connectionPointIn, translation) + return _getconnectionsdefinition(self, connections_end) + +def _updateConnectionsIdMultiple(self, translation): + connections_end = [] + for connectionPointIn in self.getconnectionPointIn(): + connections_end.extend(_updateConnectionsId(connectionPointIn, translation)) + return _getconnectionsdefinition(self, connections_end) + +def _translate(self, dx, dy): + self.setx(self.getx() + dx) + self.sety(self.gety() + dy) + +def _translateConnections(connectionPointIn, dx, dy): + connections = connectionPointIn.getconnections() + if connections is not None: + for connection in connections: + for position in connection.getposition(): + position.setx(position.getx() + dx) + position.sety(position.gety() + dy) + +def _translateSingle(self, dx, dy): + _translate(self, dx, dy) + if self.connectionPointIn is not None: + _translateConnections(self.connectionPointIn, dx, dy) + +def _translateMultiple(self, dx, dy): + _translate(self, dx, dy) + for connectionPointIn in self.getconnectionPointIn(): + _translateConnections(connectionPointIn, dx, dy) + +def _updateElementName(self, old_name, new_name): + pass + +_connectionsFunctions = { + "bbox": {"none": _getBoundingBox, + "single": _getBoundingBoxSingle, + "multiple": _getBoundingBoxMultiple}, + "translate": {"none": _translate, + "single": _translateSingle, + "multiple": _translateMultiple}, + "filter": {"none": lambda self, connections: None, + "single": _filterConnectionsSingle, + "multiple": _filterConnectionsMultiple}, + "update": {"none": lambda self, translation: {}, + "single": _updateConnectionsIdSingle, + "multiple": _updateConnectionsIdMultiple} +} + +def _initElementClass(name, classname, connectionPointInType="none"): + ElementNameToClass[name] = classname + cls = PLCOpenClasses.get(classname, None) + if cls: + setattr(cls, "getx", getx) + setattr(cls, "gety", gety) + setattr(cls, "setx", setx) + setattr(cls, "sety", sety) + setattr(cls, "updateElementName", _updateElementName) + setattr(cls, "getBoundingBox", _connectionsFunctions["bbox"][connectionPointInType]) + setattr(cls, "translate", _connectionsFunctions["translate"][connectionPointInType]) + setattr(cls, "filterConnections", _connectionsFunctions["filter"][connectionPointInType]) + setattr(cls, "updateConnectionsId", _connectionsFunctions["update"][connectionPointInType]) + return cls + +def _getexecutionOrder(instance, specific_values): + executionOrder = instance.getexecutionOrderId() + if executionOrder is None: + executionOrder = 0 + specific_values["executionOrder"] = executionOrder + +def _getdefaultmodifiers(instance, infos): + infos["negated"] = instance.getnegated() + infos["edge"] = instance.getedge() + +def _getinputmodifiers(instance, infos): + infos["negated"] = instance.getnegatedIn() + infos["edge"] = instance.getedgeIn() + +def _getoutputmodifiers(instance, infos): + infos["negated"] = instance.getnegatedOut() + infos["edge"] = instance.getedgeOut() + +MODIFIERS_FUNCTIONS = {"default": _getdefaultmodifiers, + "input": _getinputmodifiers, + "output": _getoutputmodifiers} + +def _getconnectioninfos(instance, connection, links=False, modifiers=None, parameter=False): + infos = {"position": connection.getrelPositionXY()} + if parameter: + infos["name"] = instance.getformalParameter() + MODIFIERS_FUNCTIONS.get(modifiers, lambda x, y: None)(instance, infos) + if links: + infos["links"] = [] + connections = connection.getconnections() + if connections is not None: + for link in connections: + dic = {"refLocalId": link.getrefLocalId(), + "points": link.getpoints(), + "formalParameter": link.getformalParameter()} + infos["links"].append(dic) + return infos + +def _getelementinfos(instance): + return {"id": instance.getlocalId(), + "x": instance.getx(), + "y": instance.gety(), + "height": instance.getheight(), + "width": instance.getwidth(), + "specific_values": {}, + "inputs": [], + "outputs": []} + +def _getvariableinfosFunction(type, input, output): + def getvariableinfos(self): + infos = _getelementinfos(self) + infos["type"] = type + specific_values = infos["specific_values"] + specific_values["name"] = self.getexpression() + _getexecutionOrder(self, specific_values) + if input and output: + infos["inputs"].append(_getconnectioninfos(self, self.connectionPointIn, True, "input")) + infos["outputs"].append(_getconnectioninfos(self, self.connectionPointOut, False, "output")) + elif input: + infos["inputs"].append(_getconnectioninfos(self, self.connectionPointIn, True, "default")) + elif output: + infos["outputs"].append(_getconnectioninfos(self, self.connectionPointOut, False, "default")) + return infos + return getvariableinfos + +def _getconnectorinfosFunction(type): + def getvariableinfos(self): + infos = _getelementinfos(self) + infos["type"] = type + infos["specific_values"]["name"] = self.getname() + if type == "connector": + infos["inputs"].append(_getconnectioninfos(self, self.connectionPointIn, True)) + elif type == "continuation": + infos["outputs"].append(_getconnectioninfos(self, self.connectionPointOut)) + return infos + return getvariableinfos + +def _getpowerrailinfosFunction(type): + def getpowerrailinfos(self): + infos = _getelementinfos(self) + infos["type"] = type + if type == "rightPowerRail": + for connectionPointIn in self.getconnectionPointIn(): + infos["inputs"].append(_getconnectioninfos(self, connectionPointIn, True)) + infos["specific_values"]["connectors"] = [True for input in infos["inputs"]] + elif type == "leftPowerRail": + for connectionPointOut in self.getconnectionPointOut(): + infos["outputs"].append(_getconnectioninfos(self, connectionPointOut)) + infos["specific_values"]["connectors"] = [True for output in infos["outputs"]] + return infos + return getpowerrailinfos + +def _getldelementinfosFunction(type): + def getldelementinfos(self): + infos = _getelementinfos(self) + infos["type"] = type + specific_values = infos["specific_values"] + specific_values["name"] = self.getvariable() + _getexecutionOrder(self, specific_values) + specific_values["negated"] = self.getnegated() + specific_values["edge"] = self.getedge() + if type == "coil": + specific_values["storage"] = self.getstorage() + infos["inputs"].append(_getconnectioninfos(self, self.connectionPointIn, True)) + infos["outputs"].append(_getconnectioninfos(self, self.connectionPointOut)) + return infos + return getldelementinfos + +DIVERGENCE_TYPES = {(True, True): "simultaneousDivergence", + (True, False): "selectionDivergence", + (False, True): "simultaneousConvergence", + (False, False): "selectionConvergence"} + +def _getdivergenceinfosFunction(divergence, simultaneous): + def getdivergenceinfos(self): + infos = _getelementinfos(self) + infos["type"] = DIVERGENCE_TYPES[(divergence, simultaneous)] + if divergence: + infos["inputs"].append(_getconnectioninfos(self, self.connectionPointIn, True)) + for connectionPointOut in self.getconnectionPointOut(): + infos["outputs"].append(_getconnectioninfos(self, connectionPointOut)) + infos["specific_values"]["connectors"] = len(infos["outputs"]) + else: + for connectionPointIn in self.getconnectionPointIn(): + infos["inputs"].append(_getconnectioninfos(self, connectionPointIn, True)) + infos["outputs"].append(_getconnectioninfos(self, self.connectionPointOut)) + infos["specific_values"]["connectors"] = len(infos["inputs"]) + return infos + return getdivergenceinfos + +cls = _initElementClass("comment", "commonObjects_comment") +if cls: + def getinfos(self): + infos = _getelementinfos(self) + infos["type"] = "comment" + infos["specific_values"]["content"] = self.getcontentText() + return infos + setattr(cls, "getinfos", getinfos) + def setcontentText(self, text): self.content.settext(text) setattr(cls, "setcontentText", setcontentText) @@ -1242,81 +1643,131 @@ self.content.updateElementName(old_name, new_name) setattr(cls, "updateElementName", updateElementName) -cls = PLCOpenClasses.get("fbdObjects_block", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) +cls = _initElementClass("block", "fbdObjects_block") +if cls: + def getBoundingBox(self): + bbox = _getBoundingBox(self) + for input in self.inputVariables.getvariable(): + bbox.union(_getConnectionsBoundingBox(input.connectionPointIn)) + return bbox + setattr(cls, "getBoundingBox", getBoundingBox) + + def getinfos(self): + infos = _getelementinfos(self) + infos["type"] = self.gettypeName() + specific_values = infos["specific_values"] + specific_values["name"] = self.getinstanceName() + _getexecutionOrder(self, specific_values) + for variable in self.inputVariables.getvariable(): + infos["inputs"].append(_getconnectioninfos(variable, variable.connectionPointIn, True, "default", True)) + for variable in self.outputVariables.getvariable(): + infos["outputs"].append(_getconnectioninfos(variable, variable.connectionPointOut, False, "default", True)) + return infos + setattr(cls, "getinfos", getinfos) def updateElementName(self, old_name, new_name): if self.typeName == old_name: self.typeName = new_name setattr(cls, "updateElementName", updateElementName) -cls = PLCOpenClasses.get("ldObjects_leftPowerRail", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - - def updateElementName(self, old_name, new_name): - pass - setattr(cls, "updateElementName", updateElementName) - -cls = PLCOpenClasses.get("ldObjects_rightPowerRail", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - - def updateElementName(self, old_name, new_name): - pass - setattr(cls, "updateElementName", updateElementName) - -cls = PLCOpenClasses.get("ldObjects_contact", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - + def filterConnections(self, connections): + for input in self.inputVariables.getvariable(): + _filterConnections(input.connectionPointIn, self.localId, connections) + setattr(cls, "filterConnections", filterConnections) + + def updateConnectionsId(self, translation): + connections_end = [] + for input in self.inputVariables.getvariable(): + connections_end.extend(_updateConnectionsId(input.connectionPointIn, translation)) + return _getconnectionsdefinition(self, connections_end) + setattr(cls, "updateConnectionsId", updateConnectionsId) + + def translate(self, dx, dy): + _translate(self, dx, dy) + for input in self.inputVariables.getvariable(): + _translateConnections(input.connectionPointIn, dx, dy) + setattr(cls, "translate", translate) + +cls = _initElementClass("leftPowerRail", "ldObjects_leftPowerRail") +if cls: + setattr(cls, "getinfos", _getpowerrailinfosFunction("leftPowerRail")) + +cls = _initElementClass("rightPowerRail", "ldObjects_rightPowerRail", "multiple") +if cls: + setattr(cls, "getinfos", _getpowerrailinfosFunction("rightPowerRail")) + +cls = _initElementClass("contact", "ldObjects_contact", "single") +if cls: + setattr(cls, "getinfos", _getldelementinfosFunction("contact")) + def updateElementName(self, old_name, new_name): if self.variable == old_name: self.variable = new_name setattr(cls, "updateElementName", updateElementName) - -cls = PLCOpenClasses.get("ldObjects_coil", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - + +cls = _initElementClass("coil", "ldObjects_coil", "single") +if cls: + setattr(cls, "getinfos", _getldelementinfosFunction("coil")) + def updateElementName(self, old_name, new_name): if self.variable == old_name: self.variable = new_name setattr(cls, "updateElementName", updateElementName) -cls = PLCOpenClasses.get("sfcObjects_step", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - - def updateElementName(self, old_name, new_name): - pass - setattr(cls, "updateElementName", updateElementName) - -cls = PLCOpenClasses.get("sfcObjects_transition", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) +cls = _initElementClass("step", "sfcObjects_step", "single") +if cls: + def getinfos(self): + infos = _getelementinfos(self) + infos["type"] = "step" + specific_values = infos["specific_values"] + specific_values["name"] = self.getname() + specific_values["initial"] = self.getinitialStep() + if self.connectionPointIn: + infos["inputs"].append(_getconnectioninfos(self, self.connectionPointIn, True)) + if self.connectionPointOut: + infos["outputs"].append(_getconnectioninfos(self, self.connectionPointOut)) + if self.connectionPointOutAction: + specific_values["action"] = _getconnectioninfos(self, self.connectionPointOutAction) + return infos + setattr(cls, "getinfos", getinfos) + +cls = PLCOpenClasses.get("transition_condition", None) +if cls: + def compatibility(self, tree): + connections = [] + for child in tree.childNodes: + if child.nodeName == "connection": + connections.append(child) + if len(connections) > 0: + node = CreateNode("connectionPointIn") + relPosition = CreateNode("relPosition") + NodeSetAttr(relPosition, "x", "0") + NodeSetAttr(relPosition, "y", "0") + node.childNodes.append(relPosition) + node.childNodes.extend(connections) + tree.childNodes = [node] + setattr(cls, "compatibility", compatibility) + +cls = _initElementClass("transition", "sfcObjects_transition", "single") +if cls: + def getinfos(self): + infos = _getelementinfos(self) + infos["type"] = "transition" + specific_values = infos["specific_values"] + priority = self.getpriority() + if priority is None: + priority = 0 + specific_values["priority"] = priority + condition = self.getconditionContent() + specific_values["condition_type"] = condition["type"] + if specific_values["condition_type"] == "connection": + specific_values["connection"] = _getconnectioninfos(self, condition["value"], True) + else: + specific_values["condition"] = condition["value"] + infos["inputs"].append(_getconnectioninfos(self, self.connectionPointIn, True)) + infos["outputs"].append(_getconnectioninfos(self, self.connectionPointOut)) + return infos + setattr(cls, "getinfos", getinfos) def setconditionContent(self, type, value): if not self.condition: @@ -1329,7 +1780,8 @@ condition.setcontent({"name" : "ST", "value" : PLCOpenClasses["formattedText"]()}) condition.settext(value) elif type == "connection": - condition = [PLCOpenClasses["connection"]()] + type = "connectionPointIn" + condition = PLCOpenClasses["connectionPointIn"]() self.condition.setcontent({"name" : type, "value" : condition}) setattr(cls, "setconditionContent", setconditionContent) @@ -1341,6 +1793,9 @@ values["value"] = content["value"].getname() elif values["type"] == "inline": values["value"] = content["value"].gettext() + elif values["type"] == "connectionPointIn": + values["type"] = "connection" + values["value"] = content["value"] return values return "" setattr(cls, "getconditionContent", getconditionContent) @@ -1355,139 +1810,52 @@ content["value"].updateElementName(old_name, new_name) setattr(cls, "updateElementName", updateElementName) - def addconnection(self): - if self.condition: - content = self.condition.getcontent() - if content["name"] != "connection": - self.condition.setcontent({"name" : "connection", "value" : [PLCOpenClasses["connection"]()]}) - content = self.condition.getcontent() - else: - content["value"].append(PLCOpenClasses["connection"]()) - setattr(cls, "addconnection", addconnection) - - def removeconnection(self, idx): - if self.condition: - content = self.condition.getcontent() - if content["name"] == "connection": - content["value"].pop(idx) - setattr(cls, "removeconnection", removeconnection) - - def removeconnections(self): - if self.condition: - content = self.condition.getcontent() - if content["name"] == "connection": - content["value"] = [PLCOpenClasses["connection"]()] - setattr(cls, "removeconnections", removeconnections) - def getconnections(self): if self.condition: content = self.condition.getcontent() - if content["name"] == "connection": - return content["value"] + if content["name"] == "connectionPointIn": + return content["value"].getconnections() setattr(cls, "getconnections", getconnections) - def setconnectionId(self, idx, id): - if self.condition: - content = self.condition.getcontent() - if content["name"] == "connection": - content["value"][idx].setrefLocalId(id) - setattr(cls, "setconnectionId", setconnectionId) - - def getconnectionId(self, idx): - if self.condition: - content = self.condition.getcontent() - if content["name"] == "connection": - return content["value"][idx].getrefLocalId() - return None - setattr(cls, "getconnectionId", getconnectionId) - - def setconnectionPoints(self, idx, points): - if self.condition: - content = self.condition.getcontent() - if content["name"] == "connection": - content["value"][idx].setpoints(points) - setattr(cls, "setconnectionPoints", setconnectionPoints) - - def getconnectionPoints(self, idx): - if self.condition: - content = self.condition.getcontent() - if content["name"] == "connection": - return content["value"][idx].getpoints() - return None - setattr(cls, "getconnectionPoints", getconnectionPoints) - - def setconnectionParameter(self, idx, parameter): - if self.condition: - content = self.condition.getcontent() - if content["name"] == "connection": - content["value"][idx].setformalParameter(parameter) - setattr(cls, "setconnectionParameter", setconnectionParameter) - - def getconnectionParameter(self, idx): - if self.condition: - content = self.condition.getcontent() - if content["name"] == "connection": - return content["value"][idx].getformalParameter() - return None - setattr(cls, "getconnectionParameter", getconnectionParameter) - -cls = PLCOpenClasses.get("sfcObjects_selectionDivergence", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - - def updateElementName(self, old_name, new_name): - pass - setattr(cls, "updateElementName", updateElementName) - -cls = PLCOpenClasses.get("sfcObjects_selectionConvergence", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - - def updateElementName(self, old_name, new_name): - pass - setattr(cls, "updateElementName", updateElementName) - -cls = PLCOpenClasses.get("sfcObjects_simultaneousDivergence", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - - def updateElementName(self, old_name, new_name): - pass - setattr(cls, "updateElementName", updateElementName) - -cls = PLCOpenClasses.get("sfcObjects_simultaneousConvergence", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - - def updateElementName(self, old_name, new_name): - pass - setattr(cls, "updateElementName", updateElementName) - -cls = PLCOpenClasses.get("sfcObjects_jumpStep", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - - def updateElementName(self, old_name, new_name): - pass - setattr(cls, "updateElementName", updateElementName) +cls = _initElementClass("selectionDivergence", "sfcObjects_selectionDivergence", "single") +if cls: + setattr(cls, "getinfos", _getdivergenceinfosFunction(True, False)) + +cls = _initElementClass("selectionConvergence", "sfcObjects_selectionConvergence", "multiple") +if cls: + setattr(cls, "getinfos", _getdivergenceinfosFunction(False, False)) + +cls = _initElementClass("simultaneousDivergence", "sfcObjects_simultaneousDivergence", "single") +if cls: + setattr(cls, "getinfos", _getdivergenceinfosFunction(True, True)) + +cls = _initElementClass("simultaneousConvergence", "sfcObjects_simultaneousConvergence", "multiple") +if cls: + setattr(cls, "getinfos", _getdivergenceinfosFunction(False, True)) + +cls = _initElementClass("jumpStep", "sfcObjects_jumpStep", "single") +if cls: + def getinfos(self): + infos = _getelementinfos(self) + infos["type"] = "jump" + infos["specific_values"]["target"] = self.gettargetName() + infos["inputs"].append(_getconnectioninfos(self, self.connectionPointIn, True)) + return infos + setattr(cls, "getinfos", getinfos) cls = PLCOpenClasses.get("actionBlock_action", None) if cls: + def compatibility(self, tree): + relPosition = reduce(lambda x, y: x | (y.nodeName == "relPosition"), tree.childNodes, False) + if not tree.hasAttribute("localId"): + NodeSetAttr(tree, "localId", "0") + if not relPosition: + node = CreateNode("relPosition") + NodeSetAttr(node, "x", "0") + NodeSetAttr(node, "y", "0") + tree.childNodes.insert(0, node) + setattr(cls, "compatibility", compatibility) + def setreferenceName(self, name): if self.reference: self.reference.setname(name) @@ -1518,13 +1886,22 @@ self.inline.updateElementName(old_name, new_name) setattr(cls, "updateElementName", updateElementName) -cls = PLCOpenClasses.get("commonObjects_actionBlock", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - +cls = _initElementClass("actionBlock", "commonObjects_actionBlock", "single") +if cls: + def compatibility(self, tree): + for child in tree.childNodes[:]: + if child.nodeName == "connectionPointOut": + tree.childNodes.remove(child) + setattr(cls, "compatibility", compatibility) + + def getinfos(self): + infos = _getelementinfos(self) + infos["type"] = "actionBlock" + infos["specific_values"]["actions"] = self.getactions() + infos["inputs"].append(_getconnectioninfos(self, self.connectionPointIn, True)) + return infos + setattr(cls, "getinfos", getinfos) + def setactions(self, actions): self.action = [] for params in actions: @@ -1536,9 +1913,9 @@ else: action.addinline() action.setinlineContent(params["value"]) - if "duration" in params: + if params.has_key("duration"): action.setduration(params["duration"]) - if "indicator" in params: + if params.has_key("indicator"): action.setindicator(params["indicator"]) self.action.append(action) setattr(cls, "setactions", setactions) @@ -1571,63 +1948,40 @@ action.updateElementName(old_name, new_name) setattr(cls, "updateElementName", updateElementName) -cls = PLCOpenClasses.get("fbdObjects_inVariable", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) +cls = _initElementClass("inVariable", "fbdObjects_inVariable") +if cls: + setattr(cls, "getinfos", _getvariableinfosFunction("input", False, True)) def updateElementName(self, old_name, new_name): if self.expression == old_name: self.expression = new_name setattr(cls, "updateElementName", updateElementName) -cls = PLCOpenClasses.get("fbdObjects_outVariable", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - +cls = _initElementClass("outVariable", "fbdObjects_outVariable", "single") +if cls: + setattr(cls, "getinfos", _getvariableinfosFunction("output", True, False)) + def updateElementName(self, old_name, new_name): if self.expression == old_name: self.expression = new_name setattr(cls, "updateElementName", updateElementName) -cls = PLCOpenClasses.get("fbdObjects_inOutVariable", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - +cls = _initElementClass("inOutVariable", "fbdObjects_inOutVariable", "single") +if cls: + setattr(cls, "getinfos", _getvariableinfosFunction("inout", True, True)) + def updateElementName(self, old_name, new_name): if self.expression == old_name: self.expression = new_name setattr(cls, "updateElementName", updateElementName) -cls = PLCOpenClasses.get("commonObjects_continuation", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - - def updateElementName(self, old_name, new_name): - pass - setattr(cls, "updateElementName", updateElementName) - -cls = PLCOpenClasses.get("commonObjects_connector", None) -if cls: - setattr(cls, "getx", getx) - setattr(cls, "gety", gety) - setattr(cls, "setx", setx) - setattr(cls, "sety", sety) - - def updateElementName(self, old_name, new_name): - pass - setattr(cls, "updateElementName", updateElementName) +cls = _initElementClass("continuation", "commonObjects_continuation") +if cls: + setattr(cls, "getinfos", _getconnectorinfosFunction("continuation")) + +cls = _initElementClass("connector", "commonObjects_connector", "single") +if cls: + setattr(cls, "getinfos", _getconnectorinfosFunction("connector")) cls = PLCOpenClasses.get("connection", None) if cls: @@ -1763,7 +2117,7 @@ elif opened == closed: i += 1 else: - raise ValueError, "\"%s\" is an invalid value!"%value + raise ValueError, _("\"%s\" is an invalid value!")%value return items cls = PLCOpenClasses.get("value_arrayValue", None) @@ -1778,7 +2132,7 @@ result = arrayValue_model.match(item) if result is not None: groups = result.groups() - element.setrepetitionValue(int(groups[0])) + element.setrepetitionValue(groups[0]) element.setvalue(groups[1].strip()) else: element.setvalue(item) @@ -1790,7 +2144,7 @@ for element in self.value: repetition = element.getrepetitionValue() if repetition is not None and repetition > 1: - values.append("%d(%s)"%(repetition, element.getvalue())) + values.append("%s(%s)"%(repetition, element.getvalue())) else: values.append(element.getvalue()) return "[%s]"%", ".join(values) diff -r d07815f10ca8 -r 323c8d76f6f2 plcopen/structures.py --- a/plcopen/structures.py Mon Jul 27 12:01:43 2009 +0200 +++ b/plcopen/structures.py Fri Aug 07 15:49:10 2009 +0200 @@ -33,6 +33,8 @@ "D" : ["DINT", "UDINT", "REAL", "DWORD"], "L" : ["LINT", "ULINT", "LREAL", "LWORD"]} +_ = lambda x:x + # Helper for emulate join on element list def JoinList(separator, mylist): if len(mylist) > 0 : @@ -92,7 +94,7 @@ generator.Program += JoinList([(", ", ())], vars) generator.Program += [(");\n", ())] else: - generator.Warnings.append("\"%s\" function cancelled in \"%s\" POU: No input connected"%(type, generator.TagName.split("::")[-1])) + generator.Warnings.append(_("\"%s\" function cancelled in \"%s\" POU: No input connected")%(type, generator.TagName.split("::")[-1])) if link: connectionPoint = link.getposition()[-1] else: @@ -134,7 +136,7 @@ output_info = (generator.TagName, "block", block.getlocalId(), "output", i) return generator.ExtractModifier(variable, [("%s.%s"%(name, variable.getformalParameter()), output_info)], output_info) if link is not None: - raise ValueError, "No output variable found" + raise ValueError, _("No output variable found") def initialise_block(type, name, block = None): return [(type, name, None, None)] @@ -160,98 +162,98 @@ - The default modifier which can be "none", "negated", "rising" or "falling" """ -BlockTypes = [{"name" : "Standard function blocks", "list": +BlockTypes = [{"name" : _("Standard function blocks"), "list": [{"name" : "SR", "type" : "functionBlock", "extensible" : False, "inputs" : [("S1","BOOL","none"),("R","BOOL","none")], "outputs" : [("Q1","BOOL","none")], - "comment" : "SR bistable\nThe SR bistable is a latch where the Set dominates.", + "comment" : _("SR bistable\nThe SR bistable is a latch where the Set dominates."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "RS", "type" : "functionBlock", "extensible" : False, "inputs" : [("S","BOOL","none"),("R1","BOOL","none")], "outputs" : [("Q1","BOOL","none")], - "comment" : "RS bistable\nThe RS bistable is a latch where the Reset dominates.", + "comment" : _("RS bistable\nThe RS bistable is a latch where the Reset dominates."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "SEMA", "type" : "functionBlock", "extensible" : False, "inputs" : [("CLAIM","BOOL","none"),("RELEASE","BOOL","none")], "outputs" : [("BUSY","BOOL","none")], - "comment" : "Semaphore\nThe semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources.", + "comment" : _("Semaphore\nThe semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "R_TRIG", "type" : "functionBlock", "extensible" : False, "inputs" : [("CLK","BOOL","none")], "outputs" : [("Q","BOOL","none")], - "comment" : "Rising edge detector\nThe output produces a single pulse when a rising edge is detected.", + "comment" : _("Rising edge detector\nThe output produces a single pulse when a rising edge is detected."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "F_TRIG", "type" : "functionBlock", "extensible" : False, "inputs" : [("CLK","BOOL","none")], "outputs" : [("Q","BOOL","none")], - "comment" : "Falling edge detector\nThe output produces a single pulse when a falling edge is detected.", + "comment" : _("Falling edge detector\nThe output produces a single pulse when a falling edge is detected."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "CTU", "type" : "functionBlock", "extensible" : False, "inputs" : [("CU","BOOL","rising"),("R","BOOL","none"),("PV","INT","none")], "outputs" : [("Q","BOOL","none"),("CV","INT","none")], - "comment" : "Up-counter\nThe up-counter can be used to signal when a count has reached a maximum value.", + "comment" : _("Up-counter\nThe up-counter can be used to signal when a count has reached a maximum value."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "CTD", "type" : "functionBlock", "extensible" : False, "inputs" : [("CD","BOOL","rising"),("LD","BOOL","none"),("PV","INT","none")], "outputs" : [("Q","BOOL","none"),("CV","INT","none")], - "comment" : "Down-counter\nThe down-counter can be used to signal when a count has reached zero, on counting down from a preset value.", + "comment" : _("Down-counter\nThe down-counter can be used to signal when a count has reached zero, on counting down from a preset value."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "CTUD", "type" : "functionBlock", "extensible" : False, "inputs" : [("CU","BOOL","rising"),("CD","BOOL","rising"),("R","BOOL","none"),("LD","BOOL","none"),("PV","INT","none")], "outputs" : [("QU","BOOL","none"),("QD","BOOL","none"),("CV","INT","none")], - "comment" : "Up-down counter\nThe up-down counter has two inputs CU and CD. It can be used to both count up on one input ans down on the other.", + "comment" : _("Up-down counter\nThe up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "TP", "type" : "functionBlock", "extensible" : False, "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], "outputs" : [("Q","BOOL","none"),("ET","TIME","none")], - "comment" : "Pulse timer\nThe pulse timer can be used to generate output pulses of a given time duration.", + "comment" : _("Pulse timer\nThe pulse timer can be used to generate output pulses of a given time duration."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "TON", "type" : "functionBlock", "extensible" : False, "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], "outputs" : [("Q","BOOL","none"),("ET","TIME","none")], - "comment" : "On-delay timer\nThe on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true.", + "comment" : _("On-delay timer\nThe on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "TOF", "type" : "functionBlock", "extensible" : False, "inputs" : [("IN","BOOL","none"),("PT","TIME","none")], "outputs" : [("Q","BOOL","none"),("ET","TIME","none")], - "comment" : "Off-delay timer\nThe off-delay timer can be used to delay setting an output false, for fixed period after input goes false.", + "comment" : _("Off-delay timer\nThe off-delay timer can be used to delay setting an output false, for fixed period after input goes false."), "generate" : generate_block, "initialise" : initialise_block}, ]}, - {"name" : "Additionnal function blocks", "list": + {"name" : _("Additionnal function blocks"), "list": ## {"name" : "RTC", "type" : "functionBlock", "extensible" : False, ## "inputs" : [("EN","BOOL","none"),("PDT","DATE_AND_TIME","none")], ## "outputs" : [("Q","BOOL","none"),("CDT","DATE_AND_TIME","none")], -## "comment" : "Real time clock\nThe real time clock has many uses including time stamping, setting dates and times of day in batch reports, in alarm messages and so on.", +## "comment" : _("Real time clock\nThe real time clock has many uses including time stamping, setting dates and times of day in batch reports, in alarm messages and so on."), ## "generate" : generate_block, "initialise" : initialise_block}, [{"name" : "INTEGRAL", "type" : "functionBlock", "extensible" : False, "inputs" : [("RUN","BOOL","none"),("R1","BOOL","none"),("XIN","REAL","none"),("X0","REAL","none"),("CYCLE","TIME","none")], "outputs" : [("Q","BOOL","none"),("XOUT","REAL","none")], - "comment" : "Integral\nThe integral function block integrates the value of input XIN over time.", + "comment" : _("Integral\nThe integral function block integrates the value of input XIN over time."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "DERIVATIVE", "type" : "functionBlock", "extensible" : False, "inputs" : [("RUN","BOOL","none"),("XIN","REAL","none"),("CYCLE","TIME","none")], "outputs" : [("XOUT","REAL","none")], - "comment" : "Derivative\nThe derivative function block produces an output XOUT proportional to the rate of change of the input XIN.", + "comment" : _("Derivative\nThe derivative function block produces an output XOUT proportional to the rate of change of the input XIN."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "PID", "type" : "functionBlock", "extensible" : False, "inputs" : [("AUTO","BOOL","none"),("PV","REAL","none"),("SP","REAL","none"),("X0","REAL","none"),("KP","REAL","none"),("TR","REAL","none"),("TD","REAL","none"),("CYCLE","TIME","none")], "outputs" : [("XOUT","REAL","none")], - "comment" : "PID\nThe PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control.", + "comment" : _("PID\nThe PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "RAMP", "type" : "functionBlock", "extensible" : False, "inputs" : [("RUN","BOOL","none"),("X0","REAL","none"),("X1","REAL","none"),("TR","TIME","none"),("CYCLE","TIME","none"),("HOLDBACK","BOOL","none"),("ERROR","REAL","none"),("PV","REAL","none")], "outputs" : [("RAMP","BOOL","none"),("XOUT","REAL","none")], - "comment" : "Ramp\nThe RAMP function block is modelled on example given in the standard but with the addition of a 'Holdback' feature.", + "comment" : _("Ramp\nThe RAMP function block is modelled on example given in the standard but with the addition of a 'Holdback' feature."), "generate" : generate_block, "initialise" : initialise_block}, {"name" : "HYSTERESIS", "type" : "functionBlock", "extensible" : False, "inputs" : [("XIN1","REAL","none"),("XIN2","REAL","none"),("EPS","REAL","none")], "outputs" : [("Q","BOOL","none")], - "comment" : "Hysteresis\nThe hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2.", + "comment" : _("Hysteresis\nThe hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2."), "generate" : generate_block, "initialise" : initialise_block}, ## {"name" : "RATIO_MONITOR", "type" : "functionBlock", "extensible" : False, ## "inputs" : [("PV1","REAL","none"),("PV2","REAL","none"),("RATIO","REAL","none"),("TIMON","TIME","none"),("TIMOFF","TIME","none"),("TOLERANCE","BOOL","none"),("RESET","BOOL","none"),("CYCLE","TIME","none")], ## "outputs" : [("ALARM","BOOL","none"),("TOTAL_ERR","BOOL","none")], -## "comment" : "Ratio monitor\nThe ratio_monitor function block checks that one process value PV1 is always a given ratio (defined by input RATIO) of a second process value PV2.", +## "comment" : _("Ratio monitor\nThe ratio_monitor function block checks that one process value PV1 is always a given ratio (defined by input RATIO) of a second process value PV2."), ## "generate" : generate_block, "initialise" : initialise_block} ]}, ] @@ -503,7 +505,12 @@ if fields[1]: # If function section name given if fields[0]: - Current_section = {"name" : fields[0], "list" : []} + words = fields[0].split('"') + if len(words) > 1: + section_name = words[1] + else: + section_name = fields[0] + Current_section = {"name" : section_name, "list" : []} Standard_Functions_Decl.append(Current_section) Function_decl_list = [] if Current_section: @@ -563,7 +570,10 @@ # create the copy of decl dict to be appended to section Function_decl_copy = Function_decl.copy() # Have to generate type description in comment with freshly redefined types - Function_decl_copy["comment"] += ( + words = Function_decl_copy["comment"].split('"') + if len(words) > 1: + Function_decl_copy["comment"] = words[1] + Function_decl_copy["usage"] = ( "\n (" + str([ " " + fctdecl[1]+":"+fctdecl[0] for fctdecl in Function_decl["inputs"]]).strip("[]").replace("'",'') + " ) => (" + diff -r d07815f10ca8 -r 323c8d76f6f2 plcopen/tc6_xml_v201.xsd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plcopen/tc6_xml_v201.xsd Fri Aug 07 15:49:10 2009 +0200 @@ -0,0 +1,1756 @@ + + + + + The complete project + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Documentation language of the project e.g. "en-US" + + + + + + + + + + + + + + + + + + + Additional userspecific information to the element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Additional userspecific information to the element + + + + + + + + + + + + + + + + Additional userspecific information to the element + + + + + + + + + + + + + + + + + + + + + Additional userspecific information to the element + + + + + + + + + + + + + + + Additional userspecific information to the element + + + + + + + + + + + + + + + + + + + + + + + + Represents a group of resources and global variables + + + + + + Represents a group of programs and tasks and global variables + + + + + + Represents a periodic or triggered task + + + + + + + Additional userspecific information to the element + + + + + + + + Vendor specific: Either a constant duration as defined in the IEC or variable name. + + + + + + + + + + + + + + + + + + + Additional userspecific information to the element + + + + + + + + + + + + + + Additional userspecific information to the element + + + + + + + + + + + + + + + + + Additional userspecific information to the element + + + + + + + + A generic data type + + + + + + + + + + Defines a range with signed bounds + + + + + + + Defines a range with unsigned bounds + + + + + + + A generic value + + + + + + Value that can be represented as a single token string + + + + + + + + Array value consisting of a list of occurrances - value pairs + + + + + + + + + + + + + + + + + + Struct value consisting of a list of member - value pairs + + + + + + + + + + + + + + + + + + + Implementation part of a POU, action or transistion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Additional userspecific information to the element + + + + + + + + + List of variable declarations that share the same memory attributes (CONSTANT, RETAIN, NON_RETAIN, PERSISTENT) + + + + + + + + + + + + + + + List of variable declarations without attributes + + + + + + Declaration of a variable + + + + + + + + + + + + + + + + + + + List of access variable declarations + + + + + + Declaration of an access variable + + + + + + + + + Name that is visible to the communication partner + + + + + Variable name including instance path inside the configuration + + + + + + + + + + + + List of VAR_CONFIG variables + + + + + + Declaration of an access variable + + + + + + + + + + Variable name including instance path + + + + + + + + + + + + Defines a graphical position in X, Y coordinates + + + + + + + Describes a connection between the consumer element (eg. input variable of a function block) and the producer element (eg. output variable of a function block). It may contain a list of positions that describes the path of the connection. + + + + + All positions of the directed connection path. If any positions are given, the list has to contain the first (input pin of the consumer element) as well as the last (output pin of the producer element). + + + + + + + + Identifies the element the connection starts from. + + + + + If present: + This attribute denotes the name of the VAR_OUTPUT / VAR_IN_OUTparameter of the pou block that is the start of the connection. + If not present: + If the refLocalId attribute refers to a pou block, the start of the connection is the first output of this block, which is not ENO. + If the refLocalId attribute refers to any other element type, the start of the connection is the elements single native output. + + + + + + Defines a connection point on the consumer side + + + + + Relative position of the connection pin. Origin is the anchor position of the block. + + + + + + + The operand is a valid iec variable e.g. avar[0] or an iec expression or multiple token text e.g. a + b (*sum*). An iec 61131-3 parser has to be used to extract variable information. + + + + + + + + + + Defines a connection point on the producer side + + + + + Relative position of the connection pin. Origin is the anchor position of the block. + + + + + The operand is a valid iec variable e.g. avar[0]. + + + + + + + + + Represents a program or function block instance either running with or without a task + + + + + + + + + + + + Formatted text according to parts of XHTML 1.1 + + + + + + + + Application specific data defined in external schemata + + + + + + + + + + Uniquely identifies the additional data element. + + + + + Recommended processor handling for unknown data elements. +Specifies if the processor should try to preserve the additional data element, dismiss the element (e.g. because the data is invalid if not updated correctly) or use the processors default behaviour for unknown data. + + + + + + + + + + + + + + + + List of additional data elements used in the document with description + + + + + + + + + + Unique name of the additional data element. + + + + + Version of additional data, eg. schema version. + + + + + Vendor responsible for the definition of the additional data element. + + + + + + + + + Collection of elementary IEC 61131-3 datatypes + + + + + + + + + + + + + + + + + + + + + + + + + The single byte character string type + + + + + + + + The wide character (WORD) string type + + + + + + + + + + + + + + + + + + + Collection of derived IEC 61131-3 datatypes + + + + + + + + + + + + + Reference to a user defined datatype or POU. Variable declarations use this type to declare e.g. function block instances. + + + + The user defined alias type + + + + + + + + + + + + + + + + + An enumeration value used to build up enumeration types + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Collection of datatypes not defined in IEC 61131-3 + + + + + + + + + + + + + + Collection of objects which have no direct iec scope and can be used in any graphical body. + + + + + + + + + + + + + + + + + + + + Describes a graphical object representing a conversion error. Used to keep information which can not be interpreted by the importing system + + + + + + + + + + + + + + + + + Describes a graphical object representing a variable, literal or expression used as r-value + + + + + + + + + + The operand is a valid iec variable e.g. avar[0] + + + + + + + + + + + Counterpart of the connector element + + + + Describes a graphical object representing a variable, literal or expression used as r-value + + + + + + + + + + The operand is a valid iec variable e.g. avar[0] + + + + + + + + + + + + + + + + + Association of an action with qualifier + + + + + Relative position of the action. Origin is the anchor position of the action block. + + + + + Name of an action or boolean variable. + + + + + + + + Inline implementation of an action body. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used to identify the order of execution. Also used to identify one special block if there are several blocks with the same name. + + + + + + + + + + + + + + + Used to identify the order of execution. Also used to identify one special block if there are several blocks with the same name. + + + + + + + + + Describes a graphical object representing a call statement + + + + + Anchor position of the box. Top left corner excluding the instance name. + + + + + An alternative text to be displayed in generic representation of unknown elements. + + + + + The list of used input variables (consumers) + + + + + + + Describes an inputVariable of a Function or a FunctionBlock + + + + + + + + + + + + + + + + + + The list of used inOut variables + + + + + + + Describes a inOutVariable of a Function or a FunctionBlock + + + + + + + + + + + + + + + + + + + The list of used output variables (producers) + + + + + + + Describes a outputVariable of a Function or a FunctionBlock + + + + + + + + + + + + + + + + + + Additional, vendor specific data for the element. Also defines the vendor specific meaning of the element. + + + + + + + + + Used to identify the order of execution. Also used to identify one special block if there are several blocks with the same name. + + + + + + + + + + Collection of objects which are defined in fbd. They can be used in all graphical bodies. + + + + + + Describes a graphical object representing a call statement + + + + + Anchor position of the box. Top left corner excluding the instance name. + + + + + The list of used input variables (consumers) + + + + + + + Describes an inputVariable of a Function or a FunctionBlock + + + + + + + + + + + + + + + + + + The list of used inOut variables + + + + + + + Describes a inOutVariable of a Function or a FunctionBlock + + + + + + + + + + + + + + + + + + + The list of used output variables (producers) + + + + + + + Describes a outputVariable of a Function or a FunctionBlock + + + + + + + + + + + + + + + + + + + + + + + + + + Used to identify the order of execution. Also used to identify one special block if there are several blocks with the same name. + + + + + + + + Expression used as producer + + + + Describes a graphical object representing a variable, literal or expression used as r-value + + + + + + + The operand is a valid iec variable e.g. avar[0]. + + + + + + + + + + + + + + + + + + Expression used as consumer + + + + Describes a graphical object representing a variable or expression used as l-value + + + + + + + The operand is a valid iec variable e.g. avar[0]. + + + + + + + + + + + + + + + + + + Expression used as producer and consumer + + + + Describes a graphical object representing a variable which can be used as l-value and r-value at the same time + + + + + + + + The operand is a valid iec variable e.g. avar[0]. + + + + + + + + + + + + + + + + + + + + + + Describes a graphical object representing a jump label + + + + + + + + + + + + + + + + + + Describes a graphical object representing a jump statement + + + + + + + + + + + + + + + + + + + Describes a graphical object representing areturn statement + + + + + + + + + + + + + + + + + + + Collection of objects which are defined in ld and are an extension to fbd. They can be used in ld and sfc bodies + + + + + + Describes a graphical object representing a left powerrail + + + + + + + + + + + + + + + + + + + + + Used to identify the order of execution. Also used to identify one special block if there are several blocks with the same name. + + + + + + + + + Describes a graphical object representing a right powerrail + + + + + + + + + + + + + Used to identify the order of execution. Also used to identify one special block if there are several blocks with the same name. + + + + + + + + + Describes a graphical object representing a boolean variable which can be used as l-value and r-value at the same time + + + + + + + + The operand is a valid boolean iec variable e.g. avar[0] + + + + + + + + + + + + + + + + + + + Describes a graphical object representing a variable which can be used as l-value and r-value at the same time + + + + + + + + The operand is a valid boolean iec variable e.g. avar[0] + + + + + + + + + + + + + + + + + + + + Collection of objects which are defined in sfc. They can only be used in sfc bodies + + + + + A single step in a SFC Sequence. Actions are associated with a step by using an actionBlock element with a connection to the step element + + + + Contains actions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used to identify the order of execution. Also used to identify one special block if there are several blocks with the same name. + + + + + + + + + + + + + + + + + + + + + + Used to identify the order of execution. Also used to identify one special block if there are several blocks with the same name. + + + + + + + + Jump to a step, macro step or simultaneous divergence. Acts like a step. Predecessor should be a transition. + + + + + + + + + + + + + + + Used to identify the order of execution. Also used to identify one special block if there are several blocks with the same name. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The priority of a transition is evaluated, if the transition is connected to a selectionDivergence element. + + + + + Used to identify the order of execution. Also used to identify one special block if there are several blocks with the same name. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines the edge detection behaviour of a variable + + + + + + + + + + Defines the storage mode (S/R) behaviour of a variable + + + + + + + + + + Defines the different access types to an accessVariable + + + + + + + + + Defines the different types of a POU + + + + + + + +