IDEFrame.py
branch1.1 Korean release
changeset 1280 72a826dfcfbb
parent 1243 e77c95c4c7fc
child 1296 5f8e02717560
--- a/IDEFrame.py	Wed Mar 13 12:34:55 2013 +0900
+++ b/IDEFrame.py	Wed Jul 31 10:45:07 2013 +0900
@@ -22,7 +22,8 @@
 from editors.ResourceEditor import ConfigurationEditor, ResourceEditor
 from editors.DataTypeEditor import DataTypeEditor
 from PLCControler import *
-from controls import CustomTree, LibraryPanel, PouInstanceVariablesPanel, DebugVariablePanel, SearchResultPanel
+from controls import CustomTree, LibraryPanel, PouInstanceVariablesPanel, SearchResultPanel
+from controls.DebugVariablePanel import DebugVariablePanel
 from dialogs import ProjectDialog, PouDialog, PouTransitionDialog, PouActionDialog, FindInPouDialog, SearchInProjectDialog
 from util.BitmapLibrary import GetBitmap
 
@@ -210,15 +211,13 @@
 def GetDeleteElementFunction(remove_function, parent_type=None, check_function=None):
     def DeleteElementFunction(self, selected):
         name = self.ProjectTree.GetItemText(selected)
-        if check_function is None or not check_function(self.Controler, name):
+        if check_function is None or check_function(name):
             if parent_type is not None:
                 item_infos = self.ProjectTree.GetPyData(selected)
                 parent_name = item_infos["tagname"].split("::")[1]
                 remove_function(self.Controler, parent_name, name)
             else:
                 remove_function(self.Controler, name)
-        else:
-            self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!")%name)
     return DeleteElementFunction
 
 if wx.Platform == '__WXMSW__':
@@ -308,8 +307,6 @@
 
 class IDEFrame(wx.Frame):
     
-    Starting = False
-    
     # Compatibility function for wx versions < 2.6
     if wx.VERSION < (2, 6, 0):
         def Bind(self, event, function, id = None):
@@ -457,7 +454,6 @@
               style=wx.DEFAULT_FRAME_STYLE)
         self.SetClientSize(wx.Size(1000, 600))
         self.Bind(wx.EVT_ACTIVATE, self.OnActivated)
-        self.Bind(wx.EVT_SIZE, self.OnResize)
         
         self.TabsImageList = wx.ImageList(31, 16)
         self.TabsImageListIndexes = {}
@@ -526,22 +522,18 @@
         self.ProjectTree = CustomTree(id=ID_PLCOPENEDITORPROJECTTREE,
                   name='ProjectTree', parent=self.ProjectPanel, 
                   pos=wx.Point(0, 0), size=wx.Size(0, 0),
-                  style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_EDIT_LABELS)
+                  style=wx.SUNKEN_BORDER,
+                  agwStyle=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.TR_EDIT_LABELS)
         self.ProjectTree.SetBackgroundBitmap(GetBitmap("custom_tree_background"),
                                              wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM)
         add_menu = wx.Menu()
         self._init_coll_AddMenu_Items(add_menu)
         self.ProjectTree.SetAddMenu(add_menu)
-        if wx.Platform == '__WXMSW__':
-            self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnProjectTreeRightUp,
-                  id=ID_PLCOPENEDITORPROJECTTREE)
-            self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnProjectTreeItemSelected,
-                  id=ID_PLCOPENEDITORPROJECTTREE)
-        else:
-            self.ProjectTree.Bind(wx.EVT_RIGHT_UP, self.OnProjectTreeRightUp)
-            self.ProjectTree.Bind(wx.EVT_LEFT_UP, self.OnProjectTreeLeftUp)
-            self.Bind(wx.EVT_TREE_SEL_CHANGING, self.OnProjectTreeItemChanging,
-                  id=ID_PLCOPENEDITORPROJECTTREE)
+        self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnProjectTreeRightUp,
+              id=ID_PLCOPENEDITORPROJECTTREE)
+        self.ProjectTree.Bind(wx.EVT_LEFT_UP, self.OnProjectTreeLeftUp)
+        self.Bind(wx.EVT_TREE_SEL_CHANGING, self.OnProjectTreeItemChanging,
+              id=ID_PLCOPENEDITORPROJECTTREE)
         self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnProjectTreeBeginDrag,
               id=ID_PLCOPENEDITORPROJECTTREE)
         self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnProjectTreeItemBeginEdit,
@@ -550,6 +542,7 @@
               id=ID_PLCOPENEDITORPROJECTTREE)
         self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnProjectTreeItemActivated,
               id=ID_PLCOPENEDITORPROJECTTREE)
+        self.ProjectTree.Bind(wx.EVT_MOTION, self.OnProjectTreeMotion)
         
         #-----------------------------------------------------------------------
         #        Creating PLCopen Project POU Instance Variables Panel
@@ -677,12 +670,24 @@
         self.CurrentEditorToolBar = []
         self.CurrentMenu = None
         self.SelectedItem = None
+        self.LastToolTipItem = None
         self.SearchParams = None
         self.Highlights = {}
         self.DrawingMode = FREEDRAWING_MODE
         #self.DrawingMode = DRIVENDRAWING_MODE
         self.AuiTabCtrl = []
