PLCControler.py
changeset 1784 64beb9e9c749
parent 1782 5b6ad7a7fd9d
child 1785 0ff2a45dcefa
equal deleted inserted replaced
1729:31e63e25b4cc 1784:64beb9e9c749
    25 
    25 
    26 from xml.dom import minidom
    26 from xml.dom import minidom
    27 from types import StringType, UnicodeType, TupleType
    27 from types import StringType, UnicodeType, TupleType
    28 from lxml import etree
    28 from lxml import etree
    29 from copy import deepcopy
    29 from copy import deepcopy
    30 import os,sys,re
    30 import os
       
    31 import sys
       
    32 import re
    31 import datetime
    33 import datetime
    32 import util.paths as paths
    34 import util.paths as paths
    33 from time import localtime
    35 from time import localtime
    34 from collections import OrderedDict, namedtuple
    36 from collections import OrderedDict, namedtuple
    35 
    37 from util.TranslationCatalogs import NoTranslate
    36 from plcopen import *
    38 from plcopen import *
    37 from graphics.GraphicCommons import *
    39 from graphics.GraphicCommons import *
    38 from PLCGenerator import *
    40 from PLCGenerator import *
    39 
    41 
    40 duration_model = re.compile("(?:([0-9]{1,2})h)?(?:([0-9]{1,2})m(?!s))?(?:([0-9]{1,2})s)?(?:([0-9]{1,3}(?:\.[0-9]*)?)ms)?")
    42 duration_model = re.compile("(?:([0-9]{1,2})h)?(?:([0-9]{1,2})m(?!s))?(?:([0-9]{1,2})s)?(?:([0-9]{1,3}(?:\.[0-9]*)?)ms)?")
    41 
    43 
    42 ITEMS_EDITABLE = [ITEM_PROJECT,
    44 ITEMS_EDITABLE = [
    43                   ITEM_POU,
    45     ITEM_PROJECT,
    44                   ITEM_VARIABLE,
    46     ITEM_POU,
    45                   ITEM_TRANSITION,
    47     ITEM_VARIABLE,
    46                   ITEM_ACTION,
    48     ITEM_TRANSITION,
    47                   ITEM_CONFIGURATION,
    49     ITEM_ACTION,
    48                   ITEM_RESOURCE,
    50     ITEM_CONFIGURATION,
    49                   ITEM_DATATYPE
    51     ITEM_RESOURCE,
    50                  ] = range(8)
    52     ITEM_DATATYPE
    51 
    53 ] = range(8)
    52 ITEMS_UNEDITABLE = [ITEM_DATATYPES,
    54 
    53                     ITEM_FUNCTION,
    55 ITEMS_UNEDITABLE = [
    54                     ITEM_FUNCTIONBLOCK,
    56     ITEM_DATATYPES,
    55                     ITEM_PROGRAM,
    57     ITEM_FUNCTION,
    56                     ITEM_TRANSITIONS,
    58     ITEM_FUNCTIONBLOCK,
    57                     ITEM_ACTIONS,
    59     ITEM_PROGRAM,
    58                     ITEM_CONFIGURATIONS,
    60     ITEM_TRANSITIONS,
    59                     ITEM_RESOURCES,
    61     ITEM_ACTIONS,
    60                     ITEM_PROPERTIES
    62     ITEM_CONFIGURATIONS,
    61                    ] = range(8, 17)
    63     ITEM_RESOURCES,
    62 
    64     ITEM_PROPERTIES
    63 ITEMS_VARIABLE = [ITEM_VAR_LOCAL,
    65 ] = range(8, 17)
    64                   ITEM_VAR_GLOBAL,
    66 
    65                   ITEM_VAR_EXTERNAL,
    67 ITEMS_VARIABLE = [
    66                   ITEM_VAR_TEMP,
    68     ITEM_VAR_LOCAL,
    67                   ITEM_VAR_INPUT,
    69     ITEM_VAR_GLOBAL,
    68                   ITEM_VAR_OUTPUT,
    70     ITEM_VAR_EXTERNAL,
    69                   ITEM_VAR_INOUT
    71     ITEM_VAR_TEMP,
    70                  ] = range(17, 24)
    72     ITEM_VAR_INPUT,
       
    73     ITEM_VAR_OUTPUT,
       
    74     ITEM_VAR_INOUT
       
    75 ] = range(17, 24)
    71 
    76 
    72 VAR_CLASS_INFOS = {
    77 VAR_CLASS_INFOS = {
    73     "Local":    ("localVars",    ITEM_VAR_LOCAL),
    78     "Local":    ("localVars",    ITEM_VAR_LOCAL),
    74     "Global":   ("globalVars",   ITEM_VAR_GLOBAL),
    79     "Global":   ("globalVars",   ITEM_VAR_GLOBAL),
    75     "External": ("externalVars", ITEM_VAR_EXTERNAL),
    80     "External": ("externalVars", ITEM_VAR_EXTERNAL),
    76     "Temp":     ("tempVars",     ITEM_VAR_TEMP),
    81     "Temp":     ("tempVars",     ITEM_VAR_TEMP),
    77     "Input":    ("inputVars",    ITEM_VAR_INPUT),
    82     "Input":    ("inputVars",    ITEM_VAR_INPUT),
    78     "Output":   ("outputVars",   ITEM_VAR_OUTPUT),
    83     "Output":   ("outputVars",   ITEM_VAR_OUTPUT),
    79     "InOut":    ("inOutVars",    ITEM_VAR_INOUT)}
    84     "InOut":    ("inOutVars",    ITEM_VAR_INOUT)}
    80 
    85 
    81 POU_TYPES = {"program": ITEM_PROGRAM,
    86 POU_TYPES = {
    82              "functionBlock": ITEM_FUNCTIONBLOCK,
    87     "program": ITEM_PROGRAM,
    83              "function": ITEM_FUNCTION,
    88     "functionBlock": ITEM_FUNCTIONBLOCK,
    84             }
    89     "function": ITEM_FUNCTION,
       
    90 }
    85 
    91 
    86 LOCATIONS_ITEMS = [LOCATION_CONFNODE,
    92 LOCATIONS_ITEMS = [LOCATION_CONFNODE,
    87                    LOCATION_MODULE,
    93                    LOCATION_MODULE,
    88                    LOCATION_GROUP,
    94                    LOCATION_GROUP,
    89                    LOCATION_VAR_INPUT,
    95                    LOCATION_VAR_INPUT,
    90                    LOCATION_VAR_OUTPUT,
    96                    LOCATION_VAR_OUTPUT,
    91                    LOCATION_VAR_MEMORY] = range(6)
    97                    LOCATION_VAR_MEMORY] = range(6)
    92 
    98 
    93 ScriptDirectory = paths.AbsDir(__file__)
    99 ScriptDirectory = paths.AbsDir(__file__)
    94 
   100 
       
   101 
    95 def GetUneditableNames():
   102 def GetUneditableNames():
    96     _ = lambda x:x
   103     _ = NoTranslate
    97     return [_("User-defined POUs"), _("Functions"), _("Function Blocks"),
   104     return [_("User-defined POUs"), _("Functions"), _("Function Blocks"),
    98             _("Programs"), _("Data Types"), _("Transitions"), _("Actions"),
   105             _("Programs"), _("Data Types"), _("Transitions"), _("Actions"),
    99             _("Configurations"), _("Resources"), _("Properties")]
   106             _("Configurations"), _("Resources"), _("Properties")]
       
   107 
       
   108 
   100 UNEDITABLE_NAMES = GetUneditableNames()
   109 UNEDITABLE_NAMES = GetUneditableNames()
   101 [USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS,
   110 [USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS,
   102  DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS,
   111  DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS,
   103  RESOURCES, PROPERTIES] = UNEDITABLE_NAMES
   112  RESOURCES, PROPERTIES] = UNEDITABLE_NAMES
   104 
   113 
   105 #-------------------------------------------------------------------------------
       
   106 #                 Helper object for loading library in xslt stylesheets
       
   107 #-------------------------------------------------------------------------------
       
   108 
   114 
   109 class LibraryResolver(etree.Resolver):
   115 class LibraryResolver(etree.Resolver):
       
   116     """Helper object for loading library in xslt stylesheets"""
   110 
   117 
   111     def __init__(self, controller, debug=False):
   118     def __init__(self, controller, debug=False):
   112         self.Controller = controller
   119         self.Controller = controller
   113         self.Debug = debug
   120         self.Debug = debug
   114 
   121 
   124             else:
   131             else:
   125                 for ctn in self.Controller.ConfNodeTypes:
   132                 for ctn in self.Controller.ConfNodeTypes:
   126                     lib_el.append(deepcopy(ctn["types"]))
   133                     lib_el.append(deepcopy(ctn["types"]))
   127             return self.resolve_string(etree.tostring(lib_el), context)
   134             return self.resolve_string(etree.tostring(lib_el), context)
   128 
   135 
   129 #-------------------------------------------------------------------------------
   136 # -------------------------------------------------------------------------------
   130 #           Helpers functions for translating list of arguments
   137 #           Helpers functions for translating list of arguments
   131 #                       from xslt to valid arguments
   138 #                       from xslt to valid arguments
   132 #-------------------------------------------------------------------------------
   139 # -------------------------------------------------------------------------------
   133 
   140 
   134 _StringValue = lambda x: x
   141 
   135 _BoolValue = lambda x: x in ["true", "0"]
   142 def _StringValue(x):
       
   143     return x
       
   144 
       
   145 
       
   146 def _BoolValue(x):
       
   147     return x in ["true", "0"]
       
   148 
   136 
   149 
   137 def _translate_args(translations, args):
   150 def _translate_args(translations, args):
   138     return [translate(arg[0]) if len(arg) > 0 else None
   151     return [translate(arg[0]) if len(arg) > 0 else None
   139             for translate, arg in
   152             for translate, arg in
   140             zip(translations, args)]
   153             zip(translations, args)]
   141 
   154 
   142 #-------------------------------------------------------------------------------
   155 # -------------------------------------------------------------------------------
   143 #                 Helpers object for generating pou var list
   156 #                 Helpers object for generating pou var list
   144 #-------------------------------------------------------------------------------
   157 # -------------------------------------------------------------------------------
       
   158 
   145 
   159 
   146 class _VariableInfos(object):
   160 class _VariableInfos(object):
   147     __slots__ = ["Name", "Class", "Option", "Location", "InitialValue",
   161     __slots__ = ["Name", "Class", "Option", "Location", "InitialValue",
   148                  "Edit", "Documentation", "Type", "Tree", "Number"]
   162                  "Edit", "Documentation", "Type", "Tree", "Number"]
       
   163 
   149     def __init__(self, *args):
   164     def __init__(self, *args):
   150         for attr, value in zip(self.__slots__, args):
   165         for attr, value in zip(self.__slots__, args):
   151             setattr(self, attr, value if value is not None else "")
   166             setattr(self, attr, value if value is not None else "")
       
   167 
   152     def copy(self):
   168     def copy(self):
   153         return _VariableInfos(*[getattr(self, attr) for attr in self.__slots__])
   169         return _VariableInfos(*[getattr(self, attr) for attr in self.__slots__])
       
   170 
   154 
   171 
   155 class VariablesInfosFactory:
   172 class VariablesInfosFactory:
   156 
   173 
   157     def __init__(self, variables):
   174     def __init__(self, variables):
   158         self.Variables = variables
   175         self.Variables = variables
   186     def AddVariable(self, context, *args):
   203     def AddVariable(self, context, *args):
   187         self.Variables.append(_VariableInfos(*(_translate_args(
   204         self.Variables.append(_VariableInfos(*(_translate_args(
   188             [_StringValue] * 5 + [_BoolValue] + [_StringValue], args) +
   205             [_StringValue] * 5 + [_BoolValue] + [_StringValue], args) +
   189             [self.GetType(), self.GetTree()])))
   206             [self.GetType(), self.GetTree()])))
   190 
   207 
   191 #-------------------------------------------------------------------------------
   208 # -------------------------------------------------------------------------------
   192 #            Helpers object for generating pou variable instance list
   209 #            Helpers object for generating pou variable instance list
   193 #-------------------------------------------------------------------------------
   210 # -------------------------------------------------------------------------------
       
   211 
   194 
   212 
   195 def class_extraction(value):
   213 def class_extraction(value):
   196     class_type = {
   214     class_type = {
   197         "configuration": ITEM_CONFIGURATION,
   215         "configuration": ITEM_CONFIGURATION,
   198         "resource": ITEM_RESOURCE,
   216         "resource": ITEM_RESOURCE,
   210     if var_type is not None:
   228     if var_type is not None:
   211         return var_type[1]
   229         return var_type[1]
   212 
   230 
   213     return None
   231     return None
   214 
   232 
       
   233 
   215 class _VariablesTreeItemInfos(object):
   234 class _VariablesTreeItemInfos(object):
   216     __slots__ = ["name", "var_class", "type", "edit", "debug", "variables"]
   235     __slots__ = ["name", "var_class", "type", "edit", "debug", "variables"]
       
   236 
   217     def __init__(self, *args):
   237     def __init__(self, *args):
   218         for attr, value in zip(self.__slots__, args):
   238         for attr, value in zip(self.__slots__, args):
   219             setattr(self, attr, value if value is not None else "")
   239             setattr(self, attr, value if value is not None else "")
       
   240 
   220     def copy(self):
   241     def copy(self):
   221         return _VariableTreeItem(*[getattr(self, attr) for attr in self.__slots__])
   242         return _VariableTreeItem(*[getattr(self, attr) for attr in self.__slots__])
       
   243 
   222 
   244 
   223 class VariablesTreeInfosFactory:
   245 class VariablesTreeInfosFactory:
   224 
   246 
   225     def __init__(self):
   247     def __init__(self):
   226         self.Root = None
   248         self.Root = None
   239             self.Root.variables.append(_VariablesTreeItemInfos(
   261             self.Root.variables.append(_VariablesTreeItemInfos(
   240                 *(_translate_args(
   262                 *(_translate_args(
   241                     [_StringValue, class_extraction, _StringValue] +
   263                     [_StringValue, class_extraction, _StringValue] +
   242                     [_BoolValue] * 2, args) + [[]])))
   264                     [_BoolValue] * 2, args) + [[]])))
   243 
   265 
   244 #-------------------------------------------------------------------------------
       
   245 #            Helpers object for generating instances path list
       
   246 #-------------------------------------------------------------------------------
       
   247 
   266 
   248 class InstancesPathFactory:
   267 class InstancesPathFactory:
   249 
   268     """Helpers object for generating instances path list"""
   250     def __init__(self, instances):
   269     def __init__(self, instances):
   251         self.Instances = instances
   270         self.Instances = instances
   252 
   271 
   253     def AddInstance(self, context, *args):
   272     def AddInstance(self, context, *args):
   254         self.Instances.append(args[0][0])
   273         self.Instances.append(args[0][0])
   255 
   274 
   256 #-------------------------------------------------------------------------------
       
   257 #            Helpers object for generating instance tagname
       
   258 #-------------------------------------------------------------------------------
       
   259 
   275 
   260 class InstanceTagName:
   276 class InstanceTagName:
       
   277     """Helpers object for generating instance tagname"""
   261 
   278 
   262     def __init__(self, controller):
   279     def __init__(self, controller):
   263         self.Controller = controller
   280         self.Controller = controller
   264         self.TagName = None
   281         self.TagName = None
   265 
   282 
   279         self.TagName = self.Controller.ComputePouActionName(args[0][0], args[0][1])
   296         self.TagName = self.Controller.ComputePouActionName(args[0][0], args[0][1])
   280 
   297 
   281     def TransitionTagName(self, context, *args):
   298     def TransitionTagName(self, context, *args):
   282         self.TagName = self.Controller.ComputePouTransitionName(args[0][0], args[0][1])
   299         self.TagName = self.Controller.ComputePouTransitionName(args[0][0], args[0][1])
   283 
   300 
   284 #-------------------------------------------------------------------------------
   301 
       
   302 # -------------------------------------------------------------------------------
   285 #           Helpers object for generating pou block instances list
   303 #           Helpers object for generating pou block instances list
   286 #-------------------------------------------------------------------------------
   304 # -------------------------------------------------------------------------------
       
   305 
   287 
   306 
   288 _Point = namedtuple("Point", ["x", "y"])
   307 _Point = namedtuple("Point", ["x", "y"])
   289 
   308 
   290 _BlockInstanceInfos = namedtuple("BlockInstanceInfos",
   309 _BlockInstanceInfos = namedtuple(
       
   310     "BlockInstanceInfos",
   291     ["type", "id", "x", "y", "width", "height", "specific_values", "inputs", "outputs"])
   311     ["type", "id", "x", "y", "width", "height", "specific_values", "inputs", "outputs"])
   292 
   312 
   293 _BlockSpecificValues = (
   313 _BlockSpecificValues = (
   294     namedtuple("BlockSpecificValues",
   314     namedtuple("BlockSpecificValues",
   295                ["name", "execution_order"]),
   315                ["name", "execution_order"]),
   345     "actionBlock": (
   365     "actionBlock": (
   346         namedtuple("ActionBlockSpecificValues", ["actions"]),
   366         namedtuple("ActionBlockSpecificValues", ["actions"]),
   347         [lambda x: x]),
   367         [lambda x: x]),
   348 }
   368 }
   349 
   369 
   350 _InstanceConnectionInfos = namedtuple("InstanceConnectionInfos",
   370 _InstanceConnectionInfos = namedtuple(
       
   371     "InstanceConnectionInfos",
   351     ["name", "negated", "edge", "position", "links"])
   372     ["name", "negated", "edge", "position", "links"])
   352 
   373 
   353 _ConnectionLinkInfos = namedtuple("ConnectionLinkInfos",
   374 _ConnectionLinkInfos = namedtuple(
       
   375     "ConnectionLinkInfos",
   354     ["refLocalId", "formalParameter", "points"])
   376     ["refLocalId", "formalParameter", "points"])
       
   377 
   355 
   378 
   356 class _ActionInfos(object):
   379 class _ActionInfos(object):
   357     __slots__ = ["qualifier", "type", "value", "duration", "indicator"]
   380     __slots__ = ["qualifier", "type", "value", "duration", "indicator"]
       
   381 
   358     def __init__(self, *args):
   382     def __init__(self, *args):
   359         for attr, value in zip(self.__slots__, args):
   383         for attr, value in zip(self.__slots__, args):
   360             setattr(self, attr, value if value is not None else "")
   384             setattr(self, attr, value if value is not None else "")
       
   385 
   361     def copy(self):
   386     def copy(self):
   362         return _ActionInfos(*[getattr(self, attr) for attr in self.__slots__])
   387         return _ActionInfos(*[getattr(self, attr) for attr in self.__slots__])
       
   388 
   363 
   389 
   364 class BlockInstanceFactory:
   390 class BlockInstanceFactory:
   365 
   391 
   366     def __init__(self, block_instances):
   392     def __init__(self, block_instances):
   367         self.BlockInstances = block_instances
   393         self.BlockInstances = block_instances
   378 
   404 
   379     def AddBlockInstance(self, context, *args):
   405     def AddBlockInstance(self, context, *args):
   380         specific_values_tuple, specific_values_translation = \
   406         specific_values_tuple, specific_values_translation = \
   381             _SpecificValuesTuples.get(args[0][0], _BlockSpecificValues)
   407             _SpecificValuesTuples.get(args[0][0], _BlockSpecificValues)
   382 
   408 
   383         if (args[0][0] == "step" and len(self.SpecificValues) < 3 or
   409         if args[0][0] == "step" and len(self.SpecificValues) < 3 or \
   384             args[0][0] == "transition" and len(self.SpecificValues) < 4):
   410            args[0][0] == "transition" and len(self.SpecificValues) < 4:
   385             self.SpecificValues.append([None])
   411             self.SpecificValues.append([None])
   386         elif args[0][0] == "actionBlock" and len(self.SpecificValues) < 1:
   412         elif args[0][0] == "actionBlock" and len(self.SpecificValues) < 1:
   387             self.SpecificValues.append([[]])
   413             self.SpecificValues.append([[]])
   388         specific_values = specific_values_tuple(*_translate_args(
   414         specific_values = specific_values_tuple(*_translate_args(
   389             specific_values_translation, self.SpecificValues))
   415             specific_values_translation, self.SpecificValues))
   424         if len(self.SpecificValues) == 0:
   450         if len(self.SpecificValues) == 0:
   425             self.SpecificValues.append([[]])
   451             self.SpecificValues.append([[]])
   426         translated_args = _translate_args([_StringValue] * 5, args)
   452         translated_args = _translate_args([_StringValue] * 5, args)
   427         self.SpecificValues[0][0].append(_ActionInfos(*translated_args))
   453         self.SpecificValues[0][0].append(_ActionInfos(*translated_args))
   428 
   454 
       
   455 
   429 pou_block_instances_xslt = etree.parse(
   456 pou_block_instances_xslt = etree.parse(
   430     os.path.join(ScriptDirectory, "plcopen", "pou_block_instances.xslt"))
   457     os.path.join(ScriptDirectory, "plcopen", "pou_block_instances.xslt"))
   431 
   458 
   432 #-------------------------------------------------------------------------------
       
   433 #                         Undo Buffer for PLCOpenEditor
       
   434 #-------------------------------------------------------------------------------
       
   435 
   459 
   436 # Length of the buffer
   460 # Length of the buffer
   437 UNDO_BUFFER_LENGTH = 20
   461 UNDO_BUFFER_LENGTH = 20
   438 
   462 
   439 """
   463 
   440 Class implementing a buffer of changes made on the current editing model
       
   441 """
       
   442 class UndoBuffer:
   464 class UndoBuffer:
   443 
   465     """
   444     # Constructor initialising buffer
   466     Undo Buffer for PLCOpenEditor
   445     def __init__(self, currentstate, issaved = False):
   467     Class implementing a buffer of changes made on the current editing model
       
   468     """
       
   469 
       
   470     def __init__(self, currentstate, issaved=False):
       
   471         """
       
   472         Constructor initialising buffer
       
   473         """
   446         self.Buffer = []
   474         self.Buffer = []
   447         self.CurrentIndex = -1
   475         self.CurrentIndex = -1
   448         self.MinIndex = -1
   476         self.MinIndex = -1
   449         self.MaxIndex = -1
   477         self.MaxIndex = -1
   450         # if current state is defined
   478         # if current state is defined
   462         if issaved:
   490         if issaved:
   463             self.LastSave = 0
   491             self.LastSave = 0
   464         else:
   492         else:
   465             self.LastSave = -1
   493             self.LastSave = -1
   466 
   494 
   467     # Add a new state in buffer
       
   468     def Buffering(self, currentstate):
   495     def Buffering(self, currentstate):
       
   496         """
       
   497         Add a new state in buffer
       
   498         """
   469         self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH
   499         self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH
   470         self.Buffer[self.CurrentIndex] = currentstate
   500         self.Buffer[self.CurrentIndex] = currentstate
   471         # Actualising buffer limits
   501         # Actualising buffer limits
   472         self.MaxIndex = self.CurrentIndex
   502         self.MaxIndex = self.CurrentIndex
   473         if self.MinIndex == self.CurrentIndex:
   503         if self.MinIndex == self.CurrentIndex:
   475             if self.LastSave == self.MinIndex:
   505             if self.LastSave == self.MinIndex:
   476                 self.LastSave = -1
   506                 self.LastSave = -1
   477             self.MinIndex = (self.MinIndex + 1) % UNDO_BUFFER_LENGTH
   507             self.MinIndex = (self.MinIndex + 1) % UNDO_BUFFER_LENGTH
   478         self.MinIndex = max(self.MinIndex, 0)
   508         self.MinIndex = max(self.MinIndex, 0)
   479 
   509 
   480     # Return current state of buffer
       
   481     def Current(self):
   510     def Current(self):
       
   511         """
       
   512         Return current state of buffer
       
   513         """
   482         return self.Buffer[self.CurrentIndex]
   514         return self.Buffer[self.CurrentIndex]
   483 
   515 
   484     # Change current state to previous in buffer and return new current state
   516     # Change current state to previous in buffer and return new current state
   485     def Previous(self):
   517     def Previous(self):
   486         if self.CurrentIndex != self.MinIndex:
   518         if self.CurrentIndex != self.MinIndex:
   510     # Return True if current state is saved
   542     # Return True if current state is saved
   511     def IsCurrentSaved(self):
   543     def IsCurrentSaved(self):
   512         return self.LastSave == self.CurrentIndex
   544         return self.LastSave == self.CurrentIndex
   513 
   545 
   514 
   546 
   515 #-------------------------------------------------------------------------------
       
   516 #                           Controler for PLCOpenEditor
       
   517 #-------------------------------------------------------------------------------
       
   518 
       
   519 """
       
   520 Class which controls the operations made on the plcopen model and answers to view requests
       
   521 """
       
   522 class PLCControler:
   547 class PLCControler:
       
   548     """
       
   549     Controler for PLCOpenEditor
       
   550     Class which controls the operations made on the plcopen model and answers to view requests
       
   551     """
   523 
   552 
   524     # Create a new PLCControler
   553     # Create a new PLCControler
   525     def __init__(self):
   554     def __init__(self):
   526         self.LastNewIndex = 0
   555         self.LastNewIndex = 0
   527         self.Reset()
   556         self.Reset()
   545         self.ProgramFilePath = ""
   574         self.ProgramFilePath = ""
   546 
   575 
   547     def GetQualifierTypes(self):
   576     def GetQualifierTypes(self):
   548         return QualifierList
   577         return QualifierList
   549 
   578 
   550     def GetProject(self, debug = False):
   579     def GetProject(self, debug=False):
   551         if debug and self.CurrentCompiledProject is not None:
   580         if debug and self.CurrentCompiledProject is not None:
   552             return self.CurrentCompiledProject
   581             return self.CurrentCompiledProject
   553         else:
   582         else:
   554             return self.Project
   583             return self.Project
   555 
   584 
   556 #-------------------------------------------------------------------------------
   585     # -------------------------------------------------------------------------------
   557 #                         Project management functions
   586     #                         Project management functions
   558 #-------------------------------------------------------------------------------
   587     # -------------------------------------------------------------------------------
   559 
   588 
   560     # Return if a project is opened
   589     # Return if a project is opened
   561     def HasOpenedProject(self):
   590     def HasOpenedProject(self):
   562         return self.Project is not None
   591         return self.Project is not None
   563 
   592 
   577         self.NextCompiledProject = self.Copy(self.Project)
   606         self.NextCompiledProject = self.Copy(self.Project)
   578         self.CurrentCompiledProject = None
   607         self.CurrentCompiledProject = None
   579         self.Buffering = False
   608         self.Buffering = False
   580 
   609 
   581     # Return project data type names
   610     # Return project data type names
   582     def GetProjectDataTypeNames(self, debug = False):
   611     def GetProjectDataTypeNames(self, debug=False):
   583         project = self.GetProject(debug)
   612         project = self.GetProject(debug)
   584         if project is not None:
   613         if project is not None:
   585             return [datatype.getname() for datatype in project.getdataTypes()]
   614             return [datatype.getname() for datatype in project.getdataTypes()]
   586         return []
   615         return []
   587 
   616 
   588     # Return project pou names
   617     # Return project pou names
   589     def GetProjectPouNames(self, debug = False):
   618     def GetProjectPouNames(self, debug=False):
   590         project = self.GetProject(debug)
   619         project = self.GetProject(debug)
   591         if project is not None:
   620         if project is not None:
   592             return [pou.getname() for pou in project.getpous()]
   621             return [pou.getname() for pou in project.getpous()]
   593         return []
   622         return []
   594 
   623 
   595     # Return project pou names
   624     # Return project pou names
   596     def GetProjectConfigNames(self, debug = False):
   625     def GetProjectConfigNames(self, debug=False):
   597         project = self.GetProject(debug)
   626         project = self.GetProject(debug)
   598         if project is not None:
   627         if project is not None:
   599             return [config.getname() for config in project.getconfigurations()]
   628             return [config.getname() for config in project.getconfigurations()]
   600         return []
   629         return []
   601 
   630 
   602     # Return project pou variable names
   631     # Return project pou variable names
   603     def GetProjectPouVariableNames(self, pou_name = None, debug = False):
   632     def GetProjectPouVariableNames(self, pou_name=None, debug=False):
   604         variables = []
   633         variables = []
   605         project = self.GetProject(debug)
   634         project = self.GetProject(debug)
   606         if project is not None:
   635         if project is not None:
   607             for pou in project.getpous():
   636             for pou in project.getpous():
   608                 if pou_name is None or pou_name == pou.getname():
   637                 if pou_name is None or pou_name == pou.getname():
   625     def GetFilename(self):
   654     def GetFilename(self):
   626         if self.Project is not None:
   655         if self.Project is not None:
   627             if self.ProjectIsSaved():
   656             if self.ProjectIsSaved():
   628                 return self.FileName
   657                 return self.FileName
   629             else:
   658             else:
   630                 return "~%s~"%self.FileName
   659                 return "~%s~" % self.FileName
   631         return ""
   660         return ""
   632 
   661 
   633     # Change file path and save file name or create a default one if file path not defined
   662     # Change file path and save file name or create a default one if file path not defined
   634     def SetFilePath(self, filepath):
   663     def SetFilePath(self, filepath):
   635         self.FilePath = filepath
   664         self.FilePath = filepath
   636         if filepath == "":
   665         if filepath == "":
   637             self.LastNewIndex += 1
   666             self.LastNewIndex += 1
   638             self.FileName = _("Unnamed%d")%self.LastNewIndex
   667             self.FileName = _("Unnamed%d") % self.LastNewIndex
   639         else:
   668         else:
   640             self.FileName = os.path.splitext(os.path.basename(filepath))[0]
   669             self.FileName = os.path.splitext(os.path.basename(filepath))[0]
   641 
   670 
   642     # Change project properties
   671     # Change project properties
   643     def SetProjectProperties(self, name = None, properties = None, buffer = True):
   672     def SetProjectProperties(self, name=None, properties=None, buffer=True):
   644         if self.Project is not None:
   673         if self.Project is not None:
   645             if name is not None:
   674             if name is not None:
   646                 self.Project.setname(name)
   675                 self.Project.setname(name)
   647             if properties is not None:
   676             if properties is not None:
   648                 self.Project.setfileHeader(properties)
   677                 self.Project.setfileHeader(properties)
   656         if project is not None:
   685         if project is not None:
   657             return project.getname()
   686             return project.getname()
   658         return None
   687         return None
   659 
   688 
   660     # Return project properties
   689     # Return project properties
   661     def GetProjectProperties(self, debug = False):
   690     def GetProjectProperties(self, debug=False):
   662         project = self.GetProject(debug)
   691         project = self.GetProject(debug)
   663         if project is not None:
   692         if project is not None:
   664             properties = project.getfileHeader()
   693             properties = project.getfileHeader()
   665             properties.update(project.getcontentHeader())
   694             properties.update(project.getcontentHeader())
   666             return properties
   695             return properties
   667         return None
   696         return None
   668 
   697 
   669     # Return project informations
   698     # Return project informations
   670     def GetProjectInfos(self, debug = False):
   699     def GetProjectInfos(self, debug=False):
   671         project = self.GetProject(debug)
   700         project = self.GetProject(debug)
   672         if project is not None:
   701         if project is not None:
   673             infos = {"name": project.getname(), "type": ITEM_PROJECT}
   702             infos = {"name": project.getname(), "type": ITEM_PROJECT}
   674             datatypes = {"name": DATA_TYPES, "type": ITEM_DATATYPES, "values":[]}
   703             datatypes = {"name": DATA_TYPES, "type": ITEM_DATATYPES, "values": []}
   675             for datatype in project.getdataTypes():
   704             for datatype in project.getdataTypes():
   676                 datatypes["values"].append({"name": datatype.getname(), "type": ITEM_DATATYPE,
   705                 datatypes["values"].append({
   677                     "tagname": self.ComputeDataTypeName(datatype.getname()), "values": []})
   706                     "name": datatype.getname(),
   678             pou_types = {"function": {"name": FUNCTIONS, "type": ITEM_FUNCTION, "values":[]},
   707                     "type": ITEM_DATATYPE,
   679                          "functionBlock": {"name": FUNCTION_BLOCKS, "type": ITEM_FUNCTIONBLOCK, "values":[]},
   708                     "tagname": self.ComputeDataTypeName(datatype.getname()),
   680                          "program": {"name": PROGRAMS, "type": ITEM_PROGRAM, "values":[]}}
   709                     "values": []})
       
   710             pou_types = {
       
   711                 "function": {
       
   712                     "name":   FUNCTIONS,
       
   713                     "type":   ITEM_FUNCTION,
       
   714                     "values": []
       
   715                 },
       
   716                 "functionBlock": {
       
   717                     "name":   FUNCTION_BLOCKS,
       
   718                     "type":   ITEM_FUNCTIONBLOCK,
       
   719                     "values": []
       
   720                 },
       
   721                 "program": {
       
   722                     "name":   PROGRAMS,
       
   723                     "type":   ITEM_PROGRAM,
       
   724                     "values": []
       
   725                 }
       
   726             }
   681             for pou in project.getpous():
   727             for pou in project.getpous():
   682                 pou_type = pou.getpouType()
   728                 pou_type = pou.getpouType()
   683                 pou_infos = {"name": pou.getname(), "type": ITEM_POU,
   729                 pou_infos = {"name": pou.getname(), "type": ITEM_POU,
   684                              "tagname": self.ComputePouName(pou.getname())}
   730                              "tagname": self.ComputePouName(pou.getname())}
   685                 pou_values = []
   731                 pou_values = []
   686                 if pou.getbodyType() == "SFC":
   732                 if pou.getbodyType() == "SFC":
   687                     transitions = []
   733                     transitions = []
   688                     for transition in pou.gettransitionList():
   734                     for transition in pou.gettransitionList():
   689                         transitions.append({"name": transition.getname(), "type": ITEM_TRANSITION,
   735                         transitions.append({
       
   736                             "name": transition.getname(),
       
   737                             "type": ITEM_TRANSITION,
   690                             "tagname": self.ComputePouTransitionName(pou.getname(), transition.getname()),
   738                             "tagname": self.ComputePouTransitionName(pou.getname(), transition.getname()),
   691                             "values": []})
   739                             "values": []})
   692                     pou_values.append({"name": TRANSITIONS, "type": ITEM_TRANSITIONS, "values": transitions})
   740                     pou_values.append({"name": TRANSITIONS, "type": ITEM_TRANSITIONS, "values": transitions})
   693                     actions = []
   741                     actions = []
   694                     for action in pou.getactionList():
   742                     for action in pou.getactionList():
   695                         actions.append({"name": action.getname(), "type": ITEM_ACTION,
   743                         actions.append({
       
   744                             "name": action.getname(),
       
   745                             "type": ITEM_ACTION,
   696                             "tagname": self.ComputePouActionName(pou.getname(), action.getname()),
   746                             "tagname": self.ComputePouActionName(pou.getname(), action.getname()),
   697                             "values": []})
   747                             "values": []})
   698                     pou_values.append({"name": ACTIONS, "type": ITEM_ACTIONS, "values": actions})
   748                     pou_values.append({"name": ACTIONS, "type": ITEM_ACTIONS, "values": actions})
   699                 if pou_type in pou_types:
   749                 if pou_type in pou_types:
   700                     pou_infos["values"] = pou_values
   750                     pou_infos["values"] = pou_values
   701                     pou_types[pou_type]["values"].append(pou_infos)
   751                     pou_types[pou_type]["values"].append(pou_infos)
   702             configurations = {"name": CONFIGURATIONS, "type": ITEM_CONFIGURATIONS, "values": []}
   752             configurations = {"name": CONFIGURATIONS, "type": ITEM_CONFIGURATIONS, "values": []}
   703             for config in project.getconfigurations():
   753             for config in project.getconfigurations():
   704                 config_name = config.getname()
   754                 config_name = config.getname()
   705                 config_infos = {"name": config_name, "type": ITEM_CONFIGURATION,
   755                 config_infos = {
       
   756                     "name": config_name,
       
   757                     "type": ITEM_CONFIGURATION,
   706                     "tagname": self.ComputeConfigurationName(config.getname()),
   758                     "tagname": self.ComputeConfigurationName(config.getname()),
   707                     "values": []}
   759                     "values": []}
   708                 resources = {"name": RESOURCES, "type": ITEM_RESOURCES, "values": []}
   760                 resources = {"name": RESOURCES, "type": ITEM_RESOURCES, "values": []}
   709                 for resource in config.getresource():
   761                 for resource in config.getresource():
   710                     resource_name = resource.getname()
   762                     resource_name = resource.getname()
   711                     resource_infos = {"name": resource_name, "type": ITEM_RESOURCE,
   763                     resource_infos = {
       
   764                         "name": resource_name,
       
   765                         "type": ITEM_RESOURCE,
   712                         "tagname": self.ComputeConfigurationResourceName(config.getname(), resource.getname()),
   766                         "tagname": self.ComputeConfigurationResourceName(config.getname(), resource.getname()),
   713                         "values": []}
   767                         "values": []}
   714                     resources["values"].append(resource_infos)
   768                     resources["values"].append(resource_infos)
   715                 config_infos["values"] = [resources]
   769                 config_infos["values"] = [resources]
   716                 configurations["values"].append(config_infos)
   770                 configurations["values"].append(config_infos)
   717             infos["values"] = [datatypes, pou_types["function"], pou_types["functionBlock"],
   771             infos["values"] = [datatypes, pou_types["function"], pou_types["functionBlock"],
   718                                pou_types["program"], configurations]
   772                                pou_types["program"], configurations]
   719             return infos
   773             return infos
   720         return None
   774         return None
   721 
   775 
   722     def GetPouVariables(self, tagname, debug = False):
   776     def GetPouVariables(self, tagname, debug=False):
   723         pou_type = None
   777         pou_type = None
   724         project = self.GetProject(debug)
   778         project = self.GetProject(debug)
   725         if project is not None:
   779         if project is not None:
   726             factory = VariablesTreeInfosFactory()
   780             factory = VariablesTreeInfosFactory()
   727 
   781 
   730 
   784 
   731             pou_variable_xslt_tree = etree.XSLT(
   785             pou_variable_xslt_tree = etree.XSLT(
   732                 etree.parse(
   786                 etree.parse(
   733                     os.path.join(ScriptDirectory, "plcopen", "pou_variables.xslt"),
   787                     os.path.join(ScriptDirectory, "plcopen", "pou_variables.xslt"),
   734                     parser),
   788                     parser),
   735                 extensions = {("pou_vars_ns", name): getattr(factory, name)
   789                 extensions={("pou_vars_ns", name): getattr(factory, name)
   736                               for name in ["SetRoot", "AddVariable"]})
   790                             for name in ["SetRoot", "AddVariable"]})
   737 
   791 
   738             obj = None
   792             obj = None
   739             words = tagname.split("::")
   793             words = tagname.split("::")
   740             if words[0] == "P":
   794             if words[0] == "P":
   741                 obj = self.GetPou(words[1], debug)
   795                 obj = self.GetPou(words[1], debug)
   745                 pou_variable_xslt_tree(obj)
   799                 pou_variable_xslt_tree(obj)
   746                 return factory.GetRoot()
   800                 return factory.GetRoot()
   747 
   801 
   748         return None
   802         return None
   749 
   803 
   750     def GetInstanceList(self, root, name, debug = False):
   804     def GetInstanceList(self, root, name, debug=False):
   751         instances = []
   805         instances = []
   752         project = self.GetProject(debug)
   806         project = self.GetProject(debug)
   753         if project is not None:
   807         if project is not None:
   754             factory = InstancesPathFactory(instances)
   808             factory = InstancesPathFactory(instances)
   755 
   809 
   758 
   812 
   759             instances_path_xslt_tree = etree.XSLT(
   813             instances_path_xslt_tree = etree.XSLT(
   760                 etree.parse(
   814                 etree.parse(
   761                     os.path.join(ScriptDirectory, "plcopen", "instances_path.xslt"),
   815                     os.path.join(ScriptDirectory, "plcopen", "instances_path.xslt"),
   762                     parser),
   816                     parser),
   763                 extensions = {
   817                 extensions={
   764                     ("instances_ns", "AddInstance"): factory.AddInstance})
   818                     ("instances_ns", "AddInstance"): factory.AddInstance})
   765 
   819 
   766             instances_path_xslt_tree(root,
   820             instances_path_xslt_tree(
   767                 instance_type=etree.XSLT.strparam(name))
   821                 root, instance_type=etree.XSLT.strparam(name))
   768 
   822 
   769         return instances
   823         return instances
   770 
   824 
   771     def SearchPouInstances(self, tagname, debug = False):
   825     def SearchPouInstances(self, tagname, debug=False):
   772         project = self.GetProject(debug)
   826         project = self.GetProject(debug)
   773         if project is not None:
   827         if project is not None:
   774             words = tagname.split("::")
   828             words = tagname.split("::")
   775             if words[0] == "P":
   829             if words[0] == "P":
   776                 return self.GetInstanceList(project, words[1])
   830                 return self.GetInstanceList(project, words[1])
   782                 return ["%s.%s" % (instance, words[2])
   836                 return ["%s.%s" % (instance, words[2])
   783                         for instance in self.SearchPouInstances(
   837                         for instance in self.SearchPouInstances(
   784                             self.ComputePouName(words[1]), debug)]
   838                             self.ComputePouName(words[1]), debug)]
   785         return []
   839         return []
   786 
   840 
   787     def GetPouInstanceTagName(self, instance_path, debug = False):
   841     def GetPouInstanceTagName(self, instance_path, debug=False):
   788         project = self.GetProject(debug)
   842         project = self.GetProject(debug)
   789         factory = InstanceTagName(self)
   843         factory = InstanceTagName(self)
   790 
   844 
   791         parser = etree.XMLParser()
   845         parser = etree.XMLParser()
   792         parser.resolvers.add(LibraryResolver(self, debug))
   846         parser.resolvers.add(LibraryResolver(self, debug))
   793 
   847 
   794         instance_tagname_xslt_tree = etree.XSLT(
   848         instance_tagname_xslt_tree = etree.XSLT(
   795             etree.parse(
   849             etree.parse(
   796                 os.path.join(ScriptDirectory, "plcopen", "instance_tagname.xslt"),
   850                 os.path.join(ScriptDirectory, "plcopen", "instance_tagname.xslt"),
   797                 parser),
   851                 parser),
   798             extensions = {("instance_tagname_ns", name): getattr(factory, name)
   852             extensions={("instance_tagname_ns", name): getattr(factory, name)
   799                           for name in ["ConfigTagName", "ResourceTagName",
   853                         for name in ["ConfigTagName",
   800                                        "PouTagName", "ActionTagName",
   854                                      "ResourceTagName",
   801                                        "TransitionTagName"]})
   855                                      "PouTagName",
   802 
   856                                      "ActionTagName",
   803         instance_tagname_xslt_tree(project,
   857                                      "TransitionTagName"]})
   804             instance_path=etree.XSLT.strparam(instance_path))
   858 
       
   859         instance_tagname_xslt_tree(
       
   860             project, instance_path=etree.XSLT.strparam(instance_path))
   805 
   861 
   806         return factory.GetTagName()
   862         return factory.GetTagName()
   807 
   863 
   808     def GetInstanceInfos(self, instance_path, debug = False):
   864     def GetInstanceInfos(self, instance_path, debug=False):
   809         tagname = self.GetPouInstanceTagName(instance_path)
   865         tagname = self.GetPouInstanceTagName(instance_path)
   810         if tagname is not None:
   866         if tagname is not None:
   811             infos = self.GetPouVariables(tagname, debug)
   867             infos = self.GetPouVariables(tagname, debug)
   812             infos.type = tagname
   868             infos.type = tagname
   813             return infos
   869             return infos
   820                     if var_infos.name == var_name:
   876                     if var_infos.name == var_name:
   821                         return var_infos
   877                         return var_infos
   822         return None
   878         return None
   823 
   879 
   824     # Return if data type given by name is used by another data type or pou
   880     # Return if data type given by name is used by another data type or pou
   825     def DataTypeIsUsed(self, name, debug = False):
   881     def DataTypeIsUsed(self, name, debug=False):
   826         project = self.GetProject(debug)
   882         project = self.GetProject(debug)
   827         if project is not None:
   883         if project is not None:
   828             return len(self.GetInstanceList(project, name, debug)) > 0
   884             return len(self.GetInstanceList(project, name, debug)) > 0
   829         return False
   885         return False
   830 
   886 
   831     # Return if pou given by name is used by another pou
   887     # Return if pou given by name is used by another pou
   832     def PouIsUsed(self, name, debug = False):
   888     def PouIsUsed(self, name, debug=False):
   833         project = self.GetProject(debug)
   889         project = self.GetProject(debug)
   834         if project is not None:
   890         if project is not None:
   835             return len(self.GetInstanceList(project, name, debug)) > 0
   891             return len(self.GetInstanceList(project, name, debug)) > 0
   836         return False
   892         return False
   837 
   893 
   838     # Return if pou given by name is directly or undirectly used by the reference pou
   894     # Return if pou given by name is directly or undirectly used by the reference pou
   839     def PouIsUsedBy(self, name, reference, debug = False):
   895     def PouIsUsedBy(self, name, reference, debug=False):
   840         pou_infos = self.GetPou(reference, debug)
   896         pou_infos = self.GetPou(reference, debug)
   841         if pou_infos is not None:
   897         if pou_infos is not None:
   842             return len(self.GetInstanceList(pou_infos, name, debug)) > 0
   898             return len(self.GetInstanceList(pou_infos, name, debug)) > 0
   843         return False
   899         return False
   844 
   900 
   888             if next_row == to_location[0] and next_col > to_location[1] or next_row > to_location[0]:
   944             if next_row == to_location[0] and next_col > to_location[1] or next_row > to_location[0]:
   889                 return infos
   945                 return infos
   890             row, col = next_row, next_col
   946             row, col = next_row, next_col
   891         return infos
   947         return infos
   892 
   948 
   893 #-------------------------------------------------------------------------------
   949     # -------------------------------------------------------------------------------
   894 #                        Project Pous management functions
   950     #                        Project Pous management functions
   895 #-------------------------------------------------------------------------------
   951     # -------------------------------------------------------------------------------
   896 
   952 
   897     # Add a Data Type to Project
   953     # Add a Data Type to Project
   898     def ProjectAddDataType(self, datatype_name=None):
   954     def ProjectAddDataType(self, datatype_name=None):
   899         if self.Project is not None:
   955         if self.Project is not None:
   900             if datatype_name is None:
   956             if datatype_name is None:
   940         '''
   996         '''
   941         Adds the POU defined by 'pou_xml' to the current project with type 'pou_type'
   997         Adds the POU defined by 'pou_xml' to the current project with type 'pou_type'
   942         '''
   998         '''
   943         try:
   999         try:
   944             new_pou, error = LoadPou(pou_xml)
  1000             new_pou, error = LoadPou(pou_xml)
   945         except:
  1001         except Exception:
   946             error = ""
  1002             error = ""
   947         if error is not None:
  1003         if error is not None:
   948             return _("Couldn't paste non-POU object.")
  1004             return _("Couldn't paste non-POU object.")
   949 
  1005 
   950         name = new_pou.getname()
  1006         name = new_pou.getname()
   967             # prevent violations of POU content restrictions:
  1023             # prevent violations of POU content restrictions:
   968             # function blocks cannot be pasted as functions,
  1024             # function blocks cannot be pasted as functions,
   969             # programs cannot be pasted as functions or function blocks
  1025             # programs cannot be pasted as functions or function blocks
   970             if orig_type == 'functionBlock' and pou_type == 'function' or \
  1026             if orig_type == 'functionBlock' and pou_type == 'function' or \
   971                orig_type == 'program' and pou_type in ['function', 'functionBlock']:
  1027                orig_type == 'program' and pou_type in ['function', 'functionBlock']:
   972                 msg = _('''{a1} "{a2}" can't be pasted as a {a3}.''').format(a1 = orig_type, a2 = name, a3 = pou_type)
  1028                 msg = _('''{a1} "{a2}" can't be pasted as a {a3}.''').format(a1=orig_type, a2=name, a3=pou_type)
   973                 return msg
  1029                 return msg
   974 
  1030 
   975             new_pou.setpouType(pou_type)
  1031             new_pou.setpouType(pou_type)
   976 
  1032 
   977         self.Project.insertpou(0, new_pou)
  1033         self.Project.insertpou(0, new_pou)
  1137             if resource is not None:
  1193             if resource is not None:
  1138                 resource.setname(new_name)
  1194                 resource.setname(new_name)
  1139                 self.BufferProject()
  1195                 self.BufferProject()
  1140 
  1196 
  1141     # Return the description of the pou given by its name
  1197     # Return the description of the pou given by its name
  1142     def GetPouDescription(self, name, debug = False):
  1198     def GetPouDescription(self, name, debug=False):
  1143         project = self.GetProject(debug)
  1199         project = self.GetProject(debug)
  1144         if project is not None:
  1200         if project is not None:
  1145             # Found the pou correponding to name and return its type
  1201             # Found the pou correponding to name and return its type
  1146             pou = project.getpou(name)
  1202             pou = project.getpou(name)
  1147             if pou is not None:
  1203             if pou is not None:
  1148                 return pou.getdescription()
  1204                 return pou.getdescription()
  1149         return ""
  1205         return ""
  1150 
  1206 
  1151     # Return the description of the pou given by its name
  1207     # Return the description of the pou given by its name
  1152     def SetPouDescription(self, name, description, debug = False):
  1208     def SetPouDescription(self, name, description, debug=False):
  1153         project = self.GetProject(debug)
  1209         project = self.GetProject(debug)
  1154         if project is not None:
  1210         if project is not None:
  1155             # Found the pou correponding to name and return its type
  1211             # Found the pou correponding to name and return its type
  1156             pou = project.getpou(name)
  1212             pou = project.getpou(name)
  1157             if pou is not None:
  1213             if pou is not None:
  1158                 pou.setdescription(description)
  1214                 pou.setdescription(description)
  1159                 self.BufferProject()
  1215                 self.BufferProject()
  1160 
  1216 
  1161     # Return the type of the pou given by its name
  1217     # Return the type of the pou given by its name
  1162     def GetPouType(self, name, debug = False):
  1218     def GetPouType(self, name, debug=False):
  1163         project = self.GetProject(debug)
  1219         project = self.GetProject(debug)
  1164         if project is not None:
  1220         if project is not None:
  1165             # Found the pou correponding to name and return its type
  1221             # Found the pou correponding to name and return its type
  1166             pou = project.getpou(name)
  1222             pou = project.getpou(name)
  1167             if pou is not None:
  1223             if pou is not None:
  1168                 return pou.getpouType()
  1224                 return pou.getpouType()
  1169         return None
  1225         return None
  1170 
  1226 
  1171     # Return pous with SFC language
  1227     # Return pous with SFC language
  1172     def GetSFCPous(self, debug = False):
  1228     def GetSFCPous(self, debug=False):
  1173         list = []
  1229         list = []
  1174         project = self.GetProject(debug)
  1230         project = self.GetProject(debug)
  1175         if project is not None:
  1231         if project is not None:
  1176             for pou in project.getpous():
  1232             for pou in project.getpous():
  1177                 if pou.getBodyType() == "SFC":
  1233                 if pou.getBodyType() == "SFC":
  1178                     list.append(pou.getname())
  1234                     list.append(pou.getname())
  1179         return list
  1235         return list
  1180 
  1236 
  1181     # Return the body language of the pou given by its name
  1237     # Return the body language of the pou given by its name
  1182     def GetPouBodyType(self, name, debug = False):
  1238     def GetPouBodyType(self, name, debug=False):
  1183         project = self.GetProject(debug)
  1239         project = self.GetProject(debug)
  1184         if project is not None:
  1240         if project is not None:
  1185             # Found the pou correponding to name and return its body language
  1241             # Found the pou correponding to name and return its body language
  1186             pou = project.getpou(name)
  1242             pou = project.getpou(name)
  1187             if pou is not None:
  1243             if pou is not None:
  1188                 return pou.getbodyType()
  1244                 return pou.getbodyType()
  1189         return None
  1245         return None
  1190 
  1246 
  1191     # Return the actions of a pou
  1247     # Return the actions of a pou
  1192     def GetPouTransitions(self, pou_name, debug = False):
  1248     def GetPouTransitions(self, pou_name, debug=False):
  1193         transitions = []
  1249         transitions = []
  1194         project = self.GetProject(debug)
  1250         project = self.GetProject(debug)
  1195         if project is not None:
  1251         if project is not None:
  1196             # Found the pou correponding to name and return its transitions if SFC
  1252             # Found the pou correponding to name and return its transitions if SFC
  1197             pou = project.getpou(pou_name)
  1253             pou = project.getpou(pou_name)
  1199                 for transition in pou.gettransitionList():
  1255                 for transition in pou.gettransitionList():
  1200                     transitions.append(transition.getname())
  1256                     transitions.append(transition.getname())
  1201         return transitions
  1257         return transitions
  1202 
  1258 
  1203     # Return the body language of the transition given by its name
  1259     # Return the body language of the transition given by its name
  1204     def GetTransitionBodyType(self, pou_name, pou_transition, debug = False):
  1260     def GetTransitionBodyType(self, pou_name, pou_transition, debug=False):
  1205         project = self.GetProject(debug)
  1261         project = self.GetProject(debug)
  1206         if project is not None:
  1262         if project is not None:
  1207             # Found the pou correponding to name
  1263             # Found the pou correponding to name
  1208             pou = project.getpou(pou_name)
  1264             pou = project.getpou(pou_name)
  1209             if pou is not None:
  1265             if pou is not None:
  1212                 if transition is not None:
  1268                 if transition is not None:
  1213                     return transition.getbodyType()
  1269                     return transition.getbodyType()
  1214         return None
  1270         return None
  1215 
  1271 
  1216     # Return the actions of a pou
  1272     # Return the actions of a pou
  1217     def GetPouActions(self, pou_name, debug = False):
  1273     def GetPouActions(self, pou_name, debug=False):
  1218         actions = []
  1274         actions = []
  1219         project = self.GetProject(debug)
  1275         project = self.GetProject(debug)
  1220         if project is not None:
  1276         if project is not None:
  1221             # Found the pou correponding to name and return its actions if SFC
  1277             # Found the pou correponding to name and return its actions if SFC
  1222             pou = project.getpou(pou_name)
  1278             pou = project.getpou(pou_name)
  1224                 for action in pou.getactionList():
  1280                 for action in pou.getactionList():
  1225                     actions.append(action.getname())
  1281                     actions.append(action.getname())
  1226         return actions
  1282         return actions
  1227 
  1283 
  1228     # Return the body language of the pou given by its name
  1284     # Return the body language of the pou given by its name
  1229     def GetActionBodyType(self, pou_name, pou_action, debug = False):
  1285     def GetActionBodyType(self, pou_name, pou_action, debug=False):
  1230         project = self.GetProject(debug)
  1286         project = self.GetProject(debug)
  1231         if project is not None:
  1287         if project is not None:
  1232             # Found the pou correponding to name and return its body language
  1288             # Found the pou correponding to name and return its body language
  1233             pou = project.getpou(pou_name)
  1289             pou = project.getpou(pou_name)
  1234             if pou is not None:
  1290             if pou is not None:
  1330 
  1386 
  1331         variables_infos_xslt_tree = etree.XSLT(
  1387         variables_infos_xslt_tree = etree.XSLT(
  1332             etree.parse(
  1388             etree.parse(
  1333                 os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt"),
  1389                 os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt"),
  1334                 parser),
  1390                 parser),
  1335             extensions = {("var_infos_ns", name): getattr(factory, name)
  1391             extensions={("var_infos_ns", name): getattr(factory, name)
  1336                 for name in ["SetType", "AddDimension", "AddTree",
  1392                         for name in ["SetType", "AddDimension", "AddTree",
  1337                              "AddVarToTree", "AddVariable"]})
  1393                                      "AddVarToTree", "AddVariable"]})
  1338         variables_infos_xslt_tree(object_with_vars,
  1394         variables_infos_xslt_tree(
  1339             tree=etree.XSLT.strparam(str(tree)))
  1395             object_with_vars, tree=etree.XSLT.strparam(str(tree)))
  1340 
  1396 
  1341         return variables
  1397         return variables
  1342 
  1398 
  1343     # Add a global var to configuration to configuration
  1399     # Add a global var to configuration to configuration
  1344     def AddConfigurationGlobalVar(self, config_name, var_type, var_name,
  1400     def AddConfigurationGlobalVar(self, config_name, var_type, var_name,
  1345                                            location="", description=""):
  1401                                   location="", description=""):
  1346         if self.Project is not None:
  1402         if self.Project is not None:
  1347             # Found the configuration corresponding to name
  1403             # Found the configuration corresponding to name
  1348             configuration = self.Project.getconfiguration(config_name)
  1404             configuration = self.Project.getconfiguration(config_name)
  1349             if configuration is not None:
  1405             if configuration is not None:
  1350                 # Set configuration global vars
  1406                 # Set configuration global vars
  1362                 configuration.setglobalVars([
  1418                 configuration.setglobalVars([
  1363                     varlist for vartype, varlist
  1419                     varlist for vartype, varlist
  1364                     in self.ExtractVarLists(vars)])
  1420                     in self.ExtractVarLists(vars)])
  1365 
  1421 
  1366     # Return the configuration globalvars
  1422     # Return the configuration globalvars
  1367     def GetConfigurationGlobalVars(self, name, debug = False):
  1423     def GetConfigurationGlobalVars(self, name, debug=False):
  1368         project = self.GetProject(debug)
  1424         project = self.GetProject(debug)
  1369         if project is not None:
  1425         if project is not None:
  1370             # Found the configuration corresponding to name
  1426             # Found the configuration corresponding to name
  1371             configuration = project.getconfiguration(name)
  1427             configuration = project.getconfiguration(name)
  1372             if configuration is not None:
  1428             if configuration is not None:
  1374                 return self.GetVariableDictionary(configuration, debug)
  1430                 return self.GetVariableDictionary(configuration, debug)
  1375 
  1431 
  1376         return []
  1432         return []
  1377 
  1433 
  1378     # Return configuration variable names
  1434     # Return configuration variable names
  1379     def GetConfigurationVariableNames(self, config_name = None, debug = False):
  1435     def GetConfigurationVariableNames(self, config_name=None, debug=False):
  1380         variables = []
  1436         variables = []
  1381         project = self.GetProject(debug)
  1437         project = self.GetProject(debug)
  1382         if project is not None:
  1438         if project is not None:
  1383             for configuration in self.Project.getconfigurations():
  1439             for configuration in self.Project.getconfigurations():
  1384                 if config_name is None or config_name == configuration.getname():
  1440                 if config_name is None or config_name == configuration.getname():
  1385                     variables.extend(
  1441                     variables.extend(
  1386                         [var.getname() for var in reduce(
  1442                         [var.getname() for var in reduce(
  1387                             lambda x, y: x + y, [varlist.getvariable()
  1443                             lambda x, y: x + y, [
       
  1444                                 varlist.getvariable()
  1388                                 for varlist in configuration.globalVars],
  1445                                 for varlist in configuration.globalVars],
  1389                             [])])
  1446                             [])])
  1390         return variables
  1447         return variables
  1391 
  1448 
  1392     # Replace the resource globalvars by those given
  1449     # Replace the resource globalvars by those given
  1399                 resource.setglobalVars([
  1456                 resource.setglobalVars([
  1400                     varlist for vartype, varlist
  1457                     varlist for vartype, varlist
  1401                     in self.ExtractVarLists(vars)])
  1458                     in self.ExtractVarLists(vars)])
  1402 
  1459 
  1403     # Return the resource globalvars
  1460     # Return the resource globalvars
  1404     def GetConfigurationResourceGlobalVars(self, config_name, name, debug = False):
  1461     def GetConfigurationResourceGlobalVars(self, config_name, name, debug=False):
  1405         project = self.GetProject(debug)
  1462         project = self.GetProject(debug)
  1406         if project is not None:
  1463         if project is not None:
  1407             # Found the resource corresponding to name
  1464             # Found the resource corresponding to name
  1408             resource = project.getconfigurationResource(config_name, name)
  1465             resource = project.getconfigurationResource(config_name, name)
  1409             if resource is not None:
  1466             if resource is not None:
  1411                 return self.GetVariableDictionary(resource, debug)
  1468                 return self.GetVariableDictionary(resource, debug)
  1412 
  1469 
  1413         return []
  1470         return []
  1414 
  1471 
  1415     # Return resource variable names
  1472     # Return resource variable names
  1416     def GetConfigurationResourceVariableNames(self,
  1473     def GetConfigurationResourceVariableNames(
  1417                 config_name = None, resource_name = None, debug = False):
  1474             self, config_name=None, resource_name=None, debug=False):
  1418         variables = []
  1475         variables = []
  1419         project = self.GetProject(debug)
  1476         project = self.GetProject(debug)
  1420         if project is not None:
  1477         if project is not None:
  1421             for configuration in self.Project.getconfigurations():
  1478             for configuration in self.Project.getconfigurations():
  1422                 if config_name is None or config_name == configuration.getname():
  1479                 if config_name is None or config_name == configuration.getname():
  1423                     for resource in configuration.getresource():
  1480                     for resource in configuration.getresource():
  1424                         if resource_name is None or resource.getname() == resource_name:
  1481                         if resource_name is None or resource.getname() == resource_name:
  1425                             variables.extend(
  1482                             variables.extend(
  1426                                 [var.getname() for var in reduce(
  1483                                 [var.getname() for var in reduce(
  1427                                     lambda x, y: x + y, [varlist.getvariable()
  1484                                     lambda x, y: x + y, [
       
  1485                                         varlist.getvariable()
  1428                                         for varlist in resource.globalVars],
  1486                                         for varlist in resource.globalVars],
  1429                                     [])])
  1487                                     [])])
  1430         return variables
  1488         return variables
  1431 
  1489 
  1432     # Return the interface for the given pou
  1490     # Return the interface for the given pou
  1433     def GetPouInterfaceVars(self, pou, tree=False, debug = False):
  1491     def GetPouInterfaceVars(self, pou, tree=False, debug=False):
  1434         interface = pou.interface
  1492         interface = pou.interface
  1435         # Verify that the pou has an interface
  1493         # Verify that the pou has an interface
  1436         if interface is not None:
  1494         if interface is not None:
  1437             # Extract variables defined in interface
  1495             # Extract variables defined in interface
  1438             return self.GetVariableDictionary(interface, tree, debug)
  1496             return self.GetVariableDictionary(interface, tree, debug)
  1495 
  1553 
  1496                 return_type_infos_xslt_tree = etree.XSLT(
  1554                 return_type_infos_xslt_tree = etree.XSLT(
  1497                     etree.parse(
  1555                     etree.parse(
  1498                         os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt"),
  1556                         os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt"),
  1499                         parser),
  1557                         parser),
  1500                     extensions = {("var_infos_ns", name): getattr(factory, name)
  1558                     extensions={("var_infos_ns", name): getattr(factory, name)
  1501                                   for name in ["SetType", "AddDimension",
  1559                                 for name in ["SetType", "AddDimension",
  1502                                                "AddTree", "AddVarToTree"]})
  1560                                              "AddTree", "AddVarToTree"]})
  1503                 return_type_infos_xslt_tree(return_type,
  1561                 return_type_infos_xslt_tree(
  1504                     tree=etree.XSLT.strparam(str(tree)))
  1562                     return_type, tree=etree.XSLT.strparam(str(tree)))
  1505                 if tree:
  1563                 if tree:
  1506                     return [factory.GetType(), factory.GetTree()]
  1564                     return [factory.GetType(), factory.GetTree()]
  1507                 return factory.GetType()
  1565                 return factory.GetType()
  1508 
  1566 
  1509         if tree:
  1567         if tree:
  1514     def AddConfNodeTypesList(self, typeslist):
  1572     def AddConfNodeTypesList(self, typeslist):
  1515         self.ConfNodeTypes.extend(typeslist)
  1573         self.ConfNodeTypes.extend(typeslist)
  1516         addedcat = [{"name": _("%s POUs") % confnodetypes["name"],
  1574         addedcat = [{"name": _("%s POUs") % confnodetypes["name"],
  1517                      "list": [pou.getblockInfos()
  1575                      "list": [pou.getblockInfos()
  1518                               for pou in confnodetypes["types"].getpous()]}
  1576                               for pou in confnodetypes["types"].getpous()]}
  1519                      for confnodetypes in typeslist]
  1577                     for confnodetypes in typeslist]
  1520         self.TotalTypes.extend(addedcat)
  1578         self.TotalTypes.extend(addedcat)
  1521         for cat in addedcat:
  1579         for cat in addedcat:
  1522             for desc in cat["list"]:
  1580             for desc in cat["list"]:
  1523                 BlkLst = self.TotalTypesDict.setdefault(desc["name"],[])
  1581                 BlkLst = self.TotalTypesDict.setdefault(desc["name"], [])
  1524                 BlkLst.append((section["name"], desc))
  1582                 BlkLst.append((section["name"], desc))
  1525 
  1583 
  1526     # Function that clear the confnode list
  1584     # Function that clear the confnode list
  1527     def ClearConfNodeTypes(self):
  1585     def ClearConfNodeTypes(self):
  1528         self.ConfNodeTypes = []
  1586         self.ConfNodeTypes = []
  1529         self.TotalTypesDict = StdBlckDct.copy()
  1587         self.TotalTypesDict = StdBlckDct.copy()
  1530         self.TotalTypes = StdBlckLst[:]
  1588         self.TotalTypes = StdBlckLst[:]
  1531 
  1589 
  1532     def GetConfNodeDataTypes(self, exclude = None, only_locatables = False):
  1590     def GetConfNodeDataTypes(self, exclude=None, only_locatables=False):
  1533         return [{"name": _("%s Data Types") % confnodetypes["name"],
  1591         return [{"name": _("%s Data Types") % confnodetypes["name"],
  1534                  "list": [
  1592                  "list": [
  1535                     datatype.getname()
  1593                     datatype.getname()
  1536                     for datatype in confnodetypes["types"].getdataTypes()
  1594                     for datatype in confnodetypes["types"].getdataTypes()
  1537                     if not only_locatables or self.IsLocatableDataType(datatype, debug)]}
  1595                     if not only_locatables or self.IsLocatableDataType(datatype, debug)]}
  1568 
  1626 
  1569             global_vars.append(tempvar)
  1627             global_vars.append(tempvar)
  1570         return global_vars
  1628         return global_vars
  1571 
  1629 
  1572     # Function that returns the block definition associated to the block type given
  1630     # Function that returns the block definition associated to the block type given
  1573     def GetBlockType(self, typename, inputs = None, debug = False):
  1631     def GetBlockType(self, typename, inputs=None, debug=False):
  1574         result_blocktype = None
  1632         result_blocktype = None
  1575         for sectioname, blocktype in self.TotalTypesDict.get(typename,[]):
  1633         for sectioname, blocktype in self.TotalTypesDict.get(typename, []):
  1576             if inputs is not None and inputs != "undefined":
  1634             if inputs is not None and inputs != "undefined":
  1577                 block_inputs = tuple([var_type for name, var_type, modifier in blocktype["inputs"]])
  1635                 block_inputs = tuple([var_type for name, var_type, modifier in blocktype["inputs"]])
  1578                 if reduce(lambda x, y: x and y, map(lambda x: x[0] == "ANY" or self.IsOfType(*x), zip(inputs, block_inputs)), True):
  1636                 if reduce(lambda x, y: x and y, map(lambda x: x[0] == "ANY" or self.IsOfType(*x), zip(inputs, block_inputs)), True):
  1579                     return blocktype
  1637                     return blocktype
  1580             else:
  1638             else:
  1595                 blocktype_infos = blocktype.getblockInfos()
  1653                 blocktype_infos = blocktype.getblockInfos()
  1596                 if inputs in [None, "undefined"]:
  1654                 if inputs in [None, "undefined"]:
  1597                     return blocktype_infos
  1655                     return blocktype_infos
  1598 
  1656 
  1599                 if inputs == tuple([var_type
  1657                 if inputs == tuple([var_type
  1600                     for name, var_type, modifier in blocktype_infos["inputs"]]):
  1658                                     for name, var_type, modifier in blocktype_infos["inputs"]]):
  1601                     return blocktype_infos
  1659                     return blocktype_infos
  1602 
  1660 
  1603         return None
  1661         return None
  1604 
  1662 
  1605     # Return Block types checking for recursion
  1663     # Return Block types checking for recursion
  1606     def GetBlockTypes(self, tagname = "", debug = False):
  1664     def GetBlockTypes(self, tagname="", debug=False):
  1607         typename = None
  1665         typename = None
  1608         words = tagname.split("::")
  1666         words = tagname.split("::")
  1609         name = None
  1667         name = None
  1610         project = self.GetProject(debug)
  1668         project = self.GetProject(debug)
  1611         if project is not None:
  1669         if project is not None:
  1612             pou_type = None
  1670             pou_type = None
  1613             if words[0] in ["P","T","A"]:
  1671             if words[0] in ["P", "T", "A"]:
  1614                 name = words[1]
  1672                 name = words[1]
  1615                 pou_type = self.GetPouType(name, debug)
  1673                 pou_type = self.GetPouType(name, debug)
  1616             filter = (["function"]
  1674             filter = (["function"]
  1617                       if pou_type == "function" or words[0] == "T"
  1675                       if pou_type == "function" or words[0] == "T"
  1618                       else ["functionBlock", "function"])
  1676                       else ["functionBlock", "function"])
  1619             blocktypes = [
  1677             blocktypes = [
  1620                 {"name": category["name"],
  1678                 {"name": category["name"],
  1621                  "list": [block for block in category["list"]
  1679                  "list": [block for block in category["list"]
  1622                           if block["type"] in filter]}
  1680                           if block["type"] in filter]}
  1623                 for category in self.TotalTypes]
  1681                 for category in self.TotalTypes]
  1624             blocktypes.append({"name" : USER_DEFINED_POUS,
  1682             blocktypes.append({
       
  1683                 "name": USER_DEFINED_POUS,
  1625                 "list": [pou.getblockInfos()
  1684                 "list": [pou.getblockInfos()
  1626                          for pou in project.getpous(name, filter)
  1685                          for pou in project.getpous(name, filter)
  1627                          if (name is None or
  1686                          if (name is None or
  1628                              len(self.GetInstanceList(pou, name, debug)) == 0)]})
  1687                              len(self.GetInstanceList(pou, name, debug)) == 0)]
       
  1688             })
  1629             return blocktypes
  1689             return blocktypes
  1630         return self.TotalTypes
  1690         return self.TotalTypes
  1631 
  1691 
  1632     # Return Function Block types checking for recursion
  1692     # Return Function Block types checking for recursion
  1633     def GetFunctionBlockTypes(self, tagname = "", debug = False):
  1693     def GetFunctionBlockTypes(self, tagname="", debug=False):
  1634         project = self.GetProject(debug)
  1694         project = self.GetProject(debug)
  1635         words = tagname.split("::")
  1695         words = tagname.split("::")
  1636         name = None
  1696         name = None
  1637         if project is not None and words[0] in ["P","T","A"]:
  1697         if project is not None and words[0] in ["P", "T", "A"]:
  1638             name = words[1]
  1698             name = words[1]
  1639         blocktypes = []
  1699         blocktypes = []
  1640         for blocks in self.TotalTypesDict.itervalues():
  1700         for blocks in self.TotalTypesDict.itervalues():
  1641             for sectioname,block in blocks:
  1701             for sectioname, block in blocks:
  1642                 if block["type"] == "functionBlock":
  1702                 if block["type"] == "functionBlock":
  1643                     blocktypes.append(block["name"])
  1703                     blocktypes.append(block["name"])
  1644         if project is not None:
  1704         if project is not None:
  1645             blocktypes.extend([pou.getname()
  1705             blocktypes.extend([
       
  1706                 pou.getname()
  1646                 for pou in project.getpous(name, ["functionBlock"])
  1707                 for pou in project.getpous(name, ["functionBlock"])
  1647                 if (name is None or
  1708                 if (name is None or
  1648                     len(self.GetInstanceList(pou, name, debug)) == 0)])
  1709                     len(self.GetInstanceList(pou, name, debug)) == 0)])
  1649         return blocktypes
  1710         return blocktypes
  1650 
  1711 
  1651     # Return Block types checking for recursion
  1712     # Return Block types checking for recursion
  1652     def GetBlockResource(self, debug = False):
  1713     def GetBlockResource(self, debug=False):
  1653         blocktypes = []
  1714         blocktypes = []
  1654         for category in StdBlckLst[:-1]:
  1715         for category in StdBlckLst[:-1]:
  1655             for blocktype in category["list"]:
  1716             for blocktype in category["list"]:
  1656                 if blocktype["type"] == "program":
  1717                 if blocktype["type"] == "program":
  1657                     blocktypes.append(blocktype["name"])
  1718                     blocktypes.append(blocktype["name"])
  1661                 [pou.getname()
  1722                 [pou.getname()
  1662                  for pou in project.getpous(filter=["program"])])
  1723                  for pou in project.getpous(filter=["program"])])
  1663         return blocktypes
  1724         return blocktypes
  1664 
  1725 
  1665     # Return Data Types checking for recursion
  1726     # Return Data Types checking for recursion
  1666     def GetDataTypes(self, tagname = "", basetypes = True, confnodetypes = True, only_locatables = False, debug = False):
  1727     def GetDataTypes(self, tagname="", basetypes=True, confnodetypes=True, only_locatables=False, debug=False):
  1667         if basetypes:
  1728         if basetypes:
  1668             datatypes = self.GetBaseTypes()
  1729             datatypes = self.GetBaseTypes()
  1669         else:
  1730         else:
  1670             datatypes = []
  1731             datatypes = []
  1671         project = self.GetProject(debug)
  1732         project = self.GetProject(debug)
  1675             if words[0] in ["D"]:
  1736             if words[0] in ["D"]:
  1676                 name = words[1]
  1737                 name = words[1]
  1677             datatypes.extend([
  1738             datatypes.extend([
  1678                 datatype.getname()
  1739                 datatype.getname()
  1679                 for datatype in project.getdataTypes(name)
  1740                 for datatype in project.getdataTypes(name)
  1680                 if (not only_locatables or self.IsLocatableDataType(datatype, debug))
  1741                 if ((not only_locatables or self.IsLocatableDataType(datatype, debug))
  1681                     and (name is None or
  1742                     and (name is None or
  1682                          len(self.GetInstanceList(datatype, name, debug)) == 0)])
  1743                          len(self.GetInstanceList(datatype, name, debug)) == 0))])
  1683         if confnodetypes:
  1744         if confnodetypes:
  1684             for category in self.GetConfNodeDataTypes(name, only_locatables):
  1745             for category in self.GetConfNodeDataTypes(name, only_locatables):
  1685                 datatypes.extend(category["list"])
  1746                 datatypes.extend(category["list"])
  1686         return datatypes
  1747         return datatypes
  1687 
  1748 
  1688     # Return Data Type Object
  1749     # Return Data Type Object
  1689     def GetPou(self, typename, debug = False):
  1750     def GetPou(self, typename, debug=False):
  1690         project = self.GetProject(debug)
  1751         project = self.GetProject(debug)
  1691         if project is not None:
  1752         if project is not None:
  1692             result = project.getpou(typename)
  1753             result = project.getpou(typename)
  1693             if result is not None:
  1754             if result is not None:
  1694                 return result
  1755                 return result
  1700             result = confnodetype["types"].getpou(typename)
  1761             result = confnodetype["types"].getpou(typename)
  1701             if result is not None:
  1762             if result is not None:
  1702                 return result
  1763                 return result
  1703         return None
  1764         return None
  1704 
  1765 
  1705 
       
  1706     # Return Data Type Object
  1766     # Return Data Type Object
  1707     def GetDataType(self, typename, debug = False):
  1767     def GetDataType(self, typename, debug=False):
  1708         project = self.GetProject(debug)
  1768         project = self.GetProject(debug)
  1709         if project is not None:
  1769         if project is not None:
  1710             result = project.getdataType(typename)
  1770             result = project.getdataType(typename)
  1711             if result is not None:
  1771             if result is not None:
  1712                 return result
  1772                 return result
  1728         return (basetype_content.getname() if basetype_content_type == "derived"
  1788         return (basetype_content.getname() if basetype_content_type == "derived"
  1729                 else basetype_content_type.upper())
  1789                 else basetype_content_type.upper())
  1730         return None
  1790         return None
  1731 
  1791 
  1732     # Return Base Type of given possible derived type
  1792     # Return Base Type of given possible derived type
  1733     def GetBaseType(self, typename, debug = False):
  1793     def GetBaseType(self, typename, debug=False):
  1734         if TypeHierarchy.has_key(typename):
  1794         if typename in TypeHierarchy:
  1735             return typename
  1795             return typename
  1736 
  1796 
  1737         datatype = self.GetDataType(typename, debug)
  1797         datatype = self.GetDataType(typename, debug)
  1738         if datatype is not None:
  1798         if datatype is not None:
  1739             basetype = self.GetDataTypeBaseType(datatype)
  1799             basetype = self.GetDataTypeBaseType(datatype)
  1747         '''
  1807         '''
  1748         return the list of datatypes defined in IEC 61131-3.
  1808         return the list of datatypes defined in IEC 61131-3.
  1749         TypeHierarchy_list has a rough order to it (e.g. SINT, INT, DINT, ...),
  1809         TypeHierarchy_list has a rough order to it (e.g. SINT, INT, DINT, ...),
  1750         which makes it easy for a user to find a type in a menu.
  1810         which makes it easy for a user to find a type in a menu.
  1751         '''
  1811         '''
  1752         return [x for x,y in TypeHierarchy_list if not x.startswith("ANY")]
  1812         return [x for x, y in TypeHierarchy_list if not x.startswith("ANY")]
  1753 
  1813 
  1754     def IsOfType(self, typename, reference, debug = False):
  1814     def IsOfType(self, typename, reference, debug=False):
  1755         if reference is None or typename == reference:
  1815         if reference is None or typename == reference:
  1756             return True
  1816             return True
  1757 
  1817 
  1758         basetype = TypeHierarchy.get(typename)
  1818         basetype = TypeHierarchy.get(typename)
  1759         if basetype is not None:
  1819         if basetype is not None:
  1770     def IsEndType(self, typename):
  1830     def IsEndType(self, typename):
  1771         if typename is not None:
  1831         if typename is not None:
  1772             return not typename.startswith("ANY")
  1832             return not typename.startswith("ANY")
  1773         return True
  1833         return True
  1774 
  1834 
  1775     def IsLocatableDataType(self, datatype, debug = False):
  1835     def IsLocatableDataType(self, datatype, debug=False):
  1776         basetype_content = datatype.baseType.getcontent()
  1836         basetype_content = datatype.baseType.getcontent()
  1777         basetype_content_type = basetype_content.getLocalTag()
  1837         basetype_content_type = basetype_content.getLocalTag()
  1778         if basetype_content_type in ["enum", "struct"]:
  1838         if basetype_content_type in ["enum", "struct"]:
  1779             return False
  1839             return False
  1780         elif basetype_content_type == "derived":
  1840         elif basetype_content_type == "derived":
  1783             array_base_type = basetype_content.baseType.getcontent()
  1843             array_base_type = basetype_content.baseType.getcontent()
  1784             if array_base_type.getLocalTag() == "derived":
  1844             if array_base_type.getLocalTag() == "derived":
  1785                 return self.IsLocatableType(array_base_type.getname(), debug)
  1845                 return self.IsLocatableType(array_base_type.getname(), debug)
  1786         return True
  1846         return True
  1787 
  1847 
  1788     def IsLocatableType(self, typename, debug = False):
  1848     def IsLocatableType(self, typename, debug=False):
  1789         if isinstance(typename, TupleType) or self.GetBlockType(typename) is not None:
  1849         if isinstance(typename, TupleType) or self.GetBlockType(typename) is not None:
  1790             return False
  1850             return False
  1791 
  1851 
  1792         # the size of these types is implementation dependend
  1852         # the size of these types is implementation dependend
  1793         if typename in ["TIME", "DATE", "DT", "TOD"]:
  1853         if typename in ["TIME", "DATE", "DT", "TOD"]:
  1794             return False
  1854             return False
  1795         
  1855 
  1796         datatype = self.GetDataType(typename, debug)
  1856         datatype = self.GetDataType(typename, debug)
  1797         if datatype is not None:
  1857         if datatype is not None:
  1798             return self.IsLocatableDataType(datatype)
  1858             return self.IsLocatableDataType(datatype)
  1799         return True
  1859         return True
  1800 
  1860 
  1801     def IsEnumeratedType(self, typename, debug = False):
  1861     def IsEnumeratedType(self, typename, debug=False):
  1802         if isinstance(typename, TupleType):
  1862         if isinstance(typename, TupleType):
  1803             typename = typename[1]
  1863             typename = typename[1]
  1804         datatype = self.GetDataType(typename, debug)
  1864         datatype = self.GetDataType(typename, debug)
  1805         if datatype is not None:
  1865         if datatype is not None:
  1806             basetype_content = datatype.baseType.getcontent()
  1866             basetype_content = datatype.baseType.getcontent()
  1808             if basetype_content_type == "derived":
  1868             if basetype_content_type == "derived":
  1809                 return self.IsEnumeratedType(basetype_content_type, debug)
  1869                 return self.IsEnumeratedType(basetype_content_type, debug)
  1810             return basetype_content_type == "enum"
  1870             return basetype_content_type == "enum"
  1811         return False
  1871         return False
  1812 
  1872 
  1813     def IsSubrangeType(self, typename, exclude=None, debug = False):
  1873     def IsSubrangeType(self, typename, exclude=None, debug=False):
  1814         if typename == exclude:
  1874         if typename == exclude:
  1815             return False
  1875             return False
  1816         if isinstance(typename, TupleType):
  1876         if isinstance(typename, TupleType):
  1817             typename = typename[1]
  1877             typename = typename[1]
  1818         datatype = self.GetDataType(typename, debug)
  1878         datatype = self.GetDataType(typename, debug)
  1824             elif basetype_content_type in ["subrangeSigned", "subrangeUnsigned"]:
  1884             elif basetype_content_type in ["subrangeSigned", "subrangeUnsigned"]:
  1825                 return not self.IsOfType(
  1885                 return not self.IsOfType(
  1826                     self.GetDataTypeBaseType(datatype), exclude)
  1886                     self.GetDataTypeBaseType(datatype), exclude)
  1827         return False
  1887         return False
  1828 
  1888 
  1829     def IsNumType(self, typename, debug = False):
  1889     def IsNumType(self, typename, debug=False):
  1830         return self.IsOfType(typename, "ANY_NUM", debug) or\
  1890         return self.IsOfType(typename, "ANY_NUM", debug) or\
  1831                self.IsOfType(typename, "ANY_BIT", debug)
  1891                self.IsOfType(typename, "ANY_BIT", debug)
  1832 
  1892 
  1833     def GetDataTypeRange(self, typename, debug = False):
  1893     def GetDataTypeRange(self, typename, debug=False):
  1834         range = DataTypeRange.get(typename)
  1894         range = DataTypeRange.get(typename)
  1835         if range is not None:
  1895         if range is not None:
  1836             return range
  1896             return range
  1837         datatype = self.GetDataType(typename, debug)
  1897         datatype = self.GetDataType(typename, debug)
  1838         if datatype is not None:
  1898         if datatype is not None:
  1844             elif basetype_content_type == "derived":
  1904             elif basetype_content_type == "derived":
  1845                 return self.GetDataTypeRange(basetype_content.getname(), debug)
  1905                 return self.GetDataTypeRange(basetype_content.getname(), debug)
  1846         return None
  1906         return None
  1847 
  1907 
  1848     # Return Subrange types
  1908     # Return Subrange types
  1849     def GetSubrangeBaseTypes(self, exclude, debug = False):
  1909     def GetSubrangeBaseTypes(self, exclude, debug=False):
  1850         subrange_basetypes = DataTypeRange.keys()
  1910         subrange_basetypes = DataTypeRange.keys()
  1851         project = self.GetProject(debug)
  1911         project = self.GetProject(debug)
  1852         if project is not None:
  1912         if project is not None:
  1853             subrange_basetypes.extend(
  1913             subrange_basetypes.extend(
  1854                 [datatype.getname() for datatype in project.getdataTypes()
  1914                 [datatype.getname() for datatype in project.getdataTypes()
  1858                 [datatype.getname() for datatype in confnodetype["types"].getdataTypes()
  1918                 [datatype.getname() for datatype in confnodetype["types"].getdataTypes()
  1859                  if self.IsSubrangeType(datatype.getname(), exclude, debug)])
  1919                  if self.IsSubrangeType(datatype.getname(), exclude, debug)])
  1860         return subrange_basetypes
  1920         return subrange_basetypes
  1861 
  1921 
  1862     # Return Enumerated Values
  1922     # Return Enumerated Values
  1863     def GetEnumeratedDataValues(self, typename = None, debug = False):
  1923     def GetEnumeratedDataValues(self, typename=None, debug=False):
  1864         values = []
  1924         values = []
  1865         if typename is not None:
  1925         if typename is not None:
  1866             datatype_obj = self.GetDataType(typename, debug)
  1926             datatype_obj = self.GetDataType(typename, debug)
  1867             if datatype_obj is not None:
  1927             if datatype_obj is not None:
  1868                 basetype_content = datatype_obj.baseType.getcontent()
  1928                 basetype_content = datatype_obj.baseType.getcontent()
  1880                 values.extend(project.GetEnumeratedDataTypeValues())
  1940                 values.extend(project.GetEnumeratedDataTypeValues())
  1881             for confnodetype in self.ConfNodeTypes:
  1941             for confnodetype in self.ConfNodeTypes:
  1882                 values.extend(confnodetype["types"].GetEnumeratedDataTypeValues())
  1942                 values.extend(confnodetype["types"].GetEnumeratedDataTypeValues())
  1883         return values
  1943         return values
  1884 
  1944 
  1885 #-------------------------------------------------------------------------------
  1945     # -------------------------------------------------------------------------------
  1886 #                   Project Element tag name computation functions
  1946     #                   Project Element tag name computation functions
  1887 #-------------------------------------------------------------------------------
  1947     # -------------------------------------------------------------------------------
  1888 
  1948 
  1889     # Compute a data type name
  1949     # Compute a data type name
  1890     def ComputeDataTypeName(self, datatype):
  1950     def ComputeDataTypeName(self, datatype):
  1891         return "D::%s" % datatype
  1951         return "D::%s" % datatype
  1892 
  1952 
  1910     def ComputeConfigurationResourceName(self, config, resource):
  1970     def ComputeConfigurationResourceName(self, config, resource):
  1911         return "R::%s::%s" % (config, resource)
  1971         return "R::%s::%s" % (config, resource)
  1912 
  1972 
  1913     def GetElementType(self, tagname):
  1973     def GetElementType(self, tagname):
  1914         words = tagname.split("::")
  1974         words = tagname.split("::")
  1915         return {"D" : ITEM_DATATYPE, "P" : ITEM_POU,
  1975         return {
  1916                 "T" : ITEM_TRANSITION, "A" : ITEM_ACTION,
  1976             "D": ITEM_DATATYPE,
  1917                 "C" : ITEM_CONFIGURATION, "R" : ITEM_RESOURCE}[words[0]]
  1977             "P": ITEM_POU,
  1918 
  1978             "T": ITEM_TRANSITION,
  1919 #-------------------------------------------------------------------------------
  1979             "A": ITEM_ACTION,
  1920 #                    Project opened Data types management functions
  1980             "C": ITEM_CONFIGURATION,
  1921 #-------------------------------------------------------------------------------
  1981             "R": ITEM_RESOURCE
       
  1982         }[words[0]]
       
  1983 
       
  1984     # -------------------------------------------------------------------------------
       
  1985     #                    Project opened Data types management functions
       
  1986     # -------------------------------------------------------------------------------
  1922 
  1987 
  1923     # Return the data type informations
  1988     # Return the data type informations
  1924     def GetDataTypeInfos(self, tagname, debug = False):
  1989     def GetDataTypeInfos(self, tagname, debug=False):
  1925         project = self.GetProject(debug)
  1990         project = self.GetProject(debug)
  1926         if project is not None:
  1991         if project is not None:
  1927             words = tagname.split("::")
  1992             words = tagname.split("::")
  1928             if words[0] == "D":
  1993             if words[0] == "D":
  1929                 infos = {}
  1994                 infos = {}
  1937                     infos["min"] = basetype_content.range.getlower()
  2002                     infos["min"] = basetype_content.range.getlower()
  1938                     infos["max"] = basetype_content.range.getupper()
  2003                     infos["max"] = basetype_content.range.getupper()
  1939                     base_type = basetype_content.baseType.getcontent()
  2004                     base_type = basetype_content.baseType.getcontent()
  1940                     base_type_type = base_type.getLocalTag()
  2005                     base_type_type = base_type.getLocalTag()
  1941                     infos["base_type"] = (base_type.getname()
  2006                     infos["base_type"] = (base_type.getname()
  1942                         if base_type_type == "derived"
  2007                                           if base_type_type == "derived"
  1943                         else base_type_type)
  2008                                           else base_type_type)
  1944                 elif basetype_content_type == "enum":
  2009                 elif basetype_content_type == "enum":
  1945                     infos["type"] = "Enumerated"
  2010                     infos["type"] = "Enumerated"
  1946                     infos["values"] = []
  2011                     infos["values"] = []
  1947                     for value in basetype_content.xpath("ppx:values/ppx:value", namespaces=PLCOpenParser.NSMAP):
  2012                     for value in basetype_content.xpath("ppx:values/ppx:value", namespaces=PLCOpenParser.NSMAP):
  1948                         infos["values"].append(value.getname())
  2013                         infos["values"].append(value.getname())
  1952                     for dimension in basetype_content.getdimension():
  2017                     for dimension in basetype_content.getdimension():
  1953                         infos["dimensions"].append((dimension.getlower(), dimension.getupper()))
  2018                         infos["dimensions"].append((dimension.getlower(), dimension.getupper()))
  1954                     base_type = basetype_content.baseType.getcontent()
  2019                     base_type = basetype_content.baseType.getcontent()
  1955                     base_type_type = base_type.getLocalTag()
  2020                     base_type_type = base_type.getLocalTag()
  1956                     infos["base_type"] = (base_type.getname()
  2021                     infos["base_type"] = (base_type.getname()
  1957                         if base_type_type == "derived"
  2022                                           if base_type_type == "derived"
  1958                         else base_type_type.upper())
  2023                                           else base_type_type.upper())
  1959                 elif basetype_content_type == "struct":
  2024                 elif basetype_content_type == "struct":
  1960                     infos["type"] = "Structure"
  2025                     infos["type"] = "Structure"
  1961                     infos["elements"] = []
  2026                     infos["elements"] = []
  1962                     for element in basetype_content.getvariable():
  2027                     for element in basetype_content.getvariable():
  1963                         element_infos = {}
  2028                         element_infos = {}
  1969                             for dimension in element_type.getdimension():
  2034                             for dimension in element_type.getdimension():
  1970                                 dimensions.append((dimension.getlower(), dimension.getupper()))
  2035                                 dimensions.append((dimension.getlower(), dimension.getupper()))
  1971                             base_type = element_type.baseType.getcontent()
  2036                             base_type = element_type.baseType.getcontent()
  1972                             base_type_type = base_type.getLocalTag()
  2037                             base_type_type = base_type.getLocalTag()
  1973                             element_infos["Type"] = ("array",
  2038                             element_infos["Type"] = ("array",
  1974                                 base_type.getname()
  2039                                                      base_type.getname()
  1975                                 if base_type_type == "derived"
  2040                                                      if base_type_type == "derived"
  1976                                 else base_type_type.upper(), dimensions)
  2041                                                      else base_type_type.upper(),
       
  2042                                                      dimensions)
  1977                         elif element_type_type == "derived":
  2043                         elif element_type_type == "derived":
  1978                             element_infos["Type"] = element_type.getname()
  2044                             element_infos["Type"] = element_type.getname()
  1979                         else:
  2045                         else:
  1980                             element_infos["Type"] = element_type_type.upper()
  2046                             element_infos["Type"] = element_type_type.upper()
  1981                         if element.initialValue is not None:
  2047                         if element.initialValue is not None:
  1984                             element_infos["Initial Value"] = ""
  2050                             element_infos["Initial Value"] = ""
  1985                         infos["elements"].append(element_infos)
  2051                         infos["elements"].append(element_infos)
  1986                 else:
  2052                 else:
  1987                     infos["type"] = "Directly"
  2053                     infos["type"] = "Directly"
  1988                     infos["base_type"] = (basetype_content.getname()
  2054                     infos["base_type"] = (basetype_content.getname()
  1989                         if basetype_content_type == "derived"
  2055                                           if basetype_content_type == "derived"
  1990                         else basetype_content_type.upper())
  2056                                           else basetype_content_type.upper())
  1991 
  2057 
  1992                 if datatype.initialValue is not None:
  2058                 if datatype.initialValue is not None:
  1993                     infos["initial"] = datatype.initialValue.getvalue()
  2059                     infos["initial"] = datatype.initialValue.getvalue()
  1994                 else:
  2060                 else:
  1995                     infos["initial"] = ""
  2061                     infos["initial"] = ""
  2114                 datatype.initialValue.setvalue(infos["initial"])
  2180                 datatype.initialValue.setvalue(infos["initial"])
  2115             else:
  2181             else:
  2116                 datatype.initialValue = None
  2182                 datatype.initialValue = None
  2117             self.BufferProject()
  2183             self.BufferProject()
  2118 
  2184 
  2119 #-------------------------------------------------------------------------------
  2185     # -------------------------------------------------------------------------------
  2120 #                       Project opened Pous management functions
  2186     #                       Project opened Pous management functions
  2121 #-------------------------------------------------------------------------------
  2187     # -------------------------------------------------------------------------------
  2122 
  2188 
  2123     # Return edited element
  2189     # Return edited element
  2124     def GetEditedElement(self, tagname, debug = False):
  2190     def GetEditedElement(self, tagname, debug=False):
  2125         project = self.GetProject(debug)
  2191         project = self.GetProject(debug)
  2126         if project is not None:
  2192         if project is not None:
  2127             words = tagname.split("::")
  2193             words = tagname.split("::")
  2128             if words[0] == "D":
  2194             if words[0] == "D":
  2129                 return project.getdataType(words[1])
  2195                 return project.getdataType(words[1])
  2143         return None
  2209         return None
  2144 
  2210 
  2145     # Return edited element name
  2211     # Return edited element name
  2146     def GetEditedElementName(self, tagname):
  2212     def GetEditedElementName(self, tagname):
  2147         words = tagname.split("::")
  2213         words = tagname.split("::")
  2148         if words[0] in ["P","C","D"]:
  2214         if words[0] in ["P", "C", "D"]:
  2149             return words[1]
  2215             return words[1]
  2150         else:
  2216         else:
  2151             return words[2]
  2217             return words[2]
  2152         return None
  2218         return None
  2153 
  2219 
  2154     # Return edited element name and type
  2220     # Return edited element name and type
  2155     def GetEditedElementType(self, tagname, debug = False):
  2221     def GetEditedElementType(self, tagname, debug=False):
  2156         words = tagname.split("::")
  2222         words = tagname.split("::")
  2157         if words[0] in ["P","T","A"]:
  2223         if words[0] in ["P", "T", "A"]:
  2158             return words[1], self.GetPouType(words[1], debug)
  2224             return words[1], self.GetPouType(words[1], debug)
  2159         return None, None
  2225         return None, None
  2160 
  2226 
  2161     # Return language in which edited element is written
  2227     # Return language in which edited element is written
  2162     def GetEditedElementBodyType(self, tagname, debug = False):
  2228     def GetEditedElementBodyType(self, tagname, debug=False):
  2163         words = tagname.split("::")
  2229         words = tagname.split("::")
  2164         if words[0] == "P":
  2230         if words[0] == "P":
  2165             return self.GetPouBodyType(words[1], debug)
  2231             return self.GetPouBodyType(words[1], debug)
  2166         elif words[0] == 'T':
  2232         elif words[0] == 'T':
  2167             return self.GetTransitionBodyType(words[1], words[2], debug)
  2233             return self.GetTransitionBodyType(words[1], words[2], debug)
  2168         elif words[0] == 'A':
  2234         elif words[0] == 'A':
  2169             return self.GetActionBodyType(words[1], words[2], debug)
  2235             return self.GetActionBodyType(words[1], words[2], debug)
  2170         return None
  2236         return None
  2171 
  2237 
  2172     # Return the edited element variables
  2238     # Return the edited element variables
  2173     def GetEditedElementInterfaceVars(self, tagname, tree=False, debug = False):
  2239     def GetEditedElementInterfaceVars(self, tagname, tree=False, debug=False):
  2174         words = tagname.split("::")
  2240         words = tagname.split("::")
  2175         if words[0] in ["P","T","A"]:
  2241         if words[0] in ["P", "T", "A"]:
  2176             project = self.GetProject(debug)
  2242             project = self.GetProject(debug)
  2177             if project is not None:
  2243             if project is not None:
  2178                 pou = project.getpou(words[1])
  2244                 pou = project.getpou(words[1])
  2179                 if pou is not None:
  2245                 if pou is not None:
  2180                     return self.GetPouInterfaceVars(pou, tree, debug)
  2246                     return self.GetPouInterfaceVars(pou, tree, debug)
  2181         return []
  2247         return []
  2182 
  2248 
  2183     # Return the edited element return type
  2249     # Return the edited element return type
  2184     def GetEditedElementInterfaceReturnType(self, tagname, tree=False, debug = False):
  2250     def GetEditedElementInterfaceReturnType(self, tagname, tree=False, debug=False):
  2185         words = tagname.split("::")
  2251         words = tagname.split("::")
  2186         if words[0] == "P":
  2252         if words[0] == "P":
  2187             project = self.GetProject(debug)
  2253             project = self.GetProject(debug)
  2188             if project is not None:
  2254             if project is not None:
  2189                 pou = self.Project.getpou(words[1])
  2255                 pou = self.Project.getpou(words[1])
  2199             element = self.GetEditedElement(tagname)
  2265             element = self.GetEditedElement(tagname)
  2200             if element is not None:
  2266             if element is not None:
  2201                 element.settext(text)
  2267                 element.settext(text)
  2202 
  2268 
  2203     # Return the edited element text
  2269     # Return the edited element text
  2204     def GetEditedElementText(self, tagname, debug = False):
  2270     def GetEditedElementText(self, tagname, debug=False):
  2205         element = self.GetEditedElement(tagname, debug)
  2271         element = self.GetEditedElement(tagname, debug)
  2206         if element is not None:
  2272         if element is not None:
  2207             return element.gettext()
  2273             return element.gettext()
  2208         return ""
  2274         return ""
  2209 
  2275 
  2210     # Return the edited element transitions
  2276     # Return the edited element transitions
  2211     def GetEditedElementTransitions(self, tagname, debug = False):
  2277     def GetEditedElementTransitions(self, tagname, debug=False):
  2212         pou = self.GetEditedElement(tagname, debug)
  2278         pou = self.GetEditedElement(tagname, debug)
  2213         if pou is not None and pou.getbodyType() == "SFC":
  2279         if pou is not None and pou.getbodyType() == "SFC":
  2214             transitions = []
  2280             transitions = []
  2215             for transition in pou.gettransitionList():
  2281             for transition in pou.gettransitionList():
  2216                 transitions.append(transition.getname())
  2282                 transitions.append(transition.getname())
  2217             return transitions
  2283             return transitions
  2218         return []
  2284         return []
  2219 
  2285 
  2220     # Return edited element transitions
  2286     # Return edited element transitions
  2221     def GetEditedElementActions(self, tagname, debug = False):
  2287     def GetEditedElementActions(self, tagname, debug=False):
  2222         pou = self.GetEditedElement(tagname, debug)
  2288         pou = self.GetEditedElement(tagname, debug)
  2223         if pou is not None and pou.getbodyType() == "SFC":
  2289         if pou is not None and pou.getbodyType() == "SFC":
  2224             actions = []
  2290             actions = []
  2225             for action in pou.getactionList():
  2291             for action in pou.getactionList():
  2226                 actions.append(action.getname())
  2292                 actions.append(action.getname())
  2227             return actions
  2293             return actions
  2228         return []
  2294         return []
  2229 
  2295 
  2230     # Return the names of the pou elements
  2296     # Return the names of the pou elements
  2231     def GetEditedElementVariables(self, tagname, debug = False):
  2297     def GetEditedElementVariables(self, tagname, debug=False):
  2232         words = tagname.split("::")
  2298         words = tagname.split("::")
  2233         if words[0] in ["P","T","A"]:
  2299         if words[0] in ["P", "T", "A"]:
  2234             return self.GetProjectPouVariableNames(words[1], debug)
  2300             return self.GetProjectPouVariableNames(words[1], debug)
  2235         elif words[0] in ["C", "R"]:
  2301         elif words[0] in ["C", "R"]:
  2236             names = self.GetConfigurationVariableNames(words[1], debug)
  2302             names = self.GetConfigurationVariableNames(words[1], debug)
  2237             if words[0] == "R":
  2303             if words[0] == "R":
  2238                 names.extend(self.GetConfigurationResourceVariableNames(
  2304                 names.extend(self.GetConfigurationResourceVariableNames(
  2239                     words[1], words[2], debug))
  2305                     words[1], words[2], debug))
  2240             return names
  2306             return names
  2241         return []
  2307         return []
  2242 
  2308 
  2243     def GetEditedElementCopy(self, tagname, debug = False):
  2309     def GetEditedElementCopy(self, tagname, debug=False):
  2244         element = self.GetEditedElement(tagname, debug)
  2310         element = self.GetEditedElement(tagname, debug)
  2245         if element is not None:
  2311         if element is not None:
  2246             return element.tostring()
  2312             return element.tostring()
  2247         return ""
  2313         return ""
  2248 
  2314 
  2249     def GetEditedElementInstancesCopy(self, tagname, blocks_id = None, wires = None, debug = False):
  2315     def GetEditedElementInstancesCopy(self, tagname, blocks_id=None, wires=None, debug=False):
  2250         element = self.GetEditedElement(tagname, debug)
  2316         element = self.GetEditedElement(tagname, debug)
  2251         text = ""
  2317         text = ""
  2252         if element is not None:
  2318         if element is not None:
  2253             wires = dict([(wire, True)
  2319             wires = dict([(wire, True)
  2254                           for wire in wires
  2320                           for wire in wires
  2271         names = exclude.copy()
  2337         names = exclude.copy()
  2272         if tagname is not None:
  2338         if tagname is not None:
  2273             names.update(dict([(varname.upper(), True)
  2339             names.update(dict([(varname.upper(), True)
  2274                                for varname in self.GetEditedElementVariables(tagname, debug)]))
  2340                                for varname in self.GetEditedElementVariables(tagname, debug)]))
  2275             words = tagname.split("::")
  2341             words = tagname.split("::")
  2276             if words[0] in ["P","T","A"]:
  2342             if words[0] in ["P", "T", "A"]:
  2277                 element = self.GetEditedElement(tagname, debug)
  2343                 element = self.GetEditedElement(tagname, debug)
  2278                 if element is not None and element.getbodyType() not in ["ST", "IL"]:
  2344                 if element is not None and element.getbodyType() not in ["ST", "IL"]:
  2279                     for instance in element.getinstances():
  2345                     for instance in element.getinstances():
  2280                         if isinstance(instance,
  2346                         if isinstance(
  2281                             (PLCOpenParser.GetElementClass("step", "sfcObjects"),
  2347                                 instance,
  2282                              PLCOpenParser.GetElementClass("connector", "commonObjects"),
  2348                                 (PLCOpenParser.GetElementClass("step",         "sfcObjects"),
  2283                              PLCOpenParser.GetElementClass("continuation", "commonObjects"))):
  2349                                  PLCOpenParser.GetElementClass("connector",    "commonObjects"),
       
  2350                                  PLCOpenParser.GetElementClass("continuation", "commonObjects"))):
  2284                             names[instance.getname().upper()] = True
  2351                             names[instance.getname().upper()] = True
  2285         else:
  2352         else:
  2286             project = self.GetProject(debug)
  2353             project = self.GetProject(debug)
  2287             if project is not None:
  2354             if project is not None:
  2288                 for datatype in project.getdataTypes():
  2355                 for datatype in project.getdataTypes():
  2300                     for resource in config.getresource():
  2367                     for resource in config.getresource():
  2301                         names[resource.getname().upper()] = True
  2368                         names[resource.getname().upper()] = True
  2302 
  2369 
  2303         i = start_idx
  2370         i = start_idx
  2304         while name is None or names.get(name.upper(), False):
  2371         while name is None or names.get(name.upper(), False):
  2305             name = (format%i)
  2372             name = (format % i)
  2306             i += 1
  2373             i += 1
  2307         return name
  2374         return name
  2308 
  2375 
  2309     def PasteEditedElementInstances(self, tagname, text, new_pos, middle=False, debug=False):
  2376     def PasteEditedElementInstances(self, tagname, text, new_pos, middle=False, debug=False):
  2310         element = self.GetEditedElement(tagname, debug)
  2377         element = self.GetEditedElement(tagname, debug)
  2323             used_id = dict([(instance.getlocalId(), True) for instance in element.getinstances()])
  2390             used_id = dict([(instance.getlocalId(), True) for instance in element.getinstances()])
  2324             new_id = {}
  2391             new_id = {}
  2325 
  2392 
  2326             try:
  2393             try:
  2327                 instances, error = LoadPouInstances(text, bodytype)
  2394                 instances, error = LoadPouInstances(text, bodytype)
  2328             except:
  2395             except Exception:
  2329                 instances, error = [], ""
  2396                 instances, error = [], ""
  2330             if error is not None or len(instances) == 0:
  2397             if error is not None or len(instances) == 0:
  2331                 return _("Invalid plcopen element(s)!!!")
  2398                 return _("Invalid plcopen element(s)!!!")
  2332 
  2399 
  2333             exclude = {}
  2400             exclude = {}
  2338                     blocktype = instance.gettypeName()
  2405                     blocktype = instance.gettypeName()
  2339                     blocktype_infos = self.GetBlockType(blocktype)
  2406                     blocktype_infos = self.GetBlockType(blocktype)
  2340                     blockname = instance.getinstanceName()
  2407                     blockname = instance.getinstanceName()
  2341                     if blocktype_infos["type"] != "function" and blockname is not None:
  2408                     if blocktype_infos["type"] != "function" and blockname is not None:
  2342                         if element_type == "function":
  2409                         if element_type == "function":
  2343                             return _("FunctionBlock \"%s\" can't be pasted in a Function!!!")%blocktype
  2410                             return _("FunctionBlock \"%s\" can't be pasted in a Function!!!") % blocktype
  2344                         blockname = self.GenerateNewName(tagname,
  2411                         blockname = self.GenerateNewName(tagname,
  2345                                                          blockname,
  2412                                                          blockname,
  2346                                                          "%s%%d"%blocktype,
  2413                                                          "%s%%d" % blocktype,
  2347                                                          debug=debug)
  2414                                                          debug=debug)
  2348                         exclude[blockname] = True
  2415                         exclude[blockname] = True
  2349                         instance.setinstanceName(blockname)
  2416                         instance.setinstanceName(blockname)
  2350                         self.AddEditedElementPouVar(tagname, blocktype, blockname)
  2417                         self.AddEditedElementPouVar(tagname, blocktype, blockname)
  2351                 elif instance_type == "step":
  2418                 elif instance_type == "step":
  2355                                                     exclude=exclude,
  2422                                                     exclude=exclude,
  2356                                                     debug=debug)
  2423                                                     debug=debug)
  2357                     exclude[stepname] = True
  2424                     exclude[stepname] = True
  2358                     instance.setname(stepname)
  2425                     instance.setname(stepname)
  2359                 localid = instance.getlocalId()
  2426                 localid = instance.getlocalId()
  2360                 if not used_id.has_key(localid):
  2427                 if localid not in used_id:
  2361                     new_id[localid] = True
  2428                     new_id[localid] = True
  2362 
  2429 
  2363             idx = 1
  2430             idx = 1
  2364             translate_id = {}
  2431             translate_id = {}
  2365             bbox = rect()
  2432             bbox = rect()
  2366             for instance in instances:
  2433             for instance in instances:
  2367                 localId = instance.getlocalId()
  2434                 localId = instance.getlocalId()
  2368                 bbox.union(instance.getBoundingBox())
  2435                 bbox.union(instance.getBoundingBox())
  2369                 if used_id.has_key(localId):
  2436                 if localId in used_id:
  2370                     while used_id.has_key(idx) or new_id.has_key(idx):
  2437                     while (idx in used_id) or (idx in new_id):
  2371                         idx += 1
  2438                         idx += 1
  2372                     new_id[idx] = True
  2439                     new_id[idx] = True
  2373                     instance.setlocalId(idx)
  2440                     instance.setlocalId(idx)
  2374                     translate_id[localId] = idx
  2441                     translate_id[localId] = idx
  2375 
  2442 
  2402                     instance.setexecutionOrderId(0)
  2469                     instance.setexecutionOrderId(0)
  2403                 instance.translate(*diff)
  2470                 instance.translate(*diff)
  2404 
  2471 
  2405             return new_id, connections
  2472             return new_id, connections
  2406 
  2473 
  2407     def GetEditedElementInstancesInfos(self, tagname, debug = False):
  2474     def GetEditedElementInstancesInfos(self, tagname, debug=False):
  2408         element_instances = OrderedDict()
  2475         element_instances = OrderedDict()
  2409         element = self.GetEditedElement(tagname, debug)
  2476         element = self.GetEditedElement(tagname, debug)
  2410         if element is not None:
  2477         if element is not None:
  2411             factory = BlockInstanceFactory(element_instances)
  2478             factory = BlockInstanceFactory(element_instances)
  2412 
  2479 
  2413             pou_block_instances_xslt_tree = etree.XSLT(
  2480             pou_block_instances_xslt_tree = etree.XSLT(
  2414                 pou_block_instances_xslt,
  2481                 pou_block_instances_xslt,
  2415                 extensions = {
  2482                 extensions={
  2416                     ("pou_block_instances_ns", name): getattr(factory, name)
  2483                     ("pou_block_instances_ns", name): getattr(factory, name)
  2417                     for name in ["AddBlockInstance", "SetSpecificValues",
  2484                     for name in ["AddBlockInstance", "SetSpecificValues",
  2418                                  "AddInstanceConnection", "AddConnectionLink",
  2485                                  "AddInstanceConnection", "AddConnectionLink",
  2419                                  "AddLinkPoint", "AddAction"]})
  2486                                  "AddLinkPoint", "AddAction"]})
  2420 
  2487 
  2438             points = wire.GetPoints(handle != 0)
  2505             points = wire.GetPoints(handle != 0)
  2439             if handle == 0:
  2506             if handle == 0:
  2440                 result = wire.GetConnectedInfos(-1)
  2507                 result = wire.GetConnectedInfos(-1)
  2441             else:
  2508             else:
  2442                 result = wire.GetConnectedInfos(0)
  2509                 result = wire.GetConnectedInfos(0)
  2443             if result != None:
  2510             if result is not None:
  2444                 refLocalId, formalParameter = result
  2511                 refLocalId, formalParameter = result
  2445                 connections = connection.getconnections()
  2512                 connections = connection.getconnections()
  2446                 if connections is None or len(connection.getconnections()) <= idx:
  2513                 if connections is None or len(connection.getconnections()) <= idx:
  2447                     connection.addconnection()
  2514                     connection.addconnection()
  2448                 connection.setconnectionId(idx, refLocalId)
  2515                 connection.setconnectionId(idx, refLocalId)
  2463             derived_type = PLCOpenParser.CreateElement("derived", "dataType")
  2530             derived_type = PLCOpenParser.CreateElement("derived", "dataType")
  2464             derived_type.setname(var_type)
  2531             derived_type.setname(var_type)
  2465             var_type_obj.setcontent(derived_type)
  2532             var_type_obj.setcontent(derived_type)
  2466         return var_type_obj
  2533         return var_type_obj
  2467 
  2534 
  2468     def AddEditedElementPouVar(self, tagname, var_type, name,**args):
  2535     def AddEditedElementPouVar(self, tagname, var_type, name, **args):
  2469         if self.Project is not None:
  2536         if self.Project is not None:
  2470             words = tagname.split("::")
  2537             words = tagname.split("::")
  2471             if words[0] in ['P', 'T', 'A']:
  2538             if words[0] in ['P', 'T', 'A']:
  2472                 pou = self.Project.getpou(words[1])
  2539                 pou = self.Project.getpou(words[1])
  2473                 if pou is not None:
  2540                 if pou is not None:
  2498             if words[0] in ['P', 'T', 'A']:
  2565             if words[0] in ['P', 'T', 'A']:
  2499                 pou = self.Project.getpou(words[1])
  2566                 pou = self.Project.getpou(words[1])
  2500                 if pou is not None:
  2567                 if pou is not None:
  2501                     pou.removepouVar(type, name)
  2568                     pou.removepouVar(type, name)
  2502 
  2569 
  2503     def AddEditedElementBlock(self, tagname, id, blocktype, blockname = None):
  2570     def AddEditedElementBlock(self, tagname, id, blocktype, blockname=None):
  2504         element = self.GetEditedElement(tagname)
  2571         element = self.GetEditedElement(tagname)
  2505         if element is not None:
  2572         if element is not None:
  2506             block = PLCOpenParser.CreateElement("block", "fbdObjects")
  2573             block = PLCOpenParser.CreateElement("block", "fbdObjects")
  2507             block.setlocalId(id)
  2574             block.setlocalId(id)
  2508             block.settypeName(blocktype)
  2575             block.settypeName(blocktype)
  3051             instance = element.getinstance(id)
  3118             instance = element.getinstance(id)
  3052             if isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")):
  3119             if isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")):
  3053                 self.RemoveEditedElementPouVar(tagname, instance.gettypeName(), instance.getinstanceName())
  3120                 self.RemoveEditedElementPouVar(tagname, instance.gettypeName(), instance.getinstanceName())
  3054             element.removeinstance(id)
  3121             element.removeinstance(id)
  3055 
  3122 
  3056     def GetEditedResourceVariables(self, tagname, debug = False):
  3123     def GetEditedResourceVariables(self, tagname, debug=False):
  3057         varlist = []
  3124         varlist = []
  3058         words = tagname.split("::")
  3125         words = tagname.split("::")
  3059         for var in self.GetConfigurationGlobalVars(words[1], debug):
  3126         for var in self.GetConfigurationGlobalVars(words[1], debug):
  3060             if var.Type == "BOOL":
  3127             if var.Type == "BOOL":
  3061                 varlist.append(var.Name)
  3128                 varlist.append(var.Name)
  3074                 new_task = PLCOpenParser.CreateElement("task", "resource")
  3141                 new_task = PLCOpenParser.CreateElement("task", "resource")
  3075                 resource.appendtask(new_task)
  3142                 resource.appendtask(new_task)
  3076                 new_task.setname(task["Name"])
  3143                 new_task.setname(task["Name"])
  3077                 if task["Triggering"] == "Interrupt":
  3144                 if task["Triggering"] == "Interrupt":
  3078                     new_task.setsingle(task["Single"])
  3145                     new_task.setsingle(task["Single"])
  3079 ##                result = duration_model.match(task["Interval"]).groups()
  3146 #                result = duration_model.match(task["Interval"]).groups()
  3080 ##                if reduce(lambda x, y: x or y != None, result):
  3147 #                if reduce(lambda x, y: x or y != None, result):
  3081 ##                    values = []
  3148 #                    values = []
  3082 ##                    for value in result[:-1]:
  3149 #                    for value in result[:-1]:
  3083 ##                        if value != None:
  3150 #                        if value != None:
  3084 ##                            values.append(int(value))
  3151 #                            values.append(int(value))
  3085 ##                        else:
  3152 #                        else:
  3086 ##                            values.append(0)
  3153 #                            values.append(0)
  3087 ##                    if result[-1] is not None:
  3154 #                    if result[-1] is not None:
  3088 ##                        values.append(int(float(result[-1]) * 1000))
  3155 #                        values.append(int(float(result[-1]) * 1000))
  3089 ##                    new_task.setinterval(datetime.time(*values))
  3156 #                    new_task.setinterval(datetime.time(*values))
  3090                 if task["Triggering"] == "Cyclic":
  3157                 if task["Triggering"] == "Cyclic":
  3091                     new_task.setinterval(task["Interval"])
  3158                     new_task.setinterval(task["Interval"])
  3092                 new_task.setpriority(int(task["Priority"]))
  3159                 new_task.setpriority(int(task["Priority"]))
  3093                 if task["Name"] != "":
  3160                 if task["Name"] != "":
  3094                     task_list[task["Name"]] = new_task
  3161                     task_list[task["Name"]] = new_task
  3101                     new_instance = PLCOpenParser.CreateElement("pouInstance", "resource")
  3168                     new_instance = PLCOpenParser.CreateElement("pouInstance", "resource")
  3102                     resource.appendpouInstance(new_instance)
  3169                     resource.appendpouInstance(new_instance)
  3103                 new_instance.setname(instance["Name"])
  3170                 new_instance.setname(instance["Name"])
  3104                 new_instance.settypeName(instance["Type"])
  3171                 new_instance.settypeName(instance["Type"])
  3105 
  3172 
  3106     def GetEditedResourceInfos(self, tagname, debug = False):
  3173     def GetEditedResourceInfos(self, tagname, debug=False):
  3107         resource = self.GetEditedElement(tagname, debug)
  3174         resource = self.GetEditedElement(tagname, debug)
  3108         if resource is not None:
  3175         if resource is not None:
  3109             tasks = resource.gettask()
  3176             tasks = resource.gettask()
  3110             instances = resource.getpouInstance()
  3177             instances = resource.getpouInstance()
  3111             tasks_data = []
  3178             tasks_data = []
  3118                     new_task["Single"] = single
  3185                     new_task["Single"] = single
  3119                 else:
  3186                 else:
  3120                     new_task["Single"] = ""
  3187                     new_task["Single"] = ""
  3121                 interval = task.getinterval()
  3188                 interval = task.getinterval()
  3122                 if interval is not None:
  3189                 if interval is not None:
  3123 ##                    text = ""
  3190                     # text = ""
  3124 ##                    if interval.hour != 0:
  3191                     # if interval.hour != 0:
  3125 ##                        text += "%dh"%interval.hour
  3192                     #     text += "%dh"%interval.hour
  3126 ##                    if interval.minute != 0:
  3193                     # if interval.minute != 0:
  3127 ##                        text += "%dm"%interval.minute
  3194                     #     text += "%dm"%interval.minute
  3128 ##                    if interval.second != 0:
  3195                     # if interval.second != 0:
  3129 ##                        text += "%ds"%interval.second
  3196                     #     text += "%ds"%interval.second
  3130 ##                    if interval.microsecond != 0:
  3197                     # if interval.microsecond != 0:
  3131 ##                        if interval.microsecond % 1000 != 0:
  3198                     #     if interval.microsecond % 1000 != 0:
  3132 ##                            text += "%.3fms"%(float(interval.microsecond) / 1000)
  3199                     #         text += "%.3fms"%(float(interval.microsecond) / 1000)
  3133 ##                        else:
  3200                     #     else:
  3134 ##                            text += "%dms"%(interval.microsecond / 1000)
  3201                     #         text += "%dms"%(interval.microsecond / 1000)
  3135 ##                    new_task["Interval"] = text
  3202                     # new_task["Interval"] = text
  3136                     new_task["Interval"] = interval
  3203                     new_task["Interval"] = interval
  3137                 else:
  3204                 else:
  3138                     new_task["Interval"] = ""
  3205                     new_task["Interval"] = ""
  3139                 if single is not None and interval is None:
  3206                 if single is not None and interval is None:
  3140                     new_task["Triggering"] = "Interrupt"
  3207                     new_task["Triggering"] = "Interrupt"
  3170         self.CurrentCompiledProject = None
  3237         self.CurrentCompiledProject = None
  3171         self.Buffering = False
  3238         self.Buffering = False
  3172         self.CurrentElementEditing = None
  3239         self.CurrentElementEditing = None
  3173         return error
  3240         return error
  3174 
  3241 
  3175     def SaveXMLFile(self, filepath = None):
  3242     def SaveXMLFile(self, filepath=None):
  3176         if not filepath and self.FilePath == "":
  3243         if not filepath and self.FilePath == "":
  3177             return False
  3244             return False
  3178         else:
  3245         else:
  3179             contentheader = {"modificationDateTime": datetime.datetime(*localtime()[:6])}
  3246             contentheader = {"modificationDateTime": datetime.datetime(*localtime()[:6])}
  3180             self.Project.setcontentHeader(contentheader)
  3247             self.Project.setcontentHeader(contentheader)
  3187             self.MarkProjectAsSaved()
  3254             self.MarkProjectAsSaved()
  3188             if filepath:
  3255             if filepath:
  3189                 self.SetFilePath(filepath)
  3256                 self.SetFilePath(filepath)
  3190             return True
  3257             return True
  3191 
  3258 
  3192 #-------------------------------------------------------------------------------
  3259     # -------------------------------------------------------------------------------
  3193 #                       Search in Current Project Functions
  3260     #                       Search in Current Project Functions
  3194 #-------------------------------------------------------------------------------
  3261     # -------------------------------------------------------------------------------
  3195 
  3262 
  3196     def SearchInProject(self, criteria):
  3263     def SearchInProject(self, criteria):
  3197         return self.Project.Search(criteria)
  3264         return self.Project.Search(criteria)
  3198 
  3265 
  3199     def SearchInPou(self, tagname, criteria, debug=False):
  3266     def SearchInPou(self, tagname, criteria, debug=False):
  3207                     if infos[1] in ["var_local", "var_input", "var_output", "var_inout"]:
  3274                     if infos[1] in ["var_local", "var_input", "var_output", "var_inout"]:
  3208                         search_results.append((infos, start, end, text))
  3275                         search_results.append((infos, start, end, text))
  3209             return search_results
  3276             return search_results
  3210         return []
  3277         return []
  3211 
  3278 
  3212 #-------------------------------------------------------------------------------
  3279     # -------------------------------------------------------------------------------
  3213 #                      Current Buffering Management Functions
  3280     #                      Current Buffering Management Functions
  3214 #-------------------------------------------------------------------------------
  3281     # -------------------------------------------------------------------------------
  3215 
  3282 
  3216     """
       
  3217     Return a copy of the project
       
  3218     """
       
  3219     def Copy(self, model):
  3283     def Copy(self, model):
       
  3284         """Return a copy of the project"""
  3220         return deepcopy(model)
  3285         return deepcopy(model)
  3221 
  3286 
  3222     def CreateProjectBuffer(self, saved):
  3287     def CreateProjectBuffer(self, saved):
  3223         if self.ProjectBufferEnabled:
  3288         if self.ProjectBufferEnabled:
  3224             self.ProjectBuffer = UndoBuffer(PLCOpenParser.Dumps(self.Project), saved)
  3289             self.ProjectBuffer = UndoBuffer(PLCOpenParser.Dumps(self.Project), saved)