controls/LibraryPanel.py
changeset 676 0f10f5091245
child 680 b693147fb2c3
equal deleted inserted replaced
675:0ea836add01f 676:0f10f5091245
       
     1 #!/usr/bin/env python
       
     2 # -*- coding: utf-8 -*-
       
     3 
       
     4 #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
       
     5 #based on the plcopen standard. 
       
     6 #
       
     7 #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
       
     8 #
       
     9 #See COPYING file for copyrights details.
       
    10 #
       
    11 #This library is free software; you can redistribute it and/or
       
    12 #modify it under the terms of the GNU General Public
       
    13 #License as published by the Free Software Foundation; either
       
    14 #version 2.1 of the License, or (at your option) any later version.
       
    15 #
       
    16 #This library is distributed in the hope that it will be useful,
       
    17 #but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    18 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    19 #General Public License for more details.
       
    20 #
       
    21 #You should have received a copy of the GNU General Public
       
    22 #License along with this library; if not, write to the Free Software
       
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    24 
       
    25 import wx
       
    26 
       
    27 [CATEGORY, BLOCK] = range(2)
       
    28 
       
    29 [ID_LIBRARYPANEL, ID_LIBRARYSEARCHCTRL, 
       
    30  ID_LIBRARYTREE, ID_LIBRARYCOMMENT, 
       
    31 ] = [wx.NewId() for _init_ctrls in range(4)]
       
    32 
       
    33 class LibraryPanel(wx.Panel):
       
    34     
       
    35     def _init_coll_MainSizer_Items(self, parent):
       
    36         parent.AddWindow(self.SearchCtrl, 0, border=0, flag=wx.GROW)
       
    37         parent.AddWindow(self.Tree, 0, border=0, flag=wx.GROW)
       
    38         parent.AddWindow(self.Comment, 0, border=0, flag=wx.GROW)
       
    39 
       
    40     def _init_coll_MainSizer_Growables(self, parent):
       
    41         parent.AddGrowableCol(0)
       
    42         parent.AddGrowableRow(1)
       
    43     
       
    44     def _init_sizers(self):
       
    45         self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=0)
       
    46         
       
    47         self._init_coll_MainSizer_Growables(self.MainSizer)
       
    48         self._init_coll_MainSizer_Items(self.MainSizer)
       
    49         
       
    50         self.SetSizer(self.MainSizer)
       
    51     
       
    52     def _init_ctrls(self, prnt, enable_drag=False):
       
    53         wx.Panel.__init__(self, id=ID_LIBRARYPANEL,
       
    54                   name='LibraryPanel', parent=prnt,
       
    55                   pos=wx.Point(0, 0), size=wx.Size(0, 0), 
       
    56                   style=wx.TAB_TRAVERSAL)
       
    57         
       
    58         self.SearchCtrl = wx.SearchCtrl(id=ID_LIBRARYSEARCHCTRL, 
       
    59                   name='SearchCtrl', parent=self,
       
    60                   pos=wx.Point(0, 0), size=wx.Size(0, 28), style=0)
       
    61         self.SearchCtrl.ShowSearchButton(True)
       
    62         self.Bind(wx.EVT_TEXT, self.OnSearchCtrlChanged,
       
    63               id=ID_LIBRARYSEARCHCTRL)
       
    64         self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, self.OnSearchButtonClick,
       
    65               id=ID_LIBRARYSEARCHCTRL)
       
    66         search_textctrl = self.SearchCtrl.GetChildren()[0]
       
    67         search_textctrl.Bind(wx.EVT_CHAR, self.OnKeyDown)
       
    68         
       
    69         self.Tree = wx.TreeCtrl(id=ID_LIBRARYTREE,
       
    70                   name='Tree', parent=self, 
       
    71                   pos=wx.Point(0, 0), size=wx.Size(0, 0),
       
    72                   style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_HIDE_ROOT|wx.TR_LINES_AT_ROOT)
       
    73         self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeItemSelected,
       
    74               id=ID_LIBRARYTREE)
       
    75         self.Tree.Bind(wx.EVT_CHAR, self.OnKeyDown)
       
    76         if enable_drag:
       
    77             self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTreeBeginDrag,
       
    78                   id=ID_LIBRARYTREE)
       
    79         
       
    80         self.Comment = wx.TextCtrl(id=ID_LIBRARYCOMMENT,
       
    81               name='Comment', parent=self, 
       
    82               pos=wx.Point(0, 0), size=wx.Size(0, 80), 
       
    83               style=wx.TE_READONLY|wx.TE_MULTILINE)
       
    84         
       
    85         self._init_sizers()
       
    86     
       
    87     def __init__(self, parent, enable_drag=False):
       
    88         self._init_ctrls(parent, enable_drag)
       
    89         
       
    90         self.Controler = None
       
    91     
       
    92         self.BlockList = None
       
    93     
       
    94     def __del__(self):
       
    95         self.Controler = None
       
    96     
       
    97     def SetControler(self, controler):
       
    98         self.Controler = controler
       
    99     
       
   100     def SetBlockList(self, blocklist):
       
   101         self.BlockList = blocklist
       
   102         self.RefreshTree()
       
   103     
       
   104     def SetFocus(self):
       
   105         self.SearchCtrl.SetFocus()
       
   106     
       
   107     def ResetTree(self):
       
   108         self.SearchCtrl.SetValue("")
       
   109         self.Tree.DeleteAllItems()
       
   110         self.Comment.SetValue("")
       
   111     
       
   112     def RefreshTree(self):
       
   113         if self.Controler is not None:
       
   114             to_delete = []
       
   115             selected_name = None
       
   116             selected = self.Tree.GetSelection()
       
   117             if selected.IsOk():
       
   118                 selected_pydata = self.Tree.GetPyData(selected)
       
   119                 if selected_pydata is not None and selected_pydata["type"] != CATEGORY:
       
   120                     selected_name = self.Tree.GetItemText(selected)
       
   121             if self.BlockList is not None:
       
   122                 blocktypes = self.BlockList
       
   123             else:
       
   124                 blocktypes = self.Controler.GetBlockTypes()
       
   125             root = self.Tree.GetRootItem()
       
   126             if not root.IsOk():
       
   127                 root = self.Tree.AddRoot("")
       
   128             if wx.VERSION >= (2, 6, 0):
       
   129                 category_item, root_cookie = self.Tree.GetFirstChild(root)
       
   130             else:
       
   131                 category_item, root_cookie = self.Tree.GetFirstChild(root, 0)
       
   132             for category in blocktypes:
       
   133                 category_name = category["name"]
       
   134                 if not category_item.IsOk():
       
   135                     category_item = self.Tree.AppendItem(root, _(category_name))
       
   136                     if wx.Platform != '__WXMSW__':
       
   137                         category_item, root_cookie = self.Tree.GetNextChild(root, root_cookie)
       
   138                 else:
       
   139                     self.Tree.SetItemText(category_item, _(category_name))
       
   140                 self.Tree.SetPyData(category_item, {"type" : CATEGORY})
       
   141                 if wx.VERSION >= (2, 6, 0):
       
   142                     blocktype_item, category_cookie = self.Tree.GetFirstChild(category_item)
       
   143                 else:
       
   144                     blocktype_item, category_cookie = self.Tree.GetFirstChild(category_item, 0)        
       
   145                 for blocktype in category["list"]:
       
   146                     if not blocktype_item.IsOk():
       
   147                         blocktype_item = self.Tree.AppendItem(category_item, blocktype["name"])
       
   148                         if wx.Platform != '__WXMSW__':
       
   149                             blocktype_item, category_cookie = self.Tree.GetNextChild(category_item, category_cookie)
       
   150                     else:
       
   151                         self.Tree.SetItemText(blocktype_item, blocktype["name"])
       
   152                     block_data = {"type" : BLOCK, 
       
   153                                   "block_type" : blocktype["type"], 
       
   154                                   "inputs" : tuple([type for name, type, modifier in blocktype["inputs"]]), 
       
   155                                   "extension" : None}
       
   156                     if blocktype["extensible"]:
       
   157                         block_data["extension"] = len(blocktype["inputs"])
       
   158                     self.Tree.SetPyData(blocktype_item, block_data)
       
   159                     if selected_name == blocktype["name"]:
       
   160                         self.Tree.SelectItem(blocktype_item)
       
   161                         comment = blocktype["comment"]
       
   162                         self.Comment.SetValue(_(comment) + blocktype.get("usage", ""))
       
   163                     blocktype_item, category_cookie = self.Tree.GetNextChild(category_item, category_cookie)
       
   164                 while blocktype_item.IsOk():
       
   165                     to_delete.append(blocktype_item)
       
   166                     blocktype_item, category_cookie = self.Tree.GetNextChild(category_item, category_cookie)
       
   167                 category_item, root_cookie = self.Tree.GetNextChild(root, root_cookie)
       
   168             while category_item.IsOk():
       
   169                 to_delete.append(category_item)
       
   170                 category_item, root_cookie = self.Tree.GetNextChild(root, root_cookie)
       
   171             for item in to_delete:
       
   172                 self.Tree.Delete(item)
       
   173     
       
   174     def GetSelectedBlock(self):
       
   175         selected = self.Tree.GetSelection()
       
   176         if (selected.IsOk() and 
       
   177             self.Tree.GetItemParent(selected) != self.Tree.GetRootItem() and 
       
   178             selected != self.Tree.GetRootItem()):
       
   179             selected_data = self.Tree.GetPyData(selected)
       
   180             return {"type": self.Tree.GetItemText(selected), 
       
   181                     "inputs": selected_data["inputs"]}
       
   182         return None
       
   183     
       
   184     def SelectTreeItem(self, name, inputs):
       
   185         item = self.FindTreeItem(self.Tree.GetRootItem(), name, inputs)
       
   186         if item is not None and item.IsOk():
       
   187             self.Tree.SelectItem(item)
       
   188             self.Tree.EnsureVisible(item)
       
   189     
       
   190     def FindTreeItem(self, root, name, inputs = None):
       
   191         if root.IsOk():
       
   192             pydata = self.Tree.GetPyData(root)
       
   193             if pydata is not None:
       
   194                 type_inputs = pydata.get("inputs", None)
       
   195                 type_extension = pydata.get("extension", None)
       
   196                 if inputs is not None and type_inputs is not None:
       
   197                     if type_extension is not None:
       
   198                         same_inputs = type_inputs == inputs[:type_extension]
       
   199                     else:
       
   200                         same_inputs = type_inputs == inputs
       
   201                 else:
       
   202                     same_inputs = True
       
   203             if pydata is not None and self.Tree.GetItemText(root) == name and same_inputs:
       
   204                 return root
       
   205             else:
       
   206                 if wx.VERSION < (2, 6, 0):
       
   207                     item, root_cookie = self.Tree.GetFirstChild(root, 0)
       
   208                 else:
       
   209                     item, root_cookie = self.Tree.GetFirstChild(root)
       
   210                 while item.IsOk():
       
   211                     result = self.FindTreeItem(item, name, inputs)
       
   212                     if result:
       
   213                         return result
       
   214                     item, root_cookie = self.Tree.GetNextChild(root, root_cookie)
       
   215         return None
       
   216     
       
   217     def SearchInTree(self, value, mode="first"):
       
   218         root = self.Tree.GetRootItem()
       
   219         if mode == "first":
       
   220             item, item_cookie = self.Tree.GetFirstChild(root)
       
   221             selected = None
       
   222         else:
       
   223             item = self.Tree.GetSelection()
       
   224             selected = item
       
   225             if not item.IsOk():
       
   226                 item, item_cookie = self.Tree.GetFirstChild(root)
       
   227         while item.IsOk():
       
   228             item_pydata = self.Tree.GetPyData(item)
       
   229             if item_pydata["type"] == CATEGORY:
       
   230                 if mode == "previous":
       
   231                     child = self.Tree.GetLastChild(item)
       
   232                 else:
       
   233                     child, child_cookie = self.Tree.GetFirstChild(item)
       
   234                 if child.IsOk():
       
   235                     item = child
       
   236                 elif mode == "previous":
       
   237                     item = self.Tree.GetPrevSibling(item)
       
   238                 else:
       
   239                     item = self.Tree.GetNextSibling(item)
       
   240             else:
       
   241                 name = self.Tree.GetItemText(item)
       
   242                 if name.upper().startswith(value.upper()) and item != selected:
       
   243                     self.Tree.CollapseAllChildren(root)
       
   244                     self.Tree.SelectItem(item)
       
   245                     self.Tree.EnsureVisible(item)
       
   246                     return True
       
   247                 
       
   248                 elif mode == "previous":
       
   249                     previous = self.Tree.GetPrevSibling(item)
       
   250                     if previous.IsOk():
       
   251                         item = previous
       
   252                     else:
       
   253                         parent = self.Tree.GetItemParent(item)
       
   254                         item = self.Tree.GetPrevSibling(parent)
       
   255                 
       
   256                 else:
       
   257                     next = self.Tree.GetNextSibling(item)
       
   258                     if next.IsOk():
       
   259                         item = next
       
   260                     else:
       
   261                         parent = self.Tree.GetItemParent(item)
       
   262                         item = self.Tree.GetNextSibling(parent)
       
   263         return False
       
   264     
       
   265     def OnSearchCtrlChanged(self, event):
       
   266         self.SearchInTree(self.SearchCtrl.GetValue())
       
   267         event.Skip()
       
   268     
       
   269     def OnSearchButtonClick(self, event):
       
   270         self.SearchInTree(self.SearchCtrl.GetValue(), "next")
       
   271         event.Skip()
       
   272     
       
   273     def OnTreeItemSelected(self, event):
       
   274         selected = event.GetItem()
       
   275         pydata = self.Tree.GetPyData(selected)
       
   276         if pydata is not None and pydata["type"] != CATEGORY:
       
   277             blocktype = self.Controler.GetBlockType(self.Tree.GetItemText(selected), pydata["inputs"])
       
   278             if blocktype:
       
   279                 comment = blocktype["comment"]
       
   280                 self.Comment.SetValue(_(comment) + blocktype.get("usage", ""))
       
   281             else:
       
   282                 self.Comment.SetValue("")
       
   283         else:
       
   284             self.Comment.SetValue("")
       
   285         if getattr(self, "_OnTreeItemSelected", None) is not None:
       
   286             self._OnTreeItemSelected(event)
       
   287         event.Skip()
       
   288     
       
   289     def OnTreeBeginDrag(self, event):
       
   290         selected = event.GetItem()
       
   291         pydata = self.Tree.GetPyData(selected)
       
   292         if pydata is not None and pydata["type"] == BLOCK:
       
   293             data = wx.TextDataObject(str((self.Tree.GetItemText(selected), 
       
   294                 pydata["block_type"], "", pydata["inputs"])))
       
   295             dragSource = wx.DropSource(self.Tree)
       
   296             dragSource.SetData(data)
       
   297             dragSource.DoDragDrop()
       
   298     
       
   299     def OnKeyDown(self, event):
       
   300         keycode = event.GetKeyCode()
       
   301         search_value = self.SearchCtrl.GetValue()
       
   302         if keycode == wx.WXK_UP and search_value != "":
       
   303             self.SearchInTree(search_value, "previous")
       
   304         elif keycode == wx.WXK_DOWN and search_value != "":
       
   305             self.SearchInTree(search_value, "next")
       
   306         else:
       
   307             event.Skip()