-        self.DefaultPerspective = None
+        
+        # Save default perspective
+        notebooks = {}
+        for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"),
+                                     (self.BottomNoteBook, "bottomnotebook"),
+                                     (self.RightNoteBook, "rightnotebook")]:
+            notebooks[entry_name] = self.SaveTabLayout(notebook)
+        self.DefaultPerspective = {
+            "perspective": self.AUIManager.SavePerspective(),
+            "notebooks": notebooks,
+        }
+        
         
         # Initialize Printing configuring elements
         self.PrintData = wx.PrintData()
@@ -693,13 +698,11 @@
         self.PageSetupData.SetMarginBottomRight(wx.Point(10, 20))
         
         self.SetRefreshFunctions()
+        self.SetDeleteFunctions()
     
     def __del__(self):
         self.FindDialog.Destroy()
     
-    def ResetStarting(self):
-        self.Starting = False
-    
     def Show(self):
         wx.Frame.Show(self)
         wx.CallAfter(self.RestoreLastState)
@@ -709,59 +712,21 @@
             wx.CallAfter(self._Refresh, TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
         event.Skip()
 
+    def SelectTab(self, tab):
+        for notebook in [self.LeftNoteBook, self.BottomNoteBook, self.RightNoteBook]:
+            idx = notebook.GetPageIndex(tab)
+            if idx != wx.NOT_FOUND and idx != notebook.GetSelection():
+                notebook.SetSelection(idx)
+                return
+
 #-------------------------------------------------------------------------------
 #                Saving and restoring frame organization functions
 #-------------------------------------------------------------------------------
 
-    def OnResize(self, event):
-        if self.Starting:
-            self.RestoreLastLayout()
-        event.Skip()
-    
-    def EnableSaveProjectState(self):
-        return False
-    
-    def GetProjectConfiguration(self):
-        projects = {}
-        try:
-            if self.Config.HasEntry("projects"):
-                projects = cPickle.loads(str(self.Config.Read("projects")))
-        except:
-            pass
-        
-        return projects.get(
-            EncodeFileSystemPath(os.path.realpath(self.Controler.GetFilePath())), {})
-    
-    def SavePageState(self, page):
-        state = page.GetState()
-        if state is not None:
-            if self.Config.HasEntry("projects"):
-                projects = cPickle.loads(str(self.Config.Read("projects")))
-            else:
-                projects = {}
-            
-            project_infos = projects.setdefault(
-                 EncodeFileSystemPath(os.path.realpath(self.Controler.GetFilePath())), {})
-            editors_state = project_infos.setdefault("editors_state", {})
-            
-            if page.IsDebugging():
-                editors_state[page.GetInstancePath()] = state
-            else:
-                editors_state[page.GetTagName()] = state
-            
-            self.Config.Write("projects", cPickle.dumps(projects))
-            self.Config.Flush()
-    
     def GetTabInfos(self, tab):
-        if isinstance(tab, EditorPanel):
-            if tab.IsDebugging():
-                return ("debug", tab.GetInstancePath())
-            else:
-                return ("editor", tab.GetTagName())
-        else:
-            for page_name, (page_ref, page_title) in self.MainTabs.iteritems():
-                if page_ref == tab:
-                    return ("main", page_name)
+        for page_name, (page_ref, page_title) in self.MainTabs.iteritems():
+            if page_ref == tab:
+                return ("main", page_name)
         return None
     
     def SaveTabLayout(self, notebook):
@@ -854,115 +819,19 @@
         if self.Config.HasEntry("framesize"):
             frame_size = cPickle.loads(str(self.Config.Read("framesize")))
         
-        self.Starting = True
         if frame_size is None:
             self.Maximize()
         else:
             self.SetClientSize(frame_size)
-            wx.CallAfter(self.RestoreLastLayout)
-        
-    def RestoreLastLayout(self):
-        notebooks = {}
-        for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"),
-                                     (self.BottomNoteBook, "bottomnotebook"),
-                                     (self.RightNoteBook, "rightnotebook")]:
-            notebooks[entry_name] = self.SaveTabLayout(notebook)
-        self.DefaultPerspective = {
-            "perspective": self.AUIManager.SavePerspective(),
-            "notebooks": notebooks,
-        }
-        
-        try:
-            if self.Config.HasEntry("perspective"):
-                self.AUIManager.LoadPerspective(unicode(self.Config.Read("perspective")))
-        
-            if self.Config.HasEntry("notebooks"):
-                notebooks = cPickle.loads(str(self.Config.Read("notebooks")))
-                
-                for notebook in [self.LeftNoteBook, self.BottomNoteBook, self.RightNoteBook]:
-                    for idx in xrange(notebook.GetPageCount()):
-                        notebook.RemovePage(0)
-                        
-                for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"),
-                                             (self.BottomNoteBook, "bottomnotebook"),
-                                             (self.RightNoteBook, "rightnotebook")]:
-                    self.LoadTabLayout(notebook, notebooks.get(entry_name))
-        except:
-            self.ResetPerspective()
-        
-        if self.EnableSaveProjectState():
-            self.LoadProjectLayout()
-        
-        self._Refresh(EDITORTOOLBAR)
-        
-        if wx.Platform == '__WXMSW__':
-            wx.CallAfter(self.ResetStarting)
-        else:
-            self.ResetStarting()
-        wx.CallAfter(self.RefreshEditor)
-    
+        
     def SaveLastState(self):
         if not self.IsMaximized():
             self.Config.Write("framesize", cPickle.dumps(self.GetClientSize()))
         elif self.Config.HasEntry("framesize"):
             self.Config.DeleteEntry("framesize")
         
