diff --git a/src/kde/kioslave/recoll/data/help.html b/src/kde/kioslave/recoll/data/help.html index c953740b..9cf799a8 100644 --- a/src/kde/kioslave/recoll/data/help.html +++ b/src/kde/kioslave/recoll/data/help.html @@ -4,7 +4,7 @@ Recoll Kio Slave - + Recoll search

Recoll kio slave

Use this module to perform Recoll searches from any program with @@ -58,5 +58,7 @@ selection, copies, and other file operations on the results, which may be useful in some cases (or not :))

+

Recoll Search

+ diff --git a/src/kde/kioslave/recoll/dirif.cpp b/src/kde/kioslave/recoll/dirif.cpp index 4f0f144f..40272246 100644 --- a/src/kde/kioslave/recoll/dirif.cpp +++ b/src/kde/kioslave/recoll/dirif.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: dirif.cpp,v 1.4 2008-12-01 15:36:52 dockes Exp $ (C) 2008 J.F.Dockes"; +static char rcsid[] = "@(#$Id: dirif.cpp,v 1.5 2008-12-01 18:42:52 dockes Exp $ (C) 2008 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -39,7 +39,6 @@ static char rcsid[] = "@(#$Id: dirif.cpp,v 1.4 2008-12-01 15:36:52 dockes Exp $ #include #include #include - #include #include "kio_recoll.h" @@ -49,18 +48,24 @@ using namespace KIO; static const QString resultBaseName("recollResult"); -// +// Check if the input URL is of the form that konqueror builds by +// appending one of our result file names to the directory name (which +// is the search string). If it is, extract return the result document +// number. Possibly restart the search if the search string does not +// match the current one bool RecollProtocol::isRecollResult(const KUrl &url, int *num) { *num = -1; kDebug() << "url" << url << "m_srchStr" << m_srchStr; - // Does the url look like a recoll search result ?? + + // Basic checks if (!url.host().isEmpty() || url.path().isEmpty() || url.protocol().compare("recoll")) return false; QString path = url.path(); if (!path.startsWith("/")) return false; + // Look for the last '/' and check if it is followed by // resultBaseName (riiiight...) int slashpos = path.lastIndexOf("/"); @@ -72,6 +77,7 @@ bool RecollProtocol::isRecollResult(const KUrl &url, int *num) if (path.mid(slashpos, resultBaseName.length()).compare(resultBaseName)) return false; + // Extract the result number QString snum = path.mid(slashpos + resultBaseName.length()); sscanf(snum.toAscii(), "%d", num); if (*num == -1) @@ -84,7 +90,6 @@ bool RecollProtocol::isRecollResult(const KUrl &url, int *num) QString searchstring = path.mid(1, slashpos-2); kDebug() << "Comparing search strings" << m_srchStr << "and" << searchstring; if (searchstring.compare(m_srchStr)) { - kDebug() << "Starting new search"; if (!doSearch(searchstring)) return false; } @@ -92,6 +97,7 @@ bool RecollProtocol::isRecollResult(const KUrl &url, int *num) return true; } +// Translate rcldoc result into directory entry static const UDSEntry resultToUDSEntry(const Rcl::Doc& doc, int num) { UDSEntry entry; @@ -186,7 +192,9 @@ void RecollProtocol::stat(const KUrl & url) entry = resultToUDSEntry(doc, num); } } else { - // ?? + // Don't return an error here, we get stat() on yet unperformed searches + // ie stat("recoll:/some search string") + // Would have to perform the search, better to return bogus ok } entry.insert(KIO::UDSEntry::UDS_TARGET_URL, url.url()); @@ -202,8 +210,8 @@ void RecollProtocol::listDir(const KUrl& url) // autocompletion it comes with a / at the end, which offers // an opportunity to not perform it. if (url.path() != "/" && url.path().endsWith("/")) { - kDebug() << "Endswith/" << endl; - error(-1, ""); + kDebug() << "EndsWith /" << endl; + error(ERR_SLAVE_DEFINED, "Autocompletion search aborted"); return; } @@ -255,7 +263,6 @@ void RecollProtocol::listDir(const KUrl& url) vector page; int pagelen = m_source->getSeqSlice(0, numentries, page); - kDebug() << "Got " << pagelen << " results."; UDSEntryList entries; for (int i = 0; i < pagelen; i++) { entries.append(resultToUDSEntry(page[i].doc, i)); diff --git a/src/kde/kioslave/recoll/htmlif.cpp b/src/kde/kioslave/recoll/htmlif.cpp index 66e59971..a1d4cc41 100644 --- a/src/kde/kioslave/recoll/htmlif.cpp +++ b/src/kde/kioslave/recoll/htmlif.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: htmlif.cpp,v 1.3 2008-12-01 15:36:52 dockes Exp $ (C) 2005 J.F.Dockes"; +static char rcsid[] = "@(#$Id: htmlif.cpp,v 1.4 2008-12-01 18:42:52 dockes Exp $ (C) 2005 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -47,7 +47,8 @@ using namespace KIO; bool RecollKioPager::append(const string& data) { - if (!m_parent) return false; + if (!m_parent) + return false; m_parent->data(QByteArray(data.c_str())); return true; } @@ -65,7 +66,7 @@ const static string parformat = "Open  %T
" "%M %D   %U
" "%A %K"; -const string &RecollKioPager::parFormat() +const string& RecollKioPager::parFormat() { return parformat; } @@ -108,7 +109,7 @@ static string welcomedata; void RecollProtocol::welcomePage() { - kDebug() << endl; + kDebug(); mimeType("text/html"); if (welcomedata.empty()) { QString location = @@ -128,12 +129,11 @@ void RecollProtocol::welcomePage() subs['Q'] = ""; pcSubst(welcomedata, tmp, subs); data(tmp.c_str()); - kDebug() << "done" << endl; } void RecollProtocol::queryDetails() { - kDebug() << endl; + kDebug(); mimeType("text/html"); QByteArray array; QTextStream os(&array, QIODevice::WriteOnly); @@ -149,12 +149,13 @@ void RecollProtocol::queryDetails() "\">Return to results" << endl; os << "" << endl; data(array); - kDebug() << "done" << endl; } void RecollProtocol::htmlDoSearch(const QString& q, const QString &opt, int page) { - kDebug(); + kDebug() << "q" << q << "opt" << opt << "page" << page; + if (m_source.isNull()) + kDebug() << "Null source"; // Check if same search or need to start new if (q.compare(m_srchStr) || opt.compare(m_opt)) { if (!doSearch(q, opt)) @@ -177,23 +178,5 @@ void RecollProtocol::htmlDoSearch(const QString& q, const QString &opt, int page // Display mimeType("text/html"); m_pager.displayPage(); - kDebug() << "done" << endl; -} - -void RecollProtocol::outputError(const QString& errmsg) -{ - mimeType("text/html"); - QByteArray array; - QTextStream os(&array, QIODevice::WriteOnly); - - os << "" << endl; - os << "" << endl; - os << "" << endl; - os << "" << "Recoll error" << "\n" << endl; - os << "" << endl; - os << "

Recoll error: " << errmsg << "

" << endl; - os << "

New query

"<< endl; - os << "" << endl; - data(array); + kDebug() << "done"; } diff --git a/src/kde/kioslave/recoll/kio_recoll.cpp b/src/kde/kioslave/recoll/kio_recoll.cpp index 64aa58ac..f3d4ef42 100644 --- a/src/kde/kioslave/recoll/kio_recoll.cpp +++ b/src/kde/kioslave/recoll/kio_recoll.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: kio_recoll.cpp,v 1.19 2008-12-01 15:36:52 dockes Exp $ (C) 2005 J.F.Dockes"; +static char rcsid[] = "@(#$Id: kio_recoll.cpp,v 1.20 2008-12-01 18:42:52 dockes Exp $ (C) 2005 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -24,23 +24,14 @@ static char rcsid[] = "@(#$Id: kio_recoll.cpp,v 1.19 2008-12-01 15:36:52 dockes #include #include - using namespace std; -#include -#if (QT_VERSION < 0x040000) +#include #include #include #include -#else -#include -#include -#include -#endif #include - -//#include #include #include @@ -60,6 +51,7 @@ using namespace std; using namespace KIO; RclConfig *RecollProtocol::o_rclconfig; + RclConfig *RclConfig::getMainConfig() { return RecollProtocol::o_rclconfig; @@ -78,7 +70,8 @@ RecollProtocol::RecollProtocol(const QByteArray &pool, const QByteArray &app) } if (o_rclconfig->getDbDir().empty()) { // Note: this will have to be replaced by a call to a - // configuration buildin dialog for initial configuration + // configuration building dialog for initial configuration? Or + // do we assume that the QT GUO is always used for this ? m_reason = "No db directory in configuration ??"; return; } @@ -97,7 +90,7 @@ RecollProtocol::RecollProtocol(const QByteArray &pool, const QByteArray &app) // Doesn't seem needed in the kio context. RecollProtocol::~RecollProtocol() { - kDebug() << endl; + kDebug(); delete m_rcldb; } @@ -116,6 +109,7 @@ bool RecollProtocol::maybeOpenDb(string &reason) return true; } +// Not sure this is ever used void RecollProtocol::mimetype(const KUrl &url) { kDebug() << url << endl; @@ -126,6 +120,7 @@ void RecollProtocol::mimetype(const KUrl &url) bool RecollProtocol::URLToQuery(const KUrl &url, QString& q, QString& opt, int *page) { + // "recoll:/some query/" or "recoll:/some query" if (url.host().isEmpty()) { q = url.path(); opt = "l"; @@ -141,7 +136,7 @@ bool RecollProtocol::URLToQuery(const KUrl &url, QString& q, QString& opt, if (page) { QString p = url.queryItem("p"); if (p.isEmpty()) { - page = 0; + *page = 0; } else { sscanf(p.toAscii(), "%d", page); } @@ -149,9 +144,14 @@ bool RecollProtocol::URLToQuery(const KUrl &url, QString& q, QString& opt, } if (q.startsWith("/")) q.remove(0,1); + if (q.endsWith("/")) + q.chop(1); return true; } +// This is used by the html interface, but also by the directory one +// when doing file copies for exemple. This is the central dispatcher +// for requests, it has to know a little about both models. void RecollProtocol::get(const KUrl & url) { kDebug() << url << endl; @@ -199,13 +199,12 @@ void RecollProtocol::get(const KUrl & url) goto out; } } - kDebug() << "Unrecognized URL: " << url << endl; error(KIO::ERR_SLAVE_DEFINED, "Unrecognized URL"); out: finished(); - kDebug() << "done" << endl; } +// Execute Recoll search, and set the docsource etc. bool RecollProtocol::doSearch(const QString& q, const QString &qopt) { kDebug() << "query" << q << "opt" << qopt; @@ -234,11 +233,9 @@ bool RecollProtocol::doSearch(const QString& q, const QString &qopt) if (sd && clp) sd->addClause(clp); } else { - kDebug() << "Parsing query: " << qs.c_str(); sd = wasaStringToRcl(qs, m_reason); } if (!sd) { - kDebug() << "Could not build search data from user string"; m_reason = "Internal Error: cant build search"; error(KIO::ERR_SLAVE_DEFINED, m_reason.c_str()); finished(); @@ -247,26 +244,21 @@ bool RecollProtocol::doSearch(const QString& q, const QString &qopt) RefCntr sdata(sd); sdata->setStemlang("english"); - kDebug() << "Executing query"; RefCntrquery(new Rcl::Query(m_rcldb)); if (!query->setQuery(sdata)) { m_reason = "Query execute failed. Invalid query or syntax error?"; error(KIO::ERR_SLAVE_DEFINED, m_reason.c_str()); finished(); - kDebug() << "setQuery failed, returning"; return false; } - kDebug() << "Building docsequence"; DocSequenceDb *src = new DocSequenceDb(RefCntr(query), "Query results", sdata); if (src == 0) { - kDebug() << "Cant' build result sequence"; error(KIO::ERR_SLAVE_DEFINED, "Can't build result sequence"); finished(); return false; } - kDebug() << "Setting source"; m_source = RefCntr(src); return true; } diff --git a/src/kde/kioslave/recoll/kio_recoll.h b/src/kde/kioslave/recoll/kio_recoll.h index c8dcf80f..e490497d 100644 --- a/src/kde/kioslave/recoll/kio_recoll.h +++ b/src/kde/kioslave/recoll/kio_recoll.h @@ -1,5 +1,5 @@ #ifndef _RECOLL_H -/* @(#$Id: kio_recoll.h,v 1.10 2008-12-01 15:36:52 dockes Exp $ (C) 2005 J.F.Dockes */ +/* @(#$Id: kio_recoll.h,v 1.11 2008-12-01 18:42:52 dockes Exp $ (C) 2005 J.F.Dockes */ #define _RECOLL_H /* * This program is free software; you can redistribute it and/or modify @@ -22,12 +22,7 @@ using std::string; #include - -#if (QT_VERSION < 0x040000) #include -#else -#include -#endif #include #include @@ -42,6 +37,7 @@ using std::string; class RecollProtocol; +/** Specialize the recoll html pager for the kind of links we use etc. */ class RecollKioPager : public ResListPager { public: RecollKioPager() : m_parent(0) {} @@ -53,16 +49,44 @@ public: virtual string nextUrl(); virtual string prevUrl(); virtual string pageTop(); + private: RecollProtocol *m_parent; }; +/** + * A KIO slave to execute and display Recoll searches. + * + * Things are made a little complicated because KIO slaves can't hope + * that their internal state will remain consistent with their user + * application state: slaves die, are restarted, reused, at random + * between requests. + * In our case, this means that any request has to be processed + * without reference to the last operation performed. Ie, if the + * search parameters are not those from the last request, the search + * must be restarted anew. This happens for example with different + * searches in 2 konqueror screens: typically only one kio_slave will + * be used. + * The fact that we check if the search is the same as the last one, + * to avoid restarting is an optimization, not the base mechanism + * (contrary to what was initially assumed, and may have left a few + * crumbs around). + * + * We have two modes of operation, one based on html forms and result + * pages, which can potentially be developped to the full Recoll + * functionality, and one based on a directory listing model, which + * will always be more limited, but may be useful in some cases to + * allow easy copying of files etc. Which one is in use is decided by + * the form of the URL. + */ class RecollProtocol : public KIO::SlaveBase { public: RecollProtocol(const QByteArray &pool, const QByteArray &app ); virtual ~RecollProtocol(); - virtual void mimetype(const KUrl & url ); - virtual void get(const KUrl & url ); + virtual void mimetype(const KUrl& url); + virtual void get(const KUrl& url); + // The directory mode is not available with KDE 4.0, I could find + // no way to avoid crashing kdirmodel #if KDE_IS_VERSION(4,1,0) virtual void stat(const KUrl & url); virtual void listDir(const KUrl& url); @@ -71,29 +95,30 @@ class RecollProtocol : public KIO::SlaveBase { static RclConfig *o_rclconfig; friend class RecollKioPager; + private: - bool maybeOpenDb(string &reason); - void outputError(const QString& errmsg); + bool maybeOpenDb(string& reason); + bool URLToQuery(const KUrl &url, QString& q, QString& opt, int *page=0); bool doSearch(const QString& q, const QString& opt = "l"); + void welcomePage(); void queryDetails(); - void htmlDoSearch(const QString& q, const QString& opt, int page); - bool URLToQuery(const KUrl &url, QString& q, QString& opt, int *page=0); - bool isRecollResult(const KUrl &url, int *num); string makeQueryUrl(int page); + void htmlDoSearch(const QString& q, const QString& opt, int page); + + bool isRecollResult(const KUrl &url, int *num); bool m_initok; Rcl::Db *m_rcldb; - std::string m_reason; + string m_reason; - // All details about the current search state: because of how the - // KIO slaves are used / reused, we can't be sure that the next - // request will be for the same search, and we need to check and - // restart one if the data changes. This is very wasteful of - // course but hopefully won't happen too much in actual use. One - // possible workaround for some scenarios (one slave several - // konqueror windows) would be to have a small cache of recent - // searches kept open. + // Search state: because of how the KIO slaves are used / reused, + // we can't be sure that the next request will be for the same + // search, and we need to check and restart one if the data + // changes. This is very wasteful but hopefully won't happen too + // much in actual use. One possible workaround for some scenarios + // (one slave several konqueror windows) would be to have a small + // cache of recent searches kept open. RecollKioPager m_pager; RefCntr m_source; QString m_srchStr;