controls/LibraryPanel.py
changeset 1730 64d8f52bc8c8
parent 1571 486f94a8032c
child 1736 7e61baa047f0
equal deleted inserted replaced
1726:d51af006fa6b 1730:64d8f52bc8c8
    40 quickly find one functions or function blocks in this list and a text control
    40 quickly find one functions or function blocks in this list and a text control
    41 displaying informations about selected functions or function blocks
    41 displaying informations about selected functions or function blocks
    42 """
    42 """
    43 
    43 
    44 class LibraryPanel(wx.Panel):
    44 class LibraryPanel(wx.Panel):
    45     
    45 
    46     def __init__(self, parent, enable_drag=False):
    46     def __init__(self, parent, enable_drag=False):
    47         """
    47         """
    48         Constructor
    48         Constructor
    49         @param parent: Parent wx.Window of LibraryPanel
    49         @param parent: Parent wx.Window of LibraryPanel
    50         @param enable_drag: Flag indicating that function or function block can
    50         @param enable_drag: Flag indicating that function or function block can
    51         be drag'n drop from LibraryPanel (default: False)
    51         be drag'n drop from LibraryPanel (default: False)
    52         """
    52         """
    53         wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL)
    53         wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL)
    54         
    54 
    55         # Define LibraryPanel main sizer
    55         # Define LibraryPanel main sizer
    56         main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
    56         main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
    57         main_sizer.AddGrowableCol(0)
    57         main_sizer.AddGrowableCol(0)
    58         main_sizer.AddGrowableRow(1)
    58         main_sizer.AddGrowableRow(1)
    59         
    59 
    60         # Add SearchCtrl to main sizer
    60         # Add SearchCtrl to main sizer
    61         self.SearchCtrl = wx.SearchCtrl(self)
    61         self.SearchCtrl = wx.SearchCtrl(self)
    62         # Add a button with a magnifying glass, essentially to show that this
    62         # Add a button with a magnifying glass, essentially to show that this
    63         # control is for searching in tree
    63         # control is for searching in tree
    64         self.SearchCtrl.ShowSearchButton(True)
    64         self.SearchCtrl.ShowSearchButton(True)
    65         self.Bind(wx.EVT_TEXT, self.OnSearchCtrlChanged, self.SearchCtrl)
    65         self.Bind(wx.EVT_TEXT, self.OnSearchCtrlChanged, self.SearchCtrl)
    66         self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, 
    66         self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN,
    67                   self.OnSearchButtonClick, self.SearchCtrl)
    67                   self.OnSearchButtonClick, self.SearchCtrl)
    68         # Bind keyboard event on SearchCtrl text control to catch UP and DOWN
    68         # Bind keyboard event on SearchCtrl text control to catch UP and DOWN
    69         # for search previous and next occurrence
    69         # for search previous and next occurrence
    70 
    70 
    71         # This protects from fail to start when no children[0] available (possible for wxPython 3.0)
    71         # This protects from fail to start when no children[0] available (possible for wxPython 3.0)
    72         if self.SearchCtrl.GetChildren():
    72         if self.SearchCtrl.GetChildren():
    73             search_textctrl = self.SearchCtrl.GetChildren()[0]
    73             search_textctrl = self.SearchCtrl.GetChildren()[0]
    74             search_textctrl.Bind(wx.EVT_CHAR, self.OnKeyDown)
    74             search_textctrl.Bind(wx.EVT_CHAR, self.OnKeyDown)
    75 
    75 
    76         main_sizer.AddWindow(self.SearchCtrl, flag=wx.GROW)
    76         main_sizer.AddWindow(self.SearchCtrl, flag=wx.GROW)
    77         
    77 
    78         # Add Splitter window for tree and block comment to main sizer
    78         # Add Splitter window for tree and block comment to main sizer
    79         splitter_window = wx.SplitterWindow(self)
    79         splitter_window = wx.SplitterWindow(self)
    80         splitter_window.SetSashGravity(1.0)
    80         splitter_window.SetSashGravity(1.0)
    81         main_sizer.AddWindow(splitter_window, flag=wx.GROW)
    81         main_sizer.AddWindow(splitter_window, flag=wx.GROW)
    82         
    82 
    83         # Add TreeCtrl for functions and function blocks library in splitter
    83         # Add TreeCtrl for functions and function blocks library in splitter
    84         # window
    84         # window
    85         self.Tree = wx.TreeCtrl(splitter_window,
    85         self.Tree = wx.TreeCtrl(splitter_window,
    86               size=wx.Size(0, 0),  
    86               size=wx.Size(0, 0),
    87               style=wx.TR_HAS_BUTTONS|
    87               style=wx.TR_HAS_BUTTONS|
    88                     wx.TR_SINGLE|
    88                     wx.TR_SINGLE|
    89                     wx.SUNKEN_BORDER|
    89                     wx.SUNKEN_BORDER|
    90                     wx.TR_HIDE_ROOT|
    90                     wx.TR_HIDE_ROOT|
    91                     wx.TR_LINES_AT_ROOT)
    91                     wx.TR_LINES_AT_ROOT)
    93         self.Tree.Bind(wx.EVT_CHAR, self.OnKeyDown)
    93         self.Tree.Bind(wx.EVT_CHAR, self.OnKeyDown)
    94         # If drag'n drop is enabled, bind event generated when a drag begins on
    94         # If drag'n drop is enabled, bind event generated when a drag begins on
    95         # tree to start a drag'n drop
    95         # tree to start a drag'n drop
    96         if enable_drag:
    96         if enable_drag:
    97             self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTreeBeginDrag, self.Tree)
    97             self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTreeBeginDrag, self.Tree)
    98         
    98 
    99         # Add TextCtrl for function and function block informations
    99         # Add TextCtrl for function and function block informations
   100         self.Comment = wx.TextCtrl(splitter_window, size=wx.Size(0, 80), 
   100         self.Comment = wx.TextCtrl(splitter_window, size=wx.Size(0, 80),
   101               style=wx.TE_READONLY|wx.TE_MULTILINE)
   101               style=wx.TE_READONLY|wx.TE_MULTILINE)
   102         
   102 
   103         splitter_window.SplitHorizontally(self.Tree, self.Comment, -80)
   103         splitter_window.SplitHorizontally(self.Tree, self.Comment, -80)
   104         
   104 
   105         self.SetSizer(main_sizer)
   105         self.SetSizer(main_sizer)
   106         
   106 
   107         # Reference to the project controller
   107         # Reference to the project controller
   108         self.Controller = None
   108         self.Controller = None
   109         
   109 
   110         # Variable storing functions and function blocks library to display
   110         # Variable storing functions and function blocks library to display
   111         self.BlockList = None
   111         self.BlockList = None
   112     
   112 
   113     def __del__(self):
   113     def __del__(self):
   114         """
   114         """
   115         Destructor
   115         Destructor
   116         """
   116         """
   117         # Remove reference to project controller
   117         # Remove reference to project controller
   118         self.Controller = None
   118         self.Controller = None
   119     
   119 
   120     def SetController(self, controller):
   120     def SetController(self, controller):
   121         """
   121         """
   122         Set reference to project controller
   122         Set reference to project controller
   123         @param controller: Reference to project controller
   123         @param controller: Reference to project controller
   124         """
   124         """
   125         self.Controller = controller
   125         self.Controller = controller
   126     
   126 
   127     def SetBlockList(self, blocklist):
   127     def SetBlockList(self, blocklist):
   128         """
   128         """
   129         Set function and function block library to display in TreeCtrl
   129         Set function and function block library to display in TreeCtrl
   130         @param blocklist: Function and function block library
   130         @param blocklist: Function and function block library
   131         """
   131         """
   132         # Save functions and function blocks library
   132         # Save functions and function blocks library
   133         self.BlockList = blocklist
   133         self.BlockList = blocklist
   134         # Refresh TreeCtrl values
   134         # Refresh TreeCtrl values
   135         self.RefreshTree()
   135         self.RefreshTree()
   136     
   136 
   137     def SetFocus(self):
   137     def SetFocus(self):
   138         """
   138         """
   139         Called to give focus to LibraryPanel
   139         Called to give focus to LibraryPanel
   140         Override wx.Window SetFocus method 
   140         Override wx.Window SetFocus method
   141         """
   141         """
   142         # Give focus to SearchCtrl
   142         # Give focus to SearchCtrl
   143         self.SearchCtrl.SetFocus()
   143         self.SearchCtrl.SetFocus()
   144     
   144 
   145     def ResetTree(self):
   145     def ResetTree(self):
   146         """
   146         """
   147         Reset LibraryPanel values displayed in controls
   147         Reset LibraryPanel values displayed in controls
   148         """
   148         """
   149         # Clear SearchCtrl, TreeCtrl and TextCtrl
   149         # Clear SearchCtrl, TreeCtrl and TextCtrl
   150         self.SearchCtrl.SetValue("")
   150         self.SearchCtrl.SetValue("")
   151         self.Tree.DeleteAllItems()
   151         self.Tree.DeleteAllItems()
   152         self.Comment.SetValue("")
   152         self.Comment.SetValue("")
   153     
   153 
   154     def RefreshTree(self):
   154     def RefreshTree(self):
   155         """
   155         """
   156         Refresh LibraryPanel values displayed in controls
   156         Refresh LibraryPanel values displayed in controls
   157         """
   157         """
   158         # Get function and function blocks library
   158         # Get function and function blocks library
   159         blocktypes = self.BlockList
   159         blocktypes = self.BlockList
   160         if blocktypes is None and self.Controller is not None:
   160         if blocktypes is None and self.Controller is not None:
   161             # Get library from project controller if not defined
   161             # Get library from project controller if not defined
   162             blocktypes = self.Controller.GetBlockTypes()
   162             blocktypes = self.Controller.GetBlockTypes()
   163         
   163 
   164         # Refresh TreeCtrl values if a library is defined
   164         # Refresh TreeCtrl values if a library is defined
   165         if blocktypes is not None:
   165         if blocktypes is not None:
   166             # List that will contain tree items to be deleted when TreeCtrl
   166             # List that will contain tree items to be deleted when TreeCtrl
   167             # will be refreshed
   167             # will be refreshed
   168             items_to_delete = []
   168             items_to_delete = []
   169             
   169 
   170             # Get current selected item for selected it when values refreshed
   170             # Get current selected item for selected it when values refreshed
   171             selected_item = self.Tree.GetSelection()
   171             selected_item = self.Tree.GetSelection()
   172             selected_pydata = (self.Tree.GetPyData(selected_item)
   172             selected_pydata = (self.Tree.GetPyData(selected_item)
   173                                if selected_item.IsOk() and
   173                                if selected_item.IsOk() and
   174                                   selected_item != self.Tree.GetRootItem()
   174                                   selected_item != self.Tree.GetRootItem()
   177             selected_infos = ((self.Tree.GetItemText(selected_item),
   177             selected_infos = ((self.Tree.GetItemText(selected_item),
   178                                selected_pydata["inputs"])
   178                                selected_pydata["inputs"])
   179                              if selected_pydata is not None and
   179                              if selected_pydata is not None and
   180                                 selected_pydata["type"] == BLOCK
   180                                 selected_pydata["type"] == BLOCK
   181                              else (None, None))
   181                              else (None, None))
   182             
   182 
   183             # Get TreeCtrl root item (hidden)
   183             # Get TreeCtrl root item (hidden)
   184             root = self.Tree.GetRootItem()
   184             root = self.Tree.GetRootItem()
   185             if not root.IsOk():
   185             if not root.IsOk():
   186                 # Create root if not present
   186                 # Create root if not present
   187                 root = self.Tree.AddRoot("")
   187                 root = self.Tree.AddRoot("")
   188             
   188 
   189             # Iterate over functions and function blocks library categories and
   189             # Iterate over functions and function blocks library categories and
   190             # add a tree item to root item for each of them
   190             # add a tree item to root item for each of them
   191             
   191 
   192             # Get first child under root item
   192             # Get first child under root item
   193             category_item, root_cookie = self.Tree.GetFirstChild(root)
   193             category_item, root_cookie = self.Tree.GetFirstChild(root)
   194             for category in blocktypes:
   194             for category in blocktypes:
   195                 # Store category name in a local variable to prevent script
   195                 # Store category name in a local variable to prevent script
   196                 # extracting translated strings for gettext to consider "name"
   196                 # extracting translated strings for gettext to consider "name"
   197                 # to be translated
   197                 # to be translated
   198                 category_name = category["name"]
   198                 category_name = category["name"]
   199                 
   199 
   200                 # Tree item already exists, set item label
   200                 # Tree item already exists, set item label
   201                 if category_item.IsOk():
   201                 if category_item.IsOk():
   202                     self.Tree.SetItemText(category_item, _(category_name))
   202                     self.Tree.SetItemText(category_item, _(category_name))
   203                 
   203 
   204                 # Tree item doesn't exist, add new one to root
   204                 # Tree item doesn't exist, add new one to root
   205                 else:
   205                 else:
   206                     category_item = self.Tree.AppendItem(root, _(category_name))
   206                     category_item = self.Tree.AppendItem(root, _(category_name))
   207                     # On Windows, needs to get next child of root to have a
   207                     # On Windows, needs to get next child of root to have a
   208                     # reference to the newly added tree item
   208                     # reference to the newly added tree item
   209                     if wx.Platform != '__WXMSW__':
   209                     if wx.Platform != '__WXMSW__':
   210                         category_item, root_cookie = \
   210                         category_item, root_cookie = \
   211                             self.Tree.GetNextChild(root, root_cookie)
   211                             self.Tree.GetNextChild(root, root_cookie)
   212                 
   212 
   213                 # Set data associated to tree item (only save that item is a 
   213                 # Set data associated to tree item (only save that item is a
   214                 # category)
   214                 # category)
   215                 self.Tree.SetPyData(category_item, {"type" : CATEGORY})
   215                 self.Tree.SetPyData(category_item, {"type" : CATEGORY})
   216                 
   216 
   217                 # Iterate over functions and function blocks defined in library
   217                 # Iterate over functions and function blocks defined in library
   218                 # category add a tree item to category tree item for each of 
   218                 # category add a tree item to category tree item for each of
   219                 # them
   219                 # them
   220                 
   220 
   221                 # Get first child under category tree item
   221                 # Get first child under category tree item
   222                 blocktype_item, category_cookie = \
   222                 blocktype_item, category_cookie = \
   223                     self.Tree.GetFirstChild(category_item)
   223                     self.Tree.GetFirstChild(category_item)
   224                 for blocktype in category["list"]:
   224                 for blocktype in category["list"]:
   225                     
   225 
   226                     # Tree item already exists, set item label
   226                     # Tree item already exists, set item label
   227                     if blocktype_item.IsOk():
   227                     if blocktype_item.IsOk():
   228                         self.Tree.SetItemText(blocktype_item, blocktype["name"])
   228                         self.Tree.SetItemText(blocktype_item, blocktype["name"])
   229                     
   229 
   230                     # Tree item doesn't exist, add new one to category item
   230                     # Tree item doesn't exist, add new one to category item
   231                     else:
   231                     else:
   232                         blocktype_item = self.Tree.AppendItem(
   232                         blocktype_item = self.Tree.AppendItem(
   233                                             category_item, blocktype["name"])
   233                                             category_item, blocktype["name"])
   234                         # See comment when adding category
   234                         # See comment when adding category
   235                         if wx.Platform != '__WXMSW__':
   235                         if wx.Platform != '__WXMSW__':
   236                             blocktype_item, category_cookie = \
   236                             blocktype_item, category_cookie = \
   237                                 self.Tree.GetNextChild(category_item, 
   237                                 self.Tree.GetNextChild(category_item,
   238                                                        category_cookie)
   238                                                        category_cookie)
   239                     
   239 
   240                     # Define data to associate to block tree item
   240                     # Define data to associate to block tree item
   241                     comment = blocktype["comment"]
   241                     comment = blocktype["comment"]
   242                     block_data = {"type" : BLOCK, 
   242                     block_data = {"type" : BLOCK,
   243                                   "block_type" : blocktype["type"], 
   243                                   "block_type" : blocktype["type"],
   244                                   "inputs" : tuple([type 
   244                                   "inputs" : tuple([type
   245                                                     for name, type, modifier
   245                                                     for name, type, modifier
   246                                                     in blocktype["inputs"]]), 
   246                                                     in blocktype["inputs"]]),
   247                                   "extension" : (len(blocktype["inputs"])
   247                                   "extension" : (len(blocktype["inputs"])
   248                                                  if blocktype["extensible"]
   248                                                  if blocktype["extensible"]
   249                                                  else None),
   249                                                  else None),
   250                                   "comment": _(comment) + 
   250                                   "comment": _(comment) +
   251                                              blocktype.get("usage", "")}
   251                                              blocktype.get("usage", "")}
   252                     self.Tree.SetPyData(blocktype_item, block_data)
   252                     self.Tree.SetPyData(blocktype_item, block_data)
   253                     
   253 
   254                     # Select block tree item in tree if it corresponds to
   254                     # Select block tree item in tree if it corresponds to
   255                     # previously selected one
   255                     # previously selected one
   256                     if selected_infos == (blocktype["name"], 
   256                     if selected_infos == (blocktype["name"],
   257                                           blocktype["inputs"]):
   257                                           blocktype["inputs"]):
   258                         self.Tree.SelectItem(blocktype_item)
   258                         self.Tree.SelectItem(blocktype_item)
   259                         
   259 
   260                         # Update TextCtrl value
   260                         # Update TextCtrl value
   261                         self.Comment.SetValue(block_data["comment"])
   261                         self.Comment.SetValue(block_data["comment"])
   262                 
   262 
   263                     # Get next block tree item under category tree item
   263                     # Get next block tree item under category tree item
   264                     blocktype_item, category_cookie = \
   264                     blocktype_item, category_cookie = \
   265                         self.Tree.GetNextChild(category_item, category_cookie)
   265                         self.Tree.GetNextChild(category_item, category_cookie)
   266                 
   266 
   267                 # Add every remaining tree item under category tree item after
   267                 # Add every remaining tree item under category tree item after
   268                 # updating all block items to the list of items to delete
   268                 # updating all block items to the list of items to delete
   269                 while blocktype_item.IsOk():
   269                 while blocktype_item.IsOk():
   270                     items_to_delete.append(blocktype_item)
   270                     items_to_delete.append(blocktype_item)
   271                     blocktype_item, category_cookie = \
   271                     blocktype_item, category_cookie = \
   272                         self.Tree.GetNextChild(category_item, category_cookie)
   272                         self.Tree.GetNextChild(category_item, category_cookie)
   273                 
   273 
   274                 # Get next category tree item under root item
   274                 # Get next category tree item under root item
   275                 category_item, root_cookie = \
   275                 category_item, root_cookie = \
   276                     self.Tree.GetNextChild(root, root_cookie)
   276                     self.Tree.GetNextChild(root, root_cookie)
   277             
   277 
   278             # Add every remaining tree item under root item after updating all 
   278             # Add every remaining tree item under root item after updating all
   279             # category items to the list of items to delete
   279             # category items to the list of items to delete
   280             while category_item.IsOk():
   280             while category_item.IsOk():
   281                 items_to_delete.append(category_item)
   281                 items_to_delete.append(category_item)
   282                 category_item, root_cookie = \
   282                 category_item, root_cookie = \
   283                     self.Tree.GetNextChild(root, root_cookie)
   283                     self.Tree.GetNextChild(root, root_cookie)
   284             
   284 
   285             # Remove all items in list of items to delete from TreeCtrl
   285             # Remove all items in list of items to delete from TreeCtrl
   286             for item in items_to_delete:
   286             for item in items_to_delete:
   287                 self.Tree.Delete(item)
   287                 self.Tree.Delete(item)
   288     
   288 
   289     def GetSelectedBlock(self):
   289     def GetSelectedBlock(self):
   290         """
   290         """
   291         Get selected block informations
   291         Get selected block informations
   292         @return: {"type": block_type_name, "inputs": [input_type,...]} or None
   292         @return: {"type": block_type_name, "inputs": [input_type,...]} or None
   293         if no block selected
   293         if no block selected
   296         selected_item = self.Tree.GetSelection()
   296         selected_item = self.Tree.GetSelection()
   297         selected_pydata = (self.Tree.GetPyData(selected_item)
   297         selected_pydata = (self.Tree.GetPyData(selected_item)
   298                            if selected_item.IsOk() and
   298                            if selected_item.IsOk() and
   299                               selected_item != self.Tree.GetRootItem()
   299                               selected_item != self.Tree.GetRootItem()
   300                            else None)
   300                            else None)
   301         
   301 
   302         # Return value is None if selected tree item is root or a category
   302         # Return value is None if selected tree item is root or a category
   303         return ({"type": self.Tree.GetItemText(selected_item), 
   303         return ({"type": self.Tree.GetItemText(selected_item),
   304                  "inputs": selected_pydata["inputs"]}
   304                  "inputs": selected_pydata["inputs"]}
   305                 if selected_pydata is not None and 
   305                 if selected_pydata is not None and
   306                    selected_pydata["type"] == BLOCK
   306                    selected_pydata["type"] == BLOCK
   307                 else None)
   307                 else None)
   308     
   308 
   309     def SelectTreeItem(self, name, inputs):
   309     def SelectTreeItem(self, name, inputs):
   310         """
   310         """
   311         Select Tree item corresponding to block informations given 
   311         Select Tree item corresponding to block informations given
   312         @param name: Block type name
   312         @param name: Block type name
   313         @param inputs: List of block inputs type [input_type,...]
   313         @param inputs: List of block inputs type [input_type,...]
   314         """
   314         """
   315         # Find tree item corresponding to block informations
   315         # Find tree item corresponding to block informations
   316         item = self.FindTreeItem(self.Tree.GetRootItem(), name, inputs)
   316         item = self.FindTreeItem(self.Tree.GetRootItem(), name, inputs)
   317         if item is not None and item.IsOk():
   317         if item is not None and item.IsOk():
   318             # Select tree item found
   318             # Select tree item found
   319             self.Tree.SelectItem(item)
   319             self.Tree.SelectItem(item)
   320             self.Tree.EnsureVisible(item)
   320             self.Tree.EnsureVisible(item)
   321     
   321 
   322     def FindTreeItem(self, item, name, inputs = None):
   322     def FindTreeItem(self, item, name, inputs = None):
   323         """
   323         """
   324         Find Tree item corresponding to block informations given
   324         Find Tree item corresponding to block informations given
   325         Function is recursive
   325         Function is recursive
   326         @param item: Item to test
   326         @param item: Item to test
   328         @param inputs: List of block inputs type [input_type,...]
   328         @param inputs: List of block inputs type [input_type,...]
   329         """
   329         """
   330         # Return immediately if item isn't valid
   330         # Return immediately if item isn't valid
   331         if not item.IsOk():
   331         if not item.IsOk():
   332             return None
   332             return None
   333         
   333 
   334         # Get data associated to item to test
   334         # Get data associated to item to test
   335         item_pydata = self.Tree.GetPyData(item)
   335         item_pydata = self.Tree.GetPyData(item)
   336         if item_pydata is not None and item_pydata["type"] == BLOCK:
   336         if item_pydata is not None and item_pydata["type"] == BLOCK:
   337             # Only test item corresponding to block
   337             # Only test item corresponding to block
   338             
   338 
   339             # Test if block inputs type are the same than those given
   339             # Test if block inputs type are the same than those given
   340             type_inputs = item_pydata.get("inputs", None)
   340             type_inputs = item_pydata.get("inputs", None)
   341             type_extension = item_pydata.get("extension", None)
   341             type_extension = item_pydata.get("extension", None)
   342             if inputs is not None and type_inputs is not None:
   342             if inputs is not None and type_inputs is not None:
   343                 same_inputs = reduce(
   343                 same_inputs = reduce(
   349                              if type_extension is not None
   349                              if type_extension is not None
   350                              else inputs))),
   350                              else inputs))),
   351                     True)
   351                     True)
   352             else:
   352             else:
   353                 same_inputs = True
   353                 same_inputs = True
   354             
   354 
   355             # Return item if  block data corresponds to informations given
   355             # Return item if  block data corresponds to informations given
   356             if self.Tree.GetItemText(item) == name and same_inputs:
   356             if self.Tree.GetItemText(item) == name and same_inputs:
   357                 return item
   357                 return item
   358         
   358 
   359         # Test item children if item doesn't correspond
   359         # Test item children if item doesn't correspond
   360         child, child_cookie = self.Tree.GetFirstChild(item)
   360         child, child_cookie = self.Tree.GetFirstChild(item)
   361         while child.IsOk():
   361         while child.IsOk():
   362             result = self.FindTreeItem(child, name, inputs)
   362             result = self.FindTreeItem(child, name, inputs)
   363             if result:
   363             if result:
   364                 return result
   364                 return result
   365             child, child_cookie = self.Tree.GetNextChild(item, child_cookie)
   365             child, child_cookie = self.Tree.GetNextChild(item, child_cookie)
   366         
   366 
   367         return None
   367         return None
   368     
   368 
   369     def SearchInTree(self, value, mode="first"):
   369     def SearchInTree(self, value, mode="first"):
   370         """
   370         """
   371         Search in Tree and select item that name contains string given
   371         Search in Tree and select item that name contains string given
   372         @param value: String contained in block name to find
   372         @param value: String contained in block name to find
   373         @param mode: Search mode ('first', 'previous' or 'next')
   373         @param mode: Search mode ('first', 'previous' or 'next')
   376         """
   376         """
   377         # Return immediately if root isn't valid
   377         # Return immediately if root isn't valid
   378         root = self.Tree.GetRootItem()
   378         root = self.Tree.GetRootItem()
   379         if not root.IsOk():
   379         if not root.IsOk():
   380             return False
   380             return False
   381         
   381 
   382         # Set function to navigate in Tree item sibling according to search
   382         # Set function to navigate in Tree item sibling according to search
   383         # mode defined 
   383         # mode defined
   384         sibling_function = (self.Tree.GetPrevSibling
   384         sibling_function = (self.Tree.GetPrevSibling
   385                             if mode == "previous"
   385                             if mode == "previous"
   386                             else self.Tree.GetNextSibling)
   386                             else self.Tree.GetNextSibling)
   387         
   387 
   388         # Get current selected item (for next and previous mode)
   388         # Get current selected item (for next and previous mode)
   389         item = self.Tree.GetSelection()
   389         item = self.Tree.GetSelection()
   390         if not item.IsOk() or mode == "first":
   390         if not item.IsOk() or mode == "first":
   391             item, item_cookie = self.Tree.GetFirstChild(root)
   391             item, item_cookie = self.Tree.GetFirstChild(root)
   392             selected = None
   392             selected = None
   393         else:
   393         else:
   394             selected = item
   394             selected = item
   395         
   395 
   396         # Navigate through tree items until one matching found or reach tree
   396         # Navigate through tree items until one matching found or reach tree
   397         # starting or ending
   397         # starting or ending
   398         while item.IsOk():
   398         while item.IsOk():
   399             
   399 
   400             # Get item data to get item type
   400             # Get item data to get item type
   401             item_pydata = self.Tree.GetPyData(item)
   401             item_pydata = self.Tree.GetPyData(item)
   402             
   402 
   403             # Item is a block category
   403             # Item is a block category
   404             if (item == root) or item_pydata["type"] == CATEGORY:
   404             if (item == root) or item_pydata["type"] == CATEGORY:
   405                 
   405 
   406                 # Get category first or last child according to search mode 
   406                 # Get category first or last child according to search mode
   407                 # defined
   407                 # defined
   408                 child = (self.Tree.GetLastChild(item)
   408                 child = (self.Tree.GetLastChild(item)
   409                          if mode == "previous"
   409                          if mode == "previous"
   410                          else self.Tree.GetFirstChild(item)[0])
   410                          else self.Tree.GetFirstChild(item)[0])
   411                 
   411 
   412                 # If category has no child, go to sibling category
   412                 # If category has no child, go to sibling category
   413                 item = (child if child.IsOk() else sibling_function(item))
   413                 item = (child if child.IsOk() else sibling_function(item))
   414             
   414 
   415             # Item is a block
   415             # Item is a block
   416             else:
   416             else:
   417                 
   417 
   418                 # Extract item block name
   418                 # Extract item block name
   419                 name = self.Tree.GetItemText(item)
   419                 name = self.Tree.GetItemText(item)
   420                 # Test if block name contains string given
   420                 # Test if block name contains string given
   421                 if name.upper().find(value.upper()) != -1 and item != selected:
   421                 if name.upper().find(value.upper()) != -1 and item != selected:
   422                     # Select block and collapse all categories other than block
   422                     # Select block and collapse all categories other than block
   426                         self.Tree.CollapseAllChildren(child)
   426                         self.Tree.CollapseAllChildren(child)
   427                         child, child_cookie = self.Tree.GetNextChild(root, child_cookie)
   427                         child, child_cookie = self.Tree.GetNextChild(root, child_cookie)
   428                     self.Tree.SelectItem(item)
   428                     self.Tree.SelectItem(item)
   429                     self.Tree.EnsureVisible(item)
   429                     self.Tree.EnsureVisible(item)
   430                     return True
   430                     return True
   431                 
   431 
   432                 # Go to next item sibling if block not found
   432                 # Go to next item sibling if block not found
   433                 next = sibling_function(item)
   433                 next = sibling_function(item)
   434                 
   434 
   435                 # If category has no other child, go to next category sibling
   435                 # If category has no other child, go to next category sibling
   436                 item = (next
   436                 item = (next
   437                         if next.IsOk()
   437                         if next.IsOk()
   438                         else sibling_function(self.Tree.GetItemParent(item)))
   438                         else sibling_function(self.Tree.GetItemParent(item)))
   439         
   439 
   440         return False
   440         return False
   441     
   441 
   442     def OnSearchCtrlChanged(self, event):
   442     def OnSearchCtrlChanged(self, event):
   443         """
   443         """
   444         Called when SearchCtrl text control value changed
   444         Called when SearchCtrl text control value changed
   445         @param event: TextCtrl change event
   445         @param event: TextCtrl change event
   446         """
   446         """
   447         # Search for block containing SearchCtrl value in 'first' mode
   447         # Search for block containing SearchCtrl value in 'first' mode
   448         self.SearchInTree(self.SearchCtrl.GetValue())
   448         self.SearchInTree(self.SearchCtrl.GetValue())
   449         event.Skip()
   449         event.Skip()
   450     
   450 
   451     def OnSearchButtonClick(self, event):
   451     def OnSearchButtonClick(self, event):
   452         """
   452         """
   453         Called when SearchCtrl search button was clicked
   453         Called when SearchCtrl search button was clicked
   454         @param event: Button clicked event
   454         @param event: Button clicked event
   455         """
   455         """
   456         # Search for block containing SearchCtrl value in 'next' mode
   456         # Search for block containing SearchCtrl value in 'next' mode
   457         self.SearchInTree(self.SearchCtrl.GetValue(), "next")
   457         self.SearchInTree(self.SearchCtrl.GetValue(), "next")
   458         event.Skip()
   458         event.Skip()
   459     
   459 
   460     def OnTreeItemSelected(self, event):
   460     def OnTreeItemSelected(self, event):
   461         """
   461         """
   462         Called when tree item is selected
   462         Called when tree item is selected
   463         @param event: wx.TreeEvent
   463         @param event: wx.TreeEvent
   464         """
   464         """
   466         item_pydata = self.Tree.GetPyData(event.GetItem())
   466         item_pydata = self.Tree.GetPyData(event.GetItem())
   467         self.Comment.SetValue(
   467         self.Comment.SetValue(
   468             item_pydata["comment"]
   468             item_pydata["comment"]
   469             if item_pydata is not None and item_pydata["type"] == BLOCK
   469             if item_pydata is not None and item_pydata["type"] == BLOCK
   470             else "")
   470             else "")
   471         
   471 
   472         # Call extra function defined when tree item is selected
   472         # Call extra function defined when tree item is selected
   473         if getattr(self, "_OnTreeItemSelected", None) is not None:
   473         if getattr(self, "_OnTreeItemSelected", None) is not None:
   474             self._OnTreeItemSelected(event)
   474             self._OnTreeItemSelected(event)
   475         
   475 
   476         event.Skip()
   476         event.Skip()
   477     
   477 
   478     def OnTreeBeginDrag(self, event):
   478     def OnTreeBeginDrag(self, event):
   479         """
   479         """
   480         Called when a drag is started in tree
   480         Called when a drag is started in tree
   481         @param event: wx.TreeEvent
   481         @param event: wx.TreeEvent
   482         """
   482         """
   483         selected_item = event.GetItem()
   483         selected_item = event.GetItem()
   484         item_pydata = self.Tree.GetPyData(selected_item)
   484         item_pydata = self.Tree.GetPyData(selected_item)
   485         
   485 
   486         # Item dragged is a block
   486         # Item dragged is a block
   487         if item_pydata is not None and item_pydata["type"] == BLOCK:
   487         if item_pydata is not None and item_pydata["type"] == BLOCK:
   488             # Start a drag'n drop
   488             # Start a drag'n drop
   489             data = wx.TextDataObject(str(
   489             data = wx.TextDataObject(str(
   490                 (self.Tree.GetItemText(selected_item), 
   490                 (self.Tree.GetItemText(selected_item),
   491                  item_pydata["block_type"], 
   491                  item_pydata["block_type"],
   492                  "", 
   492                  "",
   493                  item_pydata["inputs"])))
   493                  item_pydata["inputs"])))
   494             dragSource = wx.DropSource(self.Tree)
   494             dragSource = wx.DropSource(self.Tree)
   495             dragSource.SetData(data)
   495             dragSource.SetData(data)
   496             dragSource.DoDragDrop()
   496             dragSource.DoDragDrop()
   497     
   497 
   498     def OnKeyDown(self, event):
   498     def OnKeyDown(self, event):
   499         """
   499         """
   500         Called when key is pressed in SearchCtrl text control
   500         Called when key is pressed in SearchCtrl text control
   501         @param event: wx.KeyEvent
   501         @param event: wx.KeyEvent
   502         """
   502         """
   503         # Get event keycode and value in SearchCtrl
   503         # Get event keycode and value in SearchCtrl
   504         keycode = event.GetKeyCode()
   504         keycode = event.GetKeyCode()
   505         search_value = self.SearchCtrl.GetValue()
   505         search_value = self.SearchCtrl.GetValue()
   506         
   506 
   507         # Up key was pressed and SearchCtrl isn't empty, search for block in
   507         # Up key was pressed and SearchCtrl isn't empty, search for block in
   508         # 'previous' mode 
   508         # 'previous' mode
   509         if keycode == wx.WXK_UP and search_value != "":
   509         if keycode == wx.WXK_UP and search_value != "":
   510             self.SearchInTree(search_value, "previous")
   510             self.SearchInTree(search_value, "previous")
   511         
   511 
   512         # Down key was pressed and SearchCtrl isn't empty, search for block in
   512         # Down key was pressed and SearchCtrl isn't empty, search for block in
   513         # 'next' mode 
   513         # 'next' mode
   514         elif keycode == wx.WXK_DOWN and search_value != "":
   514         elif keycode == wx.WXK_DOWN and search_value != "":
   515             self.SearchInTree(search_value, "next")
   515             self.SearchInTree(search_value, "next")
   516         
   516 
   517         # Handle key normally
   517         # Handle key normally
   518         else:
   518         else:
   519             event.Skip()
   519             event.Skip()