-        notebooks = {}
-        for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"),
-                                     (self.BottomNoteBook, "bottomnotebook"),
-                                     (self.RightNoteBook, "rightnotebook")]:
-            notebooks[entry_name] = self.SaveTabLayout(notebook)
-        self.Config.Write("notebooks", cPickle.dumps(notebooks))
-        
-        pane = self.AUIManager.GetPane(self.TabsOpened)
-        if pane.IsMaximized():
-            self.AUIManager.RestorePane(pane)
-        self.Config.Write("perspective", self.AUIManager.SavePerspective())
-        
-        if self.EnableSaveProjectState():
-            self.SaveProjectLayout()
-        
-            for i in xrange(self.TabsOpened.GetPageCount()):
-                self.SavePageState(self.TabsOpened.GetPage(i))
-        
         self.Config.Flush()
 
-    def SaveProjectLayout(self):
-        if self.Controler is not None:
-            tabs = []
-            
-            projects = {}
-            try:
-                 if self.Config.HasEntry("projects"):
-                    projects = cPickle.loads(str(self.Config.Read("projects")))
-            except:
-                pass
-            
-            project_infos = projects.setdefault(
-                 EncodeFileSystemPath(os.path.realpath(self.Controler.GetFilePath())), {})
-            project_infos["tabs"] = self.SaveTabLayout(self.TabsOpened)
-            if self.EnableDebug:
-                project_infos["debug_vars"] = self.DebugVariablePanel.GetDebugVariables()
-                
-            self.Config.Write("projects", cPickle.dumps(projects))
-            self.Config.Flush()
-    
-    def LoadProjectLayout(self):
-        if self.Controler is not None:
-            project = self.GetProjectConfiguration()
-            
-            try:
-                if project.has_key("tabs"):
-                    self.LoadTabLayout(self.TabsOpened, project["tabs"])
-            except:
-                self.DeleteAllPages()
-                
-            if self.EnableDebug:
-                #try:
-                self.DebugVariablePanel.SetDebugVariables(project.get("debug_vars", []))
-                #except:
-                #    self.DebugVariablePanel.ResetView()
-            
 #-------------------------------------------------------------------------------
 #                               General Functions
 #-------------------------------------------------------------------------------
@@ -998,8 +867,6 @@
             window = self.TabsOpened.GetPage(selected)
             
             if window.CheckSaveBeforeClosing():
