summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederic Back <fredericback@gmail.com>2006-09-25 11:43:38 +0000
committerFrederic Back <fredericback@gmail.com>2006-09-25 11:43:38 +0000
commit5bcf37b8944759e09fe45c341a555757b53a6e20 (patch)
tree6fdeb48f24b8f486b47af149bd345e3f00a20048
parenta6d9c932ce4cb91223e46c532489c0f514b09d4f (diff)
* Corrected several bugs
* Enabled better threading git-svn-id: file:///home/lennart/svn/public/fring/branches/c_walker@29 d0d2c35f-0a1e-0410-abeb-dabff30a67ee
-rw-r--r--src/extension/fringtools.cpp16
-rw-r--r--src/fringlib/fringui.py25
-rw-r--r--src/fringlib/fringwalker.py140
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 <b>%s</b>, %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