# HG changeset patch # User Goffi # Date 1281964260 -28800 # Node ID d6c0c5dca9b9ce9c6556c363514955c750e653b9 # Parent bd24f2aed80c52bacb135ed1dd7cf93a0887d8b3 Primitivus: new FileDialog Advanced file choosing dialog with: - path understanding when removing part with C-w - completion - listing of GTK & KDE's bookmarks - selection of file by typing the first letters of the name diff -r bd24f2aed80c -r d6c0c5dca9b9 frontends/primitivus/files_management.py --- a/frontends/primitivus/files_management.py Mon Aug 16 21:08:19 2010 +0800 +++ b/frontends/primitivus/files_management.py Mon Aug 16 21:11:00 2010 +0800 @@ -25,11 +25,17 @@ import os, os.path from xml.dom import minidom from logging import debug, info, error +from time import time class PathEdit(custom_widgets.AdvancedEdit): + """AdvancedEdit with manage file paths""" def keypress(self, size, key): - if key == 'ctrl w': + if key == '~' and self.edit_pos==0: + expanded = os.path.expanduser('~') + self.set_edit_text(os.path.normpath(expanded+'/'+self.edit_text)) + self.set_edit_pos(len(expanded)+1) + elif key == 'ctrl w': if self.edit_pos<2: return before = self.edit_text[:self.edit_pos] @@ -40,11 +46,96 @@ else: return super(PathEdit, self).keypress(size, key) +class FilesViewer(urwid.WidgetWrap): + """List specialised for files""" + + def __init__(self, onPreviousDir, onDirClick, onFileClick): + self.path='' + self.key_cache = '' + self.key_time = time() + self.onPreviousDir = onPreviousDir + self.onDirClick = onDirClick + self.onFileClick = onFileClick + self.files_list = urwid.SimpleListWalker([]) + self.show_hidden = True + listbox = urwid.ListBox(self.files_list) + urwid.WidgetWrap.__init__(self, listbox) + + def keypress(self, size, key): + if key=='meta h': + #(un)hide hidden files + self.show_hidden = not self.show_hidden + self.showDirectory(self.path) + if key=='meta d': + #jump to directories + if self.files_list: + self._w.set_focus(0) + elif key=='meta f': + for idx in range(len(self.files_list)): + if isinstance(self.files_list[idx].base_widget,urwid.Divider): + if idx 2: + self.key_cache=key + else: + self.key_cache+=key + self.key_time = time() + for idx in range(len(self.files_list)): + if isinstance(self.files_list[idx],custom_widgets.ClickableText) and self.files_list[idx].get_text().lower().startswith(self.key_cache.lower()): + self._w.set_focus(idx) + break + else: + return self._w.keypress(size, key) + + def showDirectory(self, path): + self.path = path + del self.files_list[:] + directories = [] + files = [] + try: + for filename in os.listdir(path): + fullpath = os.path.join(path,filename) + if os.path.isdir(fullpath): + directories.append(filename) + else: + files.append(filename) + except OSError: + self.files_list.append(urwid.Text(("warning",_("Impossible to list directory")),'center')) + directories.sort() + files.sort() + if os.path.abspath(path)!='/' and os.path.abspath(path) != '//': + previous_wid = custom_widgets.ClickableText('..',default_attr='directory') + urwid.connect_signal(previous_wid,'click',self.onPreviousDir) + self.files_list.append(previous_wid) + for directory in directories: + if directory.startswith('.') and not self.show_hidden: + continue + dir_wid = custom_widgets.ClickableText(directory,default_attr='directory') + urwid.connect_signal(dir_wid,'click',self.onDirClick) + self.files_list.append(dir_wid) + self.files_list.append(urwid.AttrMap(urwid.Divider('-'),'separator')) + for filename in files: + if filename.startswith('.') and not self.show_hidden: + continue + file_wid = custom_widgets.ClickableText(filename) + urwid.connect_signal(file_wid,'click',self.onFileClick) + self.files_list.append(file_wid) + + + class FileDialog(urwid.WidgetWrap): - def __init__(self,title=_("Please select a file")): + def __init__(self, ok_cb, cancel_cb, title=_("Please select a file"), style=[]): + """Create file dialog + @param title: title of the window/popup + @param style: NOT USED YET #FIXME + """ + self.ok_cb = ok_cb self.__home_path = os.path.expanduser('~') - self.path_wid = PathEdit(_('Path: '), os.getcwdu()) + self.path_wid = PathEdit(_('Path: ')) + self.path_wid.setCompletionMethod(self._directory_completion) urwid.connect_signal(self.path_wid, 'change', self.onPathChange) header = urwid.Pile([self.path_wid, urwid.Divider(u'─')]) bookm_list = urwid.SimpleListWalker([]) @@ -57,30 +148,60 @@ urwid.connect_signal(book_wid, 'click', self.onBookmarkSelected) bookm_list.append(book_wid) bookm_wid = urwid.Frame(urwid.ListBox(bookm_list), urwid.AttrMap(urwid.Text(_('Bookmarks'),'center'),'title')) - self.files_list = urwid.SimpleListWalker([urwid.Text('toto.mkv')]) - files_wid = urwid.ListBox(self.files_list) + self.files_wid = FilesViewer(self.onPreviousDir, self.onDirClick, self.onFileClick) center_row = urwid.Columns([('weight',2,bookm_wid), - ('weight',8,custom_widgets.VerticalSeparator(files_wid))]) - main_frame = custom_widgets.FocusFrame(center_row, header) + ('weight',8,custom_widgets.VerticalSeparator(self.files_wid))]) + + buttons = [] + buttons.append(custom_widgets.CustomButton(_('Cancel'),cancel_cb)) + max_len = max([button.getSize() for button in buttons]) + buttons_wid = urwid.GridFlow(buttons,max_len,1,0,'center') + main_frame = custom_widgets.FocusFrame(center_row, header, buttons_wid) decorated = custom_widgets.LabelLine(main_frame, custom_widgets.SurroundedText(title)) urwid.WidgetWrap.__init__(self, decorated) + self.path_wid.set_edit_text(os.getcwdu()) + + def _directory_completion(self, path, completion_data): + path=os.path.abspath(path) + if not os.path.isdir(path): + head,dir_start = os.path.split(path) + else: + head=path + dir_start='' + try: + filenames = os.listdir(head) + filenames.sort() + try: + start_idx=filenames.index(completion_data['last_dir'])+1 + if start_idx == len(filenames): + start_idx = 0 + except (KeyError,ValueError): + start_idx = 0 + for idx in range(start_idx,len(filenames)) + range(0,start_idx): + full_path = os.path.join(head,filenames[idx]) + if filenames[idx].lower().startswith(dir_start.lower()) and os.path.isdir(full_path): + completion_data['last_dir'] = filenames[idx] + return full_path + except OSError: + pass + return path def getBookmarks(self): - gnome_bookm = os.path.expanduser("~/.gtk-bookmarks") - kde_bookm = os.path.expanduser("~/.kde/share/apps/kfileplaces/bookmarks.xm") + gtk_bookm = os.path.expanduser("~/.gtk-bookmarks") + kde_bookm = os.path.expanduser("~/.kde/share/apps/kfileplaces/bookmarks.xml") bookmarks = set() try: - with open(gnome_bookm) as gnome_fd: - for bm in gnome_fd.readlines(): + with open(gtk_bookm) as gtk_fd: + for bm in gtk_fd.readlines(): if bm.startswith("file:///"): bookmarks.add(bm[7:].replace('\n','')) except IOError: - info(_('No Gnome bookmarks file found')) + info(_('No GTK bookmarks file found')) pass try: dom = minidom.parse(kde_bookm) - for elem in getElementsByTagName('bookmark'): + for elem in dom.getElementsByTagName('bookmark'): bm = elem.getAttribute("href") if bm.startswith("file:///"): bookmarks.add(bm[7:]) @@ -93,9 +214,21 @@ def onBookmarkSelected(self, button): self.path_wid.set_edit_text(os.path.expanduser(button.get_text())) - def onPathChange(self, edit, text): - if os.path.isdir(text): - del self.files_list[:] - files = os.listdir(text) - files.sort() - self.files_list.extend([custom_widgets.ClickableText(filename) for filename in files]) + def onPathChange(self, edit, path): + if os.path.isdir(path): + self.files_wid.showDirectory(path) + + def onPreviousDir(self, wid): + path = os.path.abspath(self.path_wid.get_edit_text()) + if not os.path.isdir(path): + path = dirname(path) + self.path_wid.set_edit_text(os.path.split(path)[0]) + + def onDirClick(self, wid): + path = os.path.abspath(self.path_wid.get_edit_text()) + if not os.path.isdir(path): + path = dirname(path) + self.path_wid.set_edit_text(os.path.join(path,wid.get_text())) + + def onFileClick(self, wid): + self.ok_cb(os.path.abspath(os.path.join(self.files_wid.path,wid.get_text())))