First working PAC version
[findit] / src / files / search.py
1 #!/usr/bin/env python
2 # -*-coding: utf-8 -*-
3 # vim: sw=4 ts=4 expandtab ai
4
5 from os import walk
6 from os.path import join, abspath, normcase, basename, isdir, getsize
7 from heapq import nlargest
8
9 from misc import *
10
11 #==============================================================================
12
13 class Control(object):
14
15     def __init__(self, ui):
16         ignore_dirs = ['/dev', '/proc', '/sys', '/mnt']
17         start_path = '.'
18         count = 7
19
20         print ui
21         if ui == 'cli':
22             self.present = Cli_Presentation(start_path, count, self.start_search)
23         elif ui == 'gtk':
24             self.present = Gtk_Presentation(start_path, count, self.start_search)
25
26         self.abstrac = Abstraction(ignore_dirs, self.present)
27
28     def start_search(self, get_data, get_stopit, label, kill_func):
29         filelist = []
30         start_path, count, outtype = get_data()
31         search_func = self.abstrac.filegetter(start_path, get_stopit, label)
32         for fsize, fpath in nlargest(count, search_func):
33             filelist.append([int(fsize), fpath, size_hum_read(fsize)])
34         self.present.show_out_toplevel(None, outtype, filelist)
35
36     def run(self):
37         return self.present.toplevel
38
39 #==============================================================================
40
41 class Abstraction(object):
42
43     def __init__(self, ignore_dirs, presentation):
44         self.ignore_dirs = ignore_dirs
45         self.presentation = presentation
46
47     def filegetter(self, startdir, get_stopit, label):
48         """Generator of file sizes and paths based on os.walk."""
49         # Проходим по всем папкам вглубь от заданного пути
50         self.full_dir_size = 0
51         for dirpath, dirnames, fnames in walk(startdir):
52             # Исключаем каталоги из поиска в соответствии со списком исключений
53             ignore_dirs = self.ignore_dirs
54             for ign_dir in ignore_dirs[:]:
55                 for dirname in dirnames[:]:
56                     if ign_dir == normcase(join(abspath(dirpath), dirname)):
57                         dirnames.remove(dirname)
58                         ignore_dirs.remove(ign_dir)
59
60             for fname in fnames:
61                 flpath = abspath(join(dirpath, fname))
62                 self.presentation.show_current_status(flpath)
63
64                 # Останавливаем цикл по нажатию кнопки стоп
65                 stopit = get_stopit()
66                 if stopit:
67                     stopit = False
68                     raise StopIteration
69                     print 'Stopped'
70                 # Проверяем можем ли мы определить размер файла - иначе пропускаем его
71                 try:
72                     # Возвращаем размер и полный путь файла
73                     yield getsize(flpath), flpath
74                 except OSError:
75                     continue
76
77 #==============================================================================
78
79 class Cli_Presentation(object):
80     def __init__(self, start_func):
81         self.stopit = False
82                   #     get_data,      get_stopit, label, kill_func)
83         start_func(self.get_data, self.get_stopit, self.kill_wind)
84         pass
85
86     def show_current_status(self, current_path):
87         print current_path
88
89 #==============================================================================
90
91 class Gtk_Presentation(object):
92
93     def __init__(self, start_path, count, start_func):
94         import gtk
95
96         # "Start path" entry
97         self.path_entry = gtk.Entry()
98         self.path_entry.set_text(start_path)
99
100         # "Files quantity" label
101         qty_label = gtk.Label('Files quantity')
102
103         # "Files quantity" spin
104         self.qty_spin = gtk.SpinButton()
105         self.qty_spin.set_numeric(True)
106         self.qty_spin.set_range(0, 65536)
107         self.qty_spin.set_increments(1, 10)
108         self.qty_spin.set_value(count)
109
110         # "Start" button
111         self.start_btn = gtk.Button('Start')
112         self.start_btn.connect('released', self.start_btn_released, start_func)
113
114         # "Stop" button
115         self.stop_btn = gtk.Button('Stop')
116         self.stop_btn.set_sensitive(False)
117         self.stop_btn.connect('clicked', self.stop_btn_clicked)
118
119         # Output selection
120         self.outtable_rbtn = gtk.RadioButton(None, 'Table')
121         self.outtable_rbtn.set_name('outtable')
122         outdiagram_rbtn = gtk.RadioButton(self.outtable_rbtn, 'Diagram')
123         outdiagram_rbtn.set_name('outdiagram')
124         out1_rbtn = gtk.RadioButton(self.outtable_rbtn, 'Another 1')
125         out1_rbtn.set_name('outanother1')
126         out2_rbtn = gtk.RadioButton(self.outtable_rbtn, 'Another 2')
127         out2_rbtn.set_name('outanother2')
128         out_rbtns = [self.outtable_rbtn, outdiagram_rbtn, out1_rbtn, out2_rbtn]
129
130         hbox = gtk.HBox(False, 4)
131         hbox.pack_start(qty_label, False, False, 0)
132         hbox.pack_start(self.qty_spin, False, False, 0)
133         hbox.pack_start(self.start_btn, False, False, 0)
134         hbox.pack_start(self.stop_btn, False, False, 0)
135         for btn in reversed(out_rbtns):
136             hbox.pack_end(btn, False, False, 0)
137
138         self.statusbar = gtk.Statusbar()
139         self.context_id = self.statusbar.get_context_id('Current walked file')
140
141         self.vbox = gtk.VBox(False, 4)
142         self.vbox.pack_start(self.path_entry, False, False, 0)
143         self.vbox.pack_start(hbox, False, False, 0)
144         self.vbox.pack_end(self.statusbar, False, False, 0)
145
146         self.toplevel = self.vbox
147
148         # for importing gtk only once (lambda not work)
149         def show_current_status(current_path):
150             self.statusbar.push(self.context_id, current_path)
151             gtk.main_iteration()
152         self.show_current_status = show_current_status
153
154 #        self.show_out_toplevel(None, 'outtable', [(11, 22, 33)])
155
156     #=== Functions ============================================================
157     def start_btn_released(self, btn, start_func):
158         self.stopit = False
159         self.stop_btn.set_sensitive(True)
160         self.start_btn.set_sensitive(False)
161         start_func(self.get_data, self.get_stopit, None, None)
162         self.stop_btn.set_sensitive(False)
163         self.start_btn.set_sensitive(True)
164
165     def stop_btn_clicked(self, widget):
166         self.stopit = True
167         self.stop_btn.set_sensitive(False)
168         self.start_btn.set_sensitive(True)
169
170     def get_data(self):
171         for btn in self.outtable_rbtn.get_group():
172             if btn.get_active():
173                 out = btn.get_name()
174         return self.path_entry.get_text(), int(self.qty_spin.get_value()), out
175
176     def get_stopit(self):
177         return self.stopit
178
179     #=== Output type selecting ================================================
180     def show_out_toplevel(self, btn, outtype, results):
181         print 'Entering <' + outtype + '> output mode...'
182         out_submodule = __import__('files.' + outtype, None, None, outtype)
183
184         try:
185             self.current_outtoplevel.destroy()
186         except:
187             pass
188
189         out_toplevel = out_submodule.Gtk_Presentation(results).toplevel
190         self.current_outtoplevel = out_toplevel
191         self.vbox.add(out_toplevel)
192         out_toplevel.show_all()
193 #        out_submodule.Gtk_Presentation().show_results(results)