-                if self.EnableSaveProjectState():
-                    self.SavePageState(window)
                 
                 # Refresh all window elements that have changed
                 wx.CallAfter(self._Refresh, TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
@@ -1010,8 +877,12 @@
                 event.Veto()
         
 
-    def GetCopyBuffer(self):
+    def GetCopyBuffer(self, primary_selection=False):
         data = None
+        if primary_selection and wx.Platform == '__WXMSW__':
+            return data
+        else:
+            wx.TheClipboard.UsePrimarySelection(primary_selection)
         if wx.TheClipboard.Open():
             dataobj = wx.TextDataObject()
             if wx.TheClipboard.GetData(dataobj):
@@ -1019,7 +890,11 @@
             wx.TheClipboard.Close()
         return data
         
-    def SetCopyBuffer(self, text):
+    def SetCopyBuffer(self, text, primary_selection=False):
+        if primary_selection and wx.Platform == '__WXMSW__':
+            return
+        else:
+            wx.TheClipboard.UsePrimarySelection(primary_selection)
         if wx.TheClipboard.Open():
             data = wx.TextDataObject()
             data.SetText(text)
@@ -1317,20 +1192,29 @@
         elif isinstance(control, wx.ComboBox):
             control.SetMark(0, control.GetLastPosition() + 1)
     
-    DeleteFunctions = {
-        ITEM_DATATYPE: GetDeleteElementFunction(PLCControler.ProjectRemoveDataType, check_function=PLCControler.DataTypeIsUsed),
-        ITEM_POU: GetDeleteElementFunction(PLCControler.ProjectRemovePou, check_function=PLCControler.PouIsUsed),
-        ITEM_TRANSITION: GetDeleteElementFunction(PLCControler.ProjectRemovePouTransition, ITEM_POU),
-        ITEM_ACTION: GetDeleteElementFunction(PLCControler.ProjectRemovePouAction, ITEM_POU),
-        ITEM_CONFIGURATION: GetDeleteElementFunction(PLCControler.ProjectRemoveConfiguration),
-        ITEM_RESOURCE: GetDeleteElementFunction(PLCControler.ProjectRemoveConfigurationResource, ITEM_CONFIGURATION)
-    }
+    def SetDeleteFunctions(self):
+        self.DeleteFunctions = {
+            ITEM_DATATYPE: GetDeleteElementFunction(
+                    PLCControler.ProjectRemoveDataType, 
+                    check_function=self.CheckDataTypeIsUsedBeforeDeletion),
+            ITEM_POU: GetDeleteElementFunction(
+                    PLCControler.ProjectRemovePou, 
+                    check_function=self.CheckPouIsUsedBeforeDeletion),
+            ITEM_TRANSITION: GetDeleteElementFunction(
+                    PLCControler.ProjectRemovePouTransition, ITEM_POU),
+            ITEM_ACTION: GetDeleteElementFunction(
+                    PLCControler.ProjectRemovePouAction, ITEM_POU),
+            ITEM_CONFIGURATION: GetDeleteElementFunction(
+                    PLCControler.ProjectRemoveConfiguration),
+            ITEM_RESOURCE: GetDeleteElementFunction(
+                    PLCControler.ProjectRemoveConfigurationResource, ITEM_CONFIGURATION)
+        }
     
     def OnDeleteMenu(self, event):
         window = self.FindFocus()
         if window == self.ProjectTree or window is None:
             selected = self.ProjectTree.GetSelection()
-            if selected.IsOk():
+            if selected is not None and selected.IsOk():
                 function = self.DeleteFunctions.get(self.ProjectTree.GetPyData(selected)["type"], None)
                 if function is not None:
                     function(self, selected)
@@ -1372,7 +1256,7 @@
             result = self.Controler.SearchInProject(criteria)
             self.ClearSearchResults()
             self.SearchResultPanel.SetSearchResults(criteria, result)
-            self.BottomNoteBook.SetSelection(self.BottomNoteBook.GetPageIndex(self.SearchResultPanel))
+            self.SelectTab(self.SearchResultPanel)
             
 #-------------------------------------------------------------------------------
 #                             Display Menu Functions
@@ -1455,33 +1339,31 @@
         notebook.SetSelection(notebook.GetPageIndex(tab))
     
     def OnPouSelectedChanging(self, event):
-        if not self.Starting:
-            selected = self.TabsOpened.GetSelection()
-            if selected >= 0:
-                window = self.TabsOpened.GetPage(selected)
-                if not window.IsDebugging():
-                    window.ResetBuffer()
+        selected = self.TabsOpened.GetSelection()
+        if selected >= 0:
+            window = self.TabsOpened.GetPage(selected)
+            if not window.IsDebugging():
+                window.ResetBuffer()
         event.Skip()
     
     def OnPouSelectedChanged(self, event):
-        if not self.Starting:
-            selected = self.TabsOpened.GetSelection()
-            if selected >= 0:
-                window = self.TabsOpened.GetPage(selected)
-                tagname = window.GetTagName()
-                if not window.IsDebugging():
-                    wx.CallAfter(self.SelectProjectTreeItem, tagname)
-                    wx.CallAfter(self.PouInstanceVariablesPanel.SetPouType, tagname)
-                    window.RefreshView()
-                    self.EnsureTabVisible(self.LibraryPanel)
-                else:
-                    instance_path = window.GetInstancePath()
-                    if tagname == "":
-                        instance_path = instance_path.rsplit(".", 1)[0]
-                        tagname = self.Controler.GetPouInstanceTagName(instance_path, self.EnableDebug)
-                    self.EnsureTabVisible(self.DebugVariablePanel)
-                    wx.CallAfter(self.PouInstanceVariablesPanel.SetPouType, tagname, instance_path)
-            wx.CallAfter(self._Refresh, FILEMENU, EDITMENU, DISPLAYMENU, EDITORTOOLBAR)
+        selected = self.TabsOpened.GetSelection()
+        if selected >= 0:
+            window = self.TabsOpened.GetPage(selected)
+            tagname = window.GetTagName()
+            if not window.IsDebugging():
+                self.SelectProjectTreeItem(tagname)
+                self.PouInstanceVariablesPanel.SetPouType(tagname)
+                window.RefreshView()
+                self.EnsureTabVisible(self.LibraryPanel)
+            else:
+                instance_path = window.GetInstancePath()
+                if tagname == "":
+                    instance_path = instance_path.rsplit(".", 1)[0]
+                    tagname = self.Controler.GetPouInstanceTagName(instance_path, self.EnableDebug)
+                self.EnsureTabVisible(self.DebugVariablePanel)
+                wx.CallAfter(self.PouInstanceVariablesPanel.SetPouType, tagname, instance_path)
+        wx.CallAfter(self._Refresh, FILEMENU, EDITMENU, DISPLAYMENU, EDITORTOOLBAR)
         event.Skip()
         
     def RefreshEditor(self):
@@ -1544,30 +1426,44 @@
 #-------------------------------------------------------------------------------
 
     def RefreshProjectTree(self):
+        # Extract current selected item tagname
+        selected = self.ProjectTree.GetSelection()
+        if selected is not None and selected.IsOk():
+            item_infos = self.ProjectTree.GetPyData(selected)
+            tagname = item_infos.get("tagname", None)
+        else:
+            tagname = None
+        
+        # Refresh treectrl items according to project infos
         infos = self.Controler.GetProjectInfos()
         root = self.ProjectTree.GetRootItem()
-        if not root.IsOk():
+        if root is None or not root.IsOk():
             root = self.ProjectTree.AddRoot(infos["name"])
         self.GenerateProjectTreeBranch(root, infos)
         self.ProjectTree.Expand(root)
-
-    def ResetSelectedItem(self):
-        self.SelectedItem = None
-
-    def GenerateProjectTreeBranch(self, root, infos):
+        
+        # Select new item corresponding to previous selected item
+        if tagname is not None:
+            self.SelectProjectTreeItem(tagname)
+
+    def GenerateProjectTreeBranch(self, root, infos, item_alone=False):
         to_delete = []
         item_name = infos["name"]
         if infos["type"] in ITEMS_UNEDITABLE:
             if len(infos["values"]) == 1:
-                return self.GenerateProjectTreeBranch(root, infos["values"][0])
+                return self.GenerateProjectTreeBranch(root, infos["values"][0], True)
             item_name = _(item_name)
         self.ProjectTree.SetItemText(root, item_name)
         self.ProjectTree.SetPyData(root, infos)
         highlight_colours = self.Highlights.get(infos.get("tagname", None), (wx.WHITE, wx.BLACK))
         self.ProjectTree.SetItemBackgroundColour(root, highlight_colours[0])
         self.ProjectTree.SetItemTextColour(root, highlight_colours[1])
+        self.ProjectTree.SetItemExtraImage(root, None)
         if infos["type"] == ITEM_POU:
-            self.ProjectTree.SetItemImage(root, self.TreeImageDict[self.Controler.GetPouBodyType(infos["name"])])
+            self.ProjectTree.SetItemImage(root, 
+                self.TreeImageDict[self.Controler.GetPouBodyType(infos["name"])])
+            if item_alone:
+                self.ProjectTree.SetItemExtraImage(root, self.Controler.GetPouType(infos["name"]))
         elif infos.has_key("icon") and infos["icon"] is not None:
             icon_name = infos["icon"]
             if not self.TreeImageDict.has_key(icon_name):
@@ -1576,56 +1472,48 @@
         elif self.TreeImageDict.has_key(infos["type"]):
             self.ProjectTree.SetItemImage(root, self.TreeImageDict[infos["type"]])      
         
-        if wx.VERSION >= (2, 6, 0):
-            item, root_cookie = self.ProjectTree.GetFirstChild(root)
-        else:
-            item, root_cookie = self.ProjectTree.GetFirstChild(root, 0)
+        item, root_cookie = self.ProjectTree.GetFirstChild(root)
         for values in infos["values"]:
             if values["type"] not in ITEMS_UNEDITABLE or len(values["values"]) > 0:
-                if not item.IsOk():
+                if item is None or not item.IsOk():
                     item = self.ProjectTree.AppendItem(root, "")
-                    if wx.Platform != '__WXMSW__':
-                        item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
+                    item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
                 self.GenerateProjectTreeBranch(item, values)
                 item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
-        while item.IsOk():
+        while item is not None and item.IsOk():
             to_delete.append(item)
             item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
         for item in to_delete:
             self.ProjectTree.Delete(item)
 
+    TagNamePartsItemTypes = {
+        "D": [ITEM_DATATYPE],
+        "P": [ITEM_POU],
+        "T": [ITEM_POU, ITEM_TRANSITION],
+        "A": [ITEM_POU, ITEM_ACTION],
+        "C": [ITEM_CONFIGURATION],
+        "R": [ITEM_CONFIGURATION, ITEM_RESOURCE]}
+
     def SelectProjectTreeItem(self, tagname):
+        result = False
         if self.ProjectTree is not None:
             root = self.ProjectTree.GetRootItem()
-            if root.IsOk():
+            if root is not None and root.IsOk():
                 words = tagname.split("::")
-                if words[0] == "D":
-                    return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_DATATYPE)])
-                elif words[0] == "P":
-                    return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU)])
-                elif words[0] == "T":
-                    return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_TRANSITION)])
-                elif words[0] == "A":
-                    return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_ACTION)])
-                elif words[0] == "C":
-                    return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION)])
-                elif words[0] == "R":
-                    return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION), (words[2], ITEM_RESOURCE)])
-        return False
+                result = self.RecursiveProjectTreeItemSelection(root,
+                    zip(words[1:], self.TagNamePartsItemTypes.get(words[0], [])))
+        return result
 
     def RecursiveProjectTreeItemSelection(self, root, items):
         found = False
