Adding support for copying a group of elements
authorlbessard
Fri, 17 Oct 2008 16:22:15 +0200
changeset 283 c4199b88cf60
parent 282 a18ddbbc5c58
child 284 6cf858411d3a
Adding support for copying a group of elements
Viewer.py
graphics/FBD_Objects.py
graphics/GraphicCommons.py
graphics/LD_Objects.py
graphics/SFC_Objects.py
--- a/Viewer.py	Mon Oct 13 16:07:52 2008 +0200
+++ b/Viewer.py	Fri Oct 17 16:22:15 2008 +0200
@@ -444,11 +444,11 @@
         wires = self.Wires.keys()
         comments = self.Comments.keys()
         if sort_blocks:
-            blocks.sort(lambda x,y:self.Blocks[x].__cmp__(self.Blocks[y]))
+            blocks.sort(lambda x, y: cmp(self.Blocks[x], self.Blocks[y]))
         if sort_wires:
-            wires.sort(lambda x,y:self.Wires[x].__cmp__(self.Wires[y]))
+            wires.sort(lambda x, y: cmp(self.Wires[x], self.Wires[y]))
         if sort_comments:
-            comments.sort(lambda x,y:self.Comments[x].__cmp__(self.Comments[y]))
+            comments.sort(lambda x, y: cmp(self.Comments[x], self.Comments[y]))
         return blocks + wires + comments
 
     def RefreshVisibleElements(self, xp = None, yp = None):
@@ -2430,7 +2430,7 @@
 #-------------------------------------------------------------------------------
     
     def Cut(self):
-        if not self.Debug and (self.IsBlock(self.SelectedElement) or self.IsComment(self.SelectedElement)):
+        if not self.Debug and (self.IsBlock(self.SelectedElement) or self.IsComment(self.SelectedElement) or isinstance(self.SelectedElement, Graphic_Group)):
             self.ParentWindow.SetCopyBuffer(self.SelectedElement.Clone(self))
             rect = self.SelectedElement.GetRedrawRect(1, 1)
             self.SelectedElement.Delete()
@@ -2442,12 +2442,12 @@
             self.RefreshRect(self.GetScrolledRect(rect), False)
         
     def Copy(self):
-        if not self.Debug and (self.IsBlock(self.SelectedElement) or self.IsComment(self.SelectedElement)):
+        if not self.Debug and (self.IsBlock(self.SelectedElement) or self.IsComment(self.SelectedElement) or isinstance(self.SelectedElement, Graphic_Group)):
             self.ParentWindow.SetCopyBuffer(self.SelectedElement.Clone(self))
             
     def Paste(self):
         element = self.ParentWindow.GetCopyBuffer()
-        if not self.Debug and element is not None and self.CanAddBlock(element):
+        if not self.Debug and element is not None and self.CanAddElement(element):
             block = self.CopyBlock(element, wx.Point(*self.CalcUnscrolledPosition(30, 30)))
             if self.SelectedElement is not None:
                 self.SelectedElement.SetSelected(False)
@@ -2458,9 +2458,15 @@
             self.RefreshVisibleElements()
             self.ParentWindow.RefreshVariablePanel(self.TagName)
             self.ParentWindow.RefreshInstancesTree()
