Mercurial > urwid-satext
annotate urwid_satext/files_management.py @ 105:20be00928875
Lower default setuptools version
From 0d607b6ed49eab758fd9b272e148f032e65fb2e2 Mon Sep 17 00:00:00 2001
python-setuptools 5.7 is not yet in Debian, so we need to set the
default version to 5.5 (the current version in sid) to avoid the newer
version to be downloaded from pypi.
author | Matteo Cypriani <mcy@lm7.fr> |
---|---|
date | Tue, 09 Sep 2014 22:09:51 -0400 |
parents | 900014ae36b8 |
children | 5bb3b7e25bf6 |
rev | line source |
---|---|
21 | 1 #!/usr/bin/python |
2 # -*- coding: utf-8 -*- | |
3 | |
64 | 4 # Urwid SàT extensions |
71 | 5 # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org) |
64 | 6 # |
7 # This program is free software: you can redistribute it and/or modify | |
8 # it under the terms of the GNU Lesser General Public License as published by | |
9 # the Free Software Foundation, either version 3 of the License, or | |
10 # (at your option) any later version. | |
11 # | |
12 # This program is distributed in the hope that it will be useful, | |
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 # GNU Lesser General Public License for more details. | |
16 # | |
17 # You should have received a copy of the GNU Lesser General Public License | |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
21 | 19 |
20 import urwid | |
30
1aeb3540aa49
files reorganisation after project separation. new README, and COPYING files
Goffi <goffi@goffi.org>
parents:
26
diff
changeset
|
21 import sat_widgets |
21 | 22 import os, os.path |
23 from xml.dom import minidom | |
24 from logging import debug, info, error | |
23 | 25 from time import time |
92
fdd0543677d4
use of new keys module in files_management
Goffi <goffi@goffi.org>
parents:
71
diff
changeset
|
26 from .keys import action_key_map as a_key |
34
875ff127b2dd
- i18n management: gettext integration + french translation
Goffi <goffi@goffi.org>
parents:
32
diff
changeset
|
27 |
875ff127b2dd
- i18n management: gettext integration + french translation
Goffi <goffi@goffi.org>
parents:
32
diff
changeset
|
28 import gettext |
875ff127b2dd
- i18n management: gettext integration + french translation
Goffi <goffi@goffi.org>
parents:
32
diff
changeset
|
29 gettext.install('urwid_satext', unicode=True) |
21 | 30 |
30
1aeb3540aa49
files reorganisation after project separation. new README, and COPYING files
Goffi <goffi@goffi.org>
parents:
26
diff
changeset
|
31 class PathEdit(sat_widgets.AdvancedEdit): |
23 | 32 """AdvancedEdit with manage file paths""" |
66 | 33 |
21 | 34 def keypress(self, size, key): |
23 | 35 if key == '~' and self.edit_pos==0: |
36 expanded = os.path.expanduser('~') | |
37 self.set_edit_text(os.path.normpath(expanded+'/'+self.edit_text)) | |
38 self.set_edit_pos(len(expanded)+1) | |
92
fdd0543677d4
use of new keys module in files_management
Goffi <goffi@goffi.org>
parents:
71
diff
changeset
|
39 elif key == a_key['EDIT_DELETE_LAST_WORD']: |
21 | 40 if self.edit_pos<2: |
41 return | |
42 before = self.edit_text[:self.edit_pos] | |
43 pos = (before[:-1] if before.endswith('/') else before).rfind("/")+1 | |
44 self.set_edit_text(before[:pos] + self.edit_text[self.edit_pos:]) | |
45 self.set_edit_pos(pos) | |
46 return | |
47 else: | |
66 | 48 return super(PathEdit, self).keypress(size, key) |
21 | 49 |
23 | 50 class FilesViewer(urwid.WidgetWrap): |
51 """List specialised for files""" | |
52 | |
58
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
53 def __init__(self, onPreviousDir, onDirClick, onFileClick = None): |
23 | 54 self.path='' |
55 self.key_cache = '' | |
56 self.key_time = time() | |
57 self.onPreviousDir = onPreviousDir | |
58 self.onDirClick = onDirClick | |
59 self.onFileClick = onFileClick | |
60 self.files_list = urwid.SimpleListWalker([]) | |
66 | 61 self.show_hidden = True |
23 | 62 listbox = urwid.ListBox(self.files_list) |
63 urwid.WidgetWrap.__init__(self, listbox) | |
64 | |
65 def keypress(self, size, key): | |
92
fdd0543677d4
use of new keys module in files_management
Goffi <goffi@goffi.org>
parents:
71
diff
changeset
|
66 if key==a_key['FILES_HIDDEN_HIDE']: |
23 | 67 #(un)hide hidden files |
68 self.show_hidden = not self.show_hidden | |
69 self.showDirectory(self.path) | |
92
fdd0543677d4
use of new keys module in files_management
Goffi <goffi@goffi.org>
parents:
71
diff
changeset
|
70 elif key==a_key['FILES_JUMP_DIRECTORIES']: |
23 | 71 #jump to directories |
72 if self.files_list: | |
73 self._w.set_focus(0) | |
92
fdd0543677d4
use of new keys module in files_management
Goffi <goffi@goffi.org>
parents:
71
diff
changeset
|
74 elif key==a_key['FILES_JUMP_FILES']: |
23 | 75 for idx in range(len(self.files_list)): |
76 if isinstance(self.files_list[idx].base_widget,urwid.Divider): | |
77 if idx<len(self.files_list)-1: | |
78 self._w.set_focus(idx+1) | |
79 break | |
80 elif len(key) == 1: | |
81 if time() - self.key_time > 2: | |
82 self.key_cache=key | |
83 else: | |
84 self.key_cache+=key | |
85 self.key_time = time() | |
86 for idx in range(len(self.files_list)): | |
30
1aeb3540aa49
files reorganisation after project separation. new README, and COPYING files
Goffi <goffi@goffi.org>
parents:
26
diff
changeset
|
87 if isinstance(self.files_list[idx],sat_widgets.ClickableText) and self.files_list[idx].get_text().lower().startswith(self.key_cache.lower()): |
23 | 88 self._w.set_focus(idx) |
89 break | |
90 else: | |
91 return self._w.keypress(size, key) | |
92 | |
93 def showDirectory(self, path): | |
93
900014ae36b8
fixed unicode issue invalid method call in files_management
Goffi <goffi@goffi.org>
parents:
92
diff
changeset
|
94 path = path.encode('utf-8') |
23 | 95 self.path = path |
96 del self.files_list[:] | |
97 directories = [] | |
98 files = [] | |
99 try: | |
100 for filename in os.listdir(path): | |
101 fullpath = os.path.join(path,filename) | |
102 if os.path.isdir(fullpath): | |
103 directories.append(filename) | |
104 else: | |
105 files.append(filename) | |
106 except OSError: | |
66 | 107 self.files_list.append(urwid.Text(("warning",_("Impossible to list directory")),'center')) |
23 | 108 directories.sort() |
109 files.sort() | |
110 if os.path.abspath(path)!='/' and os.path.abspath(path) != '//': | |
30
1aeb3540aa49
files reorganisation after project separation. new README, and COPYING files
Goffi <goffi@goffi.org>
parents:
26
diff
changeset
|
111 previous_wid = sat_widgets.ClickableText(('directory','..')) |
23 | 112 urwid.connect_signal(previous_wid,'click',self.onPreviousDir) |
113 self.files_list.append(previous_wid) | |
114 for directory in directories: | |
115 if directory.startswith('.') and not self.show_hidden: | |
116 continue | |
30
1aeb3540aa49
files reorganisation after project separation. new README, and COPYING files
Goffi <goffi@goffi.org>
parents:
26
diff
changeset
|
117 dir_wid = sat_widgets.ClickableText(('directory',directory)) |
23 | 118 urwid.connect_signal(dir_wid,'click',self.onDirClick) |
119 self.files_list.append(dir_wid) | |
120 self.files_list.append(urwid.AttrMap(urwid.Divider('-'),'separator')) | |
121 for filename in files: | |
122 if filename.startswith('.') and not self.show_hidden: | |
123 continue | |
30
1aeb3540aa49
files reorganisation after project separation. new README, and COPYING files
Goffi <goffi@goffi.org>
parents:
26
diff
changeset
|
124 file_wid = sat_widgets.ClickableText(filename) |
58
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
125 if self.onFileClick: |
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
126 urwid.connect_signal(file_wid,'click',self.onFileClick) |
23 | 127 self.files_list.append(file_wid) |
128 | |
129 | |
130 | |
21 | 131 class FileDialog(urwid.WidgetWrap): |
132 | |
23 | 133 def __init__(self, ok_cb, cancel_cb, title=_("Please select a file"), style=[]): |
134 """Create file dialog | |
135 @param title: title of the window/popup | |
58
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
136 @param style: list of string: |
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
137 - 'dir' if a dir path must be selected |
23 | 138 """ |
139 self.ok_cb = ok_cb | |
58
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
140 self._type = 'dir' if 'dir' in style else 'normal' |
21 | 141 self.__home_path = os.path.expanduser('~') |
23 | 142 self.path_wid = PathEdit(_('Path: ')) |
143 self.path_wid.setCompletionMethod(self._directory_completion) | |
21 | 144 urwid.connect_signal(self.path_wid, 'change', self.onPathChange) |
145 header = urwid.Pile([self.path_wid, urwid.Divider(u'─')]) | |
146 bookm_list = urwid.SimpleListWalker([]) | |
147 self.bookmarks = list(self.getBookmarks()) | |
148 self.bookmarks.sort() | |
149 for bookmark in self.bookmarks: | |
150 if bookmark.startswith(self.__home_path): | |
151 bookmark="~"+bookmark[len(self.__home_path):] | |
30
1aeb3540aa49
files reorganisation after project separation. new README, and COPYING files
Goffi <goffi@goffi.org>
parents:
26
diff
changeset
|
152 book_wid = sat_widgets.ClickableText(bookmark) |
21 | 153 urwid.connect_signal(book_wid, 'click', self.onBookmarkSelected) |
154 bookm_list.append(book_wid) | |
155 bookm_wid = urwid.Frame(urwid.ListBox(bookm_list), urwid.AttrMap(urwid.Text(_('Bookmarks'),'center'),'title')) | |
58
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
156 self.files_wid = FilesViewer(self.onPreviousDir, self.onDirClick, self.onFileClick if self._type == 'normal' else None) |
21 | 157 center_row = urwid.Columns([('weight',2,bookm_wid), |
30
1aeb3540aa49
files reorganisation after project separation. new README, and COPYING files
Goffi <goffi@goffi.org>
parents:
26
diff
changeset
|
158 ('weight',8,sat_widgets.VerticalSeparator(self.files_wid))]) |
23 | 159 |
160 buttons = [] | |
58
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
161 if self._type == 'dir': |
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
162 buttons.append(sat_widgets.CustomButton(_('Ok'), self._validateDir)) |
30
1aeb3540aa49
files reorganisation after project separation. new README, and COPYING files
Goffi <goffi@goffi.org>
parents:
26
diff
changeset
|
163 buttons.append(sat_widgets.CustomButton(_('Cancel'),cancel_cb)) |
23 | 164 max_len = max([button.getSize() for button in buttons]) |
165 buttons_wid = urwid.GridFlow(buttons,max_len,1,0,'center') | |
30
1aeb3540aa49
files reorganisation after project separation. new README, and COPYING files
Goffi <goffi@goffi.org>
parents:
26
diff
changeset
|
166 main_frame = sat_widgets.FocusFrame(center_row, header, buttons_wid) |
1aeb3540aa49
files reorganisation after project separation. new README, and COPYING files
Goffi <goffi@goffi.org>
parents:
26
diff
changeset
|
167 decorated = sat_widgets.LabelLine(main_frame, sat_widgets.SurroundedText(title)) |
21 | 168 urwid.WidgetWrap.__init__(self, decorated) |
23 | 169 self.path_wid.set_edit_text(os.getcwdu()) |
170 | |
58
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
171 def _validateDir(self, wid): |
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
172 """ call ok callback if current path is a dir """ |
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
173 path = os.path.abspath(self.path_wid.get_edit_text()) |
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
174 if os.path.isdir(path): |
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
175 self.ok_cb(path) |
7155b81ffdd5
new 'dir' style in FileDialog (get a dir path instead of a file
Goffi <goffi@goffi.org>
parents:
34
diff
changeset
|
176 |
23 | 177 def _directory_completion(self, path, completion_data): |
178 path=os.path.abspath(path) | |
179 if not os.path.isdir(path): | |
180 head,dir_start = os.path.split(path) | |
181 else: | |
182 head=path | |
183 dir_start='' | |
184 try: | |
185 filenames = os.listdir(head) | |
186 filenames.sort() | |
187 try: | |
188 start_idx=filenames.index(completion_data['last_dir'])+1 | |
189 if start_idx == len(filenames): | |
190 start_idx = 0 | |
191 except (KeyError,ValueError): | |
192 start_idx = 0 | |
193 for idx in range(start_idx,len(filenames)) + range(0,start_idx): | |
194 full_path = os.path.join(head,filenames[idx]) | |
195 if filenames[idx].lower().startswith(dir_start.lower()) and os.path.isdir(full_path): | |
196 completion_data['last_dir'] = filenames[idx] | |
66 | 197 return full_path |
23 | 198 except OSError: |
199 pass | |
200 return path | |
21 | 201 |
202 def getBookmarks(self): | |
23 | 203 gtk_bookm = os.path.expanduser("~/.gtk-bookmarks") |
204 kde_bookm = os.path.expanduser("~/.kde/share/apps/kfileplaces/bookmarks.xml") | |
21 | 205 bookmarks = set() |
206 try: | |
23 | 207 with open(gtk_bookm) as gtk_fd: |
208 for bm in gtk_fd.readlines(): | |
21 | 209 if bm.startswith("file:///"): |
210 bookmarks.add(bm[7:].replace('\n','')) | |
211 except IOError: | |
23 | 212 info(_('No GTK bookmarks file found')) |
21 | 213 pass |
66 | 214 |
21 | 215 try: |
216 dom = minidom.parse(kde_bookm) | |
23 | 217 for elem in dom.getElementsByTagName('bookmark'): |
21 | 218 bm = elem.getAttribute("href") |
219 if bm.startswith("file:///"): | |
220 bookmarks.add(bm[7:]) | |
221 except IOError: | |
222 info(_('No KDE bookmarks file found')) | |
223 pass | |
66 | 224 |
21 | 225 return bookmarks |
226 | |
227 def onBookmarkSelected(self, button): | |
228 self.path_wid.set_edit_text(os.path.expanduser(button.get_text())) | |
229 | |
23 | 230 def onPathChange(self, edit, path): |
231 if os.path.isdir(path): | |
232 self.files_wid.showDirectory(path) | |
233 | |
234 def onPreviousDir(self, wid): | |
235 path = os.path.abspath(self.path_wid.get_edit_text()) | |
236 if not os.path.isdir(path): | |
93
900014ae36b8
fixed unicode issue invalid method call in files_management
Goffi <goffi@goffi.org>
parents:
92
diff
changeset
|
237 path = os.path.dirname(path) |
23 | 238 self.path_wid.set_edit_text(os.path.split(path)[0]) |
239 | |
240 def onDirClick(self, wid): | |
241 path = os.path.abspath(self.path_wid.get_edit_text()) | |
242 if not os.path.isdir(path): | |
93
900014ae36b8
fixed unicode issue invalid method call in files_management
Goffi <goffi@goffi.org>
parents:
92
diff
changeset
|
243 path = os.path.dirname(path) |
23 | 244 self.path_wid.set_edit_text(os.path.join(path,wid.get_text())) |
66 | 245 |
23 | 246 def onFileClick(self, wid): |
247 self.ok_cb(os.path.abspath(os.path.join(self.files_wid.path,wid.get_text()))) |