-        if wx.VERSION >= (2, 6, 0):
-            item, root_cookie = self.ProjectTree.GetFirstChild(root)
-        else:
-            item, root_cookie = self.ProjectTree.GetFirstChild(root, 0)
-        while item.IsOk() and not found:
+        item, root_cookie = self.ProjectTree.GetFirstChild(root)
+        while item is not None and item.IsOk() and not found:
             item_infos = self.ProjectTree.GetPyData(item)
             if (item_infos["name"].split(":")[-1].strip(), item_infos["type"]) == items[0]:
                 if len(items) == 1:
                     self.SelectedItem = item
-                    wx.CallAfter(self.ProjectTree.SelectItem, item)
-                    wx.CallAfter(self.ResetSelectedItem)
+                    self.ProjectTree.SelectItem(item)
+                    self.ResetSelectedItem()
                     return True
                 else:
                     found = self.RecursiveProjectTreeItemSelection(item, items[1:])
@@ -1634,11 +1522,15 @@
             item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
         return found
 
+    def ResetSelectedItem(self):
+        self.SelectedItem = None
+
     def OnProjectTreeBeginDrag(self, event):
-        if wx.Platform == '__WXMSW__':
-            self.SelectedItem = event.GetItem()
-        if self.SelectedItem is not None and self.ProjectTree.GetPyData(self.SelectedItem)["type"] == ITEM_POU:
-            block_name = self.ProjectTree.GetItemText(self.SelectedItem)
+        selected_item = (self.SelectedItem 
+                         if self.SelectedItem is not None
+                         else event.GetItem())
+        if selected_item.IsOk() and self.ProjectTree.GetPyData(selected_item)["type"] == ITEM_POU:
+            block_name = self.ProjectTree.GetItemText(selected_item)
             block_type = self.Controler.GetPouType(block_name)
             if block_type != "program":
                 data = wx.TextDataObject(str((block_name, block_type, "")))