-
-    def CanAddBlock(self, block):
-        if self.CurrentLanguage == "SFC":
+        else:
+            message = wx.MessageDialog(self, "You can't paste the element in buffer here!", "Error", wx.OK|wx.ICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+
+    def CanAddElement(self, block):
+        if isinstance(block, Graphic_Group):
+            return block.CanAddBlocks(self)
+        elif self.CurrentLanguage == "SFC":
             return True
         elif self.CurrentLanguage == "LD" and not isinstance(block, (SFC_Step, SFC_Transition, SFC_Divergence, SFC_Jump, SFC_ActionBlock)):
             return True
@@ -2468,63 +2474,75 @@
             return True
         return False
 
+    def GenerateNewName(self, element):
+        if isinstance(element, FBD_Block):
+            names = [varname.upper() for varname in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]
+            format = "Block%d"
+        elif isinstance(element, SFC_Step):
+            names = [block.GetName().upper() for block in self.Blocks if isinstance(block, SFC_Step)]
+            format = "Step%d"
+        i = 1
+        while (format%i).upper() in names:
+            i += 1
+        return format%i
+
+    def IsNamedElement(self, element):
+        return isinstance(element, FBD_Block) and element.GetName() != "" or isinstance(element, SFC_Step)
+
     def CopyBlock(self, element, pos):
         id = self.GetNewId()
-        if isinstance(element, FBD_Block) and element.GetName() != "" or isinstance(element, SFC_Step):
-            if isinstance(element, FBD_Block):
-                names = [varname.upper() for varname in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]
-                format = "Block%d"
-            elif isinstance(element, SFC_Step):
-                names = [block.GetName().upper() for block in self.Blocks if isinstance(block, SFC_Step)]
-                format = "Step%d"
-            i = 1
-            while (format%i).upper() in names:
-                i += 1
-            name = format%i
-            block = element.Clone(self, id, name, pos)
+        if isinstance(element, Graphic_Group):
+            block = element.Clone(self, pos=pos)
         else:
-            name = None
-            block = element.Clone(self, id, pos=pos)
+            if self.IsNamedElement(element):
+                name = self.GenerateNewName(element)
+                block = element.Clone(self, id, name, pos)
+            else:
+                name = None
+                block = element.Clone(self, id, pos=pos)
+            self.AddBlockInModel(block)
+        return block
+    
+    def AddBlockInModel(self, block):
         if isinstance(block, Comment):
             self.AddComment(block)
-            self.Controler.AddEditedElementComment(self.TagName, id)
+            self.Controler.AddEditedElementComment(self.TagName, block.GetId())
             self.RefreshCommentModel(block)
         else:
             self.AddBlock(block)
             if isinstance(block, FBD_Block):
-                self.Controler.AddEditedElementBlock(self.TagName, id, block.GetType(), name)
+                self.Controler.AddEditedElementBlock(self.TagName, block.GetId(), block.GetType(), block.GetName())
                 self.RefreshBlockModel(block)
             elif isinstance(block, FBD_Variable):
-                self.Controler.AddEditedElementVariable(self.TagName, id, block.GetType())
+                self.Controler.AddEditedElementVariable(self.TagName, block.GetId(), block.GetType())
                 self.RefreshVariableModel(block)
             elif isinstance(block, FBD_Connector):
-                self.Controler.AddEditedElementConnection(self.TagName, id, block.GetType())
+                self.Controler.AddEditedElementConnection(self.TagName, block.GetId(), block.GetType())
                 self.RefreshConnectionModel(block)
             elif isinstance(block, LD_Contact):
-                self.Controler.AddEditedElementContact(self.TagName, id)
+                self.Controler.AddEditedElementContact(self.TagName, block.GetId())
                 self.RefreshContactModel(block)
             elif isinstance(block, LD_Coil):
-                self.Controler.AddEditedElementCoil(self.TagName, id)
+                self.Controler.AddEditedElementCoil(self.TagName, block.GetId())
                 self.RefreshCoilModel(block)
             elif isinstance(block, LD_PowerRail):
-                self.Controler.AddEditedElementPowerRail(self.TagName, id, block.GetType())
+                self.Controler.AddEditedElementPowerRail(self.TagName, block.GetId(), block.GetType())
                 self.RefreshPowerRailModel(block)
             elif isinstance(block, SFC_Step):
-                self.Controler.AddEditedElementStep(self.TagName, id)
+                self.Controler.AddEditedElementStep(self.TagName, block.GetId())
                 self.RefreshStepModel(block)    
             elif isinstance(block, SFC_Transition):
-                self.Controler.AddEditedElementTransition(self.TagName, id)
+                self.Controler.AddEditedElementTransition(self.TagName, block.GetId())
                 self.RefreshTransitionModel(block)       
             elif isinstance(block, SFC_Divergence):
-                self.Controler.AddEditedElementDivergence(self.TagName, id, block.GetType())
+                self.Controler.AddEditedElementDivergence(self.TagName, block.GetId(), block.GetType())
                 self.RefreshDivergenceModel(block)
             elif isinstance(block, SFC_Jump):
-                self.Controler.AddEditedElementJump(self.TagName, id)
+                self.Controler.AddEditedElementJump(self.TagName, block.GetId())
                 self.RefreshJumpModel(block)       
             elif isinstance(block, SFC_ActionBlock):
-                self.Controler.AddEditedElementActionBlock(self.TagName, id)
+                self.Controler.AddEditedElementActionBlock(self.TagName, block.GetId())
                 self.RefreshActionBlockModel(block)
-        return block
 
 
 #-------------------------------------------------------------------------------
--- a/graphics/FBD_Objects.py	Mon Oct 13 16:07:52 2008 +0200
+++ b/graphics/FBD_Objects.py	Fri Oct 17 16:22:15 2008 +0200
@@ -61,10 +61,15 @@
         block.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
             block.SetPosition(pos.x, pos.y)
+        else:
+            block.SetPosition(self.Pos.x, self.Pos.y)
         block.Inputs = [input.Clone(block) for input in self.Inputs]
         block.Outputs = [output.Clone(block) for output in self.Outputs]
         return block
     
+    def GetConnectorTranslation(self, element):
+        return dict(zip(self.Inputs + self.Outputs, element.Inputs + element.Outputs))
+    
     def Flush(self):
         for input in self.Inputs:
             input.Flush()
@@ -440,12 +445,22 @@
         variable.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
             variable.SetPosition(pos.x, pos.y)
+        else:
+            variable.SetPosition(self.Pos.x, self.Pos.y)
         if self.Input:
             variable.Input = self.Input.Clone(variable)
         if self.Output:
             variable.Output = self.Output.Clone(variable)
         return variable
     
+    def GetConnectorTranslation(self, element):
+        connectors = {}
+        if self.Input is not None:
+            connector[self.Input] = element.Input
+        if self.Output is not None:
+            connectors[self.Output] = element.Output
+        return connectors
+    
     def Flush(self):
         if self.Input is not None:
             self.Input.Flush()
@@ -706,9 +721,14 @@
         connection.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
             connection.SetPosition(pos.x, pos.y)
+        else:
+            connection.SetPosition(self.Pos.x, self.Pos.y)
         connection.Connector = self.Connector.Clone(connection)
         return connection
     
+    def GetConnectorTranslation(self, element):
+        return {self.Connector : element.Connector}
+
     # Unconnect connector
     def Clean(self):
         if self.Connector:
--- a/graphics/GraphicCommons.py	Mon Oct 13 16:07:52 2008 +0200
+++ b/graphics/GraphicCommons.py	Fri Oct 17 16:22:15 2008 +0200
@@ -323,6 +323,9 @@
     def SpreadCurrent(self):
         pass
     
+    def GetConnectorTranslation(self, element):
+        return {}
+    
     def IsOfType(self, type, reference):
         return self.Parent.IsOfType(type, reference)
     
@@ -674,6 +677,51 @@
     def __del__(self):
         self.Elements = []
     
+    # Make a clone of this element
+    def Clone(self, parent, pos = None):
+        group = Graphic_Group(parent)
+        connectors = {}
+        wires = []
+        if pos is not None:
+            dx, dy = pos.x - self.BoundingBox.x, pos.y - self.BoundingBox.y
+        for element in self.Elements:
+            if isinstance(element, Wire):
+                wires.append(element)
+            else:
+                if pos is not None:
+                    x, y = element.GetPosition()
+                    new_pos = wx.Point(x + dx, y + dy)
+                    newid = parent.GetNewId()
+                    if parent.IsNamedElement(element):
+                        name = parent.GenerateNewName(element)
+                        new_element = element.Clone(parent, newid, name, pos = new_pos)
+                    else:
+                        new_element = element.Clone(parent, newid, pos = new_pos)
+                else:
+                    new_element = element.Clone(parent)
+                connectors.update(element.GetConnectorTranslation(new_element))
+                group.SelectElement(new_element)
+        for element in wires:
+            if pos is not None:
+                new_wire = element.Clone(parent, connectors, dx, dy)
+            else:
+                new_wire = element.Clone(parent, connectors)
+            if new_wire is not None:
+                parent.AddWire(new_wire)
+                group.SelectElement(new_wire)
+        if pos is not None:
+            for element in group.Elements:
+                if not isinstance(element, Wire):
+                    parent.AddBlockInModel(element)
+        return group
+    
+    def CanAddBlocks(self, parent):
+        valid = True
+        for element in self.Elements:
+            if not isinstance(element, Wire):
+                valid &= parent.CanAddElement(element)
+        return valid
+    
     def IsVisible(self):
         for element in self.Elements:
             if element.IsVisible():
@@ -690,16 +738,6 @@
                 if startblock in self.Elements and endblock in self.Elements:
                     self.WireExcluded.append(element)
     
-    # Make a clone of this group
-    def Clone(self, parent):
-        clone = Graphic_Group(parent)
-        elements = []
-        # Makes a clone of all the elements in this group
-        for element in self.Elements:
-            elements.append(element.Clone(parent))
-        clone.SetElements(elements)
-        return clone
-    
     # Returns the RedrawRect
     def GetRedrawRect(self, movex = 0, movey = 0):
         rect = None
@@ -1309,6 +1347,19 @@
                 rect = rect.Union(wx.Rect(x, y, width, height))
         return rect
     
+    def Clone(self, parent, connectors = {}, dx = 0, dy = 0):
+        start_connector = connectors.get(self.StartConnected, None)
+        end_connector = connectors.get(self.EndConnected, None)
+        if start_connector is not None and end_connector is not None:
+            wire = Wire(parent)
+            wire.SetPoints([(point.x + dx, point.y + dy) for point in self.Points])
+            start_connector.Connect((wire, 0), False)
+            end_connector.Connect((wire, -1), False)
+            wire.ConnectStartPoint(start_connector.GetPosition(), start_connector)
+            wire.ConnectEndPoint(end_connector.GetPosition(), end_connector)
+            return wire
+        return None
+    
     # Forbids to change the wire position
     def SetPosition(x, y):
         pass
--- a/graphics/LD_Objects.py	Mon Oct 13 16:07:52 2008 +0200
+++ b/graphics/LD_Objects.py	Fri Oct 17 16:22:15 2008 +0200
@@ -61,6 +61,8 @@
         powerrail.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
             powerrail.SetPosition(pos.x, pos.y)
+        else:
+            powerrail.SetPosition(self.Pos.x, self.Pos.y)
         powerrail.Connectors = []
         for connector in self.Connectors:
             if connector is not None:
@@ -69,6 +71,10 @@
                 powerrail.Connectors.append(None)
         return powerrail
     
+    def GetConnectorTranslation(self, element):
+        return dict(zip([connector for connector in self.Connectors if connector is not None],
+                        [connector for connector in element.Connectors if connector is not None]))
+    
     # Returns the RedrawRect
     def GetRedrawRect(self, movex = 0, movey = 0):
         rect = Graphic_Element.GetRedrawRect(self, movex, movey)
@@ -434,10 +440,15 @@
         contact.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
             contact.SetPosition(pos.x, pos.y)
+        else:
+            contact.SetPosition(self.Pos.x, self.Pos.y)
         contact.Input = self.Input.Clone(contact)
         contact.Output = self.Output.Clone(contact)
         return contact
     
+    def GetConnectorTranslation(self, element):
+        return {self.Input : element.Input, self.Output : element.Output}
+    
     # Returns the RedrawRect
     def GetRedrawRect(self, movex = 0, movey = 0):
         rect = Graphic_Element.GetRedrawRect(self, movex, movey)
@@ -714,10 +725,15 @@
         coil.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
             coil.SetPosition(pos.x, pos.y)
+        else:
+            coil.SetPosition(self.Pos.x, self.Pos.y)
         coil.Input = self.Input.Clone(coil)
         coil.Output = self.Output.Clone(coil)
         return coil
     
+    def GetConnectorTranslation(self, element):
+        return {self.Input : element.Input, self.Output : element.Output}
+    
     # Returns the RedrawRect
     def GetRedrawRect(self, movex = 0, movey = 0):
         rect = Graphic_Element.GetRedrawRect(self, movex, movey)
--- a/graphics/SFC_Objects.py	Mon Oct 13 16:07:52 2008 +0200
+++ b/graphics/SFC_Objects.py	Fri Oct 17 16:22:15 2008 +0200
@@ -101,6 +101,8 @@
         step.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
             step.SetPosition(pos.x, pos.y)
+        else:
+            step.SetPosition(self.Pos.x, self.Pos.y)
         if self.Input:
             step.Input = self.Input.Clone(step)
         if self.Output:
@@ -109,6 +111,16 @@
             step.Action = self.Action.Clone(step)
         return step
     
+    def GetConnectorTranslation(self, element):
+        connectors = {}
+        if self.Input is not None:
+            connector[self.Input] = element.Input
+        if self.Output is not None:
+            connectors[self.Output] = element.Output
+        if self.Action is not None:
+            connectors[self.Action] = element.Action
+        return connectors
+    
     # Returns the RedrawRect
     def GetRedrawRect(self, movex = 0, movey = 0):
         rect = Graphic_Element.GetRedrawRect(self, movex, movey)
@@ -589,12 +601,20 @@
         transition.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
             transition.SetPosition(pos.x, pos.y)
+        else:
+            transition.SetPosition(self.Pos.x, self.Pos.y)
         transition.Input = self.Input.Clone(transition)
         transition.Output = self.Output.Clone(transition)
         if self.Type == "connection":
             transition.Condition = self.Condition.Clone(transition)
         return transition
     
+    def GetConnectorTranslation(self, element):
+        connectors = {self.Input : element.Input, self.Output : element.Output}
+        if self.Type == "connection" and self.Condition is not None:
+            connectors[self.Condition] = element.Condition
+        return connectors
+    
     # Returns the RedrawRect
     def GetRedrawRect(self, movex = 0, movey = 0):
         rect = Graphic_Element.GetRedrawRect(self, movex, movey)
@@ -1023,10 +1043,15 @@
         divergence.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
             divergence.SetPosition(pos.x, pos.y)
+        else:
+            divergence.SetPosition(self.Pos.x, self.Pos.y)
         divergence.Inputs = [input.Clone(divergence) for input in self.Inputs]
         divergence.Outputs = [output.Clone(divergence) for output in self.Outputs]
         return divergence
     
+    def GetConnectorTranslation(self, element):
+        return dict(zip(self.Inputs + self.Outputs, element.Inputs + element.Outputs))
+    
     # Returns the RedrawRect
     def GetRedrawRect(self, movex = 0, movey = 0):
         rect = Graphic_Element.GetRedrawRect(self, movex, movey)
@@ -1453,9 +1478,14 @@
         jump.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
             jump.SetPosition(pos.x, pos.y)
+        else:
+            jump.SetPosition(self.Pos.x, self.Pos.y)
         jump.Input = self.Input.Clone(jump)
         return jump
     
+    def GetConnectorTranslation(self, element):
+        return {self.Input : element.Input}
+    
     # Returns the RedrawRect
     def GetRedrawRect(self, movex = 0, movey = 0):
         rect = Graphic_Element.GetRedrawRect(self, movex, movey)
@@ -1694,10 +1724,15 @@
         action_block.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
             action_block.SetPosition(pos.x, pos.y)
+        else:
+            action_block.SetPosition(self.Pos.x, self.Pos.y)
         action_block.Input = self.Input.Clone(action_block)
         return action_block
     
-        # Returns the RedrawRect
+    def GetConnectorTranslation(self, element):
+        return {self.Input : element.Input}
+    
+    # Returns the RedrawRect
     def GetRedrawRect(self, movex = 0, movey = 0):
         rect = Graphic_Element.GetRedrawRect(self, movex, movey)
         rect = rect.Union(self.Input.GetRedrawRect(movex, movey))