diff options
Diffstat (limited to 'src/fringlib/fringwalker.py')
-rw-r--r-- | src/fringlib/fringwalker.py | 140 |
1 files changed, 93 insertions, 47 deletions
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 |