@@ -1682,7 +1574,7 @@
                     if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames() if name != old_name]:
                         message = _("\"%s\" pou already exists!")%new_name
                         abort = True
-                    elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables()]:
+                    elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariableNames()]:
                         messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
                         if messageDialog.ShowModal() == wx.ID_NO:
                             abort = True
@@ -1696,7 +1588,7 @@
                 elif item_infos["type"] == ITEM_TRANSITION:
                     if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
                         message = _("A POU named \"%s\" already exists!")%new_name
-                    elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables(pou_name) if name != old_name]:
+                    elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariableNames(pou_name) if name != old_name]:
                         message = _("A variable with \"%s\" as name already exists in this pou!")%new_name
                     else:
                         words = item_infos["tagname"].split("::")
@@ -1707,7 +1599,7 @@
                 elif item_infos["type"] == ITEM_ACTION:
                     if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
                         message = _("A POU named \"%s\" already exists!")%new_name
-                    elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables(pou_name) if name != old_name]:
+                    elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariableNames(pou_name) if name != old_name]:
                         message = _("A variable with \"%s\" as name already exists in this pou!")%new_name
                     else:
                         words = item_infos["tagname"].split("::")
@@ -1724,7 +1616,7 @@
                         if messageDialog.ShowModal() == wx.ID_NO:
                             abort = True
                         messageDialog.Destroy()
-                    elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables()]:
+                    elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariableNames()]:
                         messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
                         if messageDialog.ShowModal() == wx.ID_NO:
                             abort = True
@@ -1743,7 +1635,7 @@
                         if messageDialog.ShowModal() == wx.ID_NO:
                             abort = True
                         messageDialog.Destroy()
-                    elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables()]:
+                    elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariableNames()]:
                         messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
                         if messageDialog.ShowModal() == wx.ID_NO:
                             abort = True
@@ -1780,23 +1672,52 @@
             event.Skip()
     
     def ProjectTreeItemSelect(self, select_item):
-        name = self.ProjectTree.GetItemText(select_item)
-        item_infos = self.ProjectTree.GetPyData(select_item)
-        if item_infos["type"] in [ITEM_DATATYPE, ITEM_POU,
-                                  ITEM_CONFIGURATION, ITEM_RESOURCE,
-                                  ITEM_TRANSITION, ITEM_ACTION]:
-            self.EditProjectElement(item_infos["type"], item_infos["tagname"], True)
-            self.PouInstanceVariablesPanel.SetPouType(item_infos["tagname"])
+        if select_item is not None and select_item.IsOk():
+            name = self.ProjectTree.GetItemText(select_item)
+            item_infos = self.ProjectTree.GetPyData(select_item)
+            if item_infos["type"] in [ITEM_DATATYPE, ITEM_POU,
+                                      ITEM_CONFIGURATION, ITEM_RESOURCE,
+                                      ITEM_TRANSITION, ITEM_ACTION]:
+                self.EditProjectElement(item_infos["type"], item_infos["tagname"], True)
+                self.PouInstanceVariablesPanel.SetPouType(item_infos["tagname"])
         
     def OnProjectTreeLeftUp(self, event):
         if self.SelectedItem is not None:
             self.ProjectTree.SelectItem(self.SelectedItem)
             self.ProjectTreeItemSelect(self.SelectedItem)
-            wx.CallAfter(self.ResetSelectedItem)
+            self.ResetSelectedItem()
         event.Skip()
     
