controls/LibraryPanel.py
changeset 814 5743cbdff669
child 1068 ef088254ba4b
equal deleted inserted replaced
813:1460273f40ed 814:5743cbdff669
       
     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 #-------------------------------------------------------------------------------
       
    28 #                                 Helpers
       
    29 #-------------------------------------------------------------------------------
       
    30 
       
    31 [CATEGORY, BLOCK] = range(2)
       
    32 
       
    33 #-------------------------------------------------------------------------------
       
    34 #                              Library Panel
       
    35 #-------------------------------------------------------------------------------
       
    36 
       
    37 class LibraryPanel(wx.Panel):
       
    38     
       
    39     def __init__(self, parent, enable_drag=False):
       
    40         wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL)
       
    41         
       
    42         main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
       
    43         main_sizer.AddGrowableCol(0)
       
    44         main_sizer.AddGrowableRow(1)
       
    45         
       
    46         self.SearchCtrl = wx.SearchCtrl(self)
       
    47         self.SearchCtrl.ShowSearchButton(True)
       
    48         self.Bind(wx.EVT_TEXT, self.OnSearchCtrlChanged, self.SearchCtrl)
       
    49         self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, 
       
    50               self.OnSearchButtonClick, self.SearchCtrl)
       
    51         search_textctrl = self.SearchCtrl.GetChildren()[0]
       
    52         search_textctrl.Bind(wx.EVT_CHAR, self.OnKeyDown)
       
    53         main_sizer.AddWindow(self.SearchCtrl, flag=wx.GROW)
       
    54         
       
    55         splitter_window = wx.SplitterWindow(self)
       
    56         splitter_window.SetSashGravity(1.0)
       
    57         main_sizer.AddWindow(splitter_window, flag=wx.GROW)
       
    58         
       
    59         self.Tree = wx.TreeCtrl(splitter_window,
       
    60               size=wx.Size(0, 0),  
       
    61               style=wx.TR_HAS_BUTTONS|
       
    62                     wx.TR_SINGLE|
       
    63                     wx.SUNKEN_BORDER|
       
    64                     wx.TR_HIDE_ROOT|
       
    65                     wx.TR_LINES_AT_ROOT)
       
    66         self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeItemSelected, self.Tree)
       
    67         self.Tree.Bind(wx.EVT_CHAR, self.OnKeyDown)
       
    68         if enable_drag:
       
    69             self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTreeBeginDrag, self.Tree)
       
    70         
       
    71         self.Comment = wx.TextCtrl(splitter_window, size=wx.Size(0, 80), 
       
    72               style=wx.TE_READONLY|wx.TE_MULTILINE)
       
    73         
       
    74         splitter_window.SplitHorizontally(self.Tree, self.Comment, -80)
       
    75         
       
    76         self.SetSizer(main_sizer)
       
    77             
       
    78         self.Controller = None
       
    79     
       
    80         self.BlockList = None
       
    81     
       
    82     def __del__(self):
       
    83         self.Controller = None
       
    84     
       
    85     def SetController(self, controller):
       
    86         self.Controller = controller
       
    87     
       
    88     def SetBlockList(self, blocklist):
       
    89         self.BlockList = blocklist
       
    90         self.RefreshTree()
       
    91     
       
    92     def SetFocus(self):
       
    93         self.SearchCtrl.SetFocus()
       
    94     
       
    95     def ResetTree(self):
       
    96         self.SearchCtrl.SetValue("")
       
    97         self.Tree.DeleteAllItems()
       
    98         self.Comment.SetValue("")
       
    99     
       
   100     def RefreshTree(self):
       
   101         if self.Controller is not None:
       
   102             to_delete = []
       
   103             selected_name = None
       
   104             selected = self.Tree.GetSelection()
       
   105             if selected.IsOk():
       
   106                 selected_pydata = self.Tree.GetPyData(selected)
       
   107                 if selected_pydata is not None and selected_pydata["type"] != CATEGORY:
       
   108                     selected_name = self.Tree.GetItemText(selected)
       
   109             if self.BlockList is not None:
       
   110                 blocktypes = self.BlockList
       
   111             else:
       
   112                 blocktypes = self.Controller.GetBlockTypes()
       
   113             root = self.Tree.GetRootItem()
       
   114             if not root.IsOk():
       
   115                 root = self.Tree.AddRoot("")
       
   116             category_item, root_cookie = self.Tree.GetFirstChild(root)
       
   117             for category in blocktypes:
       
   118                 category_name = category["name"]
       
   119                 if not category_item.IsOk():
       
   120                     category_item = self.Tree.AppendItem(root, _(category_name))
       
   121                     if wx.Platform != '__WXMSW__':
       
   122                         category_item, root_cookie = self.Tree.GetNextChild(root, root_cookie)
       
   123                 else:
       
   124                     self.Tree.SetItemText(category_item, _(category_name))
       
   125                 self.Tree.SetPyData(category_item, {"type" : CATEGORY})
       
   126                 blocktype_item, category_cookie = self.Tree.GetFirstChild(category_item)
       
   127                 for blocktype in category["list"]:
       
   128                     if not blocktype_item.IsOk():
       
   129                         blocktype_item = self.Tree.AppendItem(category_item, blocktype["name"])
       
   130                         if wx.Platform != '__WXMSW__':
       
   131                             blocktype_item, category_cookie = self.Tree.GetNextChild(category_item, category_cookie)
       
   132                     else:
       
   133                         self.Tree.SetItemText(blocktype_item, blocktype["name"])
       
   134                     block_data = {"type" : BLOCK, 
       
   135                                   "block_type" : blocktype["type"], 
       
   136                                   "inputs" : tuple([type for name, type, modifier in blocktype["inputs"]]), 
       
   137                                   "extension" : None}
       
   138                     if blocktype["extensible"]:
       
   139                         block_data["extension"] = len(blocktype["inputs"])
       
   140                     self.Tree.SetPyData(blocktype_item, block_data)
       
   141                     if selected_name == blocktype["name"]:
       
   142                         self.Tree.SelectItem(blocktype_item)
       
   143                         comment = blocktype["comment"]
       
   144                         self.Comment.SetValue(_(comment) + blocktype.get("usage", ""))
       
   145                     blocktype_item, category_cookie = self.Tree.GetNextChild(category_item, category_cookie)
       
   146                 while blocktype_item.IsOk():
       
   147                     to_delete.append(blocktype_item)
       
   148                     blocktype_item, category_cookie = self.Tree.GetNextChild(category_item, category_cookie)
       
   149                 category_item, root_cookie = self.Tree.GetNextChild(root, root_cookie)
       
   150             while category_item.IsOk():
       
   151                 to_delete.append(category_item)
       
   152                 category_item, root_cookie = self.Tree.GetNextChild(root, root_cookie)
       
   153             for item in to_delete:
       
   154                 self.Tree.Delete(item)
       
   155     
       
   156     def GetSelectedBlock(self):
       
   157         selected = self.Tree.GetSelection()
       
   158         if (selected.IsOk() and 
       
   159             self.Tree.GetItemParent(selected) != self.Tree.GetRootItem() and 
       
   160             selected != self.Tree.GetRootItem()):
       
   161             selected_data = self.Tree.GetPyData(selected)
       
   162             return {"type": self.Tree.GetItemText(selected), 
       
   163                     "inputs": selected_data["inputs"]}
       
   164         return None
       
   165     
       
   166     def SelectTreeItem(self, name, inputs):
       
   167         item = self.FindTreeItem(self.Tree.GetRootItem(), name, inputs)
       
   168         if item is not None and item.IsOk():
       
   169             self.Tree.SelectItem(item)
       
   170             self.Tree.EnsureVisible(item)
       
   171     
       
   172     def FindTreeItem(self, root, name, inputs = None):
       
   173         if root.IsOk():
       
   174             pydata = self.Tree.GetPyData(root)
       
   175             if pydata is not None:
       
   176                 type_inputs = pydata.get("inputs", None)
       
   177                 type_extension = pydata.get("extension", None)
       
   178                 if inputs is not None and type_inputs is not None:
       
   179                     if type_extension is not None:
       
   180                         same_inputs = type_inputs == inputs[:type_extension]
       
   181                     else:
       
   182                         same_inputs = type_inputs == inputs
       
   183                 else:
       
   184                     same_inputs = True
       
   185             if pydata is not None and self.Tree.GetItemText(root) == name and same_inputs:
       
   186                 return root
       
   187             else:
       
   188                 if wx.VERSION < (2, 6, 0):
       
   189                     item, root_cookie = self.Tree.GetFirstChild(root, 0)
       
   190                 else:
       
   191                     item, root_cookie = self.Tree.GetFirstChild(root)
       
   192                 while item.IsOk():
       
   193                     result = self.FindTreeItem(item, name, inputs)
       
   194                     if result:
       
   195                         return result
       
   196                     item, root_cookie = self.Tree.GetNextChild(root, root_cookie)
       
   197         return None
       
   198     
       
   199     def SearchInTree(self, value, mode="first"):
       
   200         root = self.Tree.GetRootItem()
       
   201         if not root.IsOk():
       
   202             return False
       
   203         
       
   204         if mode == "first":
       
   205             item, item_cookie = self.Tree.GetFirstChild(root)
       
   206             selected = None
       
   207         else:
       
   208             item = self.Tree.GetSelection()
       
   209             selected = item
       
   210             if not item.IsOk():
       
   211                 item, item_cookie = self.Tree.GetFirstChild(root)
       
   212         while item.IsOk():
       
   213             item_pydata = self.Tree.GetPyData(item)
       
   214             if item_pydata["type"] == CATEGORY:
       
   215                 if mode == "previous":
       
   216                     child = self.Tree.GetLastChild(item)
       
   217                 else:
       
   218                     child, child_cookie = self.Tree.GetFirstChild(item)
       
   219                 if child.IsOk():
       
   220                     item = child
       
   221                 elif mode == "previous":
       
   222                     item = self.Tree.GetPrevSibling(item)
       
   223                 else:
       
   224                     item = self.Tree.GetNextSibling(item)
       
   225             else:
       
   226                 name = self.Tree.GetItemText(item)
       
   227                 if name.upper().startswith(value.upper()) and item != selected:
       
   228                     child, child_cookie = self.Tree.GetFirstChild(root)
       
   229                     while child.IsOk():
       
   230                         self.Tree.CollapseAllChildren(child)
       
   231                         child, child_cookie = self.Tree.GetNextChild(root, child_cookie)
       
   232                     self.Tree.SelectItem(item)
       
   233                     self.Tree.EnsureVisible(item)
       
   234                     return True
       
   235                 
       
   236                 elif mode == "previous":
       
   237                     previous = self.Tree.GetPrevSibling(item)
       
   238                     if previous.IsOk():
       
   239                         item = previous
       
   240                     else:
       
   241                         parent = self.Tree.GetItemParent(item)
       
   242                         item = self.Tree.GetPrevSibling(parent)
       
   243                 
       
   244                 else:
       
   245                     next = self.Tree.GetNextSibling(item)
       
   246                     if next.IsOk():
       
   247                         item = next
       
   248                     else:
       
   249                         parent = self.Tree.GetItemParent(item)
       
   250                         item = self.Tree.GetNextSibling(parent)
       
   251         return False
       
   252     
       
   253     def OnSearchCtrlChanged(self, event):
       
   254         self.SearchInTree(self.SearchCtrl.GetValue())
       
   255         event.Skip()
       
   256     
       
   257     def OnSearchButtonClick(self, event):
       
   258         self.SearchInTree(self.SearchCtrl.GetValue(), "next")
       
   259         event.Skip()
       
   260     
       
   261     def OnTreeItemSelected(self, event):
       
   262         selected = event.GetItem()
       
   263         pydata = self.Tree.GetPyData(selected)
       
   264         if pydata is not None and pydata["type"] != CATEGORY:
       
   265             blocktype = self.Controller.GetBlockType(self.Tree.GetItemText(selected), pydata["inputs"])
       
   266             if blocktype:
       
   267                 comment = blocktype["comment"]
       
   268                 self.Comment.SetValue(_(comment) + blocktype.get("usage", ""))
       
   269             else:
       
   270                 self.Comment.SetValue("")
       
   271         else:
       
   272             self.Comment.SetValue("")
       
   273         if getattr(self, "_OnTreeItemSelected", None) is not None:
       
   274             self._OnTreeItemSelected(event)
       
   275         event.Skip()
       
   276     
       
   277     def OnTreeBeginDrag(self, event):
       
   278         selected = event.GetItem()
       
   279         pydata = self.Tree.GetPyData(selected)
       
   280         if pydata is not None and pydata["type"] == BLOCK:
       
   281             data = wx.TextDataObject(str((self.Tree.GetItemText(selected), 
       
   282                 pydata["block_type"], "", pydata["inputs"])))
       
   283             dragSource = wx.DropSource(self.Tree)
       
   284             dragSource.SetData(data)
       
   285             dragSource.DoDragDrop()
       
   286     
       
   287     def OnKeyDown(self, event):
       
   288         keycode = event.GetKeyCode()
       
   289         search_value = self.SearchCtrl.GetValue()
       
   290         if keycode == wx.WXK_UP and search_value != "":
       
   291             self.SearchInTree(search_value, "previous")
       
   292         elif keycode == wx.WXK_DOWN and search_value != "":
       
   293             self.SearchInTree(search_value, "next")
       
   294         else:
       
   295             event.Skip()