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
This commit is contained in:
parent
0974b10241
commit
663851e2c4
1 changed files with 152 additions and 19 deletions
|
|
@ -25,11 +25,17 @@ from tools.jid import JID
|
|||
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 @@ class PathEdit(custom_widgets.AdvancedEdit):
|
|||
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<len(self.files_list)-1:
|
||||
self._w.set_focus(idx+1)
|
||||
break
|
||||
elif len(key) == 1:
|
||||
if time() - self.key_time > 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 @@ class FileDialog(urwid.WidgetWrap):
|
|||
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 @@ class FileDialog(urwid.WidgetWrap):
|
|||
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())))
|
||||
|
|
|
|||
Loading…
Reference in a new issue