--- a/src/python/samples/recollgui/qrecoll.py
+++ b/src/python/samples/recollgui/qrecoll.py
@@ -15,42 +15,96 @@
 
 from PyQt4 import QtCore, QtGui
 
+
+####################
+# Highlighting methods. Just for showing the groups usage, we add the
+# original string for the match to the highlighted text. I don't think
+# you'd want to do this in a real app, but maybe some kind of tooltip?
+class HlMeths:
+    def __init__(self, groups):
+        self.groups = groups
+
+    def startMatch(self, idx):
+        ugroup = " ".join(self.groups[idx][0])
+        return '<font size="tiny">'+ugroup+'</font><font color="blue">'
+
+    def endMatch(self):
+        return '</font>'
+
+############
+# Data extraction. The 2 following methods use the extractor module
+# and get the data from the original document
+#
+# Extract and return document text (in text or html format, indicated
+# by newdoc.mimetype)
+def textextract(doc):
+    extractor = rclextract.Extractor(doc)
+    newdoc = extractor.textextract(doc.ipath)
+    return newdoc
+# Extract document in original format (ie: application/msword) and
+# save it to a file. This only works if ipath is not null (else just
+# use the url !)
+def extractofile(doc, outfilename=""):
+    extractor = rclextract.Extractor(doc)
+    outfilename = extractor.idoctofile(doc.ipath, doc.mimetype, \
+                                       ofilename=outfilename)
+    return outfilename
+
+#########
+# RecollQuery wraps a recoll.query object in a Qt model
 class RecollQuery(QtCore.QAbstractTableModel):
     def __init__(self):
         QtCore.QAbstractTableModel.__init__(self)
         self.totres = -1
+        self.db = None
         self.query = None
+        self.qtext = ""
         self.docs = []
         self.pagelen = 10
         self.attrs = ("filename", "title", "mtime", "url", "ipath")
+
     def rowCount(self, parent):
         ret = len(self.docs)
         #print "RecollQuery.rowCount(): ", ret
         return ret
+
     def columnCount(self, parent):
         #print "RecollQuery.columnCount()"
         if parent.isValid():
             return 0
         else:
             return len(self.attrs)
-    def setquery(self, db, q):
+
+    def setquery(self, db, q, sortfield="", ascending=True):
         """Parse and execute query on open db"""
-        print "RecollQuery.setquery():"
+        #print "RecollQuery.setquery():"
         # Get query object
         self.query = db.query()
+        if sortfield:
+            self.query.sortby(sortfield, ascending)
         # Parse/run input query string
         self.totres = self.query.execute(q)
+        self.qtext = q
+        self.db = db
         self.docs = []
         self.fetchMore(None)
+
     def getdoc(self, index):
         if index.row() < len(self.docs):
             return self.docs[index.row()]
         else:
             return None
+
+    def sort(self, col, order):
+        #print "sort", col, order
+        self.setquery(self.db, self.qtext, sortfield=self.attrs[col],
+                      ascending = order)
+
     def headerData(self, idx, orient, role):
         if orient == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
             return self.attrs[idx]
         return None
+
     def data(self, index, role):
         #print "RecollQuery.data: row %d, role: " % (index.row(),), role
         if not index.isValid():
@@ -70,12 +124,14 @@
             return value
         else:
             return QtCore.QVariant()
+
     def canFetchMore(self, parent):
         #print "RecollQuery.canFetchMore:"
         if len(self.docs) < self.totres:
             return True
         else:
             return False
