# HG changeset patch # User lbessard # Date 1188229070 -7200 # Node ID c798a68c556069b919d14d695356c6707280d397 # Parent b22f661cbcfbf9009100c46a9cb4701ab5f8cfb9 Lots of bugs fixed Support for prioritized transition added into SFC diff -r b22f661cbcfb -r c798a68c5560 Dialogs.py --- a/Dialogs.py Thu Aug 23 09:50:35 2007 +0200 +++ b/Dialogs.py Mon Aug 27 17:37:50 2007 +0200 @@ -296,24 +296,25 @@ dc = wx.ClientDC(self.Preview) dc.Clear() item = self.TypeTree.GetSelection() - pydata = self.TypeTree.GetPyData(item) - if pydata["type"] == CATEGORY: - self.Block = None - else: - blocktype = self.TypeTree.GetItemText(item) - if blocktype: - self.Block = FBD_Block(self.Preview, blocktype, self.Name.GetValue(), extension = self.Inputs.GetValue(), inputs = pydata["inputs"]) - width, height = self.MinBlockSize - min_width, min_height = self.Block.GetMinSize() - width, height = max(min_width, width), max(min_height, height) - self.Block.SetSize(width, height) - clientsize = self.Preview.GetClientSize() - x = (clientsize.width - width) / 2 - y = (clientsize.height - height) / 2 - self.Block.SetPosition(x, y) - self.Block.Draw(dc) + if item.IsOk(): + pydata = self.TypeTree.GetPyData(item) + if pydata["type"] == CATEGORY: + self.Block = None else: - self.Block = None + blocktype = self.TypeTree.GetItemText(item) + if blocktype: + self.Block = FBD_Block(self.Preview, blocktype, self.Name.GetValue(), extension = self.Inputs.GetValue(), inputs = pydata["inputs"]) + width, height = self.MinBlockSize + min_width, min_height = self.Block.GetMinSize() + width, height = max(min_width, width), max(min_height, height) + self.Block.SetSize(width, height) + clientsize = self.Preview.GetClientSize() + x = (clientsize.width - width) / 2 + y = (clientsize.height - height) / 2 + self.Block.SetPosition(x, y) + self.Block.Draw(dc) + else: + self.Block = None def OnPaint(self, event): if self.Block: @@ -1363,10 +1364,11 @@ [ID_TRANSITIONCONTENTDIALOG, ID_TRANSITIONCONTENTDIALOGSPACER, ID_TRANSITIONCONTENTDIALOGREFERENCE, ID_TRANSITIONCONTENTDIALOGINLINE, - ID_TRANSITIONCONTENTDIALOGPREVIEW, ID_TRANSITIONCONTENTDIALOGRADIOBUTTON1, - ID_TRANSITIONCONTENTDIALOGRADIOBUTTON2, ID_TRANSITIONCONTENTDIALOGRADIOBUTTON3, - ID_TRANSITIONCONTENTDIALOGSTATICTEXT1, ID_TRANSITIONCONTENTDIALOGSTATICTEXT2, -] = [wx.NewId() for _init_ctrls in range(10)] + ID_TRANSITIONCONTENTDIALOGPRIORITY, ID_TRANSITIONCONTENTDIALOGPREVIEW, + ID_TRANSITIONCONTENTDIALOGRADIOBUTTON1, ID_TRANSITIONCONTENTDIALOGRADIOBUTTON2, + ID_TRANSITIONCONTENTDIALOGRADIOBUTTON3, ID_TRANSITIONCONTENTDIALOGSTATICTEXT1, + ID_TRANSITIONCONTENTDIALOGSTATICTEXT2, ID_TRANSITIONCONTENTDIALOGSTATICTEXT3, +] = [wx.NewId() for _init_ctrls in range(12)] class TransitionContentDialog(wx.Dialog): def _init_coll_flexGridSizer1_Items(self, parent): @@ -1388,6 +1390,8 @@ parent.AddWindow(self.radioButton2, 0, border=0, flag=wx.GROW) parent.AddWindow(self.Inline, 0, border=0, flag=wx.GROW) parent.AddWindow(self.radioButton3, 0, border=0, flag=wx.GROW) + parent.AddWindow(self.staticText3, 0, border=0, flag=wx.GROW) + parent.AddWindow(self.Priority, 0, border=0, flag=wx.GROW) parent.AddWindow(self.Spacer, 0, border=0, flag=wx.GROW) def _init_coll_LeftGridSizer_Growables(self, parent): @@ -1405,7 +1409,7 @@ def _init_sizers(self): self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) self.MainSizer = wx.BoxSizer(wx.HORIZONTAL) - self.LeftGridSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=7, vgap=5) + self.LeftGridSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=9, vgap=5) self.RightGridSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) @@ -1421,9 +1425,9 @@ def _init_ctrls(self, prnt): wx.Dialog.__init__(self, id=ID_TRANSITIONCONTENTDIALOG, name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223), - size=wx.Size(350, 260), style=wx.DEFAULT_DIALOG_STYLE, + size=wx.Size(350, 300), style=wx.DEFAULT_DIALOG_STYLE, title='Edit transition') - self.SetClientSize(wx.Size(350, 260)) + self.SetClientSize(wx.Size(350, 300)) self.staticText1 = wx.StaticText(id=ID_TRANSITIONCONTENTDIALOGSTATICTEXT1, label='Type:', name='staticText1', parent=self, @@ -1433,6 +1437,10 @@ label='Preview:', name='staticText2', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) + self.staticText3 = wx.StaticText(id=ID_TRANSITIONCONTENTDIALOGSTATICTEXT3, + label='Priority:', name='staticText3', parent=self, + pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) + self.radioButton1 = wx.RadioButton(id=ID_TRANSITIONCONTENTDIALOGRADIOBUTTON1, label='Reference', name='radioButton1', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0) @@ -1463,6 +1471,11 @@ if not self.Connection: self.radioButton3.Hide() + self.Priority = wx.SpinCtrl(id=ID_TRANSITIONCONTENTDIALOGPRIORITY, + name='Priority', parent=self, pos=wx.Point(0, 0), + size=wx.Size(0, 24), style=wx.SP_ARROW_KEYS, min=0) + self.Bind(wx.EVT_TEXT, self.OnPriorityChanged, id=ID_TRANSITIONCONTENTDIALOGPRIORITY) + self.Preview = wx.Panel(id=ID_TRANSITIONCONTENTDIALOGPREVIEW, name='Preview', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL|wx.SIMPLE_BORDER) @@ -1541,6 +1554,11 @@ self.RefreshPreview() event.Skip() + def OnPriorityChanged(self, event): + self.Element.SetPriority(int(self.Priority.GetValue())) + self.RefreshPreview() + event.Skip() + def SetTransitions(self, transitions): self.Reference.Append("") for transition in transitions: @@ -1570,10 +1588,11 @@ self.Reference.Enable(False) self.Inline.Enable(False) self.Element.SetType("connection") + self.Element.SetPriority(values["priority"]) self.RefreshPreview() def GetValues(self): - values = {} + values = {"priority" : int(self.Priority.GetValue())} if self.radioButton1.GetValue(): values["type"] = "reference" values["value"] = self.Reference.GetStringSelection() diff -r b22f661cbcfb -r c798a68c5560 LDViewer.py --- a/LDViewer.py Thu Aug 23 09:50:35 2007 +0200 +++ b/LDViewer.py Mon Aug 27 17:37:50 2007 +0200 @@ -188,56 +188,55 @@ def loadInstance(self, instance, ids): Viewer.loadInstance(self, instance, ids) - if instance["type"] == "leftPowerRail": - element = self.FindElementById(instance["id"]) - rung = Graphic_Group(self) - rung.SelectElement(element) - self.Rungs.append(rung) - elif instance["type"] == "rightPowerRail": - rungs = [] - for connector in instance["connectors"]: - for link in connector["links"]: + if self.GetDrawingMode() != FREEDRAWING_MODE: + if instance["type"] == "leftPowerRail": + element = self.FindElementById(instance["id"]) + rung = Graphic_Group(self) + rung.SelectElement(element) + self.Rungs.append(rung) + elif instance["type"] == "rightPowerRail": + rungs = [] + for connector in instance["connectors"]: + for link in connector["links"]: + connected = self.FindElementById(link["refLocalId"]) + rung = self.FindRung(connected) + if rung not in rungs: + rungs.append(rung) + if len(rungs) > 1: + raise "ValueError", "Ladder element with id %d is on more than one rung."%instance["id"] + element = self.FindElementById(instance["id"]) + self.Rungs[rungs[0]].SelectElement(element) + for connector in element.GetConnectors(): + for wire, num in connector.GetWires(): + self.Rungs[rungs[0]].SelectElement(wire) + self.RefreshPosition(element) + elif instance["type"] in ["contact", "coil"]: + rungs = [] + for link in instance["connectors"]["input"]["links"]: connected = self.FindElementById(link["refLocalId"]) rung = self.FindRung(connected) if rung not in rungs: rungs.append(rung) - if len(rungs) > 1: - raise "ValueError", "Ladder element with id %d is on more than one rung."%instance["id"] - element = self.FindElementById(instance["id"]) - self.Rungs[rungs[0]].SelectElement(element) - for connector in element.GetConnectors(): - for wire, num in connector.GetWires(): + if len(rungs) > 1: + raise "ValueError", "Ladder element with id %d is on more than one rung."%instance["id"] + element = self.FindElementById(instance["id"]) + self.Rungs[rungs[0]].SelectElement(element) + for wire, num in element.GetConnectors()["input"].GetWires(): self.Rungs[rungs[0]].SelectElement(wire) - if self.GetDrawingMode() != FREEDRAWING_MODE: self.RefreshPosition(element) - elif instance["type"] in ["contact", "coil"]: - rungs = [] - for link in instance["connectors"]["input"]["links"]: - connected = self.FindElementById(link["refLocalId"]) - rung = self.FindRung(connected) - if rung not in rungs: - rungs.append(rung) - if len(rungs) > 1: - raise "ValueError", "Ladder element with id %d is on more than one rung."%instance["id"] - element = self.FindElementById(instance["id"]) - self.Rungs[rungs[0]].SelectElement(element) - for wire, num in element.GetConnectors()["input"].GetWires(): - self.Rungs[rungs[0]].SelectElement(wire) - if self.GetDrawingMode() != FREEDRAWING_MODE: - self.RefreshPosition(element) - elif instance["type"] == "comment": - element = self.FindElementById(instance["id"]) - pos = element.GetPosition() - i = 0 - inserted = False - while i < len(self.RungComments) and not inserted: - ipos = self.RungComments[i].GetPosition() - if pos[1] < ipos[1]: - self.RungComments.insert(i, element) - inserted = True - i += 1 - if not inserted: - self.RungComments.append(element) + elif instance["type"] == "comment": + element = self.FindElementById(instance["id"]) + pos = element.GetPosition() + i = 0 + inserted = False + while i < len(self.RungComments) and not inserted: + ipos = self.RungComments[i].GetPosition() + if pos[1] < ipos[1]: + self.RungComments.insert(i, element) + inserted = True + i += 1 + if not inserted: + self.RungComments.append(element) #------------------------------------------------------------------------------- # Search Element functions @@ -249,10 +248,13 @@ return i return None - def FindElement(self, pos): - if self.GetDrawingMode() == FREEDRAWING_MODE: - return Viewer.FindElement(self, pos) + def FindElement(self, pos, exclude_group = False): + if self.GetDrawingMode() == FREEDRAWING_MODE: + return Viewer.FindElement(self, pos, exclude_group) + if self.SelectedElement and not (exclude_group and isinstance(self.SelectedElement, Graphic_Group)): + if self.SelectedElement.HitTest(pos) or self.SelectedElement.TestHandle(pos) != (0, 0): + return self.SelectedElement elements = [] for element in self.GetElements(sort_wires=True): if element.HitTest(pos) or element.TestHandle(pos) != (0, 0): diff -r b22f661cbcfb -r c798a68c5560 PLCControler.py --- a/PLCControler.py Thu Aug 23 09:50:35 2007 +0200 +++ b/PLCControler.py Mon Aug 27 17:37:50 2007 +0200 @@ -196,11 +196,15 @@ # Return project pou names def GetProjectPouNames(self): - return [pou.getName() for pou in self.Project.getPous()] + if self.Project: + return [pou.getName() for pou in self.Project.getPous()] + return [] # Return project pou names def GetProjectConfigNames(self): - return [config.getName() for config in self.Project.getConfigurations()] + if self.Project: + return [config.getName() for config in self.Project.getConfigurations()] + return [] # Return project pou variables def GetProjectPouVariables(self, pou_name=None): @@ -383,6 +387,7 @@ def ProjectAddPou(self, name, pou_type, body_type): # Add the pou to project self.Project.appendPou(name, pou_type, body_type) + self.SetPouInterfaceReturnType(name, "BOOL") self.RefreshPouUsingTree() self.RefreshBlockTypes() self.BufferProject() @@ -455,9 +460,15 @@ pou = self.Project.getPou(old_name) pou.setName(new_name) # If pou is currently opened, change its name in the list of opened pous - if old_name in self.ElementsOpened: - idx = self.ElementsOpened.index(old_name) - self.ElementsOpened[idx] = new_name + for idx, element in enumerate(self.ElementsOpened): + words = element.split("::") + if words[0] in ["P","T","A"] and words[1] == old_name: + if words[0] == "P": + self.ElementsOpened[idx] = self.ComputePouName(new_name) + elif words[0] == "T": + self.ElementsOpened[idx] = self.ComputePouTransitionName(new_name, words[2]) + else: + self.ElementsOpened[idx] = self.ComputePouActionName(new_name, words[2]) self.Project.updateElementName(old_name, new_name) self.RefreshPouUsingTree() self.RefreshBlockTypes() @@ -491,7 +502,7 @@ self.ElementsOpened[idx] = new_computedname self.BufferProject() - # Change the name of a pou action + # Change the name of a pou variable def ChangePouVariableName(self, pou_name, old_name, new_name): # Found the pou action corresponding to old name and change its name to new name pou = self.Project.getPou(pou_name) @@ -509,7 +520,12 @@ configuration.setName(new_name) # If configuration is currently opened, change its name in the list of opened elements for idx, element in enumerate(self.ElementsOpened): - self.ElementsOpened[idx] = element.replace(old_name, new_name) + words = element.split("::") + if words[0] in ["C","R"] and words[1] == old_name: + if words[0] == "C": + self.ElementsOpened[idx] = self.ComputeConfigurationName(new_name) + else: + self.ElementsOpened[idx] = self.ComputeConfigurationResourceName(new_name, words[2]) self.BufferProject() # Change the name of a configuration resource @@ -865,15 +881,14 @@ if type == "function": blocktypes = [] for category in BlockTypes[:-1]: - if category["name"] != "SVGUI function blocks": - cat = {"name" : category["name"], "list" : []} - for block in category["list"]: - if block["type"] == "function": - cat["list"].append(block) - if len(cat["list"]) > 0: - blocktypes.append(cat) + cat = {"name" : category["name"], "list" : []} + for block in category["list"]: + if block["type"] == "function": + cat["list"].append(block) + if len(cat["list"]) > 0: + blocktypes.append(cat) else: - blocktypes = [category for category in BlockTypes[:-1] if category["name"] != "SVGUI function blocks"] + blocktypes = [category for category in BlockTypes[:-1]] if self.Project: blocktypes.append({"name" : "User-defined POUs", "list": []}) for blocktype in BlockTypes[-1]["list"]: @@ -887,6 +902,7 @@ if self.CurrentElementEditing != None: if self.Project: current_name = self.ElementsOpened[self.CurrentElementEditing] + print current_name words = current_name.split("::") if len(words) == 1: name = current_name @@ -898,10 +914,9 @@ type = None blocktypes = [] for category in BlockTypes[:-1]: - if category["name"] != "SVGUI function blocks": - for block in category["list"]: - if block["type"] != "function": - blocktypes.append(block["name"]) + for block in category["list"]: + if block["type"] != "function": + blocktypes.append(block["name"]) if self.Project: for blocktype in BlockTypes[-1]["list"]: if blocktype["name"] != name and not self.PouIsUsedBy(name, blocktype["name"]) and not (type == "function" and blocktype["type"] != "function"): @@ -932,15 +947,17 @@ names = [] for pou_name in self.ElementsOpened: words = pou_name.split("::") - if len(words) == 1: - names.append(pou_name) - elif len(words) == 2: + if words[0] in ["P","C"]: names.append(words[1]) else: names.append("%s-%s"%(words[1],words[2])) return names # Compute a pou transition name + def ComputePouName(self, pou): + return "P::%s" % pou + + # Compute a pou transition name def ComputePouTransitionName(self, pou, transition): return "T::%s::%s" % (pou, transition) @@ -967,6 +984,10 @@ return None # Open a pou transition by giving pou and transition names + def OpenPouEditing(self, pou): + return self.OpenElementEditing(self.ComputePouName(pou)) + + # Open a pou transition by giving pou and transition names def OpenPouTransitionEditing(self, pou, transition): return self.OpenElementEditing(self.ComputePouTransitionName(pou, transition)) @@ -983,8 +1004,8 @@ return self.OpenElementEditing(self.ComputeConfigurationResourceName(config, resource)) # Return if pou given by name is opened - def IsElementEditing(self, name): - return name in self.ElementsOpened + def IsPouEditing(self, pou): + return self.ComputePouName(pou) in self.ElementsOpened # Return if pou transition given by pou and transition names is opened def IsPouTransitionEditing(self, pou, transition): @@ -995,45 +1016,49 @@ return self.ComputePouActionName(pou, action) in self.ElementsOpened # Return if pou action given by configuration name is opened - def IsConfigurationEditing(self, pou): + def IsConfigurationEditing(self, config): return self.ComputeConfigurationName(config) in self.ElementsOpened # Return if pou action given by configuration and resource names is opened - def IsConfigurationResourceEditing(self, pou, resource): + def IsConfigurationResourceEditing(self, config, resource): return self.ComputeConfigurationResourceName(config, resource) in self.ElementsOpened - # Close current pou editing + # Close current element editing def CloseElementEditing(self): # Remove pou from list of pou opened self.ElementsOpened.pop(self.CurrentElementEditing) - # Update index of current pou editing + # Update index of current element editing if len(self.ElementsOpened) > 0: self.CurrentElementEditing = min(self.CurrentElementEditing, len(self.ElementsOpened) - 1) else: self.CurrentElementEditing = None - # Change current pou editing for pou given by name + # Change current element editing for pou given by name def ChangeElementEditing(self, name): - # Verify that pou is opened + # Verify that element is opened if name in self.ElementsOpened: - # Change current pou editing + # Change current element editing self.CurrentElementEditing = self.ElementsOpened.index(name) return self.CurrentElementEditing return None - - # Change current pou editing for transition given by pou and transition names + + # Change current element editing for pou given by pou name + def ChangePouEditing(self, pou): + return self.ChangeElementEditing(self.ComputePouName(pou)) + + # Change current element editing for transition given by pou and transition names def ChangePouTransitionEditing(self, pou, transition): return self.ChangeElementEditing(self.ComputePouTransitionName(pou, transition)) - # Change current pou editing for action given by pou and action names + # Change current element editing for action given by pou and action names def ChangePouActionEditing(self, pou, action): return self.ChangeElementEditing(self.ComputePouActionName(pou, action)) - # Change current pou editing for action given by configuration name + # Change current element editing for configuration given by configuration name def ChangeConfigurationEditing(self, config): return self.ChangeElementEditing(self.ComputeConfigurationName(config)) - # Change current pou editing for action given by configuration and resource names + # Change current element editing for resource given by configuration and resource names def ChangeConfigurationResourceEditing(self, config, resource): return self.ChangeElementEditing(self.ComputeConfigurationResourceName(config, resource)) @@ -1047,21 +1072,18 @@ if self.CurrentElementEditing != None: name = self.ElementsOpened[self.CurrentElementEditing] words = name.split("::") - if len(words) == 1: - return self.Project.getPou(name) - else: - if words[0] in ['T', 'A']: - pou = self.Project.getPou(words[1]) - if words[0] == 'T': - return pou.getTransition(words[2]) - elif words[0] == 'A': - return pou.getAction(words[2]) - elif words[0] == 'C': - result = self.Project.getConfiguration(words[1]) - return result - elif words[0] == 'R': - result = self.Project.getConfigurationResource(words[1], words[2]) - return result + if words[0] == "P": + return self.Project.getPou(words[1]) + if words[0] in ['T', 'A']: + pou = self.Project.getPou(words[1]) + if words[0] == 'T': + return pou.getTransition(words[2]) + elif words[0] == 'A': + return pou.getAction(words[2]) + elif words[0] == 'C': + return self.Project.getConfiguration(words[1]) + elif words[0] == 'R': + return self.Project.getConfigurationResource(words[1], words[2]) return None # Return current pou editing name @@ -1070,9 +1092,7 @@ if self.CurrentElementEditing != None: name = self.ElementsOpened[self.CurrentElementEditing] words = name.split("::") - if len(words) == 1: - return name - elif len(words) == 2: + if words[0] in ["P","C"]: return words[1] else: return words[2] @@ -1087,11 +1107,7 @@ if self.CurrentElementEditing != None: name = self.ElementsOpened[self.CurrentElementEditing] words = name.split("::") - if len(words) == 1: - return self.GetPouType(name) - elif len(words) == 2: - return None - elif words[0] != "R": + if words[0] == "P": return self.GetPouType(words[1]) return None @@ -1100,13 +1116,12 @@ if self.CurrentElementEditing != None: name = self.ElementsOpened[self.CurrentElementEditing] words = name.split("::") - if len(words) == 1: - return self.GetPouBodyType(name) - else: - if words[0] == 'T': - return self.GetTransitionBodyType(words[1], words[2]) - elif words[0] == 'A': - return self.GetActionBodyType(words[1], words[2]) + if words[0] == "P": + return self.GetPouBodyType(words[1]) + elif words[0] == 'T': + return self.GetTransitionBodyType(words[1], words[2]) + elif words[0] == 'A': + return self.GetActionBodyType(words[1], words[2]) return None # Return the variables of the current pou editing @@ -1114,10 +1129,7 @@ if self.CurrentElementEditing != None: current_name = self.ElementsOpened[self.CurrentElementEditing] words = current_name.split("::") - if len(words) == 1: - pou = self.Project.getPou(current_name) - return self.GetPouInterfaceVars(pou) - else: + if words[0] in ["P","T","A"]: pou = self.Project.getPou(words[1]) return self.GetPouInterfaceVars(pou) return [] @@ -1127,8 +1139,8 @@ if self.CurrentElementEditing != None: current_name = self.ElementsOpened[self.CurrentElementEditing] words = current_name.split("::") - if len(words) == 1: - pou = self.Project.getPou(current_name) + if words[0] == "P": + pou = self.Project.getPou(words[1]) return self.GetPouInterfaceReturnType(pou) elif words[0] == 'T': return "BOOL" @@ -1173,9 +1185,7 @@ if self.CurrentElementEditing != None: current_name = self.ElementsOpened[self.CurrentElementEditing] words = current_name.split("::") - if len(words) == 1: - return self.GetProjectPouVariables(current_name) - else: + if words[0] in ["P","T","A"]: return self.GetProjectPouVariables(words[1]) return [] @@ -1345,6 +1355,11 @@ elif isinstance(instance, plcopen.transition): infos["type"] = "transition" condition = instance.getConditionContent() + priority = instance.getPriority() + if priority == None: + infos["priority"] = 0 + else: + infos["priority"] = priority infos["condition_type"] = condition["type"] infos["connectors"] = {"input":{},"output":{}} infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition() @@ -1433,14 +1448,12 @@ def GetCurrentPouVarValueType(self, varname): current_name = self.ElementsOpened[self.CurrentElementEditing] words = current_name.split("::") - if len(words) == 1: - pou = self.Project.getPou(current_name) - else: + if words[0] in ["P","T","A"]: pou = self.Project.getPou(words[1]) - for type, varlist in pou.getVars(): - for var in varlist.getVariable(): - if var.getName() == varname: - return var.getType() + for type, varlist in pou.getVars(): + for var in varlist.getVariable(): + if var.getName() == varname: + return var.getType() return "" def SetConnectionWires(self, connection, connector): @@ -1475,9 +1488,7 @@ if self.CurrentElementEditing != None: name = self.ElementsOpened[self.CurrentElementEditing] words = name.split("::") - if len(words) == 1: - element.addPouVar(blocktype, blockname) - elif words[0] in ['T', 'A']: + if words[0] in ["P","T","A"]: pou = self.Project.getPou(words[1]) pou.addPouVar(blocktype, blockname) element.addInstance("block", block) @@ -1823,6 +1834,11 @@ transition.setX(value) elif param == "y": transition.setY(value) + elif param == "priority": + if value != 0: + transition.setPriority(value) + else: + transition.setPriority(None) elif param == "connectors": input_connector = value["input"] position = input_connector.GetRelPosition() diff -r b22f661cbcfb -r c798a68c5560 PLCGenerator.py --- a/PLCGenerator.py Thu Aug 23 09:50:35 2007 +0200 +++ b/PLCGenerator.py Mon Aug 27 17:37:50 2007 +0200 @@ -53,7 +53,6 @@ compute += "\n" return compute - def GeneratePouProgram(pou_name): if not pouComputed.get(pou_name, True): pouComputed[pou_name] = True @@ -468,7 +467,7 @@ steps.extend(self.ExtractConvergenceInputs(step, pou)) elif isinstance(instance, plcopen.simultaneousConvergence): steps.extend(self.ExtractConvergenceInputs(instance, pou)) - transition_infos = {"from": [], "to" : []} + transition_infos = {"priority": transition.getPriority(), "from": [], "to" : []} transitionValues = transition.getConditionContent() if transitionValues["type"] == "inline": transition_infos["content"] = "\n := %s;\n"%transitionValues["value"] @@ -552,7 +551,10 @@ def ComputeSFCTransition(self, transition): if transition in self.SFCNetworks["Transitions"].keys(): transition_infos = self.SFCNetworks["Transitions"].pop(transition) - self.Program += " TRANSITION FROM " + self.Program += " TRANSITION" + if transition_infos["priority"] != None: + self.Program += " (PRIORITY := %d)"%transition_infos["priority"] + self.Program += " FROM " if len(transition_infos["from"]) > 1: self.Program += "(%s)"%", ".join(transition_infos["from"]) else: diff -r b22f661cbcfb -r c798a68c5560 PLCOpenEditor.py --- a/PLCOpenEditor.py Thu Aug 23 09:50:35 2007 +0200 +++ b/PLCOpenEditor.py Mon Aug 27 17:37:50 2007 +0200 @@ -64,10 +64,7 @@ sys.exit() elif len(args) == 1: fileOpen = args[0] -CWD = "" -for path in sys.path: - if os.path.isfile(os.path.join(path, "PLCOpenEditor.py")): - CWD = path +CWD = os.path.split(__file__)[0] [ID_PLCOPENEDITOR, ID_PLCOPENEDITORPROJECTTREE, ID_PLCOPENEDITORSPLITTERWINDOW1, ID_PLCOPENEDITOREDITORPANEL, @@ -352,17 +349,17 @@ self.splitterWindow1 = wx.SplitterWindow(id=ID_PLCOPENEDITORSPLITTERWINDOW1, name='splitterWindow1', parent=self, point=wx.Point(0, 0), - size=wx.Size(-1, -1), style=wx.SP_3D) + size=wx.Size(0, 0), style=wx.SP_3D) self.splitterWindow1.SetNeedUpdating(True) self.splitterWindow1.SetMinimumPaneSize(1) self.EditorPanel = wx.Panel(id=ID_PLCOPENEDITOREDITORPANEL, name='TabPanel', parent=self.splitterWindow1, pos=wx.Point(0, 0), - size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL) + size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.TabsOpened = wx.Notebook(id=ID_PLCOPENEDITORTABSOPENED, name='TabsOpened', parent=self.EditorPanel, pos=wx.Point(0, - 0), size=wx.Size(-1, -1), style=0) + 0), size=wx.Size(0, 0), style=0) self.TabsOpened.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPouSelectedChanged, id=ID_PLCOPENEDITORTABSOPENED) @@ -500,14 +497,18 @@ def OnCloseFrame(self, event): if not self.Controler.ProjectIsSaved(): - dialog = wx.MessageDialog(self, "There are changes, do you want to save?", "Close Application", wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) + dialog = wx.MessageDialog(self, "There are changes, do you want to save?", "Close Application", wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) answer = dialog.ShowModal() dialog.Destroy() if answer == wx.ID_YES: self.SaveProject() event.Skip() elif answer == wx.ID_NO: + self.Controler.Reset() + wx.CallAfter(self.Close) event.Skip() + else: + event.Veto() else: event.Skip() @@ -631,8 +632,6 @@ event.Skip() def OnQuitMenu(self, event): - self.ToolBar.Reparent(self) - self.Controler.Reset() self.Close() event.Skip() @@ -895,6 +894,7 @@ if name == "Properties": self.ShowProperties() elif data in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION, ITEM_RESOURCE, ITEM_CONFIGURATION]: + idx = None if data == ITEM_CONFIGURATION: idx = self.Controler.OpenConfigurationEditing(name) if idx != None: @@ -916,31 +916,33 @@ else: idx = self.Controler.ChangeConfigurationResourceEditing(config_name, name) elif data == ITEM_POU: - idx = self.Controler.OpenElementEditing(name) + idx = self.Controler.OpenPouEditing(name) if idx != None: new_window = PouEditorPanel(self.TabsOpened, self, self.Controler, self.Controler.GetPouType(name), pou_name = name) self.TabsOpened.AddPage(new_window, "") else: - idx = self.Controler.ChangeElementEditing(name) + idx = self.Controler.ChangePouEditing(name) else: - parent = self.ProjectTree.GetItemParent(selected) - parent_name = self.ProjectTree.GetItemText(parent) - grandparent = self.ProjectTree.GetItemParent(parent) - grandparent_name = self.ProjectTree.GetItemText(grandparent) + item = self.ProjectTree.GetItemParent(selected) + item_type = self.ProjectTree.GetPyData(item) + while item_type != ITEM_POU: + item = self.ProjectTree.GetItemParent(item) + item_type = self.ProjectTree.GetPyData(item) + pou_name = self.ProjectTree.GetItemText(item) if data == ITEM_TRANSITION: - idx = self.Controler.OpenPouTransitionEditing(grandparent_name, name) + idx = self.Controler.OpenPouTransitionEditing(pou_name, name) if idx != None: - new_window = PouEditorPanel(self.TabsOpened, self, self.Controler, "transition", pou_name = grandparent_name, transition_name = name) + new_window = PouEditorPanel(self.TabsOpened, self, self.Controler, "transition", pou_name = pou_name, transition_name = name) self.TabsOpened.AddPage(new_window, "") else: - idx = self.Controler.ChangePouTransitionEditing(grandparent_name, name) + idx = self.Controler.ChangePouTransitionEditing(pou_name, name) elif data == ITEM_ACTION: - idx = self.Controler.OpenPouActionEditing(grandparent_name, name) + idx = self.Controler.OpenPouActionEditing(pou_name, name) if idx != None: - new_window = PouEditorPanel(self.TabsOpened, self, self.Controler, "action", pou_name = grandparent_name, action_name = name) + new_window = PouEditorPanel(self.TabsOpened, self, self.Controler, "action", pou_name = pou_name, action_name = name) self.TabsOpened.AddPage(new_window, "") else: - idx = self.Controler.ChangePouActionEditing(grandparent_name, name) + idx = self.Controler.ChangePouActionEditing(pou_name, name) if idx != None: old_selected = self.TabsOpened.GetSelection() if old_selected >= 0: @@ -966,34 +968,48 @@ def OnProjectTreeItemSelected(self, event): selected = event.GetItem() name = self.ProjectTree.GetItemText(selected) - if self.ProjectTree.GetItemParent(selected) == self.ProjectTree.GetRootItem() and name != "Properties": - if self.Controler.IsElementEditing(name): - idx = self.Controler.ChangeElementEditing(name) - if idx != None: - self.TabsOpened.SetSelection(idx) - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshToolBar() - else: - name = self.ProjectTree.GetItemText(selected) - parent = self.ProjectTree.GetItemParent(selected) - parent_name = self.ProjectTree.GetItemText(parent) - grandparent = self.ProjectTree.GetItemParent(parent) - grandparent_name = self.ProjectTree.GetItemText(grandparent) - if parent_name == "Transitions": - idx = self.Controler.ChangePouTransitionEditing(grandparent_name, name) - if idx != None: - self.TabsOpened.SetSelection(idx) - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshToolBar() - elif parent_name == "Action": - idx = self.Controler.ChangePouActionEditing(grandparent_name, name) - if idx != None: - self.TabsOpened.SetSelection(idx) - self.RefreshFileMenu() - self.RefreshEditMenu() - self.RefreshToolBar() + data = self.ProjectTree.GetPyData(selected) + if data in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION, ITEM_RESOURCE, ITEM_CONFIGURATION]: + idx = None + if data == ITEM_CONFIGURATION: + if self.Controler.IsConfigurationEditing(name): + idx = self.Controler.ChangeConfigurationEditing(name) + elif data == ITEM_RESOURCE: + item = self.ProjectTree.GetItemParent(selected) + item_type = self.ProjectTree.GetPyData(item) + while item_type != ITEM_CONFIGURATION: + item = self.ProjectTree.GetItemParent(item) + item_type = self.ProjectTree.GetPyData(item) + config_name = self.ProjectTree.GetItemText(item) + if self.Controler.IsConfigurationResourceEditing(config_name, name): + idx = self.Controler.ChangeConfigurationResourceEditing(config_name, name) + elif data == ITEM_POU: + if self.Controler.IsPouEditing(name): + idx = self.Controler.ChangePouEditing(name) + else: + item = self.ProjectTree.GetItemParent(selected) + item_type = self.ProjectTree.GetPyData(item) + while item_type != ITEM_POU: + item = self.ProjectTree.GetItemParent(item) + item_type = self.ProjectTree.GetPyData(item) + pou_name = self.ProjectTree.GetItemText(item) + if data == ITEM_TRANSITION: + if self.Controler.IsPouTransitionEditing(pou_name, name): + idx = self.Controler.ChangePouTransitionEditing(pou_name, name) + elif data == ITEM_ACTION: + if self.Controler.IsPouActionEditing(pou_name, name): + idx = self.Controler.ChangePouActionEditing(pou_name, name) + if idx != None: + old_selected = self.TabsOpened.GetSelection() + if old_selected >= 0: + self.TabsOpened.GetPage(old_selected).ResetBuffer() + self.TabsOpened.SetSelection(idx) + window = self.TabsOpened.GetPage(idx) + window.RefreshView() + self.RefreshTabsOpenedTitles() + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshToolBar() event.Skip() def RefreshProjectTree(self): @@ -1066,6 +1082,7 @@ self.TabsOpened.GetPage(selected).Refresh() self.RefreshTitle() self.RefreshEditMenu() + self.RefreshProjectTree() event.Skip() def OnRedoMenu(self, event): @@ -1076,6 +1093,7 @@ self.TabsOpened.GetPage(selected).Refresh() self.RefreshTitle() self.RefreshEditMenu() + self.RefreshProjectTree() event.Skip() def OnCutMenu(self, event): @@ -1112,6 +1130,8 @@ if dialog.ShowModal() == wx.ID_OK: values = dialog.GetValues() self.Controler.ProjectAddPou(values["pouName"], values["pouType"], values["language"]) + self.RefreshTitle() + self.RefreshEditMenu() self.RefreshProjectTree() dialog.Destroy() event.Skip() @@ -1129,6 +1149,8 @@ deleted = i if deleted != None: self.TabsOpened.DeletePage(i) + self.RefreshTitle() + self.RefreshEditMenu() self.RefreshProjectTree() self.RefreshToolBar() else: @@ -1138,20 +1160,26 @@ event.Skip() def OnAddConfigurationMenu(self, event): - dialog = wx.TextEntryDialog(self, "Enter configuration name:", "Create new configuration", "", wx.OK|wx.CANCEL) + dialog = ConfigurationNameDialog(self, "Please enter configuration name", "Add new configuration") + dialog.SetPouNames(self.Controler.GetProjectPouNames()) + dialog.SetPouElementNames(self.Controler.GetProjectPouVariables()) if dialog.ShowModal() == wx.ID_OK: value = dialog.GetValue() self.Controler.ProjectAddConfiguration(value) + self.RefreshTitle() + self.RefreshEditMenu() self.RefreshProjectTree() dialog.Destroy() event.Skip() def OnRemoveConfigurationMenu(self, event): configs = self.Controler.GetProjectConfigNames() - dialog = wx.SingleChoiceDialog(self, "Select Configuration to remove:", "Remove configuration", configs, wx.OK|wx.CANCEL) + dialog = wx.SingleChoiceDialog(self, "Please select a configuration", "Remove configuration", configs, wx.OK|wx.CANCEL) if dialog.ShowModal() == wx.ID_OK: selected = dialog.GetStringSelection() self.Controler.ProjectRemoveConfiguration(selected) + self.RefreshTitle() + self.RefreshEditMenu() self.RefreshProjectTree() event.Skip() @@ -1166,6 +1194,8 @@ if dialog.ShowModal() == wx.ID_OK: values = dialog.GetValues() self.Controler.ProjectAddPouTransition(pouname, values["transitionName"], values["language"]) + self.RefreshTitle() + self.RefreshEditMenu() self.RefreshProjectTree() dialog.Destroy() event.Skip() @@ -1180,6 +1210,8 @@ if dialog.ShowModal() == wx.ID_OK: selected = dialog.GetStringSelection() self.Controler.ProjectRemovePouTransition(pouname, selected) + self.RefreshTitle() + self.RefreshEditMenu() self.RefreshProjectTree() dialog.Destroy() event.Skip() @@ -1195,6 +1227,8 @@ if dialog.ShowModal() == wx.ID_OK: values = dialog.GetValues() self.Controler.ProjectAddPouAction(pouname, values["actionName"], values["language"]) + self.RefreshTitle() + self.RefreshEditMenu() self.RefreshProjectTree() dialog.Destroy() event.Skip() @@ -1209,6 +1243,8 @@ if dialog.ShowModal() == wx.ID_OK: selected = dialog.GetStringSelection() self.Controler.ProjectRemovePouAction(pouname, selected) + self.RefreshTitle() + self.RefreshEditMenu() self.RefreshProjectTree() dialog.Destroy() event.Skip() @@ -1217,10 +1253,14 @@ selected = self.ProjectTree.GetSelection() if self.ProjectTree.GetPyData(selected) == ITEM_CONFIGURATION: config_name = self.ProjectTree.GetItemText(selected) - dialog = wx.TextEntryDialog(self, "Enter Resource name:", "Create new Resource", "", wx.OK|wx.CANCEL) + dialog = ResourceNameDialog(self, "Please enter resource name", "Add new resource") + dialog.SetPouNames(self.Controler.GetProjectPouNames()) + dialog.SetPouElementNames(self.Controler.GetProjectPouVariables()) if dialog.ShowModal() == wx.ID_OK: value = dialog.GetValue() self.Controler.ProjectAddConfigurationResource(config_name, value) + self.RefreshTitle() + self.RefreshEditMenu() self.RefreshProjectTree() dialog.Destroy() event.Skip() @@ -1238,6 +1278,8 @@ if dialog.ShowModal() == wx.ID_OK: resource = dialog.GetStringSelection() self.Controler.ProjectRemoveConfigurationResource(config_name, resource) + self.RefreshTitle() + self.RefreshEditMenu() self.RefreshProjectTree() dialog.Destroy() event.Skip() @@ -1867,6 +1909,108 @@ return values #------------------------------------------------------------------------------- +# Configuration Name Dialog +#------------------------------------------------------------------------------- + +class ConfigurationNameDialog(wx.TextEntryDialog): + + def __init__(self, parent, message, caption = "Please enter configuration name", defaultValue = "", + style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition): + wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos) + + self.PouNames = [] + self.PouElementNames = [] + + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId()) + + def OnOK(self, event): + config_name = self.GetSizer().GetItem(1).GetWindow().GetValue() + if config_name == "": + message = wx.MessageDialog(self, "You must type a name!", "Error", wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + elif not TestIdentifier(config_name): + message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%config_name, "Error", wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + elif config_name.upper() in IEC_KEYWORDS: + message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%config_name, "Error", wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + elif config_name.upper() in self.PouNames: + message = wx.MessageDialog(self, "A pou with \"%s\" as name exists!"%config_name, "Error", wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + elif config_name.upper() in self.PouElementNames: + message = wx.MessageDialog(self, "A pou has an element with \"%s\" for name. It can generate a conflict. Do you wish to continue?"%config_name, "Warning", wx.YES_NO|wx.ICON_EXCLAMATION) + result = message.ShowModal() + message.Destroy() + if result == wx.ID_YES: + self.EndModal(wx.ID_OK) + else: + self.EndModal(wx.ID_OK) + + def SetPouNames(self, pou_names): + self.PouNames = [pou_name.upper() for pou_name in pou_names] + + def SetPouElementNames(self, pou_names): + self.PouElementNames = [pou_name.upper() for pou_name in pou_names] + + def GetValue(self): + return self.GetSizer().GetItem(1).GetWindow().GetValue() + +#------------------------------------------------------------------------------- +# Resource Name Dialog +#------------------------------------------------------------------------------- + +class ResourceNameDialog(wx.TextEntryDialog): + + def __init__(self, parent, message, caption = "Please enter resource name", defaultValue = "", + style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition): + wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos) + + self.PouNames = [] + self.PouElementNames = [] + + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId()) + + def OnOK(self, event): + resource_name = self.GetSizer().GetItem(1).GetWindow().GetValue() + if resource_name == "": + message = wx.MessageDialog(self, "You must type a name!", "Error", wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + elif not TestIdentifier(resource_name): + message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%resource_name, "Error", wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + elif resource_name.upper() in IEC_KEYWORDS: + message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%resource_name, "Error", wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + elif resource_name.upper() in self.PouNames: + message = wx.MessageDialog(self, "A pou with \"%s\" as name exists!"%resource_name, "Error", wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + elif resource_name.upper() in self.PouElementNames: + message = wx.MessageDialog(self, "A pou has an element with \"%s\" for name. It can generate a conflict. Do you wish to continue?"%resource_name, "Warning", wx.YES_NO|wx.ICON_EXCLAMATION) + result = message.ShowModal() + message.Destroy() + if result == wx.ID_YES: + self.EndModal(wx.ID_OK) + else: + self.EndModal(wx.ID_OK) + + def SetPouNames(self, pou_names): + self.PouNames = [pou_name.upper() for pou_name in pou_names] + + def SetPouElementNames(self, pou_names): + self.PouElementNames = [pou_name.upper() for pou_name in pou_names] + + def GetValue(self): + return self.GetSizer().GetItem(1).GetWindow().GetValue() + +#------------------------------------------------------------------------------- # Pou Editor Panel #------------------------------------------------------------------------------- @@ -1904,7 +2048,7 @@ def GetValue(self, row, col): if row < self.GetNumberRows(): if col == 0: - return self.Parent.Values.index(self.data[row]) + 1 + return self.data[row]["Number"] name = str(self.data[row].get(self.GetColLabelValue(col), "")) return name @@ -2134,14 +2278,15 @@ def _init_ctrls(self, prnt, element_type): wx.SplitterWindow.__init__(self, id=ID_POUEDITORPANEL, name='EditVariablePanel', parent=prnt, pos=wx.Point(0, 0), - size=wx.Size(-1, -1), style=wx.SP_3D) + size=wx.Size(0, 0), style=wx.SP_3D) self.SetNeedUpdating(True) self.SetMinimumPaneSize(1) if element_type == "config": self.Viewer = wx.Panel(id=ID_POUEDITORPANELVIEWER, name='ConfigPanel', parent=self, pos=wx.Point(0, 0), - size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL) + size=wx.Size(0, 0), style=0) + self.Viewer.SetSizer(wx.BoxSizer(wx.VERTICAL)) self.Viewer.ResetBuffer = lambda: None self.Viewer.RefreshView = lambda: None elif element_type == "resource": @@ -2162,7 +2307,7 @@ self.VariablePanel = wx.Panel(id=ID_POUEDITORPANELVIEWER, name='VariablePanel', parent=self, pos=wx.Point(0, 0), - size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL) + size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) self.staticText1 = wx.StaticText(id=ID_POUEDITORPANELSTATICTEXT1, label='Return Type:', name='staticText1', parent=self.VariablePanel, @@ -2171,6 +2316,7 @@ self.ReturnType = wx.Choice(id=ID_POUEDITORPANELRETURNTYPE, name='ReturnType', parent=self.VariablePanel, pos=wx.Point(0, 0), size=wx.Size(145, 24), style=0) + self.Bind(wx.EVT_CHOICE, self.OnReturnTypeChanged, id=ID_POUEDITORPANELRETURNTYPE) self.staticText2 = wx.StaticText(id=ID_POUEDITORPANELSTATICTEXT2, label='Class Filter:', name='staticText2', parent=self.VariablePanel, @@ -2252,10 +2398,10 @@ if pou_type in ["config", "resource"]: self.DefaultTypes = {"All" : "Global"} - self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No", "Edit" : "True"} + self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No", "Edit" : True} else: self.DefaultTypes = {"All" : "Local", "Interface" : "Input", "Variables" : "Local"} - self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No", "Edit" : "True"} + self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No", "Edit" : True} if pou_type in ["config", "resource"] or pou_type == "program": self.Table = VariableTable(self, [], ["#", "Name", "Class", "Type", "Location", "Initial Value", "Retain", "Constant"]) if pou_type not in ["config", "resource"]: @@ -2347,6 +2493,13 @@ self.Viewer.SetVariables(varlist) self.Viewer.SetFunctions(self.Controler.GetBlockTypes()) + def OnReturnTypeChanged(self, event): + self.Controler.SetPouInterfaceReturnType(self.PouName, self.ReturnType.GetStringSelection()) + self.Controler.BufferProject() + self.Parent.RefreshTitle() + self.Parent.RefreshEditMenu() + event.Skip() + def OnClassFilter(self, event): self.Filter = self.FilterChoiceTransfer[self.ClassFilter.GetStringSelection()] self.RefreshTypeList() @@ -2519,8 +2672,9 @@ if len(self.Table.data) > 0: self.VariablesGrid.SetGridCursor(0, 1) data = [] - for variable in self.Values: + for num, variable in enumerate(self.Values): if variable["Class"] in self.ClassList: + variable["Number"] = num + 1 data.append(variable) self.Table.SetData(data) self.Table.ResetView(self.VariablesGrid) diff -r b22f661cbcfb -r c798a68c5560 RessourceEditor.py --- a/RessourceEditor.py Thu Aug 23 09:50:35 2007 +0200 +++ b/RessourceEditor.py Mon Aug 27 17:37:50 2007 +0200 @@ -278,8 +278,7 @@ def _init_ctrls(self, prnt): wx.Panel.__init__(self, id=ID_RESOURCEEDITOR, name='', parent=prnt, - pos=wx.Point(0, 0), size=wx.Size(-1, -1), - style=wx.SUNKEN_BORDER) + size=wx.Size(0, 0), style=wx.SUNKEN_BORDER) self.staticText1 = wx.StaticText(id=ID_RESOURCEEDITORSTATICTEXT1, label=u'Tasks:', name='staticText2', parent=self, pos=wx.Point(0, diff -r b22f661cbcfb -r c798a68c5560 SFCViewer.py --- a/SFCViewer.py Thu Aug 23 09:50:35 2007 +0200 +++ b/SFCViewer.py Mon Aug 27 17:37:50 2007 +0200 @@ -46,7 +46,7 @@ def CreateTransition(self, connector, next = None): previous = connector.GetParentBlock() id = self.GetNewId() - transition = SFC_Transition(self, "reference", "", id) + transition = SFC_Transition(self, "reference", "", 0, id) pos = connector.GetPosition(False) transition.SetPosition(pos.x, pos.y + SFC_WIRE_MIN_SIZE) transition_connectors = transition.GetConnectors() @@ -384,7 +384,6 @@ self.AddBlock(step) self.Controler.AddCurrentElementEditingStep(id) self.RefreshStepModel(step) - self.Parent.RefreshProjectTree() self.RefreshBuffer() self.RefreshScrollBars() self.Refresh() @@ -439,7 +438,6 @@ self.SelectedElement.SetSelected(False) self.SelectedElement = step self.SelectedElement.SetSelected(True) - self.Parent.RefreshProjectTree() self.RefreshBuffer() self.RefreshScrollBars() self.Refresh() @@ -672,17 +670,28 @@ def AddDivergenceBranch(self, divergence): if isinstance(divergence, SFC_Divergence): - type = divergence.GetType() - if type in [SELECTION_DIVERGENCE, SIMULTANEOUS_DIVERGENCE]: + if self.GetDrawingMode() == FREEDRAWING_MODE: divergence.AddBranch() - divergence_connectors = divergence.GetConnectors() - if type == SELECTION_DIVERGENCE: - transition = self.CreateTransition(divergence_connectors["outputs"][-1]) - transition_connectors = transition.GetConnectors() - previous = transition_connectors["output"] - else: - previous = divergence_connectors["outputs"][-1] - step = self.CreateStep("Step", previous) + else: + type = divergence.GetType() + if type in [SELECTION_DIVERGENCE, SIMULTANEOUS_DIVERGENCE]: + divergence.AddBranch() + divergence_connectors = divergence.GetConnectors() + if type == SELECTION_DIVERGENCE: + transition = self.CreateTransition(divergence_connectors["outputs"][-1]) + transition_connectors = transition.GetConnectors() + previous = transition_connectors["output"] + else: + previous = divergence_connectors["outputs"][-1] + step = self.CreateStep("Step", previous) + self.RefreshBuffer() + self.RefreshScrollBars() + self.Refresh() + + def RemoveDivergenceBranch(self, divergence): + if isinstance(divergence, SFC_Divergence): + if self.GetDrawingMode() == FREEDRAWING_MODE: + divergence.RemoveHandledBranch() self.RefreshBuffer() self.RefreshScrollBars() self.Refresh() @@ -844,8 +853,7 @@ self.DeleteDivergence(next_block) else: self.RefreshDivergenceModel(next_block) - self.Parent.RefreshProjectTree() - + def DeleteDivergence(self, divergence): if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.DeleteDivergence(self, divergence) @@ -940,8 +948,7 @@ if isinstance(next_block, SFC_Divergence): next_block.RefreshPosition() previous_block.RefreshOutputModel(True) - self.Parent.RefreshProjectTree() - + def DeleteJump(self, jump): if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.DeleteJump(self, jump) @@ -976,8 +983,7 @@ self.DeleteDivergence(previous_block) else: previous_block.RefreshModel() - self.Parent.RefreshProjectTree() - + def DeleteActionBlock(self, actionblock): if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.DeleteActionBlock(self, actionblock) @@ -997,8 +1003,7 @@ self.RefreshStepModel(step) step.RefreshOutputPosition() step.RefreshOutputModel(True) - self.Parent.RefreshProjectTree() - + def DeleteWire(self, wire): if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.DeleteWire(self, wire) diff -r b22f661cbcfb -r c798a68c5560 TextViewer.py --- a/TextViewer.py Thu Aug 23 09:50:35 2007 +0200 +++ b/TextViewer.py Mon Aug 27 17:37:50 2007 +0200 @@ -92,7 +92,7 @@ class TextViewer(wx.stc.StyledTextCtrl): def __init__(self, parent, window, controler): - wx.stc.StyledTextCtrl.__init__(self, parent, ID_TEXTVIEWER, style=0) + wx.stc.StyledTextCtrl.__init__(self, parent, ID_TEXTVIEWER, size=wx.Size(0, 0), style=0) self.CmdKeyAssign(ord('+'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMIN) self.CmdKeyAssign(ord('-'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMOUT) @@ -143,7 +143,6 @@ self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE) self.Bind(wx.stc.EVT_STC_STYLENEEDED, self.OnStyleNeeded, id=ID_TEXTVIEWER) - if window and controler : self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_TEXTVIEWER) @@ -230,10 +229,10 @@ self.SetText(new_text) new_cursor_pos = GetCursorPos(old_text, new_text) if new_cursor_pos != None: - self.SetSelection(new_cursor_pos, new_cursor_pos) - self.EnsureCaretVisible() - else: - self.SetSelection(old_cursor_pos, old_cursor_pos) + self.GotoPos(new_cursor_pos) + else: + self.GotoPos(old_cursor_pos) + self.ScrollToColumn(0) self.RefreshJumpList() self.EmptyUndoBuffer() self.DisableEvents = False diff -r b22f661cbcfb -r c798a68c5560 Viewer.py --- a/Viewer.py Thu Aug 23 09:50:35 2007 +0200 +++ b/Viewer.py Mon Aug 27 17:37:50 2007 +0200 @@ -142,7 +142,8 @@ # Create a new Viewer def __init__(self, parent, window, controler): - wx.ScrolledWindow.__init__(self, parent, style=wx.SUNKEN_BORDER | wx.HSCROLL | wx.VSCROLL) + wx.ScrolledWindow.__init__(self, parent, pos=wx.Point(0, 0), size=wx.Size(0, 0), + style=wx.SUNKEN_BORDER | wx.HSCROLL | wx.VSCROLL) self._init_menus() # Adding a rubberband to Viewer self.rubberBand = RubberBand(drawingSurface=self) @@ -384,6 +385,7 @@ elif instance["type"] == "leftPowerRail": leftpowerrail = LD_PowerRail(self, LEFTRAIL, instance["id"], [True for i in range(len(instance["connectors"]))]) leftpowerrail.SetPosition(instance["x"], instance["y"]) + leftpowerrail.SetSize(instance["width"], instance["height"]) self.AddBlock(leftpowerrail) connectors = leftpowerrail.GetConnectors() for i, connector in enumerate(instance["connectors"]): @@ -391,6 +393,7 @@ elif instance["type"] == "rightPowerRail": rightpowerrail = LD_PowerRail(self, RIGHTRAIL, instance["id"], [True for i in range(len(instance["connectors"]))]) rightpowerrail.SetPosition(instance["x"], instance["y"]) + rightpowerrail.SetSize(instance["width"], instance["height"]) self.AddBlock(rightpowerrail) connectors = rightpowerrail.GetConnectors() for i, connector in enumerate(instance["connectors"]): @@ -466,7 +469,7 @@ if connectors["action"]: connectors["action"].SetPosition(wx.Point(*instance["connectors"]["action"]["position"])) elif instance["type"] == "transition": - transition = SFC_Transition(self, instance["condition_type"], instance["condition"], instance["id"]) + transition = SFC_Transition(self, instance["condition_type"], instance["condition"], instance["priority"], instance["id"]) transition.SetPosition(instance["x"], instance["y"]) self.AddBlock(transition) connectors = transition.GetConnectors() @@ -700,47 +703,54 @@ def OnNoModifierMenu(self, event): if self.SelectedElement and self.IsBlock(self.SelectedElement): self.SelectedElement.SetConnectorNegated(False) + self.RefreshBuffer() event.Skip() def OnNegatedMenu(self, event): if self.SelectedElement and self.IsBlock(self.SelectedElement): self.SelectedElement.SetConnectorNegated(True) + self.RefreshBuffer() event.Skip() def OnRisingEdgeMenu(self, event): if self.SelectedElement and self.IsBlock(self.SelectedElement): self.SelectedElement.SetConnectorEdge("rising") + self.RefreshBuffer() event.Skip() def OnFallingEdgeMenu(self, event): if self.SelectedElement and self.IsBlock(self.SelectedElement): self.SelectedElement.SetConnectorEdge("falling") + self.RefreshBuffer() event.Skip() def OnAddSegmentMenu(self, event): - if self.SelectedElement and self.IsBlock(self.SelectedElement): + if self.SelectedElement and self.IsWire(self.SelectedElement): self.SelectedElement.AddSegment() event.Skip() def OnDeleteSegmentMenu(self, event): - if self.SelectedElement and self.IsBlock(self.SelectedElement): + if self.SelectedElement and self.IsWire(self.SelectedElement): self.SelectedElement.DeleteSegment() event.Skip() def OnAddBranchMenu(self, event): if self.SelectedElement and self.IsBlock(self.SelectedElement): self.AddDivergenceBranch(self.SelectedElement) + self.RefreshBuffer() event.Skip() def OnDeleteBranchMenu(self, event): if self.SelectedElement and self.IsBlock(self.SelectedElement): self.RemoveDivergenceBranch(self.SelectedElement) + self.RefreshBuffer() event.Skip() def OnDeleteMenu(self, event): if self.SelectedElement: self.SelectedElement.Delete() self.SelectedElement = None + self.RefreshBuffer() event.Skip() #------------------------------------------------------------------------------- @@ -813,7 +823,11 @@ if self.Mode == MODE_SELECTION: elements = self.SearchElements(self.rubberBand.GetCurrentExtent()) self.rubberBand.OnLeftUp(event, self.GetLogicalDC(), self.Scaling) - if len(elements) > 0: + if len(elements) == 1: + self.SelectedElement = elements[0] + self.SelectedElement.SetSelected(True) + self.Refresh() + elif len(elements) > 1: self.SelectedElement = Graphic_Group(self) self.SelectedElement.SetElements(elements) self.SelectedElement.SetSelected(True) @@ -869,7 +883,8 @@ event.Skip() def OnViewerRightUp(self, event): - pos = event.GetPosition() + dc = self.GetLogicalDC() + pos = event.GetLogicalPosition(dc) element = self.FindElement(pos) if element: if self.SelectedElement and self.SelectedElement != element: @@ -1186,7 +1201,7 @@ if dialog.ShowModal() == wx.ID_OK: id = self.GetNewId() values = dialog.GetValues() - transition = SFC_Transition(self, values["type"], values["value"], id) + transition = SFC_Transition(self, values["type"], values["value"], values["priority"], id) transition.SetPosition(bbox.x, bbox.y) min_width, min_height = transition.GetMinSize() transition.SetSize(max(bbox.width, min_width), max(bbox.height, min_height)) @@ -1397,11 +1412,12 @@ def EditTransitionContent(self, transition): dialog = TransitionContentDialog(self.Parent, self.GetDrawingMode() == FREEDRAWING_MODE) dialog.SetTransitions(self.Controler.GetCurrentElementEditingTransitions()) - dialog.SetValues({"type":transition.GetType(),"value":transition.GetCondition()}) + dialog.SetValues({"type":transition.GetType(),"value":transition.GetCondition(), "priority":transition.GetPriority()}) dialog.SetElementSize(transition.GetSize()) if dialog.ShowModal() == wx.ID_OK: values = dialog.GetValues() transition.SetType(values["type"],values["value"]) + transition.SetPriority(values["priority"]) transition.RefreshModel() self.RefreshBuffer() self.RefreshScrollBars() @@ -1521,6 +1537,7 @@ transitionid = transition.GetId() infos = {} infos["type"] = transition.GetType() + infos["priority"] = transition.GetPriority() infos["condition"] = transition.GetCondition() infos["x"], infos["y"] = transition.GetPosition() infos["width"], infos["height"] = transition.GetSize() @@ -1710,6 +1727,7 @@ #------------------------------------------------------------------------------- def OnMoveWindow(self, event): + self.GetBestSize() self.RefreshScrollBars() event.Skip() diff -r b22f661cbcfb -r c798a68c5560 examples/example.xml --- a/examples/example.xml Thu Aug 23 09:50:35 2007 +0200 +++ b/examples/example.xml Mon Aug 27 17:37:50 2007 +0200 @@ -118,7 +118,7 @@ - + @@ -174,7 +174,7 @@ - + @@ -245,10 +245,10 @@ - + - + @@ -542,10 +542,10 @@ - + - + @@ -625,7 +625,7 @@ - + @@ -654,10 +654,10 @@ - + - + @@ -670,13 +670,13 @@ - + - + - + @@ -693,7 +693,7 @@ - + @@ -707,11 +707,11 @@ - + - + @@ -736,7 +736,7 @@ - + @@ -765,10 +765,10 @@ - + - + @@ -824,7 +824,7 @@ - + @@ -842,7 +842,7 @@ - + @@ -907,10 +907,10 @@ - + - + @@ -923,7 +923,7 @@ - + diff -r b22f661cbcfb -r c798a68c5560 graphics/GraphicCommons.py --- a/graphics/GraphicCommons.py Thu Aug 23 09:50:35 2007 +0200 +++ b/graphics/GraphicCommons.py Mon Aug 27 17:37:50 2007 +0200 @@ -1543,7 +1543,7 @@ Graphic_Element.OnLeftDown(self, event, dc, scaling) self.oldPos = pos - # Method called when a RightUp event have been generated + # Method called when a RightUp event has been generated def OnRightUp(self, event, dc, scaling): pos = GetScaledEventPosition(event, dc, scaling) # Test if a segment has been handled @@ -1556,14 +1556,14 @@ # Execute the default method for a graphic element Graphic_Element.OnRightUp(self, event, dc, scaling) - # Method called when a LeftDClick event have been generated + # Method called when a LeftDClick event has been generated def OnLeftDClick(self, event, dc, scaling): self.ResetPoints() self.GeneratePoints() self.RefreshModel() self.Parent.RefreshBuffer() - # Method called when a Motion event have been generated + # Method called when a Motion event has been generated def OnMotion(self, event, dc, scaling): pos = GetScaledEventPosition(event, dc, scaling) if not event.Dragging(): diff -r b22f661cbcfb -r c798a68c5560 graphics/LD_Objects.py --- a/graphics/LD_Objects.py Thu Aug 23 09:50:35 2007 +0200 +++ b/graphics/LD_Objects.py Mon Aug 27 17:37:50 2007 +0200 @@ -103,7 +103,7 @@ def InsertConnector(self, idx, connector = True): if connector: if self.Type == LEFTRAIL: - connector = Connector(self, "", "BOOL", wx.Point(2, 0), EAST) + connector = Connector(self, "", "BOOL", wx.Point(self.Size[0], 0), EAST) elif self.Type == RIGHTRAIL: connector = Connector(self, "", "BOOL", wx.Point(0, 0), WEST) self.Connectors.insert(idx, connector) @@ -120,15 +120,19 @@ maxy = 0 for connect in self.Connectors: connect_pos = connect.GetRelPosition() - miny = min(miny, connect_pos.y) - maxy = max(maxy, connect_pos.y) - min_pos = self.Pos.y + miny - self.Extensions[0] + miny = min(miny, connect_pos.y - self.Extensions[0]) + maxy = max(maxy, connect_pos.y - self.Extensions[0]) + min_pos = self.Pos.y + miny self.Pos.y = min(min_pos, self.Pos.y) if min_pos == self.Pos.y: for connect in self.Connectors: connect_pos = connect.GetRelPosition() - connect.SetPosition(wx.Point(connect_pos.x, connect_pos.y - miny + self.Extensions[0])) - self.Size[1] = max(maxy - miny + self.Extensions[0] + self.Extensions[1], self.Size[1]) + connect.SetPosition(wx.Point(connect_pos.x, connect_pos.y - miny)) + maxy = 0 + for connect in self.Connectors: + connect_pos = connect.GetRelPosition() + maxy = max(maxy, connect_pos.y) + self.Size[1] = max(maxy + self.Extensions[1], self.Size[1]) connector.MoveConnected() self.RefreshBoundingBox() @@ -154,13 +158,19 @@ def RefreshConnectors(self): if self.Parent.GetDrawingMode() == FREEDRAWING_MODE: height = self.Size[1] - self.Extensions[0] - self.Extensions[1] + interval = float(height) / float(max(len(self.Connectors) - 1, 1)) for i, connector in enumerate(self.Connectors): position = connector.GetRelPosition() - if self.RealConnectors: - if self.Type == LEFTRAIL: + if self.Type == LEFTRAIL: + if self.RealConnectors: connector.SetPosition(wx.Point(self.Size[0], self.Extensions[0] + int(round(self.RealConnectors[i] * height)))) - elif self.Type == RIGHTRAIL: + else: + connector.SetPosition(wx.Point(self.Size[0], self.Extensions[0] + int(round(i * height)))) + elif self.Type == RIGHTRAIL: + if self.RealConnectors: connector.SetPosition(wx.Point(0, self.Extensions[0] + int(round(self.RealConnectors[i] * height)))) + else: + connector.SetPosition(wx.Point(0, self.Extensions[0] + int(round(i * height)))) else: position = self.Extensions[0] for connector in self.Connectors: @@ -237,7 +247,6 @@ for connector in self.Connectors: position = connector.GetRelPosition() self.RealConnectors.append(float(position.y - self.Extensions[0])/float(max(1, height))) - print self.RealConnectors Graphic_Element.OnLeftDown(self, event, dc, scaling) # Method called when a LeftUp event have been generated @@ -246,13 +255,12 @@ handle_type, handle = self.Handle if handle_type == HANDLE_CONNECTOR: wires = handle.GetWires() - if len(wires) != 1: - return - if handle == wires[0][0].StartConnected: - block = wires[0][0].EndConnected.GetParentBlock() - else: - block = wires[0][0].StartConnected.GetParentBlock() - block.RefreshModel(False) + if len(wires) == 1: + if handle == wires[0][0].StartConnected: + block = wires[0][0].EndConnected.GetParentBlock() + else: + block = wires[0][0].StartConnected.GetParentBlock() + block.RefreshModel(False) Graphic_Element.OnLeftUp(self, event, dc, scaling) # Method called when a LeftDClick event have been generated diff -r b22f661cbcfb -r c798a68c5560 graphics/SFC_Objects.py --- a/graphics/SFC_Objects.py Thu Aug 23 09:50:35 2007 +0200 +++ b/graphics/SFC_Objects.py Mon Aug 27 17:37:50 2007 +0200 @@ -436,15 +436,17 @@ class SFC_Transition(Graphic_Element): # Create a new transition - def __init__(self, parent, type = "reference", condition = None, id = None): + def __init__(self, parent, type = "reference", condition = None, priority = 0, id = None): Graphic_Element.__init__(self, parent) self.Type = None self.Id = id + self.Priority = 0 self.Size = wx.Size(SFC_TRANSITION_SIZE[0], SFC_TRANSITION_SIZE[1]) # Create an input and output connector self.Input = Connector(self, "", "ANY", wx.Point(self.Size[0] / 2, 0), NORTH) self.Output = Connector(self, "", "ANY", wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH) self.SetType(type, condition) + self.SetPriority(priority) # Destructor def __del__(self): @@ -472,6 +474,14 @@ else: self.ConditionSize = dc.GetTextExtent("Transition") + # Refresh the size of text for name + def RefreshPrioritySize(self): + if self.Priority != "": + dc = wx.ClientDC(self.Parent) + self.PrioritySize = dc.GetTextExtent(str(self.Priority)) + else: + self.PrioritySize = None + # Delete this transition by calling the appropriate method def Delete(self): self.Parent.DeleteTransition(self) @@ -486,18 +496,20 @@ # Refresh the transition bounding box def RefreshBoundingBox(self): dc = wx.ClientDC(self.Parent) + bbx_x, bbx_y, bbx_width, bbx_height = self.Pos.x, self.Pos.y, self.Size[0], self.Size[1] + if self.Priority != 0: + bbx_y = self.Pos.y - self.PrioritySize[1] - 2 + bbx_width = max(self.Size[0], self.PrioritySize[0]) + bbx_height = self.Size[1] + self.PrioritySize[1] + 2 if self.Type == "connection": bbx_x = self.Pos.x - CONNECTOR_SIZE - bbx_width = self.Size[0] + CONNECTOR_SIZE - bbx_y = self.Pos.y - bbx_height = self.Size[1] + bbx_width = bbx_width + CONNECTOR_SIZE else: text_width, text_height = self.ConditionSize # Calculate the bounding box size - bbx_x = self.Pos.x - bbx_width = self.Size[0] + 5 + text_width - bbx_y = self.Pos.y - max(0, (text_height - 5 - self.Size[1]) / 2) - bbx_height = max(self.Size[1], text_height) - 5 + bbx_width = max(bbx_width, self.Size[0] + 5 + text_width) + bbx_y = min(bbx_y, self.Pos.y - max(0, (text_height - self.Size[1]) / 2)) + bbx_height = max(bbx_height, self.Pos.y - bbx_y + (self.Size[1] + text_height) / 2) self.BoundingBox = wx.Rect(bbx_x, bbx_y, bbx_width + 1, bbx_height + 1) # Returns the connector connected to input @@ -601,6 +613,16 @@ def GetType(self): return self.Type + # Changes the transition priority + def SetPriority(self, priority): + self.Priority = priority + self.RefreshPrioritySize() + self.RefreshBoundingBox() + + # Returns the transition type + def GetPriority(self): + return self.Priority + # Returns the transition condition def GetCondition(self): if self.Type != "connection": @@ -719,6 +741,10 @@ condition = "Transition" dc.DrawText(condition, self.Pos.x + self.Size[0] + 5, self.Pos.y + (self.Size[1] - text_height) / 2) + # Draw priority number + if self.Priority != 0: + priority_width, priority_height = self.PrioritySize + dc.DrawText(str(self.Priority), self.Pos.x, self.Pos.y - self.PrioritySize[1] - 2) # Draw input and output connectors self.Input.Draw(dc) self.Output.Draw(dc) @@ -815,6 +841,13 @@ self.Inputs.remove(connector) self.MoveConnector(self.Inputs[0], 0) + # Remove the handled branch from the divergence + def RemoveHandledBranch(self): + handle_type, handle = self.Handle + if handle_type == HANDLE_CONNECTOR: + handle.UnConnect(delete=True) + self.RemoveBranch(handle) + # Return the number of branches for the divergence def GetBranchNumber(self): if self.Type in [SELECTION_DIVERGENCE, SIMULTANEOUS_DIVERGENCE]: