3 # vim: sw=4 ts=4 expandtab ai
9 from os.path import join, abspath, normcase, basename, \
10 isdir, getsize, getatime, getmtime
11 from heapq import nlargest
16 try: import hildon; hildonFound = True
17 except: hildonFound = False
20 # Подразумевается, что ru/LC_MESSAGES/program.mo находится в текущем каталоге (sys.path[0])
21 # Для стандартного /usr/share/locale писать gettext.translation('findit')
22 langRU = gettext.translation('findit', sys.path[0], languages=['ru'])
25 def _(text): return text
29 winType = hildon.Window
34 ### Common functions ###########################################################
36 # Функция которая возвращает строку из числа и единиц для столбца "Размер"("Size")
37 def size_convert(size):
38 for i, unit in enumerate(['%d b', '%.1f Kb', '%.2f Mb', '%.3f Gb', '%.4f Tb']):
39 if size < 1024**(i+1):
40 return unit % (size/1024.**i)
43 # Функция поставляющая размер файла и путь к нему
44 def filegetter(startpath, obj):
45 # Список игнорируемых каталогов:
46 ignore_dirs = ['/dev', '/proc', '/sys', '/mnt']
47 # Проходим по всем папкам вглубь от заданного пути
48 for dirpath, dirnames, fnames in walk(startpath):
49 # Исключаем каталоги из поиска в соответствии со списком исключений
50 for ign_dir in ignore_dirs[:]:
51 for dirname in dirnames[:]:
52 if ign_dir == normcase(join(abspath(dirpath), dirname)):
53 dirnames.remove(dirname)
54 ignore_dirs.remove(ign_dir)
57 flpath = abspath(join(dirpath, fname))
58 # Выводим текущий опрашиваемый файл в строку статуса
59 obj.currFileLbl.set_text(flpath)
62 # Останавливаем цикл по нажатию кнопки стоп
66 # Проверяем можем ли мы определить размер файла - иначе пропускаем его
67 try: flsize = getsize(flpath)
69 # Возвращаем размер и полный путь файла
73 def toggle_fullscreen(obj):
75 obj.window.unfullscreen()
76 else: obj.window.fullscreen()
77 obj.fullscreen = not obj.fullscreen
79 # Нажатие на кнопку клавиатуры
80 def on_key_press(obj, event):
81 if hildonFound and event.keyval == gtk.keysyms.F6:
82 toggle_fullscreen(obj)
84 ### Properties dialog ##########################################################
86 class PropertiesDialog(gtk.Dialog):
87 def __init__(self, path, size, bytesize):
88 gtk.Dialog.__init__(self)
89 self.set_title( _('File properties') )
90 self.set_transient_for(app)
91 self.set_wmclass('PropertiesDialog', 'FindIT')
92 self.add_buttons(gtk.STOCK_OK, gtk.RESPONSE_OK)
93 self.set_resizable(False)
95 # Достаем свойства выбранного файла
97 access = time.strftime('%x %X', time.localtime(getatime(path)))
98 modified = time.strftime('%x %X', time.localtime(getmtime(path)))
102 table.set_border_width(10)
103 table.set_col_spacings(10)
104 table.set_row_spacings(10)
106 # Надписи (подпись: значение)
107 nameLbl = gtk.Label( _('Name') )
108 nameValueLbl = gtk.Label(name)
110 sizeLbl = gtk.Label( _('Size') )
111 sizeValueLbl = gtk.Label(size + ' (' + `bytesize` + ' b)')
113 accessLbl = gtk.Label( _('Opened') )
114 accessValueLbl = gtk.Label(access)
116 modifiedLbl = gtk.Label( _('Modified') )
117 modifiedValueLbl = gtk.Label(modified)
120 lbls = [(nameLbl, nameValueLbl), (sizeLbl, sizeValueLbl),
121 (accessLbl, accessValueLbl), (modifiedLbl, modifiedValueLbl)]
123 # Упаковка надписей в таблицу и выравнивание
124 for i, lbl in enumerate(lbls):
126 table.attach(name, 0, 1, i, i+1)
127 table.attach(value, 1, 2, i, i+1)
128 name.set_alignment(1, 0.5)
129 value.set_alignment(0, 0.5)
131 # Упаковка таблицы в vbox диалога
137 ### Main window ################################################################
139 class MainWindow(winType):
141 # Окно сообщения заданного типа с заданным текстом
142 def mess_window(self, mestype, content):
143 dialog = gtk.MessageDialog(parent=self, flags=gtk.DIALOG_MODAL,
144 type=mestype, buttons=gtk.BUTTONS_OK,
145 message_format=content)
146 dialog.set_wmclass('ErrorDialog', 'FindIT')
147 dialog.set_title( _('Error!') )
151 # Функция выполняющаяся при нажатии на кнопку "Показать"
152 def start_print(self, widget):
153 self.start_path = self.srch_p_entr.get_text()
154 # Проверяем правильное ли значение введено
155 if isdir(self.start_path):
156 self.butt_start.set_sensitive(False)
157 self.butt_stop.set_sensitive(True)
158 self.propertiesBtn.set_sensitive(False)
159 # Получаем значение количества файлов из SpinButton
160 self.fl_cnt = int( self.file_cnt.get_value() )
162 self.treestore.clear()
163 # Получаем нужное количество самых больших файлов
164 for fsize, fpath in nlargest(self.fl_cnt, filegetter(self.start_path, self)):
165 # Возвращаем значения в treeview в таком порядке - путь,
166 # размер в Мб строкой и размер в байтах
167 # self.treestore.append(None, [fpath.replace(self.start_path,'', 1),
168 # size_convert(fsize), fsize])
170 # Выдает какую-то перманентную ошибку при присвоении значений treestore -
171 # кто увидит скажите - нужна статистика
172 try: self.treestore.append(None, [fpath, size_convert(fsize), fsize])
173 except: 'error', fpath, size_convert(fsize), fsize
174 self.butt_start.set_sensitive(True)
175 self.butt_stop.set_sensitive(False)
176 self.propertiesBtn.set_sensitive(True)
178 # Иначе выводим окошко с ошибкой
179 self.mess_window('error', _('Invalid directory') )
181 # Функция выполняющаяся при нажатии на кнопку "Стоп"
182 def stop_print(self, widget):
185 # Функция выполняющаяся при нажатии на кнопку "Свойства файла"
186 def show_properties_dialog(self, btn):
187 selection = self.treeview.get_selection()
188 (model, it) = selection.get_selected()
190 path = model.get_value(it, 0)
191 size = model.get_value(it, 1)
192 bytesize = model.get_value(it, 2)
194 self.mess_window('error', _('Please select file') )
196 PropertiesDialog(path, size, bytesize)
198 ### Window initialization ##################################################
200 def __init__(self, win_width, win_height, st_path):
202 gtk.Window.__init__(self)
203 self.set_default_size(win_width, win_height)
204 self.set_border_width(4)
205 self.fullscreen = False
206 self.connect('delete_event', gtk.main_quit)
207 self.connect("key-press-event", on_key_press)
208 self.set_wmclass('MainWindow', 'FindIT')
210 ######### Добавляем элементы ################
211 # 1. Строка ввода каталога с которого начинать поиск
212 # переменная в которой храниться стартовый каталог = self.start_path
213 self.srch_p_entr = gtk.Entry()
214 self.start_path = st_path
215 self.srch_p_entr.set_text(self.start_path)
216 # Отключаем автокапитализацию(ввод первой буквы заглавной) на таблетке
218 self.srch_p_entr.set_property("hildon-input-mode", 'full')
219 # Нажатие Enter в поле ввода
220 self.srch_p_entr.connect("activate", self.start_print)
224 # 3. Надпись1 "Количество отображаемых файлов:"
225 label1 = gtk.Label( _('Files quantity') )
227 # 4. Окошко ввода количества файлов, мин значение=1 макс=65536 по умолчанию 10
228 # данные храняться в переменной self.fl_cnt
231 self.file_cnt = hildon.NumberEditor(1, 99)
232 self.file_cnt.set_value(self.fl_cnt)
234 adj = gtk.Adjustment(self.fl_cnt, 1, 65536, 1, 5, 0)
235 self.file_cnt = gtk.SpinButton(adj, 0, 0)
237 # 5.1 Кнопка "Показать"
238 self.butt_start = gtk.Button( _('Go') )
239 self.butt_start.connect('clicked', self.start_print)
241 # 5.2 Кнопка "Остановить"
242 self.butt_stop = gtk.Button( _('Stop') )
243 self.butt_stop.set_sensitive(False)
244 self.butt_stop.connect('clicked', self.stop_print)
247 # 5.3 Кнопка "Свойства файла"
248 self.propertiesBtn = gtk.Button( _('File properties') )
249 self.propertiesBtn.connect('clicked', self.show_properties_dialog)
250 self.propertiesBtn.set_sensitive(False)
255 scrollwind = gtk.ScrolledWindow()
256 scrollwind.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
258 # Определяем переменную в которой будет храниться выводимый список
259 self.treestore = gtk.TreeStore(str, str, int)
260 self.treeview = gtk.TreeView(self.treestore)
261 # На таблетке не отображаються заголовки столбцов по умолчанию -
262 # след строка заставляет их отображаться принудительно
263 self.treeview.set_headers_visible(1)
265 self.treestore.append(None, ['','', 0])
267 # Создаем и настраиваем колонку с размером файла
268 size_col = gtk.TreeViewColumn( _('Size') )
269 cell = gtk.CellRendererText()
270 cell.set_property('width', 90)
271 size_col.pack_start(cell, True)
272 size_col.add_attribute(cell, 'text', 1)
273 self.treeview.append_column(size_col)
274 # Создаем и настраиваем колонку с именем файла
275 path_col = gtk.TreeViewColumn( _('Path') )
276 cell2 = gtk.CellRendererText()
277 path_col.pack_start(cell2, True)
278 path_col.add_attribute(cell2, 'text', 0)
279 self.treeview.append_column(path_col)
281 # Добавляем сортировку для колонок
282 self.treeview.set_search_column(1)
283 path_col.set_sort_column_id(0)
284 size_col.set_sort_column_id(2)
286 # 6.2 Надпись "Найти"
288 # 6.3 Строка выводящая текущий осматриваемый файл
289 self.currFileLbl = gtk.Label()
290 self.currFileLbl.set_alignment(0, 0.5)
291 self.currFileLbl.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
293 ######### Упаковываем элементы ################
294 # Создаем основной вертикальный контейнер
295 main_Vbox = gtk.VBox(False, 4)
297 # Создаем вспомогательный горизонтальный контейнер для Надписи1,
298 # окошка ввода количества файлов и кнопки "Показать"
299 hbox1 = gtk.HBox(False, 5)
300 # Добавляем вышеперечисленные элементы во вспомогат. контейнер
301 hbox1.pack_start(label1, False, False, 5)
302 hbox1.pack_start(self.file_cnt, False, False, 0)
303 hbox1.pack_start(self.butt_start, True, True, 0)
304 hbox1.pack_start(self.butt_stop, True, True, 0)
305 hbox1.pack_start(self.propertiesBtn, True, True, 0)
307 # Добавляем элементы в основной контейнер
308 main_Vbox.pack_start(self.srch_p_entr, False, False, 0)
309 main_Vbox.pack_start(hbox1, False, False, 0)
310 scrollwind.add(self.treeview)
311 main_Vbox.pack_start(scrollwind, True, True, 0)
312 main_Vbox.pack_start(self.currFileLbl, False, False, 0)
322 ### Main call ##################################################################
324 if __name__ == '__main__':
325 # gobject.set_application_name( _('FindIT') )
326 app = MainWindow(575, 345, '.')