# HG changeset patch # User laurent # Date 1336064537 -7200 # Node ID 0f10f5091245734306a264aaf25fcf2efba6b4e5 # Parent 0ea836add01f83926e80a3878d08535ea7640472 Adding search field for finding function or function block in library tree diff -r 0ea836add01f -r 0f10f5091245 PLCOpenEditor.py --- a/PLCOpenEditor.py Wed May 02 00:32:15 2012 +0200 +++ b/PLCOpenEditor.py Thu May 03 19:02:17 2012 +0200 @@ -114,7 +114,7 @@ from DataTypeEditor import * from PLCControler import * from SearchResultPanel import SearchResultPanel -from controls import CustomGrid, CustomTable +from controls import CustomGrid, CustomTable, LibraryPanel # Define PLCOpenEditor controls id [ID_PLCOPENEDITOR, ID_PLCOPENEDITORLEFTNOTEBOOK, @@ -122,10 +122,11 @@ ID_PLCOPENEDITORTYPESTREE, ID_PLCOPENEDITORINSTANCESTREE, ID_PLCOPENEDITORMAINSPLITTER, ID_PLCOPENEDITORSECONDSPLITTER, ID_PLCOPENEDITORTHIRDSPLITTER, ID_PLCOPENEDITORLIBRARYPANEL, - ID_PLCOPENEDITORLIBRARYTREE, ID_PLCOPENEDITORLIBRARYCOMMENT, - ID_PLCOPENEDITORTABSOPENED, ID_PLCOPENEDITORTABSOPENED, - ID_PLCOPENEDITOREDITORMENUTOOLBAR, ID_PLCOPENEDITOREDITORTOOLBAR, -] = [wx.NewId() for _init_ctrls in range(16)] + ID_PLCOPENEDITORLIBRARYSEARCHCTRL, ID_PLCOPENEDITORLIBRARYTREE, + ID_PLCOPENEDITORLIBRARYCOMMENT, ID_PLCOPENEDITORTABSOPENED, + ID_PLCOPENEDITORTABSOPENED, ID_PLCOPENEDITOREDITORMENUTOOLBAR, + ID_PLCOPENEDITOREDITORTOOLBAR, +] = [wx.NewId() for _init_ctrls in range(17)] # Define PLCOpenEditor FileMenu extra items id [ID_PLCOPENEDITORFILEMENUGENERATE, @@ -305,7 +306,42 @@ self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!")%name) return DeleteElementFunction +def SimplifyTabOrganization(tabs, rect): + for tab in tabs: + if tab["pos"][0] == rect.x: + others = [t for t in tabs if t != tab] + others.sort(lambda x,y: cmp(x["pos"][0], y["pos"][0])) + for other in others: + if (other["pos"][1] == tab["pos"][1] and + other["size"][1] == tab["size"][1] and + other["pos"][0] == tab["pos"][0] + tab["size"][0] + 7): + + tab["size"] = (tab["size"][0] + other["size"][0] + 7, tab["size"][1]) + tab["pages"].extend(other["pages"]) + tabs.remove(other) + + if tab["size"][0] == rect.width: + return True + + elif tab["pos"][1] == rect.y: + others = [t for t in tabs if t != tab] + others.sort(lambda x,y: cmp(x["pos"][1], y["pos"][1])) + for other in others: + if (other["pos"][0] == tab["pos"][0] and + other["size"][0] == tab["size"][0] and + other["pos"][1] == tab["pos"][1] + tab["size"][1] + 7): + + tab["size"] = (tab["size"][0], tab["size"][1] + other["size"][1] + 7) + tab["pages"].extend(other["pages"]) + tabs.remove(other) + + if tab["size"][1] == rect.height: + return True + return False + def ComputeTabsOrganization(tabs, rect): + if len(tabs) == 0: + return tabs if len(tabs) == 1: return tabs[0] split = None @@ -335,6 +371,9 @@ return {"split": split, "tab": split_tab, "others": ComputeTabsOrganization(tabs, split_rect)} + else: + if SimplifyTabOrganization(tabs, rect): + return ComputeTabsOrganization(tabs, rect) return tabs #------------------------------------------------------------------------------- @@ -469,22 +508,6 @@ self._init_coll_DisplayMenu_Items(self.DisplayMenu) self._init_coll_HelpMenu_Items(self.HelpMenu) - def _init_coll_MainLibrarySizer_Items(self, parent): - parent.AddWindow(self.LibraryTree, 0, border=0, flag=wx.GROW) - parent.AddSizer(self.LibraryComment, 0, border=0, flag=wx.GROW) - - def _init_coll_MainLibrarySizer_Growables(self, parent): - parent.AddGrowableCol(0) - parent.AddGrowableRow(0) - - def _init_sizers(self): - self.MainLibrarySizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) - - self._init_coll_MainLibrarySizer_Growables(self.MainLibrarySizer) - self._init_coll_MainLibrarySizer_Items(self.MainLibrarySizer) - - self.LibraryPanel.SetSizer(self.MainLibrarySizer) - def _init_ctrls(self, prnt): wx.Frame.__init__(self, id=ID_PLCOPENEDITOR, name='IDEFrame', parent=prnt, pos=wx.DefaultPosition, size=wx.Size(1000, 600), @@ -537,10 +560,10 @@ self.TabsOpened = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORTABSOPENED, style=wx.aui.AUI_NB_DEFAULT_STYLE|wx.aui.AUI_NB_WINDOWLIST_BUTTON) - self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGING, - self.OnPouSelectedChanging) - self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, - self.OnPouSelectedChanged) + #self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGING, + # self.OnPouSelectedChanging) + #self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, + # self.OnPouSelectedChanged) self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnPageClose) self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_END_DRAG, @@ -705,31 +728,13 @@ # Creating Library Panel #----------------------------------------------------------------------- - self.LibraryPanel = wx.Panel(id=ID_PLCOPENEDITORLIBRARYPANEL, - name='LibraryPanel', parent=self.RightNoteBook, pos=wx.Point(0, - 0), size=wx.Size(0, 0), style=0) + self.LibraryPanel = LibraryPanel(self, True) self.MainTabs["LibraryPanel"] = (self.LibraryPanel, _("Library")) self.RightNoteBook.AddPage(*self.MainTabs["LibraryPanel"]) - - self.LibraryTree = wx.TreeCtrl(id=ID_PLCOPENEDITORLIBRARYTREE, - name='LibraryTree', parent=self.LibraryPanel, - pos=wx.Point(0, 0), size=wx.Size(0, 0), - style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_HIDE_ROOT|wx.TR_LINES_AT_ROOT) - self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnLibraryTreeItemSelected, - id=ID_PLCOPENEDITORLIBRARYTREE) - self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnLibraryTreeBeginDrag, - id=ID_PLCOPENEDITORLIBRARYTREE) - - self.LibraryComment = wx.TextCtrl(id=ID_PLCOPENEDITORLIBRARYCOMMENT, - name='LibraryComment', parent=self.LibraryPanel, - pos=wx.Point(0, 0), size=wx.Size(0, 160), - style=wx.TE_READONLY|wx.TE_MULTILINE) - + self._init_utils() self.SetMenuBar(self.MenuBar) - - self._init_sizers() - + if self.EnableDebug: self.DebugVariablePanel = DebugVariablePanel(self.RightNoteBook, self.Controler) self.MainTabs["DebugVariablePanel"] = (self.DebugVariablePanel, _("Debugger")) @@ -834,12 +839,14 @@ event.Skip() def GetProjectConfiguration(self): - if self.Config.HasEntry("projects"): - projects = cPickle.loads(str(self.Config.Read("projects"))) - else: - projects = {} - - return projects.setdefault(os.path.realpath(self.Controler.GetFilePath()), {}) + projects = {} + try: + if self.Config.HasEntry("projects"): + projects = cPickle.loads(str(self.Config.Read("projects"))) + except: + pass + + return projects.get(os.path.realpath(self.Controler.GetFilePath()), {}) def SavePageState(self, page): state = page.GetState() @@ -942,7 +949,21 @@ selected = page_idx if selected is not None: wx.CallAfter(notebook.SetSelection, selected) - + + def ResetPerspective(self): + if USE_AUI and self.DefaultPerspective is not None: + self.AUIManager.LoadPerspective(self.DefaultPerspective["perspective"]) + + for notebook in [self.LeftNoteBook, self.BottomNoteBook, self.RightNoteBook]: + for idx in xrange(notebook.GetPageCount()): + notebook.RemovePage(0) + + notebooks = self.DefaultPerspective["notebooks"] + for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"), + (self.BottomNoteBook, "bottomnotebook"), + (self.RightNoteBook, "rightnotebook")]: + self.LoadTabOrganization(notebook, notebooks.get(entry_name)) + def RestoreLastState(self): frame_size = None if self.Config.HasEntry("framesize"): @@ -966,21 +987,24 @@ "notebooks": notebooks, } - if self.Config.HasEntry("perspective"): - self.AUIManager.LoadPerspective(str(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.LoadTabOrganization(notebook, notebooks.get(entry_name)) - + try: + if self.Config.HasEntry("perspective"): + self.AUIManager.LoadPerspective(str(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.LoadTabOrganization(notebook, notebooks.get(entry_name)) + except: + self.ResetPerspective() + self.LoadProjectOrganization() def SaveLastState(self): @@ -1010,30 +1034,37 @@ if USE_AUI and self.Controler is not None: tabs = [] - if self.Config.HasEntry("projects"): - projects = cPickle.loads(str(self.Config.Read("projects"))) - else: - projects = {} + projects = {} + try: + if self.Config.HasEntry("projects"): + projects = cPickle.loads(str(self.Config.Read("projects"))) + except: + pass project_infos = projects.setdefault(os.path.realpath(self.Controler.GetFilePath()), {}) project_infos["tabs"] = self.SaveTabOrganization(self.TabsOpened) if self.EnableDebug: project_infos["debug_vars"] = self.DebugVariablePanel.GetDebugVariables() - + self.Config.Write("projects", cPickle.dumps(projects)) self.Config.Flush() def LoadProjectOrganization(self): - if USE_AUI and self.Controler is not None and self.Config.HasEntry("projects"): - projects = cPickle.loads(str(self.Config.Read("projects"))) - - project = projects.get(os.path.realpath(self.Controler.GetFilePath())) - if project is not None: - self.LoadTabOrganization(self.TabsOpened, project["tabs"]) - - if self.EnableDebug: - for variable in project["debug_vars"]: + if USE_AUI and self.Controler is not None: + project = self.GetProjectConfiguration() + + try: + if project.has_key("tabs"): + self.LoadTabOrganization(self.TabsOpened, project["tabs"]) + except: + self.DeleteAllPages() + + if self.EnableDebug: + try: + for variable in project.get("debug_vars", []): self.DebugVariablePanel.InsertValue(variable, force=True) + except: + self.DebugVariablePanel.ResetGrid() #------------------------------------------------------------------------------- # General Functions @@ -1048,7 +1079,7 @@ DISPLAYMENU : self.RefreshDisplayMenu, TYPESTREE : self.RefreshTypesTree, INSTANCESTREE : self.RefreshInstancesTree, - LIBRARYTREE : self.RefreshLibraryTree, + LIBRARYTREE : self.RefreshLibraryPanel, SCALING : self.RefreshScaling, PAGETITLES: self.RefreshPageTitles} @@ -1232,7 +1263,8 @@ self.DeleteAllPages() self.TypesTree.DeleteAllItems() self.InstancesTree.DeleteAllItems() - self.LibraryTree.DeleteAllItems() + self.LibraryPanel.ResetTree() + self.LibraryPanel.SetControler(None) self.Controler = None def OnCloseTabMenu(self, event): @@ -1493,18 +1525,7 @@ return ZoomFunction def OnResetPerspective(self, event): - if USE_AUI and self.DefaultPerspective is not None: - self.AUIManager.LoadPerspective(self.DefaultPerspective["perspective"]) - - for notebook in [self.LeftNoteBook, self.BottomNoteBook, self.RightNoteBook]: - for idx in xrange(notebook.GetPageCount()): - notebook.RemovePage(0) - - notebooks = self.DefaultPerspective["notebooks"] - for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"), - (self.BottomNoteBook, "bottomnotebook"), - (self.RightNoteBook, "rightnotebook")]: - self.LoadTabOrganization(notebook, notebooks.get(entry_name)) + self.ResetPerspective() #------------------------------------------------------------------------------- # Project Editor Panels Management Functions @@ -1749,7 +1770,7 @@ self.Controler.ChangePouName(old_name, new_name) self.RefreshEditorNames(self.Controler.ComputePouName(old_name), self.Controler.ComputePouName(new_name)) - self.RefreshLibraryTree() + self.RefreshLibraryPanel() self.RefreshPageTitles() elif itemtype == ITEM_TRANSITION: pou_name = GetParentName(self.TypesTree, item, ITEM_POU) @@ -2324,86 +2345,12 @@ self.DebugVariablePanel.InsertValue(iec_path) #------------------------------------------------------------------------------- -# Library Tree Management Functions -#------------------------------------------------------------------------------- - - def RefreshLibraryTree(self): - if self.Controler is not None: - to_delete = [] - selected_name = None - selected = self.LibraryTree.GetSelection() - if selected.IsOk(): - selected_pydata = self.LibraryTree.GetPyData(selected) - if selected_pydata is not None and selected_pydata["type"] != CATEGORY: - selected_name = self.LibraryTree.GetItemText(selected) - blocktypes = self.Controler.GetBlockTypes() - root = self.LibraryTree.GetRootItem() - if not root.IsOk(): - root = self.LibraryTree.AddRoot("") - if wx.VERSION >= (2, 6, 0): - category_item, root_cookie = self.LibraryTree.GetFirstChild(root) - else: - category_item, root_cookie = self.LibraryTree.GetFirstChild(root, 0) - for category in blocktypes: - category_name = category["name"] - if not category_item.IsOk(): - category_item = self.LibraryTree.AppendItem(root, _(category_name)) - if wx.Platform != '__WXMSW__': - category_item, root_cookie = self.LibraryTree.GetNextChild(root, root_cookie) - else: - self.LibraryTree.SetItemText(category_item, _(category_name)) - self.LibraryTree.SetPyData(category_item, {"type" : CATEGORY}) - if wx.VERSION >= (2, 6, 0): - blocktype_item, category_cookie = self.LibraryTree.GetFirstChild(category_item) - else: - blocktype_item, category_cookie = self.LibraryTree.GetFirstChild(category_item, 0) - for blocktype in category["list"]: - if not blocktype_item.IsOk(): - blocktype_item = self.LibraryTree.AppendItem(category_item, blocktype["name"]) - if wx.Platform != '__WXMSW__': - blocktype_item, category_cookie = self.LibraryTree.GetNextChild(category_item, category_cookie) - else: - self.LibraryTree.SetItemText(blocktype_item, blocktype["name"]) - self.LibraryTree.SetPyData(blocktype_item, {"type" : BLOCK, "block_type" : blocktype["type"], "inputs" : tuple([type for name, type, modifier in blocktype["inputs"]])}) - if selected_name == blocktype["name"]: - self.LibraryTree.SelectItem(blocktype_item) - comment = blocktype["comment"] - self.LibraryComment.SetValue(_(comment) + blocktype.get("usage", "")) - blocktype_item, category_cookie = self.LibraryTree.GetNextChild(category_item, category_cookie) - while blocktype_item.IsOk(): - to_delete.append(blocktype_item) - blocktype_item, category_cookie = self.LibraryTree.GetNextChild(category_item, category_cookie) - category_item, root_cookie = self.LibraryTree.GetNextChild(root, root_cookie) - while category_item.IsOk(): - to_delete.append(category_item) - category_item, root_cookie = self.LibraryTree.GetNextChild(root, root_cookie) - for item in to_delete: - self.LibraryTree.Delete(item) - - def OnLibraryTreeItemSelected(self, event): - selected = event.GetItem() - pydata = self.LibraryTree.GetPyData(selected) - if pydata is not None and pydata["type"] != CATEGORY: - blocktype = self.Controler.GetBlockType(self.LibraryTree.GetItemText(selected), pydata["inputs"]) - if blocktype: - comment = blocktype["comment"] - self.LibraryComment.SetValue(_(comment) + blocktype.get("usage", "")) - else: - self.LibraryComment.SetValue("") - else: - self.LibraryComment.SetValue("") - event.Skip() - - def OnLibraryTreeBeginDrag(self, event): - selected = event.GetItem() - pydata = self.LibraryTree.GetPyData(selected) - if pydata is not None and pydata["type"] == BLOCK: - data = wx.TextDataObject(str((self.LibraryTree.GetItemText(selected), - pydata["block_type"], "", pydata["inputs"]))) - dragSource = wx.DropSource(self.LibraryTree) - dragSource.SetData(data) - dragSource.DoDragDrop() - +# Library Panel Management Function +#------------------------------------------------------------------------------- + + def RefreshLibraryPanel(self): + self.LibraryPanel.RefreshTree() + #------------------------------------------------------------------------------- # ToolBars Management Functions #------------------------------------------------------------------------------- @@ -2984,6 +2931,7 @@ self.Controler = PLCControler() result = self.Controler.OpenXMLFile(fileOpen) if result is None: + self.LibraryPanel.SetControler(self.Controler) self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE) # Define PLCOpenEditor icon @@ -3073,6 +3021,7 @@ self.ResetView() self.Controler = PLCControler() self.Controler.CreateNewProject(properties) + self.LibraryPanel.SetControler(self.Controler) self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE) @@ -3097,6 +3046,7 @@ self.Controler = PLCControler() result = self.Controler.OpenXMLFile(filepath) if result is None: + self.LibraryPanel.SetControler(self.Controler) self.LoadProjectOrganization() self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE) self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) diff -r 0ea836add01f -r 0f10f5091245 controls/LibraryPanel.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/controls/LibraryPanel.py Thu May 03 19:02:17 2012 +0200 @@ -0,0 +1,307 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import wx + +[CATEGORY, BLOCK] = range(2) + +[ID_LIBRARYPANEL, ID_LIBRARYSEARCHCTRL, + ID_LIBRARYTREE, ID_LIBRARYCOMMENT, +] = [wx.NewId() for _init_ctrls in range(4)] + +class LibraryPanel(wx.Panel): + + def _init_coll_MainSizer_Items(self, parent): + parent.AddWindow(self.SearchCtrl, 0, border=0, flag=wx.GROW) + parent.AddWindow(self.Tree, 0, border=0, flag=wx.GROW) + parent.AddWindow(self.Comment, 0, border=0, flag=wx.GROW) + + def _init_coll_MainSizer_Growables(self, parent): + parent.AddGrowableCol(0) + parent.AddGrowableRow(1) + + def _init_sizers(self): + self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=0) + + self._init_coll_MainSizer_Growables(self.MainSizer) + self._init_coll_MainSizer_Items(self.MainSizer) + + self.SetSizer(self.MainSizer) + + def _init_ctrls(self, prnt, enable_drag=False): + wx.Panel.__init__(self, id=ID_LIBRARYPANEL, + name='LibraryPanel', parent=prnt, + pos=wx.Point(0, 0), size=wx.Size(0, 0), + style=wx.TAB_TRAVERSAL) + + self.SearchCtrl = wx.SearchCtrl(id=ID_LIBRARYSEARCHCTRL, + name='SearchCtrl', parent=self, + pos=wx.Point(0, 0), size=wx.Size(0, 28), style=0) + self.SearchCtrl.ShowSearchButton(True) + self.Bind(wx.EVT_TEXT, self.OnSearchCtrlChanged, + id=ID_LIBRARYSEARCHCTRL) + self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, self.OnSearchButtonClick, + id=ID_LIBRARYSEARCHCTRL) + search_textctrl = self.SearchCtrl.GetChildren()[0] + search_textctrl.Bind(wx.EVT_CHAR, self.OnKeyDown) + + self.Tree = wx.TreeCtrl(id=ID_LIBRARYTREE, + name='Tree', parent=self, + pos=wx.Point(0, 0), size=wx.Size(0, 0), + style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_HIDE_ROOT|wx.TR_LINES_AT_ROOT) + self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeItemSelected, + id=ID_LIBRARYTREE) + self.Tree.Bind(wx.EVT_CHAR, self.OnKeyDown) + if enable_drag: + self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTreeBeginDrag, + id=ID_LIBRARYTREE) + + self.Comment = wx.TextCtrl(id=ID_LIBRARYCOMMENT, + name='Comment', parent=self, + pos=wx.Point(0, 0), size=wx.Size(0, 80), + style=wx.TE_READONLY|wx.TE_MULTILINE) + + self._init_sizers() + + def __init__(self, parent, enable_drag=False): + self._init_ctrls(parent, enable_drag) + + self.Controler = None + + self.BlockList = None + + def __del__(self): + self.Controler = None + + def SetControler(self, controler): + self.Controler = controler + + def SetBlockList(self, blocklist): + self.BlockList = blocklist + self.RefreshTree() + + def SetFocus(self): + self.SearchCtrl.SetFocus() + + def ResetTree(self): + self.SearchCtrl.SetValue("") + self.Tree.DeleteAllItems() + self.Comment.SetValue("") + + def RefreshTree(self): + if self.Controler is not None: + to_delete = [] + selected_name = None + selected = self.Tree.GetSelection() + if selected.IsOk(): + selected_pydata = self.Tree.GetPyData(selected) + if selected_pydata is not None and selected_pydata["type"] != CATEGORY: + selected_name = self.Tree.GetItemText(selected) + if self.BlockList is not None: + blocktypes = self.BlockList + else: + blocktypes = self.Controler.GetBlockTypes() + root = self.Tree.GetRootItem() + if not root.IsOk(): + root = self.Tree.AddRoot("") + if wx.VERSION >= (2, 6, 0): + category_item, root_cookie = self.Tree.GetFirstChild(root) + else: + category_item, root_cookie = self.Tree.GetFirstChild(root, 0) + for category in blocktypes: + category_name = category["name"] + if not category_item.IsOk(): + category_item = self.Tree.AppendItem(root, _(category_name)) + if wx.Platform != '__WXMSW__': + category_item, root_cookie = self.Tree.GetNextChild(root, root_cookie) + else: + self.Tree.SetItemText(category_item, _(category_name)) + self.Tree.SetPyData(category_item, {"type" : CATEGORY}) + if wx.VERSION >= (2, 6, 0): + blocktype_item, category_cookie = self.Tree.GetFirstChild(category_item) + else: + blocktype_item, category_cookie = self.Tree.GetFirstChild(category_item, 0) + for blocktype in category["list"]: + if not blocktype_item.IsOk(): + blocktype_item = self.Tree.AppendItem(category_item, blocktype["name"]) + if wx.Platform != '__WXMSW__': + blocktype_item, category_cookie = self.Tree.GetNextChild(category_item, category_cookie) + else: + self.Tree.SetItemText(blocktype_item, blocktype["name"]) + block_data = {"type" : BLOCK, + "block_type" : blocktype["type"], + "inputs" : tuple([type for name, type, modifier in blocktype["inputs"]]), + "extension" : None} + if blocktype["extensible"]: + block_data["extension"] = len(blocktype["inputs"]) + self.Tree.SetPyData(blocktype_item, block_data) + if selected_name == blocktype["name"]: + self.Tree.SelectItem(blocktype_item) + comment = blocktype["comment"] + self.Comment.SetValue(_(comment) + blocktype.get("usage", "")) + blocktype_item, category_cookie = self.Tree.GetNextChild(category_item, category_cookie) + while blocktype_item.IsOk(): + to_delete.append(blocktype_item) + blocktype_item, category_cookie = self.Tree.GetNextChild(category_item, category_cookie) + category_item, root_cookie = self.Tree.GetNextChild(root, root_cookie) + while category_item.IsOk(): + to_delete.append(category_item) + category_item, root_cookie = self.Tree.GetNextChild(root, root_cookie) + for item in to_delete: + self.Tree.Delete(item) + + def GetSelectedBlock(self): + selected = self.Tree.GetSelection() + if (selected.IsOk() and + self.Tree.GetItemParent(selected) != self.Tree.GetRootItem() and + selected != self.Tree.GetRootItem()): + selected_data = self.Tree.GetPyData(selected) + return {"type": self.Tree.GetItemText(selected), + "inputs": selected_data["inputs"]} + return None + + def SelectTreeItem(self, name, inputs): + item = self.FindTreeItem(self.Tree.GetRootItem(), name, inputs) + if item is not None and item.IsOk(): + self.Tree.SelectItem(item) + self.Tree.EnsureVisible(item) + + def FindTreeItem(self, root, name, inputs = None): + if root.IsOk(): + pydata = self.Tree.GetPyData(root) + if pydata is not None: + type_inputs = pydata.get("inputs", None) + type_extension = pydata.get("extension", None) + if inputs is not None and type_inputs is not None: + if type_extension is not None: + same_inputs = type_inputs == inputs[:type_extension] + else: + same_inputs = type_inputs == inputs + else: + same_inputs = True + if pydata is not None and self.Tree.GetItemText(root) == name and same_inputs: + return root + else: + if wx.VERSION < (2, 6, 0): + item, root_cookie = self.Tree.GetFirstChild(root, 0) + else: + item, root_cookie = self.Tree.GetFirstChild(root) + while item.IsOk(): + result = self.FindTreeItem(item, name, inputs) + if result: + return result + item, root_cookie = self.Tree.GetNextChild(root, root_cookie) + return None + + def SearchInTree(self, value, mode="first"): + root = self.Tree.GetRootItem() + if mode == "first": + item, item_cookie = self.Tree.GetFirstChild(root) + selected = None + else: + item = self.Tree.GetSelection() + selected = item + if not item.IsOk(): + item, item_cookie = self.Tree.GetFirstChild(root) + while item.IsOk(): + item_pydata = self.Tree.GetPyData(item) + if item_pydata["type"] == CATEGORY: + if mode == "previous": + child = self.Tree.GetLastChild(item) + else: + child, child_cookie = self.Tree.GetFirstChild(item) + if child.IsOk(): + item = child + elif mode == "previous": + item = self.Tree.GetPrevSibling(item) + else: + item = self.Tree.GetNextSibling(item) + else: + name = self.Tree.GetItemText(item) + if name.upper().startswith(value.upper()) and item != selected: + self.Tree.CollapseAllChildren(root) + self.Tree.SelectItem(item) + self.Tree.EnsureVisible(item) + return True + + elif mode == "previous": + previous = self.Tree.GetPrevSibling(item) + if previous.IsOk(): + item = previous + else: + parent = self.Tree.GetItemParent(item) + item = self.Tree.GetPrevSibling(parent) + + else: + next = self.Tree.GetNextSibling(item) + if next.IsOk(): + item = next + else: + parent = self.Tree.GetItemParent(item) + item = self.Tree.GetNextSibling(parent) + return False + + def OnSearchCtrlChanged(self, event): + self.SearchInTree(self.SearchCtrl.GetValue()) + event.Skip() + + def OnSearchButtonClick(self, event): + self.SearchInTree(self.SearchCtrl.GetValue(), "next") + event.Skip() + + def OnTreeItemSelected(self, event): + selected = event.GetItem() + pydata = self.Tree.GetPyData(selected) + if pydata is not None and pydata["type"] != CATEGORY: + blocktype = self.Controler.GetBlockType(self.Tree.GetItemText(selected), pydata["inputs"]) + if blocktype: + comment = blocktype["comment"] + self.Comment.SetValue(_(comment) + blocktype.get("usage", "")) + else: + self.Comment.SetValue("") + else: + self.Comment.SetValue("") + if getattr(self, "_OnTreeItemSelected", None) is not None: + self._OnTreeItemSelected(event) + event.Skip() + + def OnTreeBeginDrag(self, event): + selected = event.GetItem() + pydata = self.Tree.GetPyData(selected) + if pydata is not None and pydata["type"] == BLOCK: + data = wx.TextDataObject(str((self.Tree.GetItemText(selected), + pydata["block_type"], "", pydata["inputs"]))) + dragSource = wx.DropSource(self.Tree) + dragSource.SetData(data) + dragSource.DoDragDrop() + + def OnKeyDown(self, event): + keycode = event.GetKeyCode() + search_value = self.SearchCtrl.GetValue() + if keycode == wx.WXK_UP and search_value != "": + self.SearchInTree(search_value, "previous") + elif keycode == wx.WXK_DOWN and search_value != "": + self.SearchInTree(search_value, "next") + else: + event.Skip() diff -r 0ea836add01f -r 0f10f5091245 controls/__init__.py --- a/controls/__init__.py Wed May 02 00:32:15 2012 +0200 +++ b/controls/__init__.py Thu May 03 19:02:17 2012 +0200 @@ -31,3 +31,4 @@ from DurationCellEditor import DurationCellEditor from LocationCellEditor import LocationCellEditor from VariablePanel import VariablePanel +from LibraryPanel import LibraryPanel diff -r 0ea836add01f -r 0f10f5091245 dialogs/FBDBlockDialog.py --- a/dialogs/FBDBlockDialog.py Wed May 02 00:32:15 2012 +0200 +++ b/dialogs/FBDBlockDialog.py Thu May 03 19:02:17 2012 +0200 @@ -25,6 +25,7 @@ import wx from graphics import * +from controls import LibraryPanel #------------------------------------------------------------------------------- # Create New Block Dialog @@ -63,9 +64,8 @@ parent.AddSizer(self.RightGridSizer, 1, border=5, flag=wx.GROW|wx.LEFT) def _init_coll_LeftBoxSizer_Items(self, parent): - parent.AddWindow(self.TypeTree, 3, border=5, flag=wx.GROW|wx.BOTTOM) - parent.AddWindow(self.TypeDesc, 1, border=0, flag=wx.GROW) - + parent.AddWindow(self.LibraryPanel, 1, border=5, flag=wx.GROW|wx.TOP) + def _init_coll_RightGridSizer_Items(self, parent): parent.AddSizer(self.RightUpGridSizer, 0, border=0, flag=wx.GROW) parent.AddWindow(self.staticText6, 0, border=0, flag=wx.GROW) @@ -137,15 +137,7 @@ label=_('Preview:'), name='staticText6', parent=self, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - self.TypeTree = wx.TreeCtrl(id=ID_FBDBLOCKDIALOGTYPETREE, - name='TypeTree', parent=self, pos=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_HIDE_ROOT|wx.TR_LINES_AT_ROOT) - self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTypeTreeItemSelected, - id=ID_FBDBLOCKDIALOGTYPETREE) - - self.TypeDesc = wx.TextCtrl(id=ID_FBDBLOCKDIALOGTYPEDESC, - name='TypeDesc', parent=self, pos=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.TE_READONLY|wx.TE_MULTILINE) + self.LibraryPanel = LibraryPanel(self) self.BlockName = wx.TextCtrl(id=ID_FBDBLOCKDIALOGNAME, value='', name='BlockName', parent=self, pos=wx.Point(0, 0), @@ -198,44 +190,22 @@ self.PouNames = [] self.PouElementNames = [] - - self.TypeTree.SetFocus() + + self.LibraryPanel.SetControler(controler) + setattr(self.LibraryPanel, "_OnTreeItemSelected", self.OnLibraryTreeItemSelected) + self.LibraryPanel.SetFocus() + + def SetBlockList(self, blocklist): + self.LibraryPanel.SetBlockList(blocklist) def SetPreviewFont(self, font): self.Preview.SetFont(font) - def FindTreeItem(self, root, name, inputs = None): - if root.IsOk(): - pydata = self.TypeTree.GetPyData(root) - if pydata is not None: - type_inputs = pydata.get("inputs", None) - type_extension = pydata.get("extension", None) - if inputs is not None and type_inputs is not None: - if type_extension is not None: - same_inputs = type_inputs == inputs[:type_extension] - else: - same_inputs = type_inputs == inputs - else: - same_inputs = True - if pydata is not None and self.TypeTree.GetItemText(root) == name and same_inputs: - return root - else: - if wx.VERSION < (2, 6, 0): - item, root_cookie = self.TypeTree.GetFirstChild(root, 0) - else: - item, root_cookie = self.TypeTree.GetFirstChild(root) - while item.IsOk(): - result = self.FindTreeItem(item, name, inputs) - if result: - return result - item, root_cookie = self.TypeTree.GetNextChild(root, root_cookie) - return None - def OnOK(self, event): - selected = self.TypeTree.GetSelection() + selected = self.LibraryPanel.GetSelectedBlock() block_name = self.BlockName.GetValue() name_enabled = self.BlockName.IsEnabled() - if not selected.IsOk() or self.TypeTree.GetItemParent(selected) == self.TypeTree.GetRootItem() or selected == self.TypeTree.GetRootItem(): + if selected is None: message = wx.MessageDialog(self, _("Form isn't complete. Valid block type must be selected!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() @@ -262,21 +232,6 @@ else: self.EndModal(wx.ID_OK) - def SetBlockList(self, blocktypes): - root = self.TypeTree.AddRoot("") - for category in blocktypes: - category_name = category["name"] - category_item = self.TypeTree.AppendItem(root, _(category_name)) - self.TypeTree.SetPyData(category_item, {"type" : CATEGORY}) - for blocktype in category["list"]: - blocktype_item = self.TypeTree.AppendItem(category_item, blocktype["name"]) - block_data = {"type" : BLOCK, - "inputs" : tuple([type for name, type, modifier in blocktype["inputs"]]), - "extension" : None} - if blocktype["extensible"]: - block_data["extension"] = len(blocktype["inputs"]) - self.TypeTree.SetPyData(blocktype_item, block_data) - def SetMinBlockSize(self, size): self.MinBlockSize = size @@ -289,11 +244,7 @@ def SetValues(self, values): blocktype = values.get("type", None) if blocktype is not None: - inputs = values.get("inputs", None) - item = self.FindTreeItem(self.TypeTree.GetRootItem(), blocktype, inputs) - if item: - self.TypeTree.SelectItem(item) - self.TypeTree.EnsureVisible(item) + self.LibraryPanel.SelectTreeItem(blocktype, values.get("inputs", None)) for name, value in values.items(): if name == "name": self.BlockName.SetValue(value) @@ -306,10 +257,7 @@ self.RefreshPreview() def GetValues(self): - values = {} - item = self.TypeTree.GetSelection() - values["type"] = self.TypeTree.GetItemText(item) - values["inputs"] = self.TypeTree.GetPyData(item)["inputs"] + values = self.LibraryPanel.GetSelectedBlock() if self.BlockName.GetValue() != "": values["name"] = self.BlockName.GetValue() values["width"], values["height"] = self.Block.GetSize() @@ -318,32 +266,23 @@ values["executionControl"] = self.ExecutionControl.GetValue() return values - def OnTypeTreeItemSelected(self, event): - selected = event.GetItem() - pydata = self.TypeTree.GetPyData(selected) - if pydata["type"] != CATEGORY: - blocktype = self.Controler.GetBlockType(self.TypeTree.GetItemText(selected), pydata["inputs"]) - if blocktype: - self.Inputs.SetValue(len(blocktype["inputs"])) - self.Inputs.Enable(blocktype["extensible"]) - self.BlockName.Enable(blocktype["type"] != "function") - comment = blocktype["comment"] - self.TypeDesc.SetValue(_(comment) + blocktype.get("usage", "")) - wx.CallAfter(self.RefreshPreview) - else: - self.BlockName.Enable(False) - self.Inputs.Enable(False) - self.Inputs.SetValue(2) - self.TypeDesc.SetValue("") - wx.CallAfter(self.ErasePreview) + def OnLibraryTreeItemSelected(self, event): + values = self.LibraryPanel.GetSelectedBlock() + if values is not None: + blocktype = self.Controler.GetBlockType(values["type"], values["inputs"]) + else: + blocktype = None + if blocktype is not None: + self.Inputs.SetValue(len(blocktype["inputs"])) + self.Inputs.Enable(blocktype["extensible"]) + self.BlockName.Enable(blocktype["type"] != "function") + wx.CallAfter(self.RefreshPreview) else: self.BlockName.Enable(False) self.Inputs.Enable(False) self.Inputs.SetValue(2) - self.TypeDesc.SetValue("") wx.CallAfter(self.ErasePreview) - event.Skip() - + def OnNameChanged(self, event): if self.BlockName.IsEnabled(): self.RefreshPreview() @@ -371,31 +310,25 @@ dc = wx.ClientDC(self.Preview) dc.SetFont(self.Preview.GetFont()) dc.Clear() - item = self.TypeTree.GetSelection() - if item.IsOk(): - pydata = self.TypeTree.GetPyData(item) - if pydata["type"] == CATEGORY: - self.Block = None - else: - blocktype = self.TypeTree.GetItemText(item) - if blocktype: - self.Block = FBD_Block(self.Preview, blocktype, - self.BlockName.GetValue(), - extension = self.Inputs.GetValue(), - inputs = pydata["inputs"], - executionControl = self.ExecutionControl.GetValue(), - executionOrder = self.ExecutionOrder.GetValue()) - width, height = self.MinBlockSize - min_width, min_height = self.Block.GetMinSize() - width, height = max(min_width, width), max(min_height, height) - self.Block.SetSize(width, height) - clientsize = self.Preview.GetClientSize() - x = (clientsize.width - width) / 2 - y = (clientsize.height - height) / 2 - self.Block.SetPosition(x, y) - self.Block.Draw(dc) - else: - self.Block = None + values = self.LibraryPanel.GetSelectedBlock() + if values is not None: + self.Block = FBD_Block(self.Preview, values["type"], + self.BlockName.GetValue(), + extension = self.Inputs.GetValue(), + inputs = values["inputs"], + executionControl = self.ExecutionControl.GetValue(), + executionOrder = self.ExecutionOrder.GetValue()) + width, height = self.MinBlockSize + min_width, min_height = self.Block.GetMinSize() + width, height = max(min_width, width), max(min_height, height) + self.Block.SetSize(width, height) + clientsize = self.Preview.GetClientSize() + x = (clientsize.width - width) / 2 + y = (clientsize.height - height) / 2 + self.Block.SetPosition(x, y) + self.Block.Draw(dc) + else: + self.Block = None def OnPaint(self, event): if self.Block is not None: