copy & paste for POUs
authorb.taylor@willowglen.ca
Fri, 18 Sep 2009 09:41:27 -0600
changeset 428 3b19c34bac04
parent 427 22d16c457d87
child 429 c270d61a671d
copy & paste for POUs
PLCControler.py
PLCOpenEditor.py
--- a/PLCControler.py	Thu Sep 17 14:17:52 2009 -0600
+++ b/PLCControler.py	Fri Sep 18 09:41:27 2009 -0600
@@ -596,6 +596,51 @@
                 self.Project.insertpou(-1, new_pou)
                 self.BufferProject()
     
+    def PastePou(self, pou_type, pou_xml):
+        '''
+        Adds the POU defined by 'pou_xml' to the current project with type 'pou_type'
+        '''
+        try:
+            tree = minidom.parseString(pou_xml)
+            root = tree.childNodes[0]
+        except:
+            return _("Couldn't paste non-POU object.")
+
+        if root.nodeName == "pou":
+            new_pou = plcopen.pous_pou()
+            new_pou.loadXMLTree(root)
+
+            name = new_pou.getname()
+            orig_type = new_pou.getpouType()
+
+            # prevent violations of POU content restrictions:
+            # function blocks cannot be pasted as functions,
+            # programs cannot be pasted as functions or function blocks
+            if orig_type == 'functionBlock' and pou_type == 'function' or \
+            orig_type == 'program' and pou_type in ['function', 'functionBlock']:
+                return _('''%s "%s" can't be pasted as a %s.''') % (orig_type, name, pou_type)
+ 
+            while self.Project.getpou(name):
+                # a POU with that name already exists.
+                # make a new name and test if a POU with that name exists.
+
+                # append an incrementing numeric suffix to the POU name. it
+                # doesn't count up perfectly, but as long as it's unique who cares?
+                if name[-1] >= '0' and name[-1] <= '9':
+                    last_digit = int(name[-1])
+                    name = name[0:-1] + str(last_digit+1)
+                else:
+                    name = name + '1'
+
+            # we've found a name that does not already exist, use it
+            new_pou.setname(name)
+            new_pou.setpouType(pou_type)
+
+            self.Project.insertpou(-1, new_pou)
+            self.BufferProject()
+        else:
+            return _("Couldn't paste non-POU object.")
+
     # Remove a Pou from project
     def ProjectRemovePou(self, pou_name):
         if self.Project is not None:
@@ -1647,6 +1692,9 @@
                 if root.nodeType == tree.ELEMENT_NODE and root.nodeName == "paste":
                     for child in root.childNodes:
                         if child.nodeType == tree.ELEMENT_NODE:
+                            if not child.nodeName in plcopen.ElementNameToClass:
+                                return _("\"%s\" element can't be pasted here!!!")%child.nodeName
+
                             classname = plcopen.ElementNameToClass[child.nodeName]
                             if not self.CheckPasteCompatibility[bodytype](classname):
                                 return _("\"%s\" element can't be pasted here!!!")%child.nodeName
--- a/PLCOpenEditor.py	Thu Sep 17 14:17:52 2009 -0600
+++ b/PLCOpenEditor.py	Fri Sep 18 09:41:27 2009 -0600
@@ -1809,9 +1809,14 @@
                 AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Action"))
                 self.Bind(wx.EVT_MENU, self.GenerateAddActionFunction(name), id=new_id)
                 menu.AppendSeparator()
+
             new_id = wx.NewId()
             AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Create a new POU from"))
             self.Bind(wx.EVT_MENU, self.OnCreatePouFromMenu, id=new_id)
+
+            AppendMenu(menu, help='', id=wx.ID_COPY, kind=wx.ITEM_NORMAL, text=_("Copy"))
+            self.Bind(wx.EVT_MENU, self.OnCopyPou, id=wx.ID_COPY)
+
             pou_type = self.Controler.GetPouType(name, self.Debug)
             if pou_type in ["function", "functionBlock"]:
                 change_menu = wx.Menu(title='')
@@ -1855,9 +1860,17 @@
                 self.PopupMenu(menu)
             elif name in ["Functions", "Function Blocks", "Programs"]:
                 menu = wx.Menu(title='')
+
                 new_id = wx.NewId()
                 AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Pou"))
                 self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction({"Functions" : "function", "Function Blocks" : "functionBlock", "Programs" : "program"}[name]), id=new_id)
+
+                AppendMenu(menu, help='', id=wx.ID_PASTE, kind=wx.ITEM_NORMAL, text=_("Paste"))
+                self.Bind(wx.EVT_MENU, self.OnPastePou, id=wx.ID_PASTE)
+
+                if self.GetCopyBuffer() is None:
+                    menu.Enable(wx.ID_PASTE, False)
+
                 self.PopupMenu(menu)
             elif name == "Configurations":
                 menu = wx.Menu(title='')
@@ -2478,6 +2491,37 @@
                 self.RefreshToolBar()
         event.Skip()
 
+    def OnCopyPou(self, event):
+        selected = self.TypesTree.GetSelection()
+
+        pou_name = self.TypesTree.GetItemText(selected)
+        pou = self.Controler.Project.getpou(pou_name)
+
+        pou_xml = pou.generateXMLText('pou', 0)
+        self.SetCopyBuffer(pou_xml)
+
+    def OnPastePou(self, event):
+        selected = self.TypesTree.GetSelection()
+
+        pou_type = self.TypesTree.GetItemText(selected)
+        pou_type = UNEDITABLE_NAMES_DICT[pou_type] # one of 'Functions', 'Function Blocks' or 'Programs'
+        pou_type = {'Functions': 'function', 'Function Blocks': 'functionBlock', 'Programs': 'program'}[pou_type]
+
+        pou_xml = self.GetCopyBuffer()
+
+        result = self.Controler.PastePou(pou_type, pou_xml)
+
+        if result is not None:
+            message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        else:
+            self.RefreshTitle()
+            self.RefreshEditMenu()
+            self.RefreshTypesTree()
+            self.RefreshLibraryTree()
+            self.RefreshToolBar()
+
 #-------------------------------------------------------------------------------
 #                        Remove Project Elements Functions
 #-------------------------------------------------------------------------------