21
|
1 #!/usr/bin/python |
|
2 # -*- coding: utf-8 -*- |
|
3 |
|
4 """ |
|
5 Primitivus: a SAT frontend |
|
6 Copyright (C) 2009, 2010 Jérôme Poisson (goffi@goffi.org) |
|
7 |
|
8 This program is free software: you can redistribute it and/or modify |
|
9 it under the terms of the GNU General Public License as published by |
|
10 the Free Software Foundation, either version 3 of the License, or |
|
11 (at your option) any later version. |
|
12 |
|
13 This program is distributed in the hope that it will be useful, |
|
14 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
16 GNU General Public License for more details. |
|
17 |
|
18 You should have received a copy of the GNU General Public License |
|
19 along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
20 """ |
|
21 |
|
22 import urwid |
|
23 import custom_widgets |
|
24 from tools.jid import JID |
|
25 import os, os.path |
|
26 from xml.dom import minidom |
|
27 from logging import debug, info, error |
23
|
28 from time import time |
21
|
29 |
|
30 class PathEdit(custom_widgets.AdvancedEdit): |
23
|
31 """AdvancedEdit with manage file paths""" |
21
|
32 |
|
33 def keypress(self, size, key): |
23
|
34 if key == '~' and self.edit_pos==0: |
|
35 expanded = os.path.expanduser('~') |
|
36 self.set_edit_text(os.path.normpath(expanded+'/'+self.edit_text)) |
|
37 self.set_edit_pos(len(expanded)+1) |
|
38 elif key == 'ctrl w': |
21
|
39 if self.edit_pos<2: |
|
40 return |
|
41 before = self.edit_text[:self.edit_pos] |
|
42 pos = (before[:-1] if before.endswith('/') else before).rfind("/")+1 |
|
43 self.set_edit_text(before[:pos] + self.edit_text[self.edit_pos:]) |
|
44 self.set_edit_pos(pos) |
|
45 return |
|
46 else: |
|
47 return super(PathEdit, self).keypress(size, key) |
|
48 |
23
|
49 class FilesViewer(urwid.WidgetWrap): |
|
50 """List specialised for files""" |
|
51 |
|
52 def __init__(self, onPreviousDir, onDirClick, onFileClick): |
|
53 self.path='' |
|
54 self.key_cache = '' |
|
55 self.key_time = time() |
|
56 self.onPreviousDir = onPreviousDir |
|
57 self.onDirClick = onDirClick |
|
58 self.onFileClick = onFileClick |
|
59 self.files_list = urwid.SimpleListWalker([]) |
|
60 self.show_hidden = True |
|
61 listbox = urwid.ListBox(self.files_list) |
|
62 urwid.WidgetWrap.__init__(self, listbox) |
|
63 |
|
64 def keypress(self, size, key): |
|
65 if key=='meta h': |
|
66 #(un)hide hidden files |
|
67 self.show_hidden = not self.show_hidden |
|
68 self.showDirectory(self.path) |
|
69 if key=='meta d': |
|
70 #jump to directories |
|
71 if self.files_list: |
|
72 self._w.set_focus(0) |
|
73 elif key=='meta f': |
|
74 for idx in range(len(self.files_list)): |
|
75 if isinstance(self.files_list[idx].base_widget,urwid.Divider): |
|
76 if idx<len(self.files_list)-1: |
|
77 self._w.set_focus(idx+1) |
|
78 break |
|
79 elif len(key) == 1: |
|
80 if time() - self.key_time > 2: |
|
81 self.key_cache=key |
|
82 else: |
|
83 self.key_cache+=key |
|
84 self.key_time = time() |
|
85 for idx in range(len(self.files_list)): |
|
86 if isinstance(self.files_list[idx],custom_widgets.ClickableText) and self.files_list[idx].get_text().lower().startswith(self.key_cache.lower()): |
|
87 self._w.set_focus(idx) |
|
88 break |
|
89 else: |
|
90 return self._w.keypress(size, key) |
|
91 |
|
92 def showDirectory(self, path): |
|
93 self.path = path |
|
94 del self.files_list[:] |
|
95 directories = [] |
|
96 files = [] |
|
97 try: |
|
98 for filename in os.listdir(path): |
|
99 fullpath = os.path.join(path,filename) |
|
100 if os.path.isdir(fullpath): |
|
101 directories.append(filename) |
|
102 else: |
|
103 files.append(filename) |
|
104 except OSError: |
|
105 self.files_list.append(urwid.Text(("warning",_("Impossible to list directory")),'center')) |
|
106 directories.sort() |
|
107 files.sort() |
|
108 if os.path.abspath(path)!='/' and os.path.abspath(path) != '//': |
|
109 previous_wid = custom_widgets.ClickableText('..',default_attr='directory') |
|
110 urwid.connect_signal(previous_wid,'click',self.onPreviousDir) |
|
111 self.files_list.append(previous_wid) |
|
112 for directory in directories: |
|
113 if directory.startswith('.') and not self.show_hidden: |
|
114 continue |
|
115 dir_wid = custom_widgets.ClickableText(directory,default_attr='directory') |
|
116 urwid.connect_signal(dir_wid,'click',self.onDirClick) |
|
117 self.files_list.append(dir_wid) |
|
118 self.files_list.append(urwid.AttrMap(urwid.Divider('-'),'separator')) |
|
119 for filename in files: |
|
120 if filename.startswith('.') and not self.show_hidden: |
|
121 continue |
|
122 file_wid = custom_widgets.ClickableText(filename) |
|
123 urwid.connect_signal(file_wid,'click',self.onFileClick) |
|
124 self.files_list.append(file_wid) |
|
125 |
|
126 |
|
127 |
21
|
128 class FileDialog(urwid.WidgetWrap): |
|
129 |
23
|
130 def __init__(self, ok_cb, cancel_cb, title=_("Please select a file"), style=[]): |
|
131 """Create file dialog |
|
132 @param title: title of the window/popup |
|
133 @param style: NOT USED YET #FIXME |
|
134 """ |
|
135 self.ok_cb = ok_cb |
21
|
136 self.__home_path = os.path.expanduser('~') |
23
|
137 self.path_wid = PathEdit(_('Path: ')) |
|
138 self.path_wid.setCompletionMethod(self._directory_completion) |
21
|
139 urwid.connect_signal(self.path_wid, 'change', self.onPathChange) |
|
140 header = urwid.Pile([self.path_wid, urwid.Divider(u'─')]) |
|
141 bookm_list = urwid.SimpleListWalker([]) |
|
142 self.bookmarks = list(self.getBookmarks()) |
|
143 self.bookmarks.sort() |
|
144 for bookmark in self.bookmarks: |
|
145 if bookmark.startswith(self.__home_path): |
|
146 bookmark="~"+bookmark[len(self.__home_path):] |
|
147 book_wid = custom_widgets.ClickableText(bookmark) |
|
148 urwid.connect_signal(book_wid, 'click', self.onBookmarkSelected) |
|
149 bookm_list.append(book_wid) |
|
150 bookm_wid = urwid.Frame(urwid.ListBox(bookm_list), urwid.AttrMap(urwid.Text(_('Bookmarks'),'center'),'title')) |
23
|
151 self.files_wid = FilesViewer(self.onPreviousDir, self.onDirClick, self.onFileClick) |
21
|
152 center_row = urwid.Columns([('weight',2,bookm_wid), |
23
|
153 ('weight',8,custom_widgets.VerticalSeparator(self.files_wid))]) |
|
154 |
|
155 buttons = [] |
|
156 buttons.append(custom_widgets.CustomButton(_('Cancel'),cancel_cb)) |
|
157 max_len = max([button.getSize() for button in buttons]) |
|
158 buttons_wid = urwid.GridFlow(buttons,max_len,1,0,'center') |
|
159 main_frame = custom_widgets.FocusFrame(center_row, header, buttons_wid) |
21
|
160 decorated = custom_widgets.LabelLine(main_frame, custom_widgets.SurroundedText(title)) |
|
161 urwid.WidgetWrap.__init__(self, decorated) |
23
|
162 self.path_wid.set_edit_text(os.getcwdu()) |
|
163 |
|
164 def _directory_completion(self, path, completion_data): |
|
165 path=os.path.abspath(path) |
|
166 if not os.path.isdir(path): |
|
167 head,dir_start = os.path.split(path) |
|
168 else: |
|
169 head=path |
|
170 dir_start='' |
|
171 try: |
|
172 filenames = os.listdir(head) |
|
173 filenames.sort() |
|
174 try: |
|
175 start_idx=filenames.index(completion_data['last_dir'])+1 |
|
176 if start_idx == len(filenames): |
|
177 start_idx = 0 |
|
178 except (KeyError,ValueError): |
|
179 start_idx = 0 |
|
180 for idx in range(start_idx,len(filenames)) + range(0,start_idx): |
|
181 full_path = os.path.join(head,filenames[idx]) |
|
182 if filenames[idx].lower().startswith(dir_start.lower()) and os.path.isdir(full_path): |
|
183 completion_data['last_dir'] = filenames[idx] |
|
184 return full_path |
|
185 except OSError: |
|
186 pass |
|
187 return path |
21
|
188 |
|
189 def getBookmarks(self): |
23
|
190 gtk_bookm = os.path.expanduser("~/.gtk-bookmarks") |
|
191 kde_bookm = os.path.expanduser("~/.kde/share/apps/kfileplaces/bookmarks.xml") |
21
|
192 bookmarks = set() |
|
193 try: |
23
|
194 with open(gtk_bookm) as gtk_fd: |
|
195 for bm in gtk_fd.readlines(): |
21
|
196 if bm.startswith("file:///"): |
|
197 bookmarks.add(bm[7:].replace('\n','')) |
|
198 except IOError: |
23
|
199 info(_('No GTK bookmarks file found')) |
21
|
200 pass |
|
201 |
|
202 try: |
|
203 dom = minidom.parse(kde_bookm) |
23
|
204 for elem in dom.getElementsByTagName('bookmark'): |
21
|
205 bm = elem.getAttribute("href") |
|
206 if bm.startswith("file:///"): |
|
207 bookmarks.add(bm[7:]) |
|
208 except IOError: |
|
209 info(_('No KDE bookmarks file found')) |
|
210 pass |
|
211 |
|
212 return bookmarks |
|
213 |
|
214 def onBookmarkSelected(self, button): |
|
215 self.path_wid.set_edit_text(os.path.expanduser(button.get_text())) |
|
216 |
23
|
217 def onPathChange(self, edit, path): |
|
218 if os.path.isdir(path): |
|
219 self.files_wid.showDirectory(path) |
|
220 |
|
221 def onPreviousDir(self, wid): |
|
222 path = os.path.abspath(self.path_wid.get_edit_text()) |
|
223 if not os.path.isdir(path): |
|
224 path = dirname(path) |
|
225 self.path_wid.set_edit_text(os.path.split(path)[0]) |
|
226 |
|
227 def onDirClick(self, wid): |
|
228 path = os.path.abspath(self.path_wid.get_edit_text()) |
|
229 if not os.path.isdir(path): |
|
230 path = dirname(path) |
|
231 self.path_wid.set_edit_text(os.path.join(path,wid.get_text())) |
|
232 |
|
233 def onFileClick(self, wid): |
|
234 self.ok_cb(os.path.abspath(os.path.join(self.files_wid.path,wid.get_text()))) |