diff --git a/src/lib/Makefile b/src/lib/Makefile index 9208ab88..9683fde3 100644 --- a/src/lib/Makefile +++ b/src/lib/Makefile @@ -7,12 +7,13 @@ all: depend $(LIBS) OBJS = base64.o conftree.o csguess.o debuglog.o \ execmd.o wipedir.o \ - fstreewalk.o mh_html.o mh_mail.o mh_exec.o mh_text.o htmlparse.o \ + fstreewalk.o mh_html.o mh_mail.o mh_exec.o mh_text.o history.o \ + htmlparse.o \ idfile.o indexer.o internfile.o md5.o \ mimehandler.o mimeparse.o mimetype.o myhtmlparse.o pathhash.o pathut.o \ rclconfig.o rcldb.o rclinit.o readfile.o smallut.o \ textsplit.o transcode.o \ - unacpp.o unac.o + unacpp.o unac.o docseq.o SRCS = ../utils/conftree.cpp ../index/csguess.cpp ../utils/debuglog.cpp \ ../utils/execmd.cpp ../utils/idfile.cpp ../utils/md5.cpp \ ../utils/wipedir.cpp ../utils/fstreewalk.cpp \ @@ -24,7 +25,8 @@ SRCS = ../utils/conftree.cpp ../index/csguess.cpp ../utils/debuglog.cpp \ ../common/rclconfig.cpp ../common/rcldb.cpp ../common/rclinit.cpp \ ../utils/base64.cpp ../utils/readfile.cpp ../utils/smallut.cpp \ ../common/textsplit.cpp ../utils/transcode.cpp \ - ../common/unacpp.cpp ../unac/unac.c + ../common/unacpp.cpp ../unac/unac.c ../query/history.cpp \ + ../query/docseq.cpp librcl.a : $(OBJS) ar ru librcl.a $(OBJS) @@ -46,6 +48,10 @@ wipedir.o : ../utils/wipedir.cpp $(CXX) $(CXXFLAGS) -c $< fstreewalk.o : ../utils/fstreewalk.cpp $(CXX) $(CXXFLAGS) -c $< +history.o : ../query/history.cpp + $(CXX) $(CXXFLAGS) -c $< +docseq.o : ../query/docseq.cpp + $(CXX) $(CXXFLAGS) -c $< mh_html.o : ../common/mh_html.cpp $(CXX) $(CXXFLAGS) -c $< mh_exec.o : ../common/mh_exec.cpp diff --git a/src/qtgui/main.cpp b/src/qtgui/main.cpp index dd22bf23..d48f27a8 100644 --- a/src/qtgui/main.cpp +++ b/src/qtgui/main.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: main.cpp,v 1.17 2005-11-24 07:16:16 dockes Exp $ (C) 2005 J.F.Dockes"; +static char rcsid[] = "@(#$Id: main.cpp,v 1.18 2005-11-25 10:02:36 dockes Exp $ (C) 2005 J.F.Dockes"; #endif #include @@ -24,6 +24,7 @@ using Rcl::AdvSearchData; #include "smallut.h" #include "wipedir.h" #include "rclinit.h" +#include "history.h" #include "recollmain.h" @@ -33,12 +34,13 @@ int recollNeedsExit; string tmpdir; bool showicons; string iconsdir; +RclQHistory *history; void getQueryStemming(bool &dostem, std::string &stemlang) { string param; if (rclconfig->getConfParam("querystemming", param)) - dostem = ConfTree::stringToBool(param); + dostem = stringToBool(param); else dostem = false; if (!rclconfig->getConfParam("querystemminglanguage", stemlang)) @@ -121,30 +123,15 @@ int main( int argc, char ** argv ) int width = settings.readNumEntry( "/Recoll/geometry/width", 590); int height = settings.readNumEntry( "/Recoll/geometry/height", 810); QSize s(width, height); - + // Create main window and set its size to previous session's RecollMain w; mainWindow = &w; w.resize(s); -#if 0 - // Once tried to set a lighter background but this doesn;t seem to work - // (no inheritance from buttons and popups) - QPalette palette = w.palette(); - palette.setColor(QColorGroup::Background, QColor(239,239,239)); - w.setPalette(palette); -#endif - - // Connect exit handlers etc.. - a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); - QTimer *timer = new QTimer(&a); - w.connect(timer, SIGNAL(timeout()), &w, SLOT(periodic100())); - timer->start(100); - string reason; rclconfig = recollinit(recollCleanup, sigcleanup, reason); - if (!rclconfig || !rclconfig->ok()) { QString msg = a.translate("Main", "Configuration problem: "); msg += reason; @@ -176,11 +163,21 @@ int main( int argc, char ** argv ) "Cannot create temporary directory")); exit(1); } - + + string historyfile = rclconfig->getConfDir(); + path_cat(historyfile, "history"); + history = new RclQHistory(historyfile); + dbdir = path_tildexpand(dbdir); rcldb = new Rcl::Db; + // Connect exit handlers etc.. + a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); + QTimer *timer = new QTimer(&a); + w.connect(timer, SIGNAL(timeout()), &w, SLOT(periodic100())); + timer->start(100); + if (!rcldb || !rcldb->open(dbdir, Rcl::Db::DbRO)) { startindexing = 1; QMessageBox::information(0, "Recoll", diff --git a/src/qtgui/recoll.h b/src/qtgui/recoll.h index 2768f1a7..fc17d869 100644 --- a/src/qtgui/recoll.h +++ b/src/qtgui/recoll.h @@ -1,24 +1,27 @@ #ifndef _RECOLL_H_INCLUDED_ #define _RECOLL_H_INCLUDED_ -/* @(#$Id: recoll.h,v 1.5 2005-11-16 15:07:20 dockes Exp $ (C) 2004 J.F.Dockes */ +/* @(#$Id: recoll.h,v 1.6 2005-11-25 10:02:36 dockes Exp $ (C) 2004 J.F.Dockes */ #include #include + #include "rclconfig.h" #include "rcldb.h" #include "idxthread.h" +#include "history.h" +#include "docseq.h" // Misc declarations in need of sharing between the UI files - extern void recollCleanup(); -extern bool maybeOpenDb(std::string &reason); extern void getQueryStemming(bool &dostem, std::string &stemlang); +extern bool maybeOpenDb(std::string &reason); extern RclConfig *rclconfig; extern Rcl::Db *rcldb; extern std::string tmpdir; extern bool showicons; extern string iconsdir; - +extern RclQHistory *history; extern int recollNeedsExit; + #endif /* _RECOLL_H_INCLUDED_ */ diff --git a/src/qtgui/recollmain.ui b/src/qtgui/recollmain.ui index 7f898fe3..df409fe3 100644 --- a/src/qtgui/recollmain.ui +++ b/src/qtgui/recollmain.ui @@ -186,6 +186,9 @@ + + + @@ -231,6 +234,17 @@ About Recoll + + + toolsDoc_HistoryAction + + + Doc History + + + Doc History + + @@ -299,6 +313,12 @@ RecollMain showAboutDialog() + + toolsDoc_HistoryAction + activated() + RecollMain + showDocHistory() + preview.h @@ -311,14 +331,15 @@ int reslist_current; bool reslist_mouseDrag; bool reslist_mouseDown; - int reslistTE_par; - int reslistTE_car; - bool reslistTE_waitingdbl; - bool reslistTE_dblclck; + int reslist_par; + int reslist_car; + bool reslist_waitingdbl; + bool reslist_dblclck; bool dostem; std::string stemlang; Preview *curPreview; advsearch *asearchform; + DocSequence *docsource; fileExit() @@ -326,6 +347,7 @@ fileStart_IndexingAction_activated() reslistTE_doubleClicked( int par, int ) reslistTE_clicked( int par, int car ) + reslistTE_delayedclick() queryText_returnPressed() Search_clicked() clearqPB_clicked() @@ -334,8 +356,8 @@ previewClosed( Preview * w ) advSearchPB_clicked() startAdvSearch( Rcl::AdvSearchData sdata ) - reslistTE_delayedclick() showAboutDialog() + showDocHistory() init() diff --git a/src/qtgui/recollmain.ui.h b/src/qtgui/recollmain.ui.h index f397a027..27196574 100644 --- a/src/qtgui/recollmain.ui.h +++ b/src/qtgui/recollmain.ui.h @@ -29,15 +29,12 @@ using std::pair; #include #include -#include "rcldb.h" -#include "rclconfig.h" +#include "recoll.h" #include "debuglog.h" #include "mimehandler.h" #include "pathut.h" -#include "recoll.h" #include "smallut.h" #include "plaintorich.h" -#include "unacpp.h" #include "advsearch.h" #include "rclversion.h" @@ -53,14 +50,18 @@ static const int respagesize = 8; void RecollMain::init() { - reslist_current = -1; reslist_winfirst = -1; - curPreview = 0; - asearchform = 0; + reslist_current = -1; reslist_mouseDrag = false; reslist_mouseDown = false; - reslistTE_waitingdbl = false; - reslistTE_dblclck = false; + reslist_par = -1; + reslist_car = -1; + reslist_waitingdbl = false; + reslist_dblclck = false; + dostem = false; + curPreview = 0; + asearchform = 0; + docsource = 0; reslistTE->viewport()->installEventFilter(this); } @@ -158,7 +159,8 @@ static const char *eventTypeToStr(int tp) } #endif -// We want to catch ^Q everywhere to mean quit. +// There are a number of events that we want to process. Not sure the +// ^Q thing is necessary (we have an action for this)? bool RecollMain::eventFilter( QObject * target, QEvent * event ) { // LOGDEB(("RecollMain::eventFilter target %p, event %s\n", target, @@ -196,6 +198,7 @@ void RecollMain::fileExit() LOGDEB1(("RecollMain: fileExit\n")); if (asearchform) delete asearchform; + // Let the exit handler clean up things exit(0); } @@ -241,11 +244,11 @@ static string urltolocalpath(string url) void RecollMain::reslistTE_doubleClicked(int par, int) { LOGDEB(("RecollMain::reslistTE_doubleClicked: par %d\n", par)); - reslistTE_dblclck = true; + reslist_dblclck = true; Rcl::Doc doc; int reldocnum = par - 1; - if (!rcldb->getDoc(reslist_winfirst + reldocnum, doc, 0)) + if (!docsource->getDoc(reslist_winfirst + reldocnum, doc, 0)) return; // Look for appropriate viewer @@ -258,6 +261,7 @@ void RecollMain::reslistTE_doubleClicked(int par, int) } string fn = urltolocalpath(doc.url); + // Substitute %u (url) and %f (file name) inside prototype command string ncmd; string::const_iterator it1; @@ -286,6 +290,7 @@ void RecollMain::reslistTE_doubleClicked(int par, int) stb->repaint(false); XFlush(qt_xdisplay()); } + history->enterDocument(fn, doc.ipath); system(ncmd.c_str()); } @@ -296,7 +301,7 @@ void RecollMain::reslistTE_doubleClicked(int par, int) // check first if this might be a double click void RecollMain::reslistTE_clicked(int par, int car) { - if (reslistTE_waitingdbl) + if (reslist_waitingdbl) return; LOGDEB(("RecollMain::reslistTE_clckd:winfirst %d par %d char %d drg %d\n", reslist_winfirst, par, car, reslist_mouseDrag)); @@ -304,24 +309,52 @@ void RecollMain::reslistTE_clicked(int par, int car) return; // remember par and car - reslistTE_par = par; - reslistTE_car = car; - reslistTE_waitingdbl = true; - reslistTE_dblclck = false; + reslist_par = par; + reslist_car = car; + reslist_waitingdbl = true; + reslist_dblclck = false; // Wait to see if there's going to be a dblclck QTimer::singleShot(150, this, SLOT(reslistTE_delayedclick()) ); } +// This gets called by a timer 100mS after a single click in the +// result list. We don't want to start a preview if the user has +// requested a native viewer by double-clicking +void RecollMain::reslistTE_delayedclick() +{ + reslist_waitingdbl = false; + if (reslist_dblclck) { + reslist_dblclck = false; + return; + } + + int par = reslist_par; + + if (reslist_current != -1) { + QColor color("white"); + reslistTE->setParagraphBackgroundColor(reslist_current+1, color); + } + QColor color("lightblue"); + reslistTE->setParagraphBackgroundColor(par, color); + + int reldocnum = par - 1; + if (curPreview && reslist_current == reldocnum) + return; + + reslist_current = reldocnum; + startPreview(reslist_winfirst + reldocnum); +} // User asked to start query. Send it to the db aand call // listNextPB_clicked to fetch and display the first page of results void RecollMain::queryText_returnPressed() { LOGDEB(("RecollMain::queryText_returnPressed()\n")); + // The db may have been closed at the end of indexing string reason; if (!maybeOpenDb(reason)) { QMessageBox::critical(0, "Recoll", QString(reason.c_str())); - return; + exit(1); } if (stemlang.empty()) getQueryStemming(dostem, stemlang); @@ -335,6 +368,10 @@ void RecollMain::queryText_returnPressed() Rcl::Db::QO_STEM : Rcl::Db::QO_NONE, stemlang)) return; curPreview = 0; + + if (docsource) + delete docsource; + docsource = new DocSequenceDb(rcldb); listNextPB_clicked(); } @@ -361,15 +398,13 @@ void RecollMain::listPrevPB_clicked() // Fill up result list window with next screen of hits void RecollMain::listNextPB_clicked() { - if (!rcldb) + if (!docsource) return; int percent; Rcl::Doc doc; - // Need to fetch one document before we can get the result count - rcldb->getDoc(0, doc, &percent); - int resCnt = rcldb->getResCnt(); + int resCnt = docsource->getResCnt(); LOGDEB(("listNextPB_clicked: rescnt %d, winfirst %d\n", resCnt, reslist_winfirst)); @@ -392,15 +427,21 @@ void RecollMain::listNextPB_clicked() for (int i = 0; i < last; i++) { doc.erase(); - if (!rcldb->getDoc(reslist_winfirst + i, doc, &percent)) { + if (!docsource->getDoc(reslist_winfirst + i, doc, &percent)) { if (i == 0) reslist_winfirst = -1; break; } if (i == 0) { - reslistTE->append("

"); - QString line = tr("

Displaying results starting at index" - " %1 (maximum set size %2)
") + // We could use a but the textedit doesnt display + // it prominently + reslistTE->append("<qt><head></head><body>"); + QString line = "<p><font size=+1><b>"; + line += docsource->title().c_str(); + line += "</b></font><br>"; + reslistTE->append(line); + line = tr("<b>Displaying results starting at index" + " %1 (maximum set size %2)</b></p>") .arg(reslist_winfirst+1) .arg(resCnt); reslistTE->append(line); @@ -512,12 +553,12 @@ void RecollMain::advSearchPB_clicked() void RecollMain::startAdvSearch(Rcl::AdvSearchData sdata) { LOGDEB(("RecollMain::startAdvSearch\n")); + // The db may have been closed at the end of indexing string reason; if (!maybeOpenDb(reason)) { QMessageBox::critical(0, "Recoll", QString(reason.c_str())); - return; + exit(1); } - if (stemlang.empty()) getQueryStemming(dostem, stemlang); @@ -528,40 +569,13 @@ void RecollMain::startAdvSearch(Rcl::AdvSearchData sdata) Rcl::Db::QO_STEM : Rcl::Db::QO_NONE, stemlang)) return; curPreview = 0; + if (docsource) + delete docsource; + docsource = new DocSequenceDb(rcldb); listNextPB_clicked(); } - -// This gets called by a timer 100mS after a single click in the -// result list. We don't want to start a preview if the user has -// requested a native viewer by double-clicking -void RecollMain::reslistTE_delayedclick() -{ - reslistTE_waitingdbl = false; - if (reslistTE_dblclck) { - reslistTE_dblclck = false; - return; - } - - int par = reslistTE_par; - - if (reslist_current != -1) { - QColor color("white"); - reslistTE->setParagraphBackgroundColor(reslist_current+1, color); - } - QColor color("lightblue"); - reslistTE->setParagraphBackgroundColor(par, color); - - int reldocnum = par - 1; - if (curPreview && reslist_current == reldocnum) - return; - - reslist_current = reldocnum; - startPreview(reslist_winfirst + reldocnum); -} - - /** * Open a preview window for a given document, or load it into new tab of * existing window. @@ -571,7 +585,7 @@ void RecollMain::reslistTE_delayedclick() void RecollMain::startPreview(int docnum) { Rcl::Doc doc; - if (!rcldb->getDoc(docnum, doc, 0)) { + if (!docsource->getDoc(docnum, doc, 0)) { QMessageBox::warning(0, "Recoll", tr("Cannot retrieve document info" " from database")); @@ -609,7 +623,7 @@ void RecollMain::startPreview(int docnum) } (void)curPreview->addEditorTab(); } - + history->enterDocument(fn, doc.ipath); curPreview->loadFileInCurrentTab(fn, st.st_size, doc); } @@ -620,3 +634,17 @@ void RecollMain::showAboutDialog() "<br>" + "http://www.recoll.org"; QMessageBox::information(this, tr("About Recoll"), vstring.c_str()); } + + +void RecollMain::showDocHistory() +{ + LOGDEB(("RecollMain::showDocHistory\n")); + reslist_current = -1; + reslist_winfirst = -1; + curPreview = 0; + + if (docsource) + delete docsource; + docsource = new DocSequenceHistory(rcldb, history); + listNextPB_clicked(); +} diff --git a/src/query/docseq.cpp b/src/query/docseq.cpp new file mode 100644 index 00000000..f2415e18 --- /dev/null +++ b/src/query/docseq.cpp @@ -0,0 +1,53 @@ +#ifndef lint +static char rcsid[] = "@(#$Id: docseq.cpp,v 1.1 2005-11-25 10:02:36 dockes Exp $ (C) 2005 J.F.Dockes"; +#endif +#include "docseq.h" + +bool DocSequenceDb::getDoc(int num, Rcl::Doc &doc, int *percent) +{ + return db ? db->getDoc(num, doc, percent) : false; +} + +int DocSequenceDb::getResCnt() +{ + if (!db) + return -1; + // Need to fetch one document before we can get the result count + Rcl::Doc doc; + int percent; + db->getDoc(0, doc, &percent); + return db->getResCnt(); +} + + +bool DocSequenceHistory::getDoc(int num, Rcl::Doc &doc, int *percent) { + // Retrieve history list + if (!hist) + return false; + if (hlist.empty()) + hlist = hist->getDocHistory(); + + if (num < 0 || num >= (int)hlist.size()) + return false; + int skip; + if (prevnum >= 0 && num >= prevnum) { + skip = num - prevnum; + } else { + skip = num; + it = hlist.begin(); + } + prevnum = num; + while (skip--) + it++; + if (percent) + *percent = 100; + return db->getDoc((*it).first, (*it).second, doc); +} + +int DocSequenceHistory::getResCnt() +{ + if (hlist.empty()) + hlist = hist->getDocHistory(); + return hlist.size(); +} + diff --git a/src/query/docseq.h b/src/query/docseq.h new file mode 100644 index 00000000..832a528e --- /dev/null +++ b/src/query/docseq.h @@ -0,0 +1,53 @@ +#ifndef _DOCSEQ_H_INCLUDED_ +#define _DOCSEQ_H_INCLUDED_ +/* @(#$Id: docseq.h,v 1.1 2005-11-25 10:02:36 dockes Exp $ (C) 2004 J.F.Dockes */ + +#include "rcldb.h" +#include "history.h" + +/** Interface for a list of documents coming from some source. + + The result list display data may come from different sources (ie: + history or Db query). We have an interface to make things cleaner. +*/ +class DocSequence { + public: + virtual bool getDoc(int num, Rcl::Doc &doc, int *percent) = 0; + virtual int getResCnt() = 0; + virtual std::string title() = 0; +}; + + +/** A DocSequence from a Db query (there should be one active for this + to make sense */ +class DocSequenceDb : public DocSequence { + public: + DocSequenceDb(Rcl::Db *d) : db(d) {} + virtual ~DocSequenceDb() {} + virtual bool getDoc(int num, Rcl::Doc &doc, int *percent); + virtual int getResCnt(); + virtual std::string title() {return string("Query results");} + private: + Rcl::Db *db; +}; + +/** A DocSequence coming from the history file */ +class DocSequenceHistory : public DocSequence { + public: + DocSequenceHistory(Rcl::Db *d, RclQHistory *h) + : db(d), hist(h), prevnum(-1) {} + virtual ~DocSequenceHistory() {} + + virtual bool getDoc(int num, Rcl::Doc &doc, int *percent); + virtual int getResCnt(); + virtual std::string title() {return string("Document history");} + private: + Rcl::Db *db; + RclQHistory *hist; + int prevnum; + + std::list< std::pair<std::string, std::string> > hlist; + std::list< std::pair<std::string, std::string> >::const_iterator it; +}; + +#endif /* _DOCSEQ_H_INCLUDED_ */