comparison urwid_satext/files_management.py @ 123:f2589475269f

file_management: unicode was badly handled. As a quick solution, we handle everything as unicode, and ignore badly encoded filenames, this may change in the future
author Goffi <goffi@goffi.org>
date Sat, 05 Mar 2016 14:32:35 +0100
parents 00b012549f88
children 1970df98643d
comparison
equal deleted inserted replaced
122:00b012549f88 123:f2589475269f
19 19
20 import urwid 20 import urwid
21 import sat_widgets 21 import sat_widgets
22 import os, os.path 22 import os, os.path
23 from xml.dom import minidom 23 from xml.dom import minidom
24 from logging import debug, info, error 24 import logging as log
25 from time import time 25 from time import time
26 from .keys import action_key_map as a_key 26 from .keys import action_key_map as a_key
27 27
28 import gettext 28 import gettext
29 gettext.install('urwid_satext', unicode=True) 29 gettext.install('urwid_satext', unicode=True)
30 30
31 class PathEdit(sat_widgets.AdvancedEdit): 31 class PathEdit(sat_widgets.AdvancedEdit):
32 """AdvancedEdit with manage file paths""" 32 """AdvancedEdit with manage file paths"""
33 33
34 def keypress(self, size, key): 34 def keypress(self, size, key):
35 if key == '~' and self.edit_pos==0: 35 if key == u'~' and self.edit_pos==0:
36 expanded = os.path.expanduser('~') 36 expanded = os.path.expanduser(u'~')
37 self.set_edit_text(os.path.normpath(expanded+'/'+self.edit_text)) 37 self.set_edit_text(os.path.normpath(expanded+u'/'+self.edit_text))
38 self.set_edit_pos(len(expanded)+1) 38 self.set_edit_pos(len(expanded)+1)
39 elif key == a_key['EDIT_DELETE_LAST_WORD']: 39 elif key == a_key['EDIT_DELETE_LAST_WORD']:
40 if self.edit_pos<2: 40 if self.edit_pos<2:
41 return 41 return
42 before = self.edit_text[:self.edit_pos] 42 before = self.edit_text[:self.edit_pos]
89 break 89 break
90 else: 90 else:
91 return self._w.keypress(size, key) 91 return self._w.keypress(size, key)
92 92
93 def showDirectory(self, path): 93 def showDirectory(self, path):
94 path = path.encode('utf-8')
95 self.path = path 94 self.path = path
96 del self.files_list[:] 95 del self.files_list[:]
97 directories = [] 96 directories = []
98 files = [] 97 files = []
99 try: 98 try:
100 for filename in os.listdir(path): 99 for filename in os.listdir(path):
100 if not isinstance(filename, unicode):
101 log.warning(u"file [{}] has a badly encode filename, ignoring it".format(filename.decode('utf-8', 'replace')))
102 continue
101 fullpath = os.path.join(path,filename) 103 fullpath = os.path.join(path,filename)
102 if os.path.isdir(fullpath): 104 if os.path.isdir(fullpath):
103 directories.append(filename) 105 directories.append(filename)
104 else: 106 else:
105 files.append(filename) 107 files.append(filename)
106 except OSError: 108 except OSError:
107 self.files_list.append(urwid.Text(("warning",_("Impossible to list directory")),'center')) 109 self.files_list.append(urwid.Text(("warning",_("Impossible to list directory")),'center'))
108 directories.sort() 110 directories.sort()
109 files.sort() 111 files.sort()
110 if os.path.abspath(path)!='/' and os.path.abspath(path) != '//': 112 if os.path.abspath(path)!=u'/' and os.path.abspath(path) != u'//':
111 previous_wid = sat_widgets.ClickableText(('directory','..')) 113 previous_wid = sat_widgets.ClickableText((u'directory',u'..'))
112 urwid.connect_signal(previous_wid,'click',self.onPreviousDir) 114 urwid.connect_signal(previous_wid,'click',self.onPreviousDir)
113 self.files_list.append(previous_wid) 115 self.files_list.append(previous_wid)
114 for directory in directories: 116 for directory in directories:
115 if directory.startswith('.') and not self.show_hidden: 117 if directory.startswith('.') and not self.show_hidden:
116 continue 118 continue
117 dir_wid = sat_widgets.ClickableText(('directory',directory)) 119 dir_wid = sat_widgets.ClickableText((u'directory',directory))
118 urwid.connect_signal(dir_wid,'click',self.onDirClick) 120 urwid.connect_signal(dir_wid,'click',self.onDirClick)
119 self.files_list.append(dir_wid) 121 self.files_list.append(dir_wid)
120 self.files_list.append(urwid.AttrMap(urwid.Divider('-'),'separator')) 122 self.files_list.append(urwid.AttrMap(urwid.Divider(u'-'),'separator'))
121 for filename in files: 123 for filename in files:
122 if filename.startswith('.') and not self.show_hidden: 124 if filename.startswith(u'.') and not self.show_hidden:
123 continue 125 continue
124 file_wid = sat_widgets.ClickableText(filename) 126 file_wid = sat_widgets.ClickableText(filename)
125 if self.onFileClick: 127 if self.onFileClick:
126 urwid.connect_signal(file_wid,'click',self.onFileClick) 128 urwid.connect_signal(file_wid,'click',self.onFileClick)
127 self.files_list.append(file_wid) 129 self.files_list.append(file_wid)
128
129 130
130 131
131 class FileDialog(urwid.WidgetWrap): 132 class FileDialog(urwid.WidgetWrap):
132 133
133 def __init__(self, ok_cb, cancel_cb, message=None, title=_("Please select a file"), style=[]): 134 def __init__(self, ok_cb, cancel_cb, message=None, title=_("Please select a file"), style=[]):
139 @param style: list of string: 140 @param style: list of string:
140 - 'dir' if a dir path must be selected 141 - 'dir' if a dir path must be selected
141 """ 142 """
142 self.ok_cb = ok_cb 143 self.ok_cb = ok_cb
143 self._type = 'dir' if 'dir' in style else 'normal' 144 self._type = 'dir' if 'dir' in style else 'normal'
144 self.__home_path = os.path.expanduser('~') 145 self.__home_path = os.path.expanduser(u'~')
145 widgets = [] 146 widgets = []
146 if message: 147 if message:
147 widgets.append(urwid.Text(message)) 148 widgets.append(urwid.Text(message))
148 widgets.append(urwid.Divider(u'─')) 149 widgets.append(urwid.Divider(u'─'))
149 self.path_wid = PathEdit(_('Path: ')) 150 self.path_wid = PathEdit(_(u'Path: '))
150 self.path_wid.setCompletionMethod(self._directory_completion) 151 self.path_wid.setCompletionMethod(self._directory_completion)
151 urwid.connect_signal(self.path_wid, 'change', self.onPathChange) 152 urwid.connect_signal(self.path_wid, 'change', self.onPathChange)
152 widgets.append(self.path_wid) 153 widgets.append(self.path_wid)
153 widgets.append(urwid.Divider(u'─')) 154 widgets.append(urwid.Divider(u'─'))
154 header = urwid.Pile(widgets) 155 header = urwid.Pile(widgets)
155 bookm_list = urwid.SimpleListWalker([]) 156 bookm_list = urwid.SimpleListWalker([])
156 self.bookmarks = list(self.getBookmarks()) 157 self.bookmarks = list(self.getBookmarks())
157 self.bookmarks.sort() 158 self.bookmarks.sort()
158 for bookmark in self.bookmarks: 159 for bookmark in self.bookmarks:
159 if bookmark.startswith(self.__home_path): 160 if bookmark.startswith(self.__home_path):
160 bookmark="~"+bookmark[len(self.__home_path):] 161 bookmark=u"~"+bookmark[len(self.__home_path):]
161 book_wid = sat_widgets.ClickableText(bookmark) 162 book_wid = sat_widgets.ClickableText(bookmark)
162 urwid.connect_signal(book_wid, 'click', self.onBookmarkSelected) 163 urwid.connect_signal(book_wid, 'click', self.onBookmarkSelected)
163 bookm_list.append(book_wid) 164 bookm_list.append(book_wid)
164 bookm_wid = urwid.Frame(urwid.ListBox(bookm_list), urwid.AttrMap(urwid.Text(_('Bookmarks'),'center'),'title')) 165 bookm_wid = urwid.Frame(urwid.ListBox(bookm_list), urwid.AttrMap(urwid.Text(_(u'Bookmarks'),'center'),'title'))
165 self.files_wid = FilesViewer(self.onPreviousDir, self.onDirClick, self.onFileClick if self._type == 'normal' else None) 166 self.files_wid = FilesViewer(self.onPreviousDir, self.onDirClick, self.onFileClick if self._type == 'normal' else None)
166 center_row = urwid.Columns([('weight',2,bookm_wid), 167 center_row = urwid.Columns([('weight',2,bookm_wid),
167 ('weight',8,sat_widgets.VerticalSeparator(self.files_wid))]) 168 ('weight',8,sat_widgets.VerticalSeparator(self.files_wid))])
168 169
169 buttons = [] 170 buttons = []
182 path = os.path.abspath(self.path_wid.get_edit_text()) 183 path = os.path.abspath(self.path_wid.get_edit_text())
183 if os.path.isdir(path): 184 if os.path.isdir(path):
184 self.ok_cb(path) 185 self.ok_cb(path)
185 186
186 def _directory_completion(self, path, completion_data): 187 def _directory_completion(self, path, completion_data):
188 assert isinstance(path, unicode)
187 path=os.path.abspath(path) 189 path=os.path.abspath(path)
188 if not os.path.isdir(path): 190 if not os.path.isdir(path):
189 head,dir_start = os.path.split(path) 191 head,dir_start = os.path.split(path)
190 else: 192 else:
191 head=path 193 head=path
192 dir_start='' 194 dir_start=u''
193 try: 195 try:
194 filenames = os.listdir(head) 196 filenames = os.listdir(head)
197 to_remove = []
198
199 # we remove badly encoded files
200 for filename in filenames:
201 if not isinstance(filename, unicode):
202 log.warning(u"file [{}] has a badly encode filename, ignoring it".format(filename.decode('utf-8', 'replace')))
203 to_remove.append(filename)
204 for filename in to_remove:
205 filenames.remove(filename)
206
195 filenames.sort() 207 filenames.sort()
196 try: 208 try:
197 start_idx=filenames.index(completion_data['last_dir'])+1 209 start_idx=filenames.index(completion_data['last_dir'])+1
198 if start_idx == len(filenames): 210 if start_idx == len(filenames):
199 start_idx = 0 211 start_idx = 0
207 except OSError: 219 except OSError:
208 pass 220 pass
209 return path 221 return path
210 222
211 def getBookmarks(self): 223 def getBookmarks(self):
212 gtk_bookm = os.path.expanduser("~/.gtk-bookmarks") 224 gtk_bookm = os.path.expanduser(u"~/.gtk-bookmarks")
213 kde_bookm = os.path.expanduser("~/.kde/share/apps/kfileplaces/bookmarks.xml") 225 kde_bookm = os.path.expanduser(u"~/.kde/share/apps/kfileplaces/bookmarks.xml")
214 bookmarks = set() 226 bookmarks = set()
215 try: 227 try:
216 with open(gtk_bookm) as gtk_fd: 228 with open(gtk_bookm) as gtk_fd:
217 for bm in gtk_fd.readlines(): 229 for bm in gtk_fd.readlines():
218 if bm.startswith("file:///"): 230 if bm.startswith("file:///"):
219 bookmarks.add(bm[7:].replace('\n','')) 231 bookmarks.add(bm[7:].replace('\n','').decode('utf-8', 'replace'))
220 except IOError: 232 except IOError:
221 info(_('No GTK bookmarks file found')) 233 log.info(_(u'No GTK bookmarks file found'))
222 pass 234 pass
223 235
224 try: 236 try:
225 dom = minidom.parse(kde_bookm) 237 dom = minidom.parse(kde_bookm)
226 for elem in dom.getElementsByTagName('bookmark'): 238 for elem in dom.getElementsByTagName('bookmark'):
227 bm = elem.getAttribute("href") 239 bm = elem.getAttribute("href")
228 if bm.startswith("file:///"): 240 if bm.startswith("file:///"):
229 bookmarks.add(bm[7:]) 241 bookmarks.add(bm[7:].decode('utf-8', 'replace'))
230 except IOError: 242 except IOError:
231 info(_('No KDE bookmarks file found')) 243 log.info(_('No KDE bookmarks file found'))
232 pass 244 pass
233 245
234 return bookmarks 246 return bookmarks
235 247
236 def onBookmarkSelected(self, button): 248 def onBookmarkSelected(self, button):