fixing conflict after merging
[findit] / src / findit.py
1 #!/usr/bin/env python
2 # -*-coding: utf-8 -*-
3 # vim: sw=4 ts=4 expandtab ai
4 # pylint: disable-msg=C0301
5
6 import gtk
7 import gobject
8 import pango
9 from os import walk
10 from os.path import join, abspath, normcase, basename, \
11                     isdir, getsize, getatime, getmtime, expanduser
12 from heapq import nlargest
13 import gettext
14 import time
15 from sys import platform
16
17 try: 
18 <<<<<<< HEAD:src/findit.py
19     import hildon; hildonFound = True
20 =======
21     import hildon
22     hildonFound = True
23 >>>>>>> master:src/findit.py
24 except ImportError:
25     hildonFound = False
26
27 try:
28     # Подразумевается, что ru/LC_MESSAGES/program.mo находится в текущем каталоге (sys.path[0])
29     # Для стандартного /usr/share/locale писать gettext.translation('findit')
30     #langRU = gettext.translation('findit', sys.path[0], languages=['ru'])
31     langRU = gettext.translation('findit')
32     langRU.install()
33 except IOError:
34     # Закомментировать перед использованием pygettext
35     def _(text): 
36         return text
37
38
39 ### Common functions ###########################################################
40
41 # Функция которая возвращает строку из числа и единиц для столбца "Размер"("Size")
42 def size_convert(size):
43     for i, unit in enumerate(['%d b', '%.1f Kb', '%.2f Mb', '%.3f Gb', '%.4f Tb']):
44         if size < 1024**(i+1):
45             return unit % (size/1024.**i)
46     return '>1024 Tb'
47
48 # Функция поставляющая размер файла и путь к нему
49 def filegetter(startdir, obj):
50     # Список игнорируемых каталогов:
51     ignore_dirs = ['/dev', '/proc', '/sys', '/mnt']
52     # Проходим по всем папкам вглубь от заданного пути
53     for dirpath, dirnames, fnames in walk(startdir):
54     # Исключаем каталоги из поиска в соответствии со списком исключений
55         for ign_dir in ignore_dirs[:]:
56             for dirname in dirnames[:]:
57                 if ign_dir == normcase(join(abspath(dirpath), dirname)):
58                     dirnames.remove(dirname)
59                     ignore_dirs.remove(ign_dir)
60
61         for fname in fnames:
62             flpath = abspath(join(dirpath, fname))
63             # Выводим текущий опрашиваемый файл в строку статуса
64             obj.currFileLbl.set_text(flpath)
65             # обновляем окно
66             gtk.main_iteration()
67             # Останавливаем цикл по нажатию кнопки стоп
68             if obj.stopit:
69                 obj.stopit = False
70                 raise StopIteration
71             # Проверяем можем ли мы определить размер файла - иначе пропускаем его
72             try:
73 <<<<<<< HEAD:src/findit.py
74                 flsize = getsize(flpath)
75 =======
76                 # Возвращаем размер и полный путь файла
77                 yield getsize(flpath), flpath
78 >>>>>>> master:src/findit.py
79             except OSError:
80                 continue
81
82 # Fullscreen
83 def toggle_fullscreen(obj):
84     if obj.fullscreen:
85         obj.window.unfullscreen()
86     else: 
87         obj.window.fullscreen()
88     obj.fullscreen = not obj.fullscreen
89
90 # Нажатие на кнопку клавиатуры
91 def on_key_press(obj, event):
92     if hildonFound and event.keyval == gtk.keysyms.F6:
93         toggle_fullscreen(obj)
94
95 ### Properties dialog ##########################################################
96
97 class PropertiesDialog(gtk.Dialog):
98     def __init__(self, path, size, bytesize):
99         gtk.Dialog.__init__(self)
100         self.set_title( _('File properties') )
101         self.set_transient_for(app)
102         self.set_wmclass('PropertiesDialog', 'FindIT')
103         self.add_buttons(gtk.STOCK_OK, gtk.RESPONSE_OK)
104         self.set_resizable(False)
105
106         # Достаем свойства выбранного файла
107         name = basename(path)
108         access = time.strftime('%x %X', time.localtime(getatime(path)))
109         modified = time.strftime('%x %X', time.localtime(getmtime(path)))
110
111         # Таблица надписей
112         table = gtk.Table()
113         table.set_border_width(10)
114         table.set_col_spacings(10)
115         table.set_row_spacings(10)
116
117         # Надписи (подпись: значение)
118         nameLbl = gtk.Label( _('Name') )
119         nameValueLbl = gtk.Label(name)
120
121         sizeLbl = gtk.Label( _('Size') )
122         sizeValueLbl = gtk.Label(size + ' (' + `bytesize` + ' b)')
123
124         accessLbl = gtk.Label( _('Opened') )
125         accessValueLbl = gtk.Label(access)
126
127         modifiedLbl = gtk.Label( _('Modified') )
128         modifiedValueLbl = gtk.Label(modified)
129
130         # Список надписей
131         lbls = [(nameLbl,   nameValueLbl),   (sizeLbl,     sizeValueLbl),
132                 (accessLbl, accessValueLbl), (modifiedLbl, modifiedValueLbl)]
133
134         # Упаковка надписей в таблицу и выравнивание
135         for i, lbl in enumerate(lbls):
136             name, value = lbl
137             table.attach(name, 0, 1, i, i+1)
138             table.attach(value, 1, 2, i, i+1)
139             name.set_alignment(1, 0.5)
140             value.set_alignment(0, 0.5)
141
142         # Упаковка таблицы в vbox диалога
143         self.vbox.add(table)
144         self.show_all()
145         self.run()
146         self.destroy()
147
148 ### Main window ################################################################
149
150 class MainWindow(gtk.Window):
151
152     # Окно сообщения заданного типа с заданным текстом
153     def mess_window(self, mestype, content):
154         dialog = gtk.MessageDialog(parent=self, flags=gtk.DIALOG_MODAL,
155                                    type=mestype, buttons=gtk.BUTTONS_OK,
156                                    message_format=content)
157         dialog.set_wmclass('ErrorDialog', 'FindIT')
158         dialog.set_title( _('Error!') )
159         dialog.run()
160         dialog.destroy()
161
162     # Функция выполняющаяся при нажатии на кнопку "Показать"
163     def start_print(self):
164         self.start_path = self.srch_p_entr.get_text()
165         # Проверяем правильное ли значение введено
166         if isdir(self.start_path):
167             self.butt_start.set_sensitive(False)
168             self.butt_stop.set_sensitive(True)
169             self.propertiesBtn.set_sensitive(False)
170             # Получаем значение количества файлов из SpinButton
171             self.fl_cnt = int( self.file_cnt.get_value() )
172             # Очищаем список
173             self.treestore.clear()
174             # Получаем нужное количество самых больших файлов
175             for fsize, fpath in nlargest(self.fl_cnt, filegetter(self.start_path, self)):
176                 # Возвращаем значения в treeview в таком порядке - путь,
177                 # размер в Мб строкой и размер в байтах
178                 # self.treestore.append(None, [fpath.replace(self.start_path,'', 1),
179                 #        size_convert(fsize), fsize])
180
181                 # Выдает какую-то перманентную ошибку при присвоении значений treestore -
182                 # кто увидит скажите - нужна статистика
183                 try: 
184                     self.treestore.append(None, [fpath, size_convert(fsize), fsize])
185                 except SystemError:
186 #                    print 'error', fpath, size_convert(fsize), fsize
187                     self.mess_window('error','Error in %s' % fpath)
188             self.butt_start.set_sensitive(True)
189             self.butt_stop.set_sensitive(False)
190             self.propertiesBtn.set_sensitive(True)
191             self.srch_p_entr.grab_focus()
192         else:
193             # Иначе выводим окошко с ошибкой
194             self.mess_window('error', _('Invalid directory') )
195
196     # Функция выполняющаяся при нажатии на кнопку "Стоп"
197     def stop_print(self):
198         self.stopit = True
199
200     # Функция выполняющаяся при нажатии на кнопку "Свойства файла"
201     def show_properties_dialog(self):
202         selection = self.treeview.get_selection()
203         (model, it) = selection.get_selected()
204         try:
205             path = model.get_value(it, 0)
206             size = model.get_value(it, 1)
207             bytesize = model.get_value(it, 2)
208         except (TypeError, ValueError):
209             self.mess_window('error', _('Please select file') )
210             return
211         PropertiesDialog(path, size, bytesize)
212
213     ### Window initialization ##################################################
214
215     def __init__(self, win_width, win_height, st_path):
216         # Создаем новое окно
217         gtk.Window.__init__(self)
218         self.set_default_size(win_width, win_height)
219         self.set_border_width(4)
220         self.fullscreen = False
221         self.connect('delete_event', gtk.main_quit)
222         self.connect("key-press-event", on_key_press)
223         self.set_wmclass('MainWindow', 'FindIT')
224
225         #########  Добавляем элементы ################
226         # 1. Строка ввода каталога с которого начинать поиск
227         #    переменная в которой храниться стартовый каталог = self.start_path
228         self.srch_p_entr = gtk.Entry()
229         self.start_path = st_path
230         self.srch_p_entr.set_text(self.start_path)
231         # Отключаем автокапитализацию(ввод первой буквы заглавной) на таблетке
232         if hildonFound:
233             self.srch_p_entr.set_property("hildon-input-mode", 'full')
234         # Нажатие Enter в поле ввода
235         self.srch_p_entr.connect("activate", self.start_print)
236
237         # 2. Кнопка "Обзор"
238
239         # 3. Надпись1 "Количество отображаемых файлов:"
240         label1 = gtk.Label( _('Files quantity') )
241
242         # 4. Окошко ввода количества файлов, мин значение=1 макс=65536 по умолчанию 10
243         #    данные храняться в переменной self.fl_cnt
244         self.fl_cnt = 10
245         if hildonFound:
246             self.file_cnt = hildon.NumberEditor(1, 99)
247             self.file_cnt.set_value(self.fl_cnt)
248         else:
249             adj = gtk.Adjustment(self.fl_cnt, 1, 65536, 1, 5, 0)
250             self.file_cnt = gtk.SpinButton(adj, 0, 0)
251
252         # 5.1 Кнопка "Показать"
253         self.butt_start = gtk.Button( _('Go') )
254         self.butt_start.connect('released', self.start_print)
255
256         # 5.2 Кнопка "Остановить"
257         self.butt_stop = gtk.Button( _('Stop') )
258         self.butt_stop.set_sensitive(False)
259         self.butt_stop.connect('clicked', self.stop_print)
260         self.stopit = False
261
262         # 5.3 Кнопка "Свойства файла"
263         self.propertiesBtn = gtk.Button( _('File properties') )
264         self.propertiesBtn.connect('clicked', self.show_properties_dialog)
265         self.propertiesBtn.set_sensitive(False)
266
267         # 6. Закладки
268
269         # 6.1 Список файлов
270         scrollwind = gtk.ScrolledWindow()
271         scrollwind.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
272
273         # Определяем переменную в которой будет храниться выводимый список
274         self.treestore = gtk.TreeStore(str, str, int)
275         self.treeview = gtk.TreeView(self.treestore)
276         # На таблетке не отображаються заголовки столбцов по умолчанию -
277         # след строка заставляет их отображаться принудительно
278         self.treeview.set_headers_visible(1)
279         self.treeview.connect('row-activated', self.show_properties_dialog)
280
281         self.treestore.append(None, ['', '', 0])
282
283         # Создаем и настраиваем колонку с размером файла
284         size_col = gtk.TreeViewColumn( _('Size') )
285         cell = gtk.CellRendererText()
286         cell.set_property('width', 90)
287         size_col.pack_start(cell, True)
288         size_col.add_attribute(cell, 'text', 1)
289         self.treeview.append_column(size_col)
290         # Создаем и настраиваем колонку с именем файла
291         path_col = gtk.TreeViewColumn( _('Path') )
292         cell2 = gtk.CellRendererText()
293         path_col.pack_start(cell2, True)
294         path_col.add_attribute(cell2, 'text', 0)
295         self.treeview.append_column(path_col)
296
297         # Добавляем сортировку для колонок
298         self.treeview.set_search_column(1)
299         path_col.set_sort_column_id(0)
300         size_col.set_sort_column_id(2)
301
302         # 6.2 Надпись "Найти"
303
304         # 6.3 Строка выводящая текущий осматриваемый файл
305         self.currFileLbl = gtk.Label()
306         self.currFileLbl.set_alignment(0, 0.5)
307         self.currFileLbl.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
308         self.currFileLbl.set_padding(2, 2)
309         currFileFrm = gtk.Frame()
310         currFileFrm.add(self.currFileLbl)
311
312         #########  Упаковываем элементы ################
313         # Создаем основной вертикальный контейнер
314         main_Vbox = gtk.VBox(False, 4)
315
316         # Создаем вспомогательный горизонтальный контейнер для Надписи1,
317         # окошка ввода количества файлов и кнопки "Показать"
318         hbox1 = gtk.HBox(False, 5)
319         # Добавляем вышеперечисленные элементы во вспомогат. контейнер
320         hbox1.pack_start(label1, False, False, 5)
321         hbox1.pack_start(self.file_cnt, False, False, 0)
322         hbox1.pack_start(self.butt_start, True, True, 0)
323         hbox1.pack_start(self.butt_stop, True, True, 0)
324         hbox1.pack_start(self.propertiesBtn, True, True, 0)
325
326         # Добавляем элементы в основной контейнер
327         main_Vbox.pack_start(self.srch_p_entr, False, False, 0)
328         main_Vbox.pack_start(hbox1, False, False, 0)
329         scrollwind.add(self.treeview)
330         main_Vbox.pack_start(scrollwind, True, True, 0)
331         main_Vbox.pack_start(currFileFrm, False, False, 0)
332
333         self.add(main_Vbox)
334
335     def run(self):
336         self.show_all()
337         gtk.main()
338
339
340 ### Main call ##################################################################
341
342 if __name__ == '__main__':
343     gobject.set_application_name( _('FindIT') )
344
345     if platform == 'win32':
346         startpath = 'c:\\'
347     else:
348         startpath = expanduser('~')
349
350     app = MainWindow(575, 345, startpath)
351     app.run()