controls/FolderTree.py
changeset 1730 64d8f52bc8c8
parent 1571 486f94a8032c
child 1736 7e61baa047f0
equal deleted inserted replaced
1726:d51af006fa6b 1730:64d8f52bc8c8
    45     elif tail == "":
    45     elif tail == "":
    46         return splitpath(head)
    46         return splitpath(head)
    47     return splitpath(head) + [tail]
    47     return splitpath(head) + [tail]
    48 
    48 
    49 class FolderTree(wx.Panel):
    49 class FolderTree(wx.Panel):
    50     
    50 
    51     def __init__(self, parent, folder, filter=None, editable=True):
    51     def __init__(self, parent, folder, filter=None, editable=True):
    52         wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL)
    52         wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL)
    53         
    53 
    54         main_sizer = wx.BoxSizer(wx.VERTICAL)
    54         main_sizer = wx.BoxSizer(wx.VERTICAL)
    55         
    55 
    56         self.Tree = wx.TreeCtrl(self, 
    56         self.Tree = wx.TreeCtrl(self,
    57               style=wx.TR_HAS_BUTTONS|
    57               style=wx.TR_HAS_BUTTONS|
    58                     wx.TR_SINGLE|
    58                     wx.TR_SINGLE|
    59                     wx.SUNKEN_BORDER|
    59                     wx.SUNKEN_BORDER|
    60                     wx.TR_HIDE_ROOT|
    60                     wx.TR_HIDE_ROOT|
    61                     wx.TR_LINES_AT_ROOT|
    61                     wx.TR_LINES_AT_ROOT|
    67             self.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnTreeItemExpanded, self.Tree)
    67             self.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnTreeItemExpanded, self.Tree)
    68         self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnTreeItemCollapsed, self.Tree)
    68         self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnTreeItemCollapsed, self.Tree)
    69         self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnTreeBeginLabelEdit, self.Tree)
    69         self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnTreeBeginLabelEdit, self.Tree)
    70         self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnTreeEndLabelEdit, self.Tree)
    70         self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnTreeEndLabelEdit, self.Tree)
    71         main_sizer.AddWindow(self.Tree, 1, flag=wx.GROW)
    71         main_sizer.AddWindow(self.Tree, 1, flag=wx.GROW)
    72         
    72 
    73         if filter is not None:
    73         if filter is not None:
    74             self.Filter = wx.ComboBox(self, style=wx.CB_READONLY)
    74             self.Filter = wx.ComboBox(self, style=wx.CB_READONLY)
    75             self.Bind(wx.EVT_COMBOBOX, self.OnFilterChanged, self.Filter)
    75             self.Bind(wx.EVT_COMBOBOX, self.OnFilterChanged, self.Filter)
    76             main_sizer.AddWindow(self.Filter, flag=wx.GROW)
    76             main_sizer.AddWindow(self.Filter, flag=wx.GROW)
    77         else:
    77         else:
    78             self.Filter = None
    78             self.Filter = None
    79         
    79 
    80         self.SetSizer(main_sizer)
    80         self.SetSizer(main_sizer)
    81         
    81 
    82         self.Folder = folder
    82         self.Folder = folder
    83         self.Editable = editable
    83         self.Editable = editable
    84         
    84 
    85         self.TreeImageList = wx.ImageList(16, 16)
    85         self.TreeImageList = wx.ImageList(16, 16)
    86         self.TreeImageDict = {}
    86         self.TreeImageDict = {}
    87         for item_type, bitmap in [(DRIVE, "tree_drive"),
    87         for item_type, bitmap in [(DRIVE, "tree_drive"),
    88                                   (FOLDER, "tree_folder"),
    88                                   (FOLDER, "tree_folder"),
    89                                   (FILE, "tree_file")]:
    89                                   (FILE, "tree_file")]:
    90             self.TreeImageDict[item_type] = self.TreeImageList.Add(GetBitmap(bitmap))
    90             self.TreeImageDict[item_type] = self.TreeImageList.Add(GetBitmap(bitmap))
    91         self.Tree.SetImageList(self.TreeImageList)
    91         self.Tree.SetImageList(self.TreeImageList)
    92         
    92 
    93         self.Filters = {}
    93         self.Filters = {}
    94         if self.Filter is not None:
    94         if self.Filter is not None:
    95             filter_parts = filter.split("|")
    95             filter_parts = filter.split("|")
    96             for idx in xrange(0, len(filter_parts), 2):
    96             for idx in xrange(0, len(filter_parts), 2):
    97                 if filter_parts[idx + 1] == "*.*":
    97                 if filter_parts[idx + 1] == "*.*":
    99                 else:
    99                 else:
   100                     self.Filters[filter_parts[idx]] = filter_parts[idx + 1].replace("*", "")
   100                     self.Filters[filter_parts[idx]] = filter_parts[idx + 1].replace("*", "")
   101                 self.Filter.Append(filter_parts[idx])
   101                 self.Filter.Append(filter_parts[idx])
   102                 if idx == 0:
   102                 if idx == 0:
   103                     self.Filter.SetStringSelection(filter_parts[idx])
   103                     self.Filter.SetStringSelection(filter_parts[idx])
   104                 
   104 
   105             self.CurrentFilter = self.Filters[self.Filter.GetStringSelection()]
   105             self.CurrentFilter = self.Filters[self.Filter.GetStringSelection()]
   106         else:
   106         else:
   107             self.CurrentFilter = ""
   107             self.CurrentFilter = ""
   108     
   108 
   109     def _GetFolderChildren(self, folderpath, recursive=True):
   109     def _GetFolderChildren(self, folderpath, recursive=True):
   110         items = []
   110         items = []
   111         if wx.Platform == '__WXMSW__' and folderpath == "/":
   111         if wx.Platform == '__WXMSW__' and folderpath == "/":
   112             for c in xrange(ord('a'), ord('z')):
   112             for c in xrange(ord('a'), ord('z')):
   113                 drive = os.path.join("%s:\\" % chr(c))
   113                 drive = os.path.join("%s:\\" % chr(c))
   125                         if recursive:
   125                         if recursive:
   126                             children = len(self._GetFolderChildren(filepath, False))
   126                             children = len(self._GetFolderChildren(filepath, False))
   127                         else:
   127                         else:
   128                             children = 0
   128                             children = 0
   129                         items.append((filename, FOLDER, children))
   129                         items.append((filename, FOLDER, children))
   130                     elif (self.CurrentFilter == "" or 
   130                     elif (self.CurrentFilter == "" or
   131                           os.path.splitext(filename)[1] == self.CurrentFilter):
   131                           os.path.splitext(filename)[1] == self.CurrentFilter):
   132                         items.append((filename, FILE, None))
   132                         items.append((filename, FILE, None))
   133         if recursive:
   133         if recursive:
   134             items.sort(sort_folder)
   134             items.sort(sort_folder)
   135         return items
   135         return items
   136     
   136 
   137     def SetFilter(self, filter):
   137     def SetFilter(self, filter):
   138         self.CurrentFilter = filter
   138         self.CurrentFilter = filter
   139     
   139 
   140     def GetTreeCtrl(self):
   140     def GetTreeCtrl(self):
   141         return self.Tree
   141         return self.Tree
   142     
   142 
   143     def RefreshTree(self):
   143     def RefreshTree(self):
   144         root = self.Tree.GetRootItem()
   144         root = self.Tree.GetRootItem()
   145         if not root.IsOk():
   145         if not root.IsOk():
   146             root = self.Tree.AddRoot("")
   146             root = self.Tree.AddRoot("")
   147         self.GenerateTreeBranch(root, self.Folder)
   147         self.GenerateTreeBranch(root, self.Folder)
   148         
   148 
   149     def GenerateTreeBranch(self, root, folderpath):
   149     def GenerateTreeBranch(self, root, folderpath):
   150         item, item_cookie = self.Tree.GetFirstChild(root)
   150         item, item_cookie = self.Tree.GetFirstChild(root)
   151         for idx, (filename, item_type, children) in enumerate(self._GetFolderChildren(folderpath)):
   151         for idx, (filename, item_type, children) in enumerate(self._GetFolderChildren(folderpath)):
   152             if not item.IsOk():
   152             if not item.IsOk():
   153                 item = self.Tree.AppendItem(root, filename, self.TreeImageDict[item_type])
   153                 item = self.Tree.AppendItem(root, filename, self.TreeImageDict[item_type])
   170             self.Tree.Delete(item)
   170             self.Tree.Delete(item)
   171 
   171 
   172     def ExpandItem(self, item):
   172     def ExpandItem(self, item):
   173         self.GenerateTreeBranch(item, self.GetPath(item))
   173         self.GenerateTreeBranch(item, self.GetPath(item))
   174         self.Tree.Expand(item)
   174         self.Tree.Expand(item)
   175     
   175 
   176     def OnTreeItemActivated(self, event):
   176     def OnTreeItemActivated(self, event):
   177         self.ExpandItem(event.GetItem())
   177         self.ExpandItem(event.GetItem())
   178         event.Skip()
   178         event.Skip()
   179     
   179 
   180     def OnTreeLeftDown(self, event):
   180     def OnTreeLeftDown(self, event):
   181         item, flags = self.Tree.HitTest(event.GetPosition())
   181         item, flags = self.Tree.HitTest(event.GetPosition())
   182         if flags & wx.TREE_HITTEST_ONITEMBUTTON and not self.Tree.IsExpanded(item):
   182         if flags & wx.TREE_HITTEST_ONITEMBUTTON and not self.Tree.IsExpanded(item):
   183             self.ExpandItem(item)
   183             self.ExpandItem(item)
   184         else:
   184         else:
   185             event.Skip()
   185             event.Skip()
   186     
   186 
   187     def OnTreeItemExpanded(self, event):
   187     def OnTreeItemExpanded(self, event):
   188         item = event.GetItem()
   188         item = event.GetItem()
   189         self.GenerateTreeBranch(item, self.GetPath(item))
   189         self.GenerateTreeBranch(item, self.GetPath(item))
   190         event.Skip()
   190         event.Skip()
   191 
   191 
   199         item = event.GetItem()
   199         item = event.GetItem()
   200         if self.Editable and not self.Tree.ItemHasChildren(item):
   200         if self.Editable and not self.Tree.ItemHasChildren(item):
   201             event.Skip()
   201             event.Skip()
   202         else:
   202         else:
   203             event.Veto()
   203             event.Veto()
   204     
   204 
   205     def OnTreeEndLabelEdit(self, event):
   205     def OnTreeEndLabelEdit(self, event):
   206         new_name = event.GetLabel()
   206         new_name = event.GetLabel()
   207         if new_name != "":
   207         if new_name != "":
   208             old_filepath = self.GetPath(event.GetItem())
   208             old_filepath = self.GetPath(event.GetItem())
   209             new_filepath = os.path.join(os.path.split(old_filepath)[0], new_name)
   209             new_filepath = os.path.join(os.path.split(old_filepath)[0], new_name)
   210             if new_filepath != old_filepath:
   210             if new_filepath != old_filepath:
   211                 if not os.path.exists(new_filepath):
   211                 if not os.path.exists(new_filepath):
   212                     os.rename(old_filepath, new_filepath)
   212                     os.rename(old_filepath, new_filepath)
   213                     event.Skip()
   213                     event.Skip()
   214                 else:
   214                 else:
   215                     message =  wx.MessageDialog(self, 
   215                     message =  wx.MessageDialog(self,
   216                         _("File '%s' already exists!") % new_name, 
   216                         _("File '%s' already exists!") % new_name,
   217                         _("Error"), wx.OK|wx.ICON_ERROR)
   217                         _("Error"), wx.OK|wx.ICON_ERROR)
   218                     message.ShowModal()
   218                     message.ShowModal()
   219                     message.Destroy()
   219                     message.Destroy()
   220                     event.Veto()
   220                     event.Veto()
   221         else:
   221         else:
   222             event.Skip()
   222             event.Skip()
   223     
   223 
   224     def OnFilterChanged(self, event):
   224     def OnFilterChanged(self, event):
   225         self.CurrentFilter = self.Filters[self.Filter.GetStringSelection()]
   225         self.CurrentFilter = self.Filters[self.Filter.GetStringSelection()]
   226         self.RefreshTree()
   226         self.RefreshTree()
   227         event.Skip()
   227         event.Skip()
   228     
   228 
   229     def _SelectItem(self, root, parts):
   229     def _SelectItem(self, root, parts):
   230         if len(parts) == 0:
   230         if len(parts) == 0:
   231             self.Tree.SelectItem(root)
   231             self.Tree.SelectItem(root)
   232         else:
   232         else:
   233             item, item_cookie = self.Tree.GetFirstChild(root)
   233             item, item_cookie = self.Tree.GetFirstChild(root)
   234             while item.IsOk():
   234             while item.IsOk():
   235                 if self.Tree.GetItemText(item) == parts[0]:
   235                 if self.Tree.GetItemText(item) == parts[0]:
   236                     if (self.Tree.ItemHasChildren(item) and 
   236                     if (self.Tree.ItemHasChildren(item) and
   237                         not self.Tree.IsExpanded(item)):
   237                         not self.Tree.IsExpanded(item)):
   238                         self.Tree.Expand(item)
   238                         self.Tree.Expand(item)
   239                         wx.CallAfter(self._SelectItem, item, parts[1:])
   239                         wx.CallAfter(self._SelectItem, item, parts[1:])
   240                     else:
   240                     else:
   241                         self._SelectItem(item, parts[1:])
   241                         self._SelectItem(item, parts[1:])
   242                     return
   242                     return
   243                 item, item_cookie = self.Tree.GetNextChild(root, item_cookie)
   243                 item, item_cookie = self.Tree.GetNextChild(root, item_cookie)
   244     
   244 
   245     def SetPath(self, path):
   245     def SetPath(self, path):
   246         if path.startswith(self.Folder):
   246         if path.startswith(self.Folder):
   247             root = self.Tree.GetRootItem()
   247             root = self.Tree.GetRootItem()
   248             if root.IsOk():
   248             if root.IsOk():
   249                 relative_path = path.replace(os.path.join(self.Folder, ""), "")
   249                 relative_path = path.replace(os.path.join(self.Folder, ""), "")
   250                 self._SelectItem(root, splitpath(relative_path))
   250                 self._SelectItem(root, splitpath(relative_path))
   251     
   251 
   252     def GetPath(self, item=None):
   252     def GetPath(self, item=None):
   253         if item is None:
   253         if item is None:
   254             item = self.Tree.GetSelection()
   254             item = self.Tree.GetSelection()
   255         if item.IsOk():
   255         if item.IsOk():
   256             filepath = self.Tree.GetItemText(item)
   256             filepath = self.Tree.GetItemText(item)