-    def OnProjectTreeItemSelected(self, event):
-        self.ProjectTreeItemSelect(event.GetItem())
+    def OnProjectTreeMotion(self, event):
+        if not event.Dragging():
+            pt = wx.Point(event.GetX(), event.GetY())
+            item, flags = self.ProjectTree.HitTest(pt)
+            if item is not None and item.IsOk() and flags & wx.TREE_HITTEST_ONITEMLABEL:
+                item_infos = self.ProjectTree.GetPyData(item)
+                if item != self.LastToolTipItem and self.LastToolTipItem is not None:
+                    self.ProjectTree.SetToolTip(None)
+                    self.LastToolTipItem = None
+                if (self.LastToolTipItem != item and 
+                    item_infos["type"] in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]):
+                    bodytype = self.Controler.GetEditedElementBodyType(
+                            item_infos["tagname"])
+                    if item_infos["type"] == ITEM_POU:
+                        block_type = {
+                            "program": _("Program"),
+                            "functionBlock": _("Function Block"),
+                            "function": _("Function")
+                        }[self.Controler.GetPouType(item_infos["name"])]
+                    elif item_infos["type"] == ITEM_TRANSITION:
+                        block_type = "Transition"
+                    else:
+                        block_type = "Action"
+                    self.LastToolTipItem = item
+                    wx.CallAfter(self.ProjectTree.SetToolTipString, 
+                        "%s : %s : %s" % (
+                            block_type, bodytype, item_infos["name"]))
+            elif self.LastToolTipItem is not None:
+                self.ProjectTree.SetToolTip(None)
+                self.LastToolTipItem = None
         event.Skip()
     
     def OnProjectTreeItemChanging(self, event):
@@ -1861,16 +1782,6 @@
                     new_window.SetIcon(GetBitmap("DATATYPE"))
                     self.AddPage(new_window, "")
             if new_window is not None:
-                if self.EnableSaveProjectState():
-                    project_infos = self.GetProjectConfiguration()
-                    if project_infos.has_key("editors_state"):
-                        if new_window.IsDebugging():
-                            state = project_infos["editors_state"].get(new_window.GetInstancePath())
-                        else:
-                            state = project_infos["editors_state"].get(tagname)
-                        if state is not None:
-                            wx.CallAfter(new_window.SetState, state)
-                
                 openedidx = self.IsOpened(tagname)
                 old_selected = self.TabsOpened.GetSelection()
                 if old_selected != openedidx:
@@ -1885,10 +1796,7 @@
             return new_window
     
     def OnProjectTreeRightUp(self, event):
-        if wx.Platform == '__WXMSW__':
-            item = event.GetItem()
-        else:
-            item, flags = self.ProjectTree.HitTest(wx.Point(event.GetX(), event.GetY()))
+        item = event.GetItem()
         self.ProjectTree.SelectItem(item)
         self.ProjectTreeItemSelect(item)
         name = self.ProjectTree.GetItemText(item)
@@ -1931,8 +1839,8 @@
                 menu = wx.Menu(title='')
                 new_id = wx.NewId()
                 AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Transition"))
-                parent = self.ProjectTree.GetItemParent(item)["type"]
-                parent_type = self.ProjectTree.GetPyData(parent)
+                parent = self.ProjectTree.GetItemParent(item)
+                parent_type = self.ProjectTree.GetPyData(parent)["type"]
                 while parent_type != ITEM_POU:
                     parent = self.ProjectTree.GetItemParent(parent)
                     parent_type = self.ProjectTree.GetPyData(parent)["type"]
@@ -1958,11 +1866,15 @@
                 while parent_type not in [ITEM_CONFIGURATION, ITEM_PROJECT]:
                     parent = self.ProjectTree.GetItemParent(parent)
                     parent_type = self.ProjectTree.GetPyData(parent)["type"]
+                parent_name = None
                 if parent_type == ITEM_PROJECT:
-                    parent_name = None
+                    config_names = self.Controler.GetProjectConfigNames()
+                    if len(config_names) > 0:
+                        parent_name = config_names[0]
                 else:
                     parent_name = self.ProjectTree.GetItemText(parent)
-                self.Bind(wx.EVT_MENU, self.GenerateAddResourceFunction(parent_name), id=new_id)
+                if parent_name is not None:
+                    self.Bind(wx.EVT_MENU, self.GenerateAddResourceFunction(parent_name), id=new_id)
             
         else:
             if item_infos["type"] == ITEM_POU:
@@ -2013,6 +1925,8 @@
             self.PopupMenu(menu)
             menu.Destroy()
         
+        self.ResetSelectedItem()
+        
         event.Skip()
 
 
@@ -2073,13 +1987,6 @@
                     icon = GetBitmap("ACTION", bodytype)
         
         if new_window is not None:
-            if self.EnableSaveProjectState():
-                project_infos = self.GetProjectConfiguration()
-                if project_infos.has_key("editors_state"):
-                    state = project_infos["editors_state"].get(instance_path)
-                    if state is not None:
-                        wx.CallAfter(new_window.SetState, state)
-            
             new_window.SetIcon(icon)
             self.AddPage(new_window, "")
             new_window.RefreshView()
@@ -2108,14 +2015,14 @@
                     elif isinstance(editor, GraphicViewer):
                         editor.ResetView(True)
                     else:
-                        editor.RefreshView()
+                        editor.SubscribeAllDataConsumers()
                 elif editor.IsDebugging():