+
     def fetchMore(self, parent):
         #print "RecollQuery.fetchMore:"
         self.beginInsertRows(QtCore.QModelIndex(), len(self.docs), \
@@ -88,26 +144,9 @@
             count += 1
         self.endInsertRows()
 
-class HlMeths:
-    def __init__(self, groups):
-        self.groups = groups
-    def startMatch(self, idx):
-        ugroup = " ".join(self.groups[idx][1])
-        return '<font color="blue">'
-    def endMatch(self):
-        return '</font>'
-
-def extract(doc):
-    extractor = rclextract.Extractor(doc)
-    newdoc = extractor.textextract(doc.ipath)
-    return newdoc
-
-def extractofile(doc, outfilename=""):
-    extractor = rclextract.Extractor(doc)
-    outfilename = extractor.idoctofile(doc.ipath, doc.mimetype, \
-                                       ofilename=outfilename)
-    return outfilename
-
+
+###
+#  UI interaction code
 class RclGui_Main(QtGui.QMainWindow):
     def __init__(self, db, parent=None):
         QtGui.QWidget.__init__(self, parent)
@@ -115,52 +154,91 @@
         self.ui.setupUi(self)
         self.db = db
         self.qmodel = RecollQuery()
+        scq = QtGui.QShortcut(QtGui.QKeySequence("Ctrl+Q"), self);
+        self.connect(scq, QtCore.SIGNAL("activated()"), self.onexit)
+        header = self.ui.resTable.horizontalHeader();
+	header.setSortIndicatorShown(True);
+	header.setSortIndicator(-1, QtCore.Qt.AscendingOrder);
+        self.ui.resTable.setSortingEnabled(True)
+        self.currentindex = -1
+        self.currentdoc = None
+        
     def on_searchEntry_returnPressed(self):
         self.startQuery()
+
     def on_resTable_clicked(self, index):
         doc = self.qmodel.getdoc(index)
+        self.currentindex = index
+        self.currentdoc = doc
+        if doc is None:
+            print "NO DoC"
+            return
+        query = self.qmodel.query
+        groups = query.getgroups()
+        meths = HlMeths(groups)
+        abs = query.makedocabstract(doc, methods=meths)
+        self.ui.resDetail.setText(abs)
+        if hasextract:
+            ipath = doc.get('ipath')
+            #print "ipath[%s]" % (ipath,)
+            self.ui.previewPB.setEnabled(True)
+            if ipath:
+                self.ui.savePB.setEnabled(True)
+            else:
+                self.ui.savePB.setEnabled(False)
+
+    # The 'checked' thing is to work around a bug in pyqt?
+    def on_previewPB_clicked(self, checked=True):
+        print "on_previewPB_clicked(self, %s):" % (repr(checked))
+        if checked:
+            return
+        newdoc = textextract(self.currentdoc)
         query = self.qmodel.query;
-        groups = self.qmodel.query.getgroups()
+        groups = query.getgroups()
         meths = HlMeths(groups)
-        if doc is not None:
-            ipath = doc.get('ipath')
-            print "ipath[", ipath, "]"
-            if index.column() == 1:
-                newdoc = extract(doc)
-                print "newdoc.mimetype:", newdoc.mimetype
-                if newdoc.mimetype == 'text/html':
-                    ishtml = True
-                else:
-                    ishtml = False
-                text = query.highlight(newdoc.text,
-                                       methods=meths,
-                                       ishtml=ishtml,
-                                       eolbr=True)
-                print text
-                
-                text = '<qt><head></head><body>' + text + '</body></qt>'
-                self.ui.resDetail.setText(text)
-            elif index.column() == 3 and ipath:
-                fn = QtGui.QFileDialog.getSaveFileName(self)
-                if fn:
-                    docitems = doc.items()
-                    fn = extractofile(doc, str(fn.toLocal8Bit()))
-                    print "Saved as", fn
-                else:
-                    print >> sys.stderr, "Canceled"
-            else:
-                abs = query.makedocabstract(doc, methods=meths)
-                self.ui.resDetail.setText(abs)
+        #print "newdoc.mimetype:", newdoc.mimetype
+        if newdoc.mimetype == 'text/html':
+            ishtml = True
+        else:
+            ishtml = False
+        text = '<qt><head></head><body>' + \
+               query.highlight(newdoc.text,
+                               methods=meths,
+                               ishtml=ishtml,
+                               eolbr=True)
+        text += '</body></qt>'
+        self.ui.resDetail.setText(text)
+
+    # The 'checked' thing is to work around a bug in pyqt?
+    def on_savePB_clicked(self, checked=True):
+        print "on_savePB_clicked(self, %s):" % (repr(checked))
+        if checked:
+            return
+        doc = self.currentdoc
+        ipath = doc.ipath
+        if not ipath:
+            return
+        fn = QtGui.QFileDialog.getSaveFileName(self)
+        if fn:
+            docitems = doc.items()
+            fn = extractofile(doc, str(fn.toLocal8Bit()))
+            print "Saved as", fn
+        else:
+            print >> sys.stderr, "Canceled"
                 
     def startQuery(self):
         self.qmodel.setquery(self.db, self.ui.searchEntry.text())
         self.ui.resTable.setModel(self.qmodel)
+
     def onexit(self):
         sys.exit(0)
-        
+
+
 def Usage():
     print >> sys.stderr, '''Usage: qt.py [<qword1> [<qword2> ...]]'''
     sys.exit(1)
+
+
 
 def main(args):