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) |