-                    editor.RegisterVariables()
-            self.DebugVariablePanel.UnregisterObsoleteData()
-    
-    def AddDebugVariable(self, iec_path, force=False):
+                    editor.SubscribeAllDataConsumers()
+            self.DebugVariablePanel.SubscribeAllDataConsumers()
+    
+    def AddDebugVariable(self, iec_path, force=False, graph=False):
         if self.EnableDebug:
-            self.DebugVariablePanel.InsertValue(iec_path, force=force)
+            self.DebugVariablePanel.InsertValue(iec_path, force=force, graph=graph)
             self.EnsureTabVisible(self.DebugVariablePanel)
             
 #-------------------------------------------------------------------------------
@@ -2349,7 +2256,7 @@
         def OnAddPouMenu(event):
             dialog = PouDialog(self, pou_type)
             dialog.SetPouNames(self.Controler.GetProjectPouNames())
-            dialog.SetPouElementNames(self.Controler.GetProjectPouVariables())
+            dialog.SetPouElementNames(self.Controler.GetProjectPouVariableNames())
             dialog.SetValues({"pouName": self.Controler.GenerateNewName(None, None, "%s%%d" % pou_type)})
             if dialog.ShowModal() == wx.ID_OK:
                 values = dialog.GetValues()
@@ -2364,7 +2271,7 @@
         def OnAddTransitionMenu(event):
             dialog = PouTransitionDialog(self)
             dialog.SetPouNames(self.Controler.GetProjectPouNames())
-            dialog.SetPouElementNames(self.Controler.GetProjectPouVariables(pou_name))
+            dialog.SetPouElementNames(self.Controler.GetProjectPouVariableNames(pou_name))
             dialog.SetValues({"transitionName": self.Controler.GenerateNewName(None, None, "transition%d")})
             if dialog.ShowModal() == wx.ID_OK: 
                 values = dialog.GetValues()
@@ -2379,7 +2286,7 @@
         def OnAddActionMenu(event):
             dialog = PouActionDialog(self)
             dialog.SetPouNames(self.Controler.GetProjectPouNames())
-            dialog.SetPouElementNames(self.Controler.GetProjectPouVariables(pou_name))
+            dialog.SetPouElementNames(self.Controler.GetProjectPouVariableNames(pou_name))
             dialog.SetValues({"actionName": self.Controler.GenerateNewName(None, None, "action%d")})
             if dialog.ShowModal() == wx.ID_OK:
                 values = dialog.GetValues()
@@ -2437,9 +2344,7 @@
         result = self.Controler.PastePou(pou_type, pou_xml)
 
         if not isinstance(result, TupleType):
-            message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
-            message.ShowModal()
-            message.Destroy()
+            self.ShowErrorMessage(result)
         else:
             self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, LIBRARYTREE)
             self.EditProjectElement(ITEM_POU, result[0])
@@ -2448,20 +2353,39 @@
 #                        Remove Project Elements Functions
 #-------------------------------------------------------------------------------
 
+    def CheckElementIsUsedBeforeDeletion(self, check_function, title, name):
+        if not check_function(name):
+            return True
+        
+        dialog = wx.MessageDialog(self, 
+            _("\"%s\" is used by one or more POUs. Do you wish to continue?") % name, 
+            title, wx.YES_NO|wx.ICON_QUESTION)
+        answer = dialog.ShowModal()
+        dialog.Destroy()
+        return answer == wx.ID_YES
+
+    def CheckDataTypeIsUsedBeforeDeletion(self, name):
+        return self.CheckElementIsUsedBeforeDeletion(
+            self.Controler.DataTypeIsUsed,
+            _("Remove Datatype"), name)
+    
+    def CheckPouIsUsedBeforeDeletion(self, name):
+        return self.CheckElementIsUsedBeforeDeletion(
+            self.Controler.PouIsUsed,
+            _("Remove Pou"), name)
+    
     def OnRemoveDataTypeMenu(self, event):
         selected = self.ProjectTree.GetSelection()
         if self.ProjectTree.GetPyData(selected)["type"] == ITEM_DATATYPE:
             name = self.ProjectTree.GetItemText(selected)
-            if not self.Controler.DataTypeIsUsed(name):
+            if self.CheckDataTypeIsUsedBeforeDeletion(name):
                 self.Controler.ProjectRemoveDataType(name)
                 tagname = self.Controler.ComputeDataTypeName(name)
                 idx = self.IsOpened(tagname)
                 if idx is not None:
                     self.TabsOpened.DeletePage(idx)
                 self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE)
-            else:
-                self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!"))
-
+            
     def OnRenamePouMenu(self, event):
         selected = self.ProjectTree.GetSelection()
         if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU: 
@@ -2471,15 +2395,13 @@
         selected = self.ProjectTree.GetSelection()
         if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU:
             name = self.ProjectTree.GetItemText(selected)
-            if not self.Controler.PouIsUsed(name):
+            if self.CheckPouIsUsedBeforeDeletion(name):
                 self.Controler.ProjectRemovePou(name)
                 tagname = self.Controler.ComputePouName(name)
                 idx = self.IsOpened(tagname)
                 if idx is not None:
                     self.TabsOpened.DeletePage(idx)
                 self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
-            else:
-                self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!"))
 
     def OnRemoveTransitionMenu(self, event):
         selected = self.ProjectTree.GetSelection()