editors/LDViewer.py
branch1.1 Korean release
changeset 968 eee7625de1f7
parent 890 b3cafb73c5e9
child 1081 9789531bc57c
equal deleted inserted replaced
808:6e205c1f05a0 968:eee7625de1f7
       
     1 #!/usr/bin/env python
       
     2 # -*- coding: utf-8 -*-
       
     3 
       
     4 #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
       
     5 #based on the plcopen standard. 
       
     6 #
       
     7 #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
       
     8 #
       
     9 #See COPYING file for copyrights details.
       
    10 #
       
    11 #This library is free software; you can redistribute it and/or
       
    12 #modify it under the terms of the GNU General Public
       
    13 #License as published by the Free Software Foundation; either
       
    14 #version 2.1 of the License, or (at your option) any later version.
       
    15 #
       
    16 #This library is distributed in the hope that it will be useful,
       
    17 #but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    18 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    19 #General Public License for more details.
       
    20 #
       
    21 #You should have received a copy of the GNU General Public
       
    22 #License along with this library; if not, write to the Free Software
       
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    24 
       
    25 import wx
       
    26 import time
       
    27 from types import *
       
    28 
       
    29 from Viewer import *
       
    30 
       
    31 def ExtractNextBlocks(block, block_list):
       
    32     current_list = [block]
       
    33     while len(current_list) > 0:
       
    34         next_list = []
       
    35         for current in current_list:
       
    36             connectors = current.GetConnectors()
       
    37             input_connectors = []
       
    38             if isinstance(current, LD_PowerRail) and current.GetType() == RIGHTRAIL:
       
    39                 input_connectors = connectors
       
    40             else:
       
    41                 if "inputs" in connectors:
       
    42                     input_connectors = connectors["inputs"]
       
    43                 if "input" in connectors:
       
    44                     input_connectors = [connectors["input"]]
       
    45             for connector in input_connectors:
       
    46                 for wire, handle in connector.GetWires():
       
    47                     next = wire.EndConnected.GetParentBlock()
       
    48                     if not isinstance(next, LD_PowerRail) and next not in block_list:
       
    49                         block_list.append(next)
       
    50                         next_list.append(next)
       
    51         current_list = next_list
       
    52     
       
    53 def CalcBranchSize(elements, stops):
       
    54     branch_size = 0
       
    55     stop_list = stops
       
    56     for stop in stops:
       
    57         ExtractNextBlocks(stop, stop_list)
       
    58     element_tree = {}
       
    59     for element in elements:
       
    60         if element not in element_tree:
       
    61             element_tree[element] = {"parents":["start"], "children":[], "weight":None}
       
    62             GenerateTree(element, element_tree, stop_list)
       
    63         elif element_tree[element]:
       
    64             element_tree[element]["parents"].append("start")
       
    65     remove_stops = {"start":[], "stop":[]}
       
    66     for element, values in element_tree.items():
       
    67         if "stop" in values["children"]:
       
    68             removed = []
       
    69             for child in values["children"]:
       
    70                 if child != "stop":
       
    71 ##                    if child in elements:
       
    72 ##                        RemoveElement(child, element_tree)
       
    73 ##                        removed.append(child)
       
    74                     if "start" in element_tree[child]["parents"]:
       
    75                         if element not in remove_stops["stop"]:
       
    76                             remove_stops["stop"].append(element)
       
    77                         if child not in remove_stops["start"]:
       
    78                             remove_stops["start"].append(child)
       
    79             for child in removed:
       
    80                 values["children"].remove(child)
       
    81     for element in remove_stops["start"]:
       
    82         element_tree[element]["parents"].remove("start")
       
    83     for element in remove_stops["stop"]:
       
    84         element_tree[element]["children"].remove("stop")
       
    85     for element, values in element_tree.items():
       
    86         if values and "stop" in values["children"]:
       
    87             CalcWeight(element, element_tree)
       
    88             if values["weight"]:
       
    89                 branch_size += values["weight"]
       
    90             else:
       
    91                 return 1
       
    92     #print branch_size
       
    93     return branch_size
       
    94 
       
    95 def RemoveElement(remove, element_tree):
       
    96     if remove in element_tree and element_tree[remove]:
       
    97         for child in element_tree[remove]["children"]:
       
    98             if child != "stop":
       
    99                 RemoveElement(child, element_tree)
       
   100         element_tree.pop(remove)
       
   101 ##        element_tree[remove] = None
       
   102 
       
   103 def GenerateTree(element, element_tree, stop_list):
       
   104     if element in element_tree:
       
   105         connectors = element.GetConnectors()
       
   106         input_connectors = []
       
   107         if isinstance(element, LD_PowerRail) and element.GetType() == RIGHTRAIL:
       
   108             input_connectors = connectors
       
   109         else:
       
   110             if "inputs" in connectors:
       
   111                 input_connectors = connectors["inputs"]
       
   112             if "input" in connectors:
       
   113                 input_connectors = [connectors["input"]]
       
   114         for connector in input_connectors:
       
   115             for wire, handle in connector.GetWires():
       
   116                 next = wire.EndConnected.GetParentBlock()
       
   117                 if isinstance(next, LD_PowerRail) and next.GetType() == LEFTRAIL or next in stop_list:
       
   118 ##                    for remove in element_tree[element]["children"]:
       
   119 ##                        RemoveElement(remove, element_tree)
       
   120 ##                    element_tree[element]["children"] = ["stop"]
       
   121                     element_tree[element]["children"].append("stop")
       
   122 ##                elif element_tree[element]["children"] == ["stop"]:
       
   123 ##                    element_tree[next] = None
       
   124                 elif next not in element_tree or element_tree[next]:
       
   125                     element_tree[element]["children"].append(next)
       
   126                     if next in element_tree:
       
   127                         element_tree[next]["parents"].append(element)
       
   128                     else:
       
   129                         element_tree[next] = {"parents":[element], "children":[], "weight":None}
       
   130                         GenerateTree(next, element_tree, stop_list)
       
   131 
       
   132 def CalcWeight(element, element_tree):
       
   133     weight = 0
       
   134     parts = None
       
   135     if element in element_tree:
       
   136         for parent in element_tree[element]["parents"]:
       
   137             if parent == "start":
       
   138                 weight += 1
       
   139             elif parent in element_tree:
       
   140                 if not parts:
       
   141                     parts = len(element_tree[parent]["children"])
       
   142                 else:
       
   143                     parts = min(parts, len(element_tree[parent]["children"]))
       
   144                 if not element_tree[parent]["weight"]:
       
   145                     CalcWeight(parent, element_tree)
       
   146                 if element_tree[parent]["weight"]:
       
   147                     weight += element_tree[parent]["weight"]
       
   148                 else:
       
   149                     element_tree[element]["weight"] = None
       
   150                     return
       
   151             else:
       
   152                 element_tree[element]["weight"] = None
       
   153                 return
       
   154         if not parts:
       
   155             parts = 1
       
   156         element_tree[element]["weight"] = max(1, weight / parts)
       
   157 
       
   158 
       
   159 #-------------------------------------------------------------------------------
       
   160 #                     Ladder Diagram Graphic elements Viewer class
       
   161 #-------------------------------------------------------------------------------
       
   162 
       
   163 
       
   164 """
       
   165 Class derived from Viewer class that implements a Viewer of Ladder Diagram
       
   166 """
       
   167 
       
   168 class LD_Viewer(Viewer):
       
   169 
       
   170     def __init__(self, parent, tagname, window, controler, debug = False, instancepath = ""):
       
   171         Viewer.__init__(self, parent, tagname, window, controler, debug, instancepath)
       
   172         self.Rungs = []
       
   173         self.RungComments = []
       
   174         self.CurrentLanguage = "LD"
       
   175 
       
   176 #-------------------------------------------------------------------------------
       
   177 #                          Refresh functions
       
   178 #-------------------------------------------------------------------------------
       
   179 
       
   180     def ResetView(self):
       
   181         self.Rungs = []
       
   182         self.RungComments = []
       
   183         Viewer.ResetView(self)
       
   184 
       
   185     def RefreshView(self, variablepanel=True, selection=None):
       
   186         Viewer.RefreshView(self, variablepanel, selection)
       
   187         wx.CallAfter(self.Refresh)
       
   188         for i, rung in enumerate(self.Rungs):
       
   189             bbox = rung.GetBoundingBox()
       
   190             if i < len(self.RungComments):
       
   191                 if self.RungComments[i]:
       
   192                     pos = self.RungComments[i].GetPosition()
       
   193                     if pos[1] > bbox.y:
       
   194                         self.RungComments.insert(i, None)
       
   195             else:
       
   196                 self.RungComments.insert(i, None)
       
   197     
       
   198     def loadInstance(self, instance, ids, selection):
       
   199         Viewer.loadInstance(self, instance, ids, selection)
       
   200         if self.GetDrawingMode() != FREEDRAWING_MODE:
       
   201             if instance["type"] == "leftPowerRail":
       
   202                 element = self.FindElementById(instance["id"])
       
   203                 rung = Graphic_Group(self)
       
   204                 rung.SelectElement(element)
       
   205                 self.Rungs.append(rung)
       
   206             elif instance["type"] == "rightPowerRail":
       
   207                 rungs = []
       
   208                 for connector in instance["inputs"]:
       
   209                     for link in connector["links"]:
       
   210                         connected = self.FindElementById(link["refLocalId"])
       
   211                         rung = self.FindRung(connected)
       
   212                         if rung not in rungs:
       
   213                             rungs.append(rung)
       
   214                 if len(rungs) > 1:
       
   215                     raise ValueError, _("Ladder element with id %d is on more than one rung.")%instance["id"]
       
   216                 element = self.FindElementById(instance["id"])
       
   217                 element_connectors = element.GetConnectors()
       
   218                 self.Rungs[rungs[0]].SelectElement(element)
       
   219                 for connector in element_connectors["inputs"]:
       
   220                     for wire, num in connector.GetWires():
       
   221                         self.Rungs[rungs[0]].SelectElement(wire)
       
   222                 wx.CallAfter(self.RefreshPosition, element)
       
   223             elif instance["type"] in ["contact", "coil"]:
       
   224                 rungs = []
       
   225                 for link in instance["inputs"][0]["links"]:
       
   226                     connected = self.FindElementById(link["refLocalId"])
       
   227                     rung = self.FindRung(connected)
       
   228                     if rung not in rungs:
       
   229                         rungs.append(rung)
       
   230                 if len(rungs) > 1:
       
   231                     raise ValueError, _("Ladder element with id %d is on more than one rung.")%instance["id"]
       
   232                 element = self.FindElementById(instance["id"])
       
   233                 element_connectors = element.GetConnectors() 
       
   234                 self.Rungs[rungs[0]].SelectElement(element)
       
   235                 for wire, num in element_connectors["inputs"][0].GetWires():
       
   236                     self.Rungs[rungs[0]].SelectElement(wire)
       
   237                 wx.CallAfter(self.RefreshPosition, element)
       
   238             elif instance["type"] == "comment":
       
   239                 element = self.FindElementById(instance["id"])
       
   240                 pos = element.GetPosition()
       
   241                 i = 0
       
   242                 inserted = False
       
   243                 while i < len(self.RungComments) and not inserted: 
       
   244                     ipos = self.RungComments[i].GetPosition()
       
   245                     if pos[1] < ipos[1]:
       
   246                         self.RungComments.insert(i, element)
       
   247                         inserted = True
       
   248                     i += 1
       
   249                 if not inserted:
       
   250                     self.RungComments.append(element)
       
   251             
       
   252 #-------------------------------------------------------------------------------
       
   253 #                          Search Element functions
       
   254 #-------------------------------------------------------------------------------
       
   255 
       
   256     def FindRung(self, element):
       
   257         for i, rung in enumerate(self.Rungs):
       
   258             if rung.IsElementIn(element):
       
   259                 return i
       
   260         return None
       
   261 
       
   262     def FindElement(self, event, exclude_group = False, connectors = True):
       
   263         if self.GetDrawingMode() == FREEDRAWING_MODE:
       
   264             return Viewer.FindElement(self, event, exclude_group, connectors)
       
   265         
       
   266         dc = self.GetLogicalDC()
       
   267         pos = event.GetLogicalPosition(dc)
       
   268         if self.SelectedElement and not isinstance(self.SelectedElement, (Graphic_Group, Wire)):
       
   269             if self.SelectedElement.HitTest(pos, connectors) or self.SelectedElement.TestHandle(pos) != (0, 0):
       
   270                 return self.SelectedElement
       
   271         elements = []
       
   272         for element in self.GetElements(sort_wires=True):
       
   273             if element.HitTest(pos, connectors) or element.TestHandle(event) != (0, 0):
       
   274                 elements.append(element)
       
   275         if len(elements) == 1:
       
   276             return elements[0]
       
   277         elif len(elements) > 1:
       
   278             group = Graphic_Group(self)
       
   279             for element in elements:
       
   280                 if self.IsBlock(element):
       
   281                     return element
       
   282                 group.SelectElement(element)
       
   283             return group
       
   284         return None
       
   285 
       
   286     def SearchElements(self, bbox):
       
   287         if self.GetDrawingMode() == FREEDRAWING_MODE:
       
   288             return Viewer.SearchElements(self, bbox)
       
   289         
       
   290         elements = []
       
   291         for element in self.Blocks.values() + self.Comments.values():
       
   292             if element.IsInSelection(bbox):
       
   293                 elements.append(element)
       
   294         return elements
       
   295 
       
   296 #-------------------------------------------------------------------------------
       
   297 #                          Mouse event functions
       
   298 #-------------------------------------------------------------------------------
       
   299 
       
   300     def OnViewerLeftDown(self, event):
       
   301         if self.GetDrawingMode() == FREEDRAWING_MODE:
       
   302             Viewer.OnViewerLeftDown(self, event)
       
   303         elif self.Mode == MODE_SELECTION:
       
   304             element = self.FindElement(event)
       
   305             if self.SelectedElement:
       
   306                 if not isinstance(self.SelectedElement, Graphic_Group):
       
   307                     if self.SelectedElement != element:
       
   308                         if self.IsWire(self.SelectedElement):
       
   309                             self.SelectedElement.SetSelectedSegment(None)
       
   310                         else:
       
   311                             self.SelectedElement.SetSelected(False)
       
   312                     else:
       
   313                         self.SelectedElement = None
       
   314                 elif element and isinstance(element, Graphic_Group):
       
   315                     if self.SelectedElement.GetElements() != element.GetElements():
       
   316                         for elt in self.SelectedElement.GetElements():
       
   317                             if self.IsWire(elt):
       
   318                                 elt.SetSelectedSegment(None)
       
   319                         self.SelectedElement.SetSelected(False)
       
   320                         self.SelectedElement = None
       
   321                 else:
       
   322                     for elt in self.SelectedElement.GetElements():
       
   323                         if self.IsWire(elt):
       
   324                             elt.SetSelectedSegment(None)
       
   325                     self.SelectedElement.SetSelected(False)
       
   326                     self.SelectedElement = None
       
   327             if element:
       
   328                 self.SelectedElement = element
       
   329                 self.SelectedElement.OnLeftDown(event, self.GetLogicalDC(), self.Scaling)
       
   330                 self.SelectedElement.Refresh()
       
   331             else:
       
   332                 self.rubberBand.Reset()
       
   333                 self.rubberBand.OnLeftDown(event, self.GetLogicalDC(), self.Scaling)
       
   334         event.Skip()
       
   335 
       
   336     def OnViewerLeftUp(self, event):
       
   337         if self.GetDrawingMode() == FREEDRAWING_MODE:
       
   338             Viewer.OnViewerLeftUp(self, event)
       
   339         elif self.rubberBand.IsShown():
       
   340             if self.Mode == MODE_SELECTION:
       
   341                 elements = self.SearchElements(self.rubberBand.GetCurrentExtent())
       
   342                 self.rubberBand.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)
       
   343                 if len(elements) > 0:
       
   344                     self.SelectedElement = Graphic_Group(self)
       
   345                     self.SelectedElement.SetElements(elements)
       
   346                     self.SelectedElement.SetSelected(True)
       
   347         elif self.Mode == MODE_SELECTION and self.SelectedElement:
       
   348             dc = self.GetLogicalDC() 
       
   349             if not isinstance(self.SelectedElement, Graphic_Group):
       
   350                 if self.IsWire(self.SelectedElement):
       
   351                     result = self.SelectedElement.TestSegment(event.GetLogicalPosition(dc), True)
       
   352                     if result and result[1] in [EAST, WEST]:
       
   353                         self.SelectedElement.SetSelectedSegment(result[0])
       
   354                 else:
       
   355                     self.SelectedElement.OnLeftUp(event, dc, self.Scaling)
       
   356             else:
       
   357                 for element in self.SelectedElement.GetElements():
       
   358                     if self.IsWire(element):
       
   359                         result = element.TestSegment(event.GetLogicalPosition(dc), True)
       
   360                         if result and result[1] in [EAST, WEST]:
       
   361                             element.SetSelectedSegment(result[0])
       
   362                     else:
       
   363                         element.OnLeftUp(event, dc, self.Scaling)
       
   364             self.SelectedElement.Refresh()
       
   365             wx.CallAfter(self.SetCurrentCursor, 0)
       
   366         event.Skip()
       
   367 
       
   368     def OnViewerRightUp(self, event):
       
   369         if self.GetDrawingMode() == FREEDRAWING_MODE:
       
   370             Viewer.OnViewerRightUp(self, event)
       
   371         else:
       
   372             element = self.FindElement(event)
       
   373             if element:
       
   374                 if self.SelectedElement and self.SelectedElement != element:
       
   375                     self.SelectedElement.SetSelected(False)
       
   376                 self.SelectedElement = element
       
   377                 if self.IsWire(self.SelectedElement):
       
   378                     self.SelectedElement.SetSelectedSegment(0)
       
   379                 else:
       
   380                     self.SelectedElement.SetSelected(True)
       
   381                     self.SelectedElement.OnRightUp(event, self.GetLogicalDC(), self.Scaling)
       
   382                     self.SelectedElement.Refresh()
       
   383                 wx.CallAfter(self.SetCurrentCursor, 0)
       
   384         event.Skip()
       
   385 
       
   386 #-------------------------------------------------------------------------------
       
   387 #                          Keyboard event functions
       
   388 #-------------------------------------------------------------------------------
       
   389 
       
   390     def OnChar(self, event):
       
   391         if self.GetDrawingMode() == FREEDRAWING_MODE:
       
   392             Viewer.OnChar(self, event)
       
   393         else:
       
   394             xpos, ypos = self.GetScrollPos(wx.HORIZONTAL), self.GetScrollPos(wx.VERTICAL)
       
   395             xmax = self.GetScrollRange(wx.HORIZONTAL) - self.GetScrollThumb(wx.HORIZONTAL)
       
   396             ymax = self.GetScrollRange(wx.VERTICAL) - self.GetScrollThumb(wx.VERTICAL)
       
   397             keycode = event.GetKeyCode()
       
   398             if keycode == wx.WXK_DELETE and self.SelectedElement:
       
   399                 if self.IsBlock(self.SelectedElement):
       
   400                     self.SelectedElement.Delete()
       
   401                 elif self.IsWire(self.SelectedElement):
       
   402                     self.DeleteWire(self.SelectedElement)
       
   403                 elif isinstance(self.SelectedElement, Graphic_Group):
       
   404                     all_wires = True
       
   405                     for element in self.SelectedElement.GetElements():
       
   406                         all_wires &= self.IsWire(element)
       
   407                     if all_wires:
       
   408                         self.DeleteWire(self.SelectedElement)
       
   409                     else:
       
   410                         self.SelectedElement.Delete()
       
   411                 self.RefreshBuffer()
       
   412                 self.RefreshScrollBars()
       
   413                 self.Refresh(False)
       
   414             elif keycode == wx.WXK_LEFT:
       
   415                 if event.ControlDown() and event.ShiftDown():
       
   416                     self.Scroll(0, ypos)
       
   417                 elif event.ControlDown():
       
   418                     self.Scroll(max(0, xpos - 1), ypos)
       
   419             elif keycode == wx.WXK_RIGHT:
       
   420                 if event.ControlDown() and event.ShiftDown():
       
   421                     self.Scroll(xmax, ypos)
       
   422                 elif event.ControlDown():
       
   423                     self.Scroll(min(xpos + 1, xmax), ypos)
       
   424             elif keycode == wx.WXK_UP:
       
   425                 if event.ControlDown() and event.ShiftDown():
       
   426                     self.Scroll(xpos, 0)
       
   427                 elif event.ControlDown():
       
   428                     self.Scroll(xpos, max(0, ypos - 1))
       
   429             elif keycode == wx.WXK_DOWN:
       
   430                 if event.ControlDown() and event.ShiftDown():
       
   431                     self.Scroll(xpos, ymax)
       
   432                 elif event.ControlDown():
       
   433                     self.Scroll(xpos, min(ypos + 1, ymax))
       
   434             else:
       
   435                 event.Skip()
       
   436 
       
   437 #-------------------------------------------------------------------------------
       
   438 #                  Model adding functions from Drop Target
       
   439 #-------------------------------------------------------------------------------
       
   440 
       
   441     def AddVariableBlock(self, x, y, scaling, var_class, var_name, var_type):
       
   442         if var_type == "BOOL":
       
   443             id = self.GetNewId()
       
   444             if var_class == INPUT:
       
   445                 contact = LD_Contact(self, CONTACT_NORMAL, var_name, id)
       
   446                 width, height = contact.GetMinSize()
       
   447                 if scaling is not None:
       
   448                     x = round(float(x) / float(scaling[0])) * scaling[0]
       
   449                     y = round(float(y) / float(scaling[1])) * scaling[1]
       
   450                     width = round(float(width) / float(scaling[0]) + 0.5) * scaling[0]
       
   451                     height = round(float(height) / float(scaling[1]) + 0.5) * scaling[1]
       
   452                 contact.SetPosition(x, y)
       
   453                 contact.SetSize(width, height)
       
   454                 self.AddBlock(contact)
       
   455                 self.Controler.AddEditedElementContact(self.GetTagName(), id)
       
   456                 self.RefreshContactModel(contact)
       
   457             else:
       
   458                 coil = LD_Coil(self, COIL_NORMAL, var_name, id)
       
   459                 width, height = coil.GetMinSize()
       
   460                 if scaling is not None:
       
   461                     x = round(float(x) / float(scaling[0])) * scaling[0]
       
   462                     y = round(float(y) / float(scaling[1])) * scaling[1]
       
   463                     width = round(float(width) / float(scaling[0]) + 0.5) * scaling[0]
       
   464                     height = round(float(height) / float(scaling[1]) + 0.5) * scaling[1]
       
   465                 coil.SetPosition(x, y)
       
   466                 coil.SetSize(width, height)
       
   467                 self.AddBlock(coil)
       
   468                 self.Controler.AddEditedElementCoil(self.GetTagName(), id)
       
   469                 self.RefreshCoilModel(coil)
       
   470             self.RefreshBuffer()
       
   471             self.RefreshScrollBars()
       
   472             self.RefreshVisibleElements()
       
   473             self.Refresh(False)
       
   474         else:
       
   475             Viewer.AddVariableBlock(self, x, y, scaling, var_class, var_name, var_type)
       
   476 
       
   477 #-------------------------------------------------------------------------------
       
   478 #                          Adding element functions
       
   479 #-------------------------------------------------------------------------------
       
   480 
       
   481     def AddLadderRung(self):
       
   482         dialog = LDElementDialog(self.ParentWindow, self.Controler, "coil")
       
   483         dialog.SetPreviewFont(self.GetFont())
       
   484         varlist = []
       
   485         vars = self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)
       
   486         if vars:
       
   487             for var in vars:
       
   488                 if var["Class"] != "Input" and var["Type"] == "BOOL":
       
   489                     varlist.append(var["Name"])
       
   490         returntype = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, self.Debug)
       
   491         if returntype == "BOOL":
       
   492             varlist.append(self.Controler.GetEditedElementName(self.TagName))
       
   493         dialog.SetVariables(varlist)
       
   494         dialog.SetValues({"name":"","type":COIL_NORMAL})
       
   495         if dialog.ShowModal() == wx.ID_OK:
       
   496             values = dialog.GetValues()
       
   497             startx, starty = LD_OFFSET[0], 0
       
   498             if len(self.Rungs) > 0:
       
   499                 bbox = self.Rungs[-1].GetBoundingBox()
       
   500                 starty = bbox.y + bbox.height
       
   501             starty += LD_OFFSET[1]
       
   502             rung = Graphic_Group(self)
       
   503             
       
   504             # Create comment
       
   505             id = self.GetNewId()
       
   506             comment = Comment(self, _("Comment"), id)
       
   507             comment.SetPosition(startx, starty)
       
   508             comment.SetSize(LD_COMMENT_DEFAULTSIZE[0], LD_COMMENT_DEFAULTSIZE[1])
       
   509             self.AddComment(comment)
       
   510             self.RungComments.append(comment)
       
   511             self.Controler.AddEditedElementComment(self.TagName, id)
       
   512             self.RefreshCommentModel(comment)
       
   513             starty += LD_COMMENT_DEFAULTSIZE[1] + LD_OFFSET[1]
       
   514             
       
   515             # Create LeftPowerRail
       
   516             id = self.GetNewId()
       
   517             leftpowerrail = LD_PowerRail(self, LEFTRAIL, id)
       
   518             leftpowerrail.SetPosition(startx, starty)
       
   519             leftpowerrail_connectors = leftpowerrail.GetConnectors()
       
   520             self.AddBlock(leftpowerrail)
       
   521             rung.SelectElement(leftpowerrail)
       
   522             self.Controler.AddEditedElementPowerRail(self.TagName, id, LEFTRAIL)
       
   523             self.RefreshPowerRailModel(leftpowerrail)
       
   524             
       
   525             # Create Coil
       
   526             id = self.GetNewId()
       
   527             coil = LD_Coil(self, values["type"], values["name"], id)
       
   528             coil.SetPosition(startx, starty + (LD_LINE_SIZE - LD_ELEMENT_SIZE[1]) / 2)
       
   529             coil_connectors = coil.GetConnectors()
       
   530             self.AddBlock(coil)
       
   531             rung.SelectElement(coil)
       
   532             self.Controler.AddEditedElementCoil(self.TagName, id)
       
   533             
       
   534             # Create Wire between LeftPowerRail and Coil
       
   535             wire = Wire(self)
       
   536             start_connector = coil_connectors["inputs"][0]
       
   537             end_connector = leftpowerrail_connectors["outputs"][0]
       
   538             start_connector.Connect((wire, 0), False)
       
   539             end_connector.Connect((wire, -1), False)
       
   540             wire.ConnectStartPoint(None, start_connector)
       
   541             wire.ConnectEndPoint(None, end_connector)
       
   542             self.AddWire(wire)
       
   543             rung.SelectElement(wire)
       
   544             
       
   545             # Create RightPowerRail
       
   546             id = self.GetNewId()
       
   547             rightpowerrail = LD_PowerRail(self, RIGHTRAIL, id)
       
   548             rightpowerrail.SetPosition(startx, starty)
       
   549             rightpowerrail_connectors = rightpowerrail.GetConnectors()
       
   550             self.AddBlock(rightpowerrail)
       
   551             rung.SelectElement(rightpowerrail)
       
   552             self.Controler.AddEditedElementPowerRail(self.TagName, id, RIGHTRAIL)
       
   553             
       
   554             # Create Wire between LeftPowerRail and Coil
       
   555             wire = Wire(self)
       
   556             start_connector = rightpowerrail_connectors["inputs"][0]
       
   557             end_connector = coil_connectors["outputs"][0]
       
   558             start_connector.Connect((wire, 0), False)
       
   559             end_connector.Connect((wire, -1), False)
       
   560             wire.ConnectStartPoint(None, start_connector)
       
   561             wire.ConnectEndPoint(None, end_connector)
       
   562             self.AddWire(wire)
       
   563             rung.SelectElement(wire)
       
   564             self.RefreshPosition(coil)
       
   565             self.Rungs.append(rung)
       
   566             self.RefreshBuffer()
       
   567             self.RefreshScrollBars()
       
   568             self.RefreshVisibleElements()
       
   569             self.Refresh(False)
       
   570 
       
   571     def AddLadderContact(self):
       
   572         wires = []
       
   573         if self.IsWire(self.SelectedElement):
       
   574             left_element = self.SelectedElement.EndConnected
       
   575             if not isinstance(left_element.GetParentBlock(), LD_Coil):
       
   576                 wires.append(self.SelectedElement)
       
   577         elif self.SelectedElement and isinstance(self.SelectedElement,Graphic_Group):
       
   578             if False not in [self.IsWire(element) for element in self.SelectedElement.GetElements()]:
       
   579                 for element in self.SelectedElement.GetElements():
       
   580                     wires.append(element)
       
   581         if len(wires) > 0:
       
   582             dialog = LDElementDialog(self.ParentWindow, self.Controler, "contact")
       
   583             dialog.SetPreviewFont(self.GetFont())
       
   584             varlist = []
       
   585             vars = self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)
       
   586             if vars:
       
   587                 for var in vars:
       
   588                     if var["Class"] != "Output" and var["Type"] == "BOOL":
       
   589                         varlist.append(var["Name"])
       
   590             dialog.SetVariables(varlist)
       
   591             dialog.SetValues({"name":"","type":CONTACT_NORMAL})
       
   592             if dialog.ShowModal() == wx.ID_OK:
       
   593                 values = dialog.GetValues()
       
   594                 points = wires[0].GetSelectedSegmentPoints()
       
   595                 id = self.GetNewId()
       
   596                 contact = LD_Contact(self, values["type"], values["name"], id)
       
   597                 contact.SetPosition(0, points[0].y - (LD_ELEMENT_SIZE[1] + 1) / 2)
       
   598                 self.AddBlock(contact)
       
   599                 self.Controler.AddEditedElementContact(self.TagName, id)
       
   600                 rungindex = self.FindRung(wires[0])
       
   601                 rung = self.Rungs[rungindex]
       
   602                 old_bbox = rung.GetBoundingBox()
       
   603                 rung.SelectElement(contact)
       
   604                 connectors = contact.GetConnectors()
       
   605                 left_elements = []
       
   606                 right_elements = []
       
   607                 left_index = []
       
   608                 right_index = []
       
   609                 for wire in wires:
       
   610                     if wire.EndConnected not in left_elements:
       
   611                         left_elements.append(wire.EndConnected)
       
   612                         left_index.append(wire.EndConnected.GetWireIndex(wire))
       
   613                     else:
       
   614                         idx = left_elements.index(wire.EndConnected)
       
   615                         left_index[idx] = min(left_index[idx], wire.EndConnected.GetWireIndex(wire))
       
   616                     if wire.StartConnected not in right_elements:
       
   617                         right_elements.append(wire.StartConnected)
       
   618                         right_index.append(wire.StartConnected.GetWireIndex(wire))
       
   619                     else:
       
   620                         idx = right_elements.index(wire.StartConnected)
       
   621                         right_index[idx] = min(right_index[idx], wire.StartConnected.GetWireIndex(wire))
       
   622                     wire.SetSelectedSegment(None)
       
   623                     wire.Clean()
       
   624                     rung.SelectElement(wire)
       
   625                     self.RemoveWire(wire)
       
   626                 wires = []
       
   627                 right_wires = []
       
   628                 for i, left_element in enumerate(left_elements):
       
   629                     wire = Wire(self)
       
   630                     wires.append(wire)
       
   631                     connectors["inputs"][0].Connect((wire, 0), False)
       
   632                     left_element.InsertConnect(left_index[i], (wire, -1), False)
       
   633                     wire.ConnectStartPoint(None, connectors["inputs"][0])
       
   634                     wire.ConnectEndPoint(None, left_element)
       
   635                 for i, right_element in enumerate(right_elements):
       
   636                     wire = Wire(self)
       
   637                     wires.append(wire)
       
   638                     right_wires.append(wire)
       
   639                     right_element.InsertConnect(right_index[i], (wire, 0), False)
       
   640                     connectors["outputs"][0].Connect((wire, -1), False)
       
   641                     wire.ConnectStartPoint(None, right_element)
       
   642                     wire.ConnectEndPoint(None, connectors["outputs"][0])
       
   643                 right_wires.reverse()
       
   644                 for wire in wires:
       
   645                     self.AddWire(wire)
       
   646                     rung.SelectElement(wire)
       
   647                 self.RefreshPosition(contact)
       
   648                 if len(right_wires) > 1:
       
   649                     group = Graphic_Group(self)
       
   650                     group.SetSelected(False)
       
   651                     for wire in right_wires:
       
   652                         wire.SetSelectedSegment(-1)
       
   653                         group.SelectElement(wire)
       
   654                     self.SelectedElement = group
       
   655                 else:
       
   656                     right_wires[0].SetSelectedSegment(-1)
       
   657                     self.SelectedElement = right_wires[0]
       
   658                 rung.RefreshBoundingBox()
       
   659                 new_bbox = rung.GetBoundingBox()
       
   660                 self.RefreshRungs(new_bbox.height - old_bbox.height, rungindex + 1)
       
   661                 self.RefreshBuffer()
       
   662                 self.RefreshScrollBars()
       
   663                 self.RefreshVisibleElements()
       
   664                 self.Refresh(False)
       
   665         else:
       
   666             message = wx.MessageDialog(self, _("You must select the wire where a contact should be added!"), _("Error"), wx.OK|wx.ICON_ERROR)
       
   667             message.ShowModal()
       
   668             message.Destroy()
       
   669 
       
   670     def AddLadderBranch(self):
       
   671         blocks = []
       
   672         if self.IsBlock(self.SelectedElement):
       
   673             blocks = [self.SelectedElement]
       
   674         elif isinstance(self.SelectedElement, Graphic_Group):
       
   675             elements = self.SelectedElement.GetElements()
       
   676             for element in elements:
       
   677                 blocks.append(element)
       
   678         if len(blocks) > 0:
       
   679             blocks_infos = []
       
   680             left_elements = []
       
   681             left_index = []
       
   682             right_elements = []
       
   683             right_index = []
       
   684             for block in blocks:
       
   685                 connectors = block.GetConnectors()
       
   686                 block_infos = {"lefts":[],"rights":[]}
       
   687                 block_infos.update(connectors)
       
   688                 for connector in block_infos["inputs"]:
       
   689                     for wire, handle in connector.GetWires():
       
   690                         found = False
       
   691                         for infos in blocks_infos:
       
   692                             if wire.EndConnected in infos["outputs"]:
       
   693                                 for left_element in infos["lefts"]:
       
   694                                     if left_element not in block_infos["lefts"]:
       
   695                                         block_infos["lefts"].append(left_element)
       
   696                                 found = True
       
   697                         if not found and wire.EndConnected not in block_infos["lefts"]:
       
   698                             block_infos["lefts"].append(wire.EndConnected)
       
   699                             if wire.EndConnected not in left_elements:
       
   700                                 left_elements.append(wire.EndConnected)
       
   701                                 left_index.append(wire.EndConnected.GetWireIndex(wire))
       
   702                             else:
       
   703                                 index = left_elements.index(wire.EndConnected)
       
   704                                 left_index[index] = max(left_index[index], wire.EndConnected.GetWireIndex(wire))
       
   705                 for connector in block_infos["outputs"]:
       
   706                     for wire, handle in connector.GetWires():
       
   707                         found = False
       
   708                         for infos in blocks_infos:
       
   709                             if wire.StartConnected in infos["inputs"]:
       
   710                                 for right_element in infos["rights"]:
       
   711                                     if right_element not in block_infos["rights"]:
       
   712                                         block_infos["rights"].append(right_element)
       
   713                                 found = True
       
   714                         if not found and wire.StartConnected not in block_infos["rights"]:
       
   715                             block_infos["rights"].append(wire.StartConnected)
       
   716                             if wire.StartConnected not in right_elements:
       
   717                                 right_elements.append(wire.StartConnected)
       
   718                                 right_index.append(wire.StartConnected.GetWireIndex(wire))
       
   719                             else:
       
   720                                 index = right_elements.index(wire.StartConnected)
       
   721                                 right_index[index] = max(right_index[index], wire.StartConnected.GetWireIndex(wire))
       
   722                 for connector in block_infos["inputs"]:
       
   723                     for infos in blocks_infos:
       
   724                         if connector in infos["rights"]:
       
   725                             infos["rights"].remove(connector)
       
   726                             if connector in right_elements:
       
   727                                 index = right_elements.index(connector)
       
   728                                 right_elements.pop(index)
       
   729                                 right_index.pop(index)
       
   730                             for right_element in block_infos["rights"]:
       
   731                                 if right_element not in infos["rights"]:
       
   732                                     infos["rights"].append(right_element)
       
   733                 for connector in block_infos["outputs"]:
       
   734                     for infos in blocks_infos:
       
   735                         if connector in infos["lefts"]:
       
   736                             infos["lefts"].remove(connector)
       
   737                             if connector in left_elements:
       
   738                                 index = left_elements.index(connector)
       
   739                                 left_elements.pop(index)
       
   740                                 left_index.pop(index)
       
   741                             for left_element in block_infos["lefts"]:
       
   742                                 if left_element not in infos["lefts"]:
       
   743                                     infos["lefts"].append(left_element)
       
   744                 blocks_infos.append(block_infos)
       
   745             for infos in blocks_infos:
       
   746                 left_elements = [element for element in infos["lefts"]]
       
   747                 for left_element in left_elements:
       
   748                     if isinstance(left_element.GetParentBlock(), LD_PowerRail):
       
   749                         infos["lefts"].remove(left_element)
       
   750                         if "LD_PowerRail" not in infos["lefts"]:
       
   751                             infos["lefts"].append("LD_PowerRail")
       
   752                 right_elements = [element for element in infos["rights"]]
       
   753                 for right_element in right_elements:
       
   754                     if isinstance(right_element.GetParentBlock(), LD_PowerRail):
       
   755                         infos["rights"].remove(right_element)
       
   756                         if "LD_PowerRail" not in infos["rights"]:
       
   757                             infos["rights"].append("LD_PowerRail")
       
   758                 infos["lefts"].sort()
       
   759                 infos["rights"].sort()
       
   760             lefts = blocks_infos[0]["lefts"]
       
   761             rights = blocks_infos[0]["rights"]
       
   762             good = True
       
   763             for infos in blocks_infos[1:]:
       
   764                 good &= infos["lefts"] == lefts
       
   765                 good &= infos["rights"] == rights
       
   766             if good:
       
   767                 rungindex = self.FindRung(blocks[0])
       
   768                 rung = self.Rungs[rungindex]
       
   769                 old_bbox = rung.GetBoundingBox()
       
   770                 left_powerrail = True
       
   771                 right_powerrail = True
       
   772                 for element in left_elements:
       
   773                     left_powerrail &= isinstance(element.GetParentBlock(), LD_PowerRail)
       
   774                 for element in right_elements:
       
   775                     right_powerrail &= isinstance(element.GetParentBlock(), LD_PowerRail)
       
   776                 if not left_powerrail or not right_powerrail:
       
   777                     wires = []
       
   778                     if left_powerrail:
       
   779                         powerrail = left_elements[0].GetParentBlock()
       
   780                         index = 0
       
   781                         for left_element in left_elements: 
       
   782                             index = max(index, powerrail.GetConnectorIndex(left_element))
       
   783                         powerrail.InsertConnector(index + 1)
       
   784                         powerrail.RefreshModel()
       
   785                         connectors = powerrail.GetConnectors()
       
   786                         right_elements.reverse()
       
   787                         for i, right_element in enumerate(right_elements):
       
   788                             new_wire = Wire(self)
       
   789                             wires.append(new_wire)
       
   790                             right_element.InsertConnect(right_index[i] + 1, (new_wire, 0), False)
       
   791                             connectors["outputs"][index + 1].Connect((new_wire, -1), False)
       
   792                             new_wire.ConnectStartPoint(None, right_element)
       
   793                             new_wire.ConnectEndPoint(None, connectors["outputs"][index + 1])
       
   794                         right_elements.reverse()
       
   795                     elif right_powerrail:
       
   796                         dialog = LDElementDialog(self.ParentWindow, self.Controleur, "coil")
       
   797                         dialog.SetPreviewFont(self.GetFont())
       
   798                         varlist = []
       
   799                         vars = self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)
       
   800                         if vars:
       
   801                             for var in vars:
       
   802                                 if var["Class"] != "Input" and var["Type"] == "BOOL":
       
   803                                     varlist.append(var["Name"])
       
   804                         returntype = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, self.Debug)
       
   805                         if returntype == "BOOL":
       
   806                             varlist.append(self.Controler.GetEditedElementName(self.TagName))
       
   807                         dialog.SetVariables(varlist)
       
   808                         dialog.SetValues({"name":"","type":COIL_NORMAL})
       
   809                         if dialog.ShowModal() == wx.ID_OK:
       
   810                             values = dialog.GetValues()
       
   811                             powerrail = right_elements[0].GetParentBlock()
       
   812                             index = 0
       
   813                             for right_element in right_elements: 
       
   814                                 index = max(index, powerrail.GetConnectorIndex(right_element))
       
   815                             powerrail.InsertConnector(index + 1)
       
   816                             powerrail.RefreshModel()
       
   817                             connectors = powerrail.GetConnectors()
       
   818                             
       
   819                             # Create Coil
       
   820                             id = self.GetNewId()
       
   821                             coil = LD_Coil(self, values["type"], values["name"], id)
       
   822                             pos = blocks[0].GetPosition()
       
   823                             coil.SetPosition(pos[0], pos[1] + LD_LINE_SIZE)
       
   824                             self.AddBlock(coil)
       
   825                             rung.SelectElement(coil)
       
   826                             self.Controler.AddEditedElementCoil(self.TagName, id)
       
   827                             coil_connectors = coil.GetConnectors()
       
   828                             
       
   829                             # Create Wire between LeftPowerRail and Coil
       
   830                             wire = Wire(self)
       
   831                             connectors["inputs"][index + 1].Connect((wire, 0), False)
       
   832                             coil_connectors["outputs"][0].Connect((wire, -1), False)
       
   833                             wire.ConnectStartPoint(None, connectors["inputs"][index + 1])
       
   834                             wire.ConnectEndPoint(None, coil_connectors["outputs"][0])
       
   835                             self.AddWire(wire)
       
   836                             rung.SelectElement(wire)
       
   837                             left_elements.reverse()
       
   838                             
       
   839                             for i, left_element in enumerate(left_elements):
       
   840                                 # Create Wire between LeftPowerRail and Coil
       
   841                                 new_wire = Wire(self)
       
   842                                 wires.append(new_wire)
       
   843                                 coil_connectors["inputs"][0].Connect((new_wire, 0), False)
       
   844                                 left_element.InsertConnect(left_index[i] + 1, (new_wire, -1), False)
       
   845                                 new_wire.ConnectStartPoint(None, coil_connectors["inputs"][0])
       
   846                                 new_wire.ConnectEndPoint(None, left_element)
       
   847                             
       
   848                             self.RefreshPosition(coil)
       
   849                     else:
       
   850                         left_elements.reverse()
       
   851                         right_elements.reverse()
       
   852                         for i, left_element in enumerate(left_elements):
       
   853                             for j, right_element in enumerate(right_elements):
       
   854                                 exist = False
       
   855                                 for wire, handle in right_element.GetWires():
       
   856                                     exist |= wire.EndConnected == left_element
       
   857                                 if not exist:
       
   858                                     new_wire = Wire(self)
       
   859                                     wires.append(new_wire)
       
   860                                     right_element.InsertConnect(right_index[j] + 1, (new_wire, 0), False)
       
   861                                     left_element.InsertConnect(left_index[i] + 1, (new_wire, -1), False)
       
   862                                     new_wire.ConnectStartPoint(None, right_element)
       
   863                                     new_wire.ConnectEndPoint(None, left_element)
       
   864                     wires.reverse()
       
   865                     for wire in wires:
       
   866                         self.AddWire(wire)
       
   867                         rung.SelectElement(wire)
       
   868                     right_elements.reverse()
       
   869                 for block in blocks:
       
   870                     self.RefreshPosition(block)
       
   871                 for right_element in right_elements:
       
   872                     self.RefreshPosition(right_element.GetParentBlock())
       
   873                 self.SelectedElement.RefreshBoundingBox()
       
   874                 rung.RefreshBoundingBox()
       
   875                 new_bbox = rung.GetBoundingBox()
       
   876                 self.RefreshRungs(new_bbox.height - old_bbox.height, rungindex + 1)
       
   877                 self.RefreshBuffer()
       
   878                 self.RefreshScrollBars()
       
   879                 self.RefreshVisibleElements()
       
   880                 self.Refresh(False)
       
   881             else:
       
   882                 message = wx.MessageDialog(self, _("The group of block must be coherent!"), _("Error"), wx.OK|wx.ICON_ERROR)
       
   883                 message.ShowModal()
       
   884                 message.Destroy()
       
   885         else:
       
   886             message = wx.MessageDialog(self, _("You must select the block or group of blocks around which a branch should be added!"), _("Error"), wx.OK|wx.ICON_ERROR)
       
   887             message.ShowModal()
       
   888             message.Destroy()
       
   889 
       
   890     def AddLadderBlock(self):
       
   891         message = wx.MessageDialog(self, _("This option isn't available yet!"), _("Warning"), wx.OK|wx.ICON_EXCLAMATION)
       
   892         message.ShowModal()
       
   893         message.Destroy()
       
   894 
       
   895 #-------------------------------------------------------------------------------
       
   896 #                          Delete element functions
       
   897 #-------------------------------------------------------------------------------
       
   898 
       
   899     def DeleteContact(self, contact):
       
   900         if self.GetDrawingMode() == FREEDRAWING_MODE:
       
   901             Viewer.DeleteContact(self, contact)
       
   902         else:
       
   903             rungindex = self.FindRung(contact)
       
   904             rung = self.Rungs[rungindex]
       
   905             old_bbox = rung.GetBoundingBox()
       
   906             connectors = contact.GetConnectors()
       
   907             input_wires = [wire for wire, handle in connectors["inputs"][0].GetWires()]
       
   908             output_wires = [wire for wire, handle in connectors["outputs"][0].GetWires()]
       
   909             left_elements = [(wire.EndConnected, wire.EndConnected.GetWireIndex(wire)) for wire in input_wires]
       
   910             right_elements = [(wire.StartConnected, wire.StartConnected.GetWireIndex(wire)) for wire in output_wires]
       
   911             for wire in input_wires:
       
   912                 wire.Clean()
       
   913                 rung.SelectElement(wire)
       
   914                 self.RemoveWire(wire)
       
   915             for wire in output_wires:
       
   916                 wire.Clean()
       
   917                 rung.SelectElement(wire)
       
   918                 self.RemoveWire(wire)
       
   919             rung.SelectElement(contact)
       
   920             contact.Clean()
       
   921             left_elements.reverse()
       
   922             right_elements.reverse()
       
   923             powerrail = len(left_elements) == 1 and isinstance(left_elements[0][0].GetParentBlock(), LD_PowerRail)
       
   924             for left_element, left_index in left_elements:
       
   925                 for right_element, right_index in right_elements:
       
   926                     wire_removed = []
       
   927                     for wire, handle in right_element.GetWires():
       
   928                         if wire.EndConnected == left_element:
       
   929                             wire_removed.append(wire)
       
   930                         elif isinstance(wire.EndConnected.GetParentBlock(), LD_PowerRail) and powerrail:
       
   931                             left_powerrail = wire.EndConnected.GetParentBlock()
       
   932                             index = left_powerrail.GetConnectorIndex(wire.EndConnected)
       
   933                             left_powerrail.DeleteConnector(index)
       
   934                             wire_removed.append(wire)
       
   935                     for wire in wire_removed:
       
   936                         wire.Clean()
       
   937                         self.RemoveWire(wire)
       
   938                         rung.SelectElement(wire)
       
   939             wires = []
       
   940             for left_element, left_index in left_elements:
       
   941                 for right_element, right_index in right_elements:
       
   942                     wire = Wire(self)
       
   943                     wires.append(wire)
       
   944                     right_element.InsertConnect(right_index, (wire, 0), False)
       
   945                     left_element.InsertConnect(left_index, (wire, -1), False)
       
   946                     wire.ConnectStartPoint(None, right_element)
       
   947                     wire.ConnectEndPoint(None, left_element)
       
   948             wires.reverse()
       
   949             for wire in wires:
       
   950                 self.AddWire(wire)
       
   951                 rung.SelectElement(wire)
       
   952             right_elements.reverse()
       
   953             for right_element, right_index in right_elements:
       
   954                 self.RefreshPosition(right_element.GetParentBlock())
       
   955             self.RemoveBlock(contact)
       
   956             self.Controler.RemoveEditedElementInstance(self.TagName, contact.GetId())
       
   957             rung.RefreshBoundingBox()
       
   958             new_bbox = rung.GetBoundingBox()
       
   959             self.RefreshRungs(new_bbox.height - old_bbox.height, rungindex + 1)
       
   960             self.SelectedElement = None
       
   961 
       
   962     def RecursiveDeletion(self, element, rung):
       
   963         connectors = element.GetConnectors()
       
   964         input_wires = [wire for wire, handle in connectors["inputs"][0].GetWires()]
       
   965         left_elements = [wire.EndConnected for wire in input_wires]
       
   966         rung.SelectElement(element)
       
   967         element.Clean()
       
   968         for wire in input_wires:
       
   969             wire.Clean()
       
   970             self.RemoveWire(wire)
       
   971             rung.SelectElement(wire)
       
   972         self.RemoveBlock(element)
       
   973         self.Controler.RemoveEditedElementInstance(self.TagName, element.GetId())
       
   974         for left_element in left_elements:
       
   975             block = left_element.GetParentBlock()
       
   976             if len(left_element.GetWires()) == 0:
       
   977                 self.RecursiveDeletion(block, rung)
       
   978             else:
       
   979                 self.RefreshPosition(block)
       
   980 
       
   981     def DeleteCoil(self, coil):
       
   982         if self.GetDrawingMode() == FREEDRAWING_MODE:
       
   983             Viewer.DeleteContact(self, coil)
       
   984         else:
       
   985             rungindex = self.FindRung(coil)
       
   986             rung = self.Rungs[rungindex]
       
   987             old_bbox = rung.GetBoundingBox()
       
   988             nbcoils = 0
       
   989             for element in rung.GetElements():
       
   990                 if isinstance(element, LD_Coil):
       
   991                     nbcoils += 1
       
   992             if nbcoils > 1:
       
   993                 connectors = coil.GetConnectors()
       
   994                 output_wires = [wire for wire, handle in connectors["outputs"][0].GetWires()]
       
   995                 right_elements = [wire.StartConnected for wire in output_wires]
       
   996                 for wire in output_wires:
       
   997                     wire.Clean()
       
   998                     self.Wires.remove(wire)
       
   999                     self.Elements.remove(wire)
       
  1000                     rung.SelectElement(wire)
       
  1001                 for right_element in right_elements:
       
  1002                     right_block = right_element.GetParentBlock()
       
  1003                     if isinstance(right_block, LD_PowerRail):
       
  1004                         if len(right_element.GetWires()) == 0:
       
  1005                             index = right_block.GetConnectorIndex(right_element)
       
  1006                             right_block.DeleteConnector(index)
       
  1007                             powerrail_connectors = right_block.GetConnectors()
       
  1008                             for connector in powerrail_connectors["inputs"]:
       
  1009                                 for wire, handle in connector.GetWires():
       
  1010                                     block = wire.EndConnected.GetParentBlock()
       
  1011                                     endpoint = wire.EndConnected.GetPosition(False)
       
  1012                                     startpoint = connector.GetPosition(False)
       
  1013                                     block.Move(0, startpoint.y - endpoint.y)
       
  1014                                     self.RefreshPosition(block)
       
  1015                 self.RecursiveDeletion(coil, rung)
       
  1016             else:
       
  1017                 for element in rung.GetElements():
       
  1018                     if self.IsWire(element):
       
  1019                         element.Clean()
       
  1020                         self.RemoveWire(element)
       
  1021                 for element in rung.GetElements():
       
  1022                     if self.IsBlock(element):
       
  1023                         self.Controler.RemoveEditedElementInstance(self.TagName, element.GetId())
       
  1024                         self.RemoveBlock(element)
       
  1025                 self.Controler.RemoveEditedElementInstance(self.TagName, self.Comments[rungindex].GetId())
       
  1026                 self.RemoveComment(self.RungComments[rungindex])
       
  1027                 self.RungComments.pop(rungindex)
       
  1028                 self.Rungs.pop(rungindex)
       
  1029                 if rungindex < len(self.Rungs):
       
  1030                     next_bbox = self.Rungs[rungindex].GetBoundingBox()
       
  1031                     self.RefreshRungs(old_bbox.y - next_bbox.y, rungindex)
       
  1032             self.SelectedElement = None
       
  1033 
       
  1034     def DeleteWire(self, wire):
       
  1035         if self.GetDrawingMode() == FREEDRAWING_MODE:
       
  1036             Viewer.DeleteWire(self, wire)
       
  1037         else:
       
  1038             wires = []
       
  1039             left_elements = []
       
  1040             right_elements = []
       
  1041             if self.IsWire(wire):
       
  1042                 wires = [wire]
       
  1043             elif isinstance(wire, Graphic_Group):
       
  1044                 for element in wire.GetElements():
       
  1045                     if self.IsWire(element):
       
  1046                         wires.append(element)
       
  1047                     else:
       
  1048                         wires = []
       
  1049                         break
       
  1050             if len(wires) > 0:
       
  1051                 rungindex = self.FindRung(wires[0])
       
  1052                 rung = self.Rungs[rungindex]
       
  1053                 old_bbox = rung.GetBoundingBox()
       
  1054                 for wire in wires:
       
  1055                     connections = wire.GetSelectedSegmentConnections()
       
  1056                     left_block = wire.EndConnected.GetParentBlock()
       
  1057                     if wire.EndConnected not in left_elements:
       
  1058                         left_elements.append(wire.EndConnected)
       
  1059                     if wire.StartConnected not in right_elements:
       
  1060                         right_elements.append(wire.StartConnected)
       
  1061                     if connections == (False, False) or connections == (False, True) and isinstance(left_block, LD_PowerRail):
       
  1062                         wire.Clean()
       
  1063                         self.RemoveWire(wire)
       
  1064                         rung.SelectElement(wire)
       
  1065                 for left_element in left_elements:
       
  1066                     left_block = left_element.GetParentBlock()
       
  1067                     if isinstance(left_block, LD_PowerRail):
       
  1068                         if len(left_element.GetWires()) == 0:
       
  1069                             index = left_block.GetConnectorIndex(left_element)
       
  1070                             left_block.DeleteConnector(index)
       
  1071                     else:
       
  1072                         connectors = left_block.GetConnectors()
       
  1073                         for connector in connectors["outputs"]:
       
  1074                             for wire, handle in connector.GetWires():
       
  1075                                 self.RefreshPosition(wire.StartConnected.GetParentBlock())
       
  1076                 for right_element in right_elements:
       
  1077                     self.RefreshPosition(right_element.GetParentBlock())
       
  1078                 rung.RefreshBoundingBox()
       
  1079                 new_bbox = rung.GetBoundingBox()
       
  1080                 self.RefreshRungs(new_bbox.height - old_bbox.height, rungindex + 1)
       
  1081                 self.SelectedElement = None
       
  1082 
       
  1083 #-------------------------------------------------------------------------------
       
  1084 #                        Refresh element position functions
       
  1085 #-------------------------------------------------------------------------------
       
  1086 
       
  1087     def RefreshPosition(self, element, recursive=True):
       
  1088         # If element is LeftPowerRail, no need to update position
       
  1089         if isinstance(element, LD_PowerRail) and element.GetType() == LEFTRAIL:
       
  1090             element.RefreshModel()
       
  1091             return
       
  1092         
       
  1093         # Extract max position of the elements connected to input
       
  1094         connectors = element.GetConnectors()
       
  1095         position = element.GetPosition()
       
  1096         maxx = 0
       
  1097         onlyone = []
       
  1098         for connector in connectors["inputs"]:
       
  1099             onlyone.append(len(connector.GetWires()) == 1)
       
  1100             for wire, handle in connector.GetWires():
       
  1101                 onlyone[-1] &= len(wire.EndConnected.GetWires()) == 1
       
  1102                 leftblock = wire.EndConnected.GetParentBlock()
       
  1103                 pos = leftblock.GetPosition()
       
  1104                 size = leftblock.GetSize()
       
  1105                 maxx = max(maxx, pos[0] + size[0])
       
  1106         
       
  1107         # Refresh position of element
       
  1108         if isinstance(element, LD_Coil):
       
  1109             interval = LD_WIRECOIL_SIZE
       
  1110         else:
       
  1111             interval = LD_WIRE_SIZE
       
  1112         if False in onlyone:
       
  1113             interval += LD_WIRE_SIZE
       
  1114         movex = maxx + interval - position[0]
       
  1115         element.Move(movex, 0)
       
  1116         position = element.GetPosition()
       
  1117         
       
  1118         # Extract blocks connected to inputs
       
  1119         blocks = []
       
  1120         for i, connector in enumerate(connectors["inputs"]):
       
  1121             for j, (wire, handle) in enumerate(connector.GetWires()):
       
  1122                 blocks.append(wire.EndConnected.GetParentBlock())
       
  1123         
       
  1124         for i, connector in enumerate(connectors["inputs"]):
       
  1125             startpoint = connector.GetPosition(False)
       
  1126             previous_blocks = []
       
  1127             block_list = []
       
  1128             start_offset = 0
       
  1129             if not onlyone[i]:
       
  1130                 middlepoint = maxx + LD_WIRE_SIZE
       
  1131             for j, (wire, handle) in enumerate(connector.GetWires()):
       
  1132                 block = wire.EndConnected.GetParentBlock()
       
  1133                 if isinstance(element, LD_PowerRail):
       
  1134                     pos = block.GetPosition()
       
  1135                     size = leftblock.GetSize()
       
  1136                     movex = position[0] - LD_WIRE_SIZE - size[0] - pos[0]
       
  1137                     block.Move(movex, 0)
       
  1138                 endpoint = wire.EndConnected.GetPosition(False)
       
  1139                 if j == 0:
       
  1140                     if not onlyone[i] and wire.EndConnected.GetWireIndex(wire) > 0:
       
  1141                         start_offset = endpoint.y - startpoint.y
       
  1142                     offset = start_offset
       
  1143                 else:
       
  1144                     offset = start_offset + LD_LINE_SIZE * CalcBranchSize(previous_blocks, blocks)
       
  1145                 if block in block_list:
       
  1146                     wires = wire.EndConnected.GetWires()
       
  1147                     endmiddlepoint = wires[0][0].StartConnected.GetPosition(False)[0] - LD_WIRE_SIZE
       
  1148                     points = [startpoint, wx.Point(middlepoint, startpoint.y),
       
  1149                               wx.Point(middlepoint, startpoint.y + offset),
       
  1150                               wx.Point(endmiddlepoint, startpoint.y + offset),
       
  1151                               wx.Point(endmiddlepoint, endpoint.y), endpoint]
       
  1152                 else:
       
  1153                     if startpoint.y + offset != endpoint.y:
       
  1154                         if isinstance(element, LD_PowerRail):
       
  1155                             element.MoveConnector(connector, startpoint.y - endpoint.y)
       
  1156                         elif isinstance(block, LD_PowerRail):
       
  1157                             block.MoveConnector(wire.EndConnected, startpoint.y - endpoint.y)
       
  1158                         else:
       
  1159                             block.Move(0, startpoint.y + offset - endpoint.y)
       
  1160                             self.RefreshPosition(block, False)
       
  1161                         endpoint = wire.EndConnected.GetPosition(False)
       
  1162                     if not onlyone[i]:
       
  1163                         points = [startpoint, wx.Point(middlepoint, startpoint.y),
       
  1164                                   wx.Point(middlepoint, endpoint.y), endpoint]
       
  1165                     else:
       
  1166                         points = [startpoint, endpoint]
       
  1167                 wire.SetPoints(points, False)
       
  1168                 previous_blocks.append(block)
       
  1169                 blocks.remove(block)
       
  1170                 ExtractNextBlocks(block, block_list)
       
  1171         
       
  1172         element.RefreshModel(False)
       
  1173         if recursive:
       
  1174             for connector in connectors["outputs"]:
       
  1175                 for wire, handle in connector.GetWires():
       
  1176                     self.RefreshPosition(wire.StartConnected.GetParentBlock())
       
  1177     
       
  1178     def RefreshRungs(self, movey, fromidx):
       
  1179         if movey != 0:
       
  1180             for i in xrange(fromidx, len(self.Rungs)):
       
  1181                 self.RungComments[i].Move(0, movey)
       
  1182                 self.RungComments[i].RefreshModel()
       
  1183                 self.Rungs[i].Move(0, movey)
       
  1184                 for element in self.Rungs[i].GetElements():
       
  1185                     if self.IsBlock(element):
       
  1186                         self.RefreshPosition(element)
       
  1187 
       
  1188 #-------------------------------------------------------------------------------
       
  1189 #                          Edit element content functions
       
  1190 #-------------------------------------------------------------------------------
       
  1191 
       
  1192     def EditPowerRailContent(self, powerrail):
       
  1193         if self.GetDrawingMode() == FREEDRAWING_MODE:
       
  1194             Viewer.EditPowerRailContent(self, powerrail)
       
  1195