diff --git a/src/python/samples/recollgui/Makefile b/src/python/samples/recollgui/Makefile new file mode 100644 index 00000000..7290a124 --- /dev/null +++ b/src/python/samples/recollgui/Makefile @@ -0,0 +1,4 @@ +all: rclmain.py + +rclmain.py: rclmain.ui + pyuic4 -o rclmain.py rclmain.ui diff --git a/src/python/samples/recollgui/qrecoll.py b/src/python/samples/recollgui/qrecoll.py index cc423e47..1a25ffb0 100755 --- a/src/python/samples/recollgui/qrecoll.py +++ b/src/python/samples/recollgui/qrecoll.py @@ -15,42 +15,96 @@ from getopt import getopt 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 ''+ugroup+'' + + def endMatch(self): + return '' + +############ +# 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 @@ class RecollQuery(QtCore.QAbstractTableModel): 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 @@ class RecollQuery(QtCore.QAbstractTableModel): count += 1 self.endInsertRows() -class HlMeths: - def __init__(self, groups): - self.groups = groups - def startMatch(self, idx): - ugroup = " ".join(self.groups[idx][1]) - return '' - def endMatch(self): - return '' - -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,53 +154,92 @@ class RclGui_Main(QtGui.QMainWindow): 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) - query = self.qmodel.query; - groups = self.qmodel.query.getgroups() + self.currentindex = index + self.currentdoc = doc + if doc is None: + print "NO DoC" + return + query = self.qmodel.query + groups = query.getgroups() meths = HlMeths(groups) - if doc is not None: + abs = query.makedocabstract(doc, methods=meths) + self.ui.resDetail.setText(abs) + if hasextract: 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 = '' + text + '' - 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" + #print "ipath[%s]" % (ipath,) + self.ui.previewPB.setEnabled(True) + if ipath: + self.ui.savePB.setEnabled(True) else: - abs = query.makedocabstract(doc, methods=meths) - self.ui.resDetail.setText(abs) + 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 = query.getgroups() + meths = HlMeths(groups) + #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) + text += '' + 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 [ [ ...]]''' sys.exit(1) + + def main(args): app = QtGui.QApplication(args) diff --git a/src/python/samples/recollgui/rclmain.ui b/src/python/samples/recollgui/rclmain.ui index eb28d314..6eaa34a9 100644 --- a/src/python/samples/recollgui/rclmain.ui +++ b/src/python/samples/recollgui/rclmain.ui @@ -30,34 +30,55 @@ - - - Qt::Vertical + + + + 0 + 4 + + + + QAbstractItemView::NoEditTriggers + + + false - - - - 0 - 4 - - - - QAbstractItemView::NoEditTriggers - - - false - - - - - - 0 - 0 - - - + + + + + 0 + 0 + + + + + + + + + + false + + + Preview + + + + + + + false + + + Save + + + + + @@ -85,5 +106,22 @@ - + + + actionExit + activated() + MainWindow + close() + + + -1 + -1 + + + 399 + 299 + + + +