Merge commit 'origin/mosfet/master' into alex2ndr/master
[findit] / src / files / search.py
diff --git a/src/files/search.py b/src/files/search.py
new file mode 100755 (executable)
index 0000000..7e7c7f2
--- /dev/null
@@ -0,0 +1,193 @@
+#!/usr/bin/env python
+# -*-coding: utf-8 -*-
+# vim: sw=4 ts=4 expandtab ai
+
+from os import walk
+from os.path import join, abspath, normcase, basename, isdir, getsize
+from heapq import nlargest
+
+from misc import *
+
+#==============================================================================
+
+class Control(object):
+
+    def __init__(self, ui):
+        ignore_dirs = ['/dev', '/proc', '/sys', '/mnt']
+        start_path = '.'
+        count = 7
+
+        print ui
+        if ui == 'cli':
+            self.present = Cli_Presentation(start_path, count, self.start_search)
+        elif ui == 'gtk':
+            self.present = Gtk_Presentation(start_path, count, self.start_search)
+
+        self.abstrac = Abstraction(ignore_dirs, self.present)
+
+    def start_search(self, get_data, get_stopit, label, kill_func):
+        filelist = []
+        start_path, count, outtype = get_data()
+        search_func = self.abstrac.filegetter(start_path, get_stopit, label)
+        for fsize, fpath in nlargest(count, search_func):
+            filelist.append([int(fsize), fpath, size_hum_read(fsize)])
+        self.present.show_out_toplevel(None, outtype, filelist)
+
+    def run(self):
+        return self.present.toplevel
+
+#==============================================================================
+
+class Abstraction(object):
+
+    def __init__(self, ignore_dirs, presentation):
+        self.ignore_dirs = ignore_dirs
+        self.presentation = presentation
+
+    def filegetter(self, startdir, get_stopit, label):
+        """Generator of file sizes and paths based on os.walk."""
+        # Проходим по всем папкам вглубь от заданного пути
+        self.full_dir_size = 0
+        for dirpath, dirnames, fnames in walk(startdir):
+            # Исключаем каталоги из поиска в соответствии со списком исключений
+            ignore_dirs = self.ignore_dirs
+            for ign_dir in ignore_dirs[:]:
+                for dirname in dirnames[:]:
+                    if ign_dir == normcase(join(abspath(dirpath), dirname)):
+                        dirnames.remove(dirname)
+                        ignore_dirs.remove(ign_dir)
+
+            for fname in fnames:
+                flpath = abspath(join(dirpath, fname))
+                self.presentation.show_current_status(flpath)
+
+                # Останавливаем цикл по нажатию кнопки стоп
+                stopit = get_stopit()
+                if stopit:
+                    stopit = False
+                    raise StopIteration
+                    print 'Stopped'
+                # Проверяем можем ли мы определить размер файла - иначе пропускаем его
+                try:
+                    # Возвращаем размер и полный путь файла
+                    yield getsize(flpath), flpath
+                except OSError:
+                    continue
+
+#==============================================================================
+
+class Cli_Presentation(object):
+    def __init__(self, start_func):
+        self.stopit = False
+                  #     get_data,      get_stopit, label, kill_func)
+        start_func(self.get_data, self.get_stopit, self.kill_wind)
+        pass
+
+    def show_current_status(self, current_path):
+        print current_path
+
+#==============================================================================
+
+class Gtk_Presentation(object):
+
+    def __init__(self, start_path, count, start_func):
+        import gtk
+
+        # "Start path" entry
+        self.path_entry = gtk.Entry()
+        self.path_entry.set_text(start_path)
+
+        # "Files quantity" label
+        qty_label = gtk.Label('Files quantity')
+
+        # "Files quantity" spin
+        self.qty_spin = gtk.SpinButton()
+        self.qty_spin.set_numeric(True)
+        self.qty_spin.set_range(0, 65536)
+        self.qty_spin.set_increments(1, 10)
+        self.qty_spin.set_value(count)
+
+        # "Start" button
+        self.start_btn = gtk.Button('Start')
+        self.start_btn.connect('released', self.start_btn_released, start_func)
+
+        # "Stop" button
+        self.stop_btn = gtk.Button('Stop')
+        self.stop_btn.set_sensitive(False)
+        self.stop_btn.connect('clicked', self.stop_btn_clicked)
+
+        # Output selection
+        self.outtable_rbtn = gtk.RadioButton(None, 'Table')
+        self.outtable_rbtn.set_name('outtable')
+        outdiagram_rbtn = gtk.RadioButton(self.outtable_rbtn, 'Diagram')
+        outdiagram_rbtn.set_name('outdiagram')
+        out1_rbtn = gtk.RadioButton(self.outtable_rbtn, 'Another 1')
+        out1_rbtn.set_name('outanother1')
+        out2_rbtn = gtk.RadioButton(self.outtable_rbtn, 'Another 2')
+        out2_rbtn.set_name('outanother2')
+        out_rbtns = [self.outtable_rbtn, outdiagram_rbtn, out1_rbtn, out2_rbtn]
+
+        hbox = gtk.HBox(False, 4)
+        hbox.pack_start(qty_label, False, False, 0)
+        hbox.pack_start(self.qty_spin, False, False, 0)
+        hbox.pack_start(self.start_btn, False, False, 0)
+        hbox.pack_start(self.stop_btn, False, False, 0)
+        for btn in reversed(out_rbtns):
+            hbox.pack_end(btn, False, False, 0)
+
+        self.statusbar = gtk.Statusbar()
+        self.context_id = self.statusbar.get_context_id('Current walked file')
+
+        self.vbox = gtk.VBox(False, 4)
+        self.vbox.pack_start(self.path_entry, False, False, 0)
+        self.vbox.pack_start(hbox, False, False, 0)
+        self.vbox.pack_end(self.statusbar, False, False, 0)
+
+        self.toplevel = self.vbox
+
+        # for importing gtk only once (lambda not work)
+        def show_current_status(current_path):
+            self.statusbar.push(self.context_id, current_path)
+            gtk.main_iteration()
+        self.show_current_status = show_current_status
+
+#        self.show_out_toplevel(None, 'outtable', [(11, 22, 33)])
+
+    #=== Functions ============================================================
+    def start_btn_released(self, btn, start_func):
+        self.stopit = False
+        self.stop_btn.set_sensitive(True)
+        self.start_btn.set_sensitive(False)
+        start_func(self.get_data, self.get_stopit, None, None)
+        self.stop_btn.set_sensitive(False)
+        self.start_btn.set_sensitive(True)
+
+    def stop_btn_clicked(self, widget):
+        self.stopit = True
+        self.stop_btn.set_sensitive(False)
+        self.start_btn.set_sensitive(True)
+
+    def get_data(self):
+        for btn in self.outtable_rbtn.get_group():
+            if btn.get_active():
+                out = btn.get_name()
+        return self.path_entry.get_text(), int(self.qty_spin.get_value()), out
+
+    def get_stopit(self):
+        return self.stopit
+
+    #=== Output type selecting ================================================
+    def show_out_toplevel(self, btn, outtype, results):
+        print 'Entering <' + outtype + '> output mode...'
+        out_submodule = __import__('files.' + outtype, None, None, outtype)
+
+        try:
+            self.current_outtoplevel.destroy()
+        except:
+            pass
+
+        out_toplevel = out_submodule.Gtk_Presentation(results).toplevel
+        self.current_outtoplevel = out_toplevel
+        self.vbox.add(out_toplevel)
+        out_toplevel.show_all()
+#        out_submodule.Gtk_Presentation().show_results(results)