From 5bcf37b8944759e09fe45c341a555757b53a6e20 Mon Sep 17 00:00:00 2001 From: Frederic Back Date: Mon, 25 Sep 2006 11:43:38 +0000 Subject: * Corrected several bugs * Enabled better threading git-svn-id: file:///home/lennart/svn/public/fring/branches/c_walker@29 d0d2c35f-0a1e-0410-abeb-dabff30a67ee --- src/extension/fringtools.cpp | 16 +++-- src/fringlib/fringui.py | 25 ++++---- src/fringlib/fringwalker.py | 140 ++++++++++++++++++++++++++++--------------- 3 files changed, 115 insertions(+), 66 deletions(-) diff --git a/src/extension/fringtools.cpp b/src/extension/fringtools.cpp index 9205816..88ec037 100644 --- a/src/extension/fringtools.cpp +++ b/src/extension/fringtools.cpp @@ -29,7 +29,7 @@ Instead of using SumList, the new build_tree will use a tuple */ /// recursive function to build a list system with directory information -PyObject* build_tree( std::string path, const bool& skipHidden) { +PyObject* build_tree( std::string path, const bool& showHidden) { PyObject* l = PyList_New(0); DIR* d = opendir(path.c_str()); if(d == 0) Py_RETURN_NONE; @@ -39,18 +39,16 @@ PyObject* build_tree( std::string path, const bool& skipHidden) { while((e = readdir(d)) != NULL) { std::string fn = e->d_name; - if(skipHidden) if(e->d_name[0] == '.') continue; + + if(!showHidden) if(e->d_name[0] == '.') continue; if(fn == "." || fn == "..") continue; fn = path+"/" +fn; struct stat s; lstat(fn.c_str(), &s); - if (s.st_size < 0) - std::cout << "alert2 " << path << ", " << total << std::endl << std::flush; - if(S_ISDIR(s.st_mode)) { - PyObject* sub = build_tree(fn,skipHidden); + PyObject* sub = build_tree(fn,showHidden); PyTuple_SetItem(sub,0,PyString_FromString(e->d_name)); PyList_Append(l, sub ); total += PyLong_AsUnsignedLong( PyTuple_GET_ITEM(sub,2) ); @@ -67,9 +65,9 @@ PyObject* build_tree( std::string path, const bool& skipHidden) { /// initial function call. static PyObject* fringtools_build_tree(PyObject *self, PyObject *args) { const char *path; - int skip_hidden = 1; - if (!PyArg_ParseTuple(args, "si", &path, &skip_hidden)) return NULL; - return build_tree(std::string(path),(skip_hidden==1)); + int show_hidden = 1; + if (!PyArg_ParseTuple(args, "si", &path, &show_hidden)) return NULL; + return build_tree(std::string(path),(show_hidden==1)); } //============================================================================== diff --git a/src/fringlib/fringui.py b/src/fringlib/fringui.py index 71b2d67..5236af6 100644 --- a/src/fringlib/fringui.py +++ b/src/fringlib/fringui.py @@ -3,7 +3,7 @@ import cairo import sys import os -from fringwalker import FringWalker, print_tree +from fringwalker import FringWalker from fringrenderer import FringRenderer from fringutil import * @@ -155,7 +155,7 @@ class UI( gtk.Window ): self.eventbox.connect("size-allocate",self.__on_resize) self.connect("delete_event", self.close) - self.__show_busy_cursor(1) + def open_folder(self,path): print "open",path @@ -235,6 +235,7 @@ class UI( gtk.Window ): self.walker.stop() if path is None: return self.walker.walk(path); + self.__show_busy_cursor(1) def __selectfolder(self,widget): """ Open a dialog to select a folder """ @@ -250,19 +251,19 @@ class UI( gtk.Window ): self.__set_path(self.path) def __move_event(self, widget, event): - - if self.busy_cursor > 0: - return f = self.renderer.get_hotspot_at(event.x, event.y) if f is None: self.label.set_text("Ready.") else: self.label.set_markup("Path %s, %s, %0.1f%%" % (f.path, pretty_size(f.size), f.value*100)) - + if f is None or not f.is_dir: - self.eventbox.window.set_cursor(None) + if self.busy_cursor > 0: cursor = gtk.gdk.Cursor(gtk.gdk.WATCH) + else: cursor = None + self.eventbox.window.set_cursor(cursor) else: + # always display a hand when hovering a link self.eventbox.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND1)) def __click_event(self, widget, event): @@ -285,11 +286,14 @@ class UI( gtk.Window ): self.image.set_from_pixmap(self.pixmap,None) self.ctx = self.pixmap.cairo_create() self.renderer.prepare_layouts(self.ctx) + self.ctx.rectangle(0,0,self.width,self.height) + self.ctx.set_source_rgb(*self.backgroundColour) + self.ctx.fill() def __list_changed(self,widget,data): - #print_tree(data) self.data = data self.redraw() + #print data.name def __walker_finished(self, widget, data): self.__list_changed(widget, data) @@ -303,13 +307,14 @@ class UI( gtk.Window ): def __show_busy_cursor(self, value): if self.busy_cursor <= 0 and self.busy_cursor+value >= 0: - self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) + if self.window: self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) self.label.set_markup("Busy...") elif self.busy_cursor > 0 and self.busy_cursor+value <= 0: - self.window.set_cursor(None) + if self.window: self.window.set_cursor(None) self.label.set_text("Ready.") self.busy_cursor += value + #print "busy state:",self.busy_cursor diff --git a/src/fringlib/fringwalker.py b/src/fringlib/fringwalker.py index 5137306..99eaeff 100644 --- a/src/fringlib/fringwalker.py +++ b/src/fringlib/fringwalker.py @@ -5,107 +5,153 @@ import time import fringtools -def print_tree( t, tab=0 ): - """ An utility function to print out the tree returned by FringWalker::_parse """ - - fn, data, size = t +def print_tree( treearray, tab=0 ): + """ An utility function to print out a tree array """ + fn, data, size = treearray print " "*tab,"%s (%i)"%(fn,size) if not data: return + if tab > 1: return for e in data: print_tree(e,tab+1) + +def treearray_cmp_fn( a, b ): + """ a and b are tuples describing a directory tree. Compare first by directory + status, then by size, and finally by name. """ + + a_dir = a[1] != None + b_dir = b[1] != None + + if a_dir and not b_dir: + return 1 + elif b_dir and not a_dir: + return -1 + elif a_dir and b_dir: + return cmp(a[2], b[2]) # compare sizes + else: + return cmp(a[0], b[0]) # compare names + + class FringWalker( gobject.GObject ): + """ Manages requests for walking directories + + Directory entries are represented by tuples of the following form: + (name, contents, size) + + name: the file name of the directory + contents: a list of entries within the entry. If None, the entry is not a directory + size: the size of the entry. + """ __gsignals__ = { 'list-changed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), 'finished': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), + 'manually-stopped': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ), 'progress': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT,gobject.TYPE_INT)), } def __init__(self): gobject.GObject.__init__(self) self.thread = None - self.stopsignal = False self.showhidden = False - def walk(self,path): - self.thread = Thread(None,self._parse,None,(path,)) - self.stopsignal = False - print "start thread (%s)"%path + self.stop() + self.thread = WalkThread(self,path,self.showhidden) self.thread.start() - def stop(self): - if self.thread is None: - return - - if not self.thread.isAlive(): + if self.thread: + self.thread.stopsignal = True self.thread = None - return - self.stopsignal = True - print "stopping thread:" - #self.thread.join() - print "ok" + def _progress_fn(self, walkthread, c, l, r): + # only emit if called from the current request + if walkthread == self.thread: + gtk.gdk.threads_enter() + self.emit("progress", c, l) + self.emit("list-changed", r) + gtk.gdk.threads_leave() + def _finished_fn(self, walkthread, r): + if walkthread == self.thread: + gtk.gdk.threads_enter() + self.emit("finished", r) + gtk.gdk.threads_leave() - def _parse(self,path): + +class WalkThread( Thread ): + """ A separate class for the thread. """ + + def __init__(self, master, path, showhidden): + """ Parameters: A FringWalker instance, a string with the path and a bool """ + Thread.__init__(self) + self.stopsignal = False + self.master = master + self.path = path + self.showhidden = showhidden + + def run(self): """ Parse the root directory """ + print "start walking",self.path + l = [] i = 0 - subdirectories = {} - + subdirectories = [] total = 0 + # make a first run for the root directory try: - for fn in os.listdir(path): + for fn in os.listdir(self.path): + + if self.stopsignal: return None if not self.showhidden and fn[0] == '.': continue - try: p = os.path.join(path, fn) + try: p = os.path.join(self.path, fn) except: continue s = os.lstat(p) if stat.S_ISDIR(s.st_mode): - subdirectories[i] = (fn,p); - l.append((fn, None, s.st_size)) + subdirectories.append( (fn,p) ); elif stat.S_ISREG(s.st_mode): l.append((fn, None, s.st_size)) total += s.st_size i += 1 - except: + except OSError: pass + + # emit an intermediate version to fill up the screen while waiting + self.master._progress_fn(self, + 0, len(subdirectories), + (os.path.split(self.path)[-1], l, total)) - gtk.gdk.threads_enter() - self.emit("list-changed",(os.path.split(path)[-1], l, total)) - gtk.gdk.threads_leave() - + # now walk the subdirectories with the faster extension function c = 0 - for n in subdirectories: + + for fn, p in subdirectories: c += 1 - fn,p = subdirectories[n] - sub = fringtools.build_tree(p,True) # call faster c++ extension + sub = fringtools.build_tree(p, self.showhidden) + if self.stopsignal: return None + total += sub[2] - - l[n] = (fn,sub[1],sub[2]); + l.append( (fn,sub[1],sub[2]) ); - if self.stopsignal: return + l.sort(treearray_cmp_fn) - # emit signals - gtk.gdk.threads_enter() - self.emit("list-changed",(os.path.split(path)[-1], l, total)) - print "%s parsed"%fn - gtk.gdk.threads_leave() + # emit an intermediate version after each directory + self.master._progress_fn(self, + c, len(subdirectories), + (os.path.split(self.path)[-1], l, total)) + + l.sort(treearray_cmp_fn) - gtk.gdk.threads_enter() - self.emit("finished",(os.path.split(path)[-1], l, total)) - gtk.gdk.threads_leave() - - print "finished walking",path + # emit final signal + self.master._finished_fn(self,(os.path.split(self.path)[-1], l, total)) + print "finished walking",self.path -- cgit