seems to work by re-rerunning search whenever it changes. Still had one crash, needs cleanup

This commit is contained in:
dockes 2008-12-01 15:36:52 +00:00
parent ae77b9fb99
commit e106918cfc
9 changed files with 320 additions and 101 deletions

View File

@ -123,5 +123,5 @@ ELSE ("${KDE_VERSION_MAJOR}.${KDE_VERSION_MINOR}" GREATER 4.0)
RENAME recoll.protocol) RENAME recoll.protocol)
ENDIF ("${KDE_VERSION_MAJOR}.${KDE_VERSION_MINOR}" GREATER 4.0) ENDIF ("${KDE_VERSION_MAJOR}.${KDE_VERSION_MINOR}" GREATER 4.0)
install(FILES data/welcome.html install(FILES data/welcome.html data/help.html
DESTINATION ${DATA_INSTALL_DIR}/kio_recoll) DESTINATION ${DATA_INSTALL_DIR}/kio_recoll)

View File

@ -1,2 +1,6 @@
#!/bin/sh #!/bin/sh
rm -rf CMakeCache.txt CMakeFiles cmake_install.cmake CMakeTmp cmake_uninstall.cmake CPackConfig.cmake CPackSourceConfig.cmake DartTestfile.txt install_manifest.txt kio_recoll_automoc.cpp kio_recoll_automoc.cpp.files kio_recoll.la kio_recoll.so lib Makefile rm -rf CMakeCache.txt CMakeFiles CTestTestfile.cmake \
cmake_install.cmake CMakeTmp cmake_uninstall.cmake \
CPackConfig.cmake CPackSourceConfig.cmake DartTestfile.txt \
install_manifest.txt kio_recoll_automoc.cpp \
kio_recoll_automoc.cpp.files kio_recoll.la kio_recoll.so lib Makefile

View File

@ -0,0 +1,62 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Recoll Kio Slave</title>
</head>
<body>
<h3>Recoll kio slave</h3>
<p>Use this module to perform Recoll searches from any program with
a KIO interface (sort of...). <b>kio_recoll</b> is primarily
designed and tested with <b>konqueror</b>, and you will
undoubtedly get even more surprising effects with other tools.</p>
<p>The module can work in two different modes, depending on the form
of the URLS that it is given:</p>
<li><b>Html interface</b>: this is what you get into when you just type
recoll: or recoll:/ in the address bar, and then click the initial
icon.</li>
<li><b>File/Directory interface</b>: which you enter when you pass
an URL ending with a '/'</li>
<p>Please note that this module is still in its infancy and that it
is still more a toy than anything else. The semantics of the
KIO slaves interface is still a bit unstable between KDE releases,
you will certainly get surprising effects from time to time.</p>
<h4>HTML interface</h4>
<p>This works more or less like the Recoll QT GUI, much
simplified. The
<a href="http://www.recoll.org/usermanual/rcl.search.lang.html">
Recoll manual</a> describes the queries that can be
performed.</p>
<p>Most pages in the interface should quite self-explanatory.</p>
<h4>File interface</h4>
<p>kio_recoll enters this mode when it receives an URL ending with
a&nbsp;'/', ie:</p>
<blockquote><i>recoll:///xapian recoll ext:.html/</i></blockquote>
<p>The <i>path</i> part of the URI is taken as a Recoll query
language string and executed. The results are displayed as
directory entries.</p>
<p>This works fine with normal documents, very badly with message
inside folders, which Konqueror has no way to access.</p>
<p>As there is no provision to page directory listings, the number
of results returned is limited to a fixed value, 100 by default,
which you can change by setting the kio_max_direntries in your
Recoll configuration file (usually ~/.recoll).
<a href="http://www.recoll.org/usermanual/rcl.install.config.html">
More information about Recoll configuration.</a></p>
<p>This interface is very limited, but allows performing multiple
selection, copies, and other file operations on the results, which
may be useful in some cases (or not :))</p>
</body>
</html>

View File

@ -7,14 +7,19 @@
<h3>Recoll search</h3> <h3>Recoll search</h3>
<p><form method="get" action="recoll://search/query"> <p>
<form method="get" action="recoll://search/query">
Query type:<br> Query type:<br>
<input type="radio" name="qtp" value="l" checked>Query language<br> <input type="radio" name="qtp" value="l" checked>Query language<br>
<input type="radio" name="qtp" value="a">All terms<br> <input type="radio" name="qtp" value="a">All terms<br>
<input type="radio" name="qtp" value="o">Any term<br> <input type="radio" name="qtp" value="o">Any term<br>
<input type="radio" name="qtp" value="f">File name<br>
Enter search string: <input type="text" name="q" size="40" value="%Q"> <input type="hidden" name="p" value="0">
<input type="submit" value="Search"></p> Enter search string: <input type="text" name="q" size="40" value="%Q">
<input type="submit" value="Search">
</form>
</p>
</body> </body>
</html> </html>

View File

@ -1,5 +1,5 @@
#ifndef lint #ifndef lint
static char rcsid[] = "@(#$Id: dirif.cpp,v 1.3 2008-11-28 09:14:42 dockes Exp $ (C) 2008 J.F.Dockes"; static char rcsid[] = "@(#$Id: dirif.cpp,v 1.4 2008-12-01 15:36:52 dockes Exp $ (C) 2008 J.F.Dockes";
#endif #endif
/* /*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -28,6 +28,7 @@ static char rcsid[] = "@(#$Id: dirif.cpp,v 1.3 2008-11-28 09:14:42 dockes Exp $
*/ */
#include <kdeversion.h> #include <kdeversion.h>
#if KDE_IS_VERSION(4,1,0) #if KDE_IS_VERSION(4,1,0)
// Couldn't get listDir() to work with kde 4.0, konqueror keeps // Couldn't get listDir() to work with kde 4.0, konqueror keeps
// crashing because of kdirmodel, couldn't find a workaround (not // crashing because of kdirmodel, couldn't find a workaround (not
@ -37,39 +38,71 @@ static char rcsid[] = "@(#$Id: dirif.cpp,v 1.3 2008-11-28 09:14:42 dockes Exp $
#include <kurl.h> #include <kurl.h>
#include <kio/global.h> #include <kio/global.h>
#include <kstandarddirs.h>
#include <kdebug.h> #include <kdebug.h>
#include "kio_recoll.h" #include "kio_recoll.h"
#include "pathut.h"
using namespace KIO; using namespace KIO;
void RecollProtocol::stat(const KUrl & url) static const QString resultBaseName("recollResult");
{
kDebug() << url << endl ;
//
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 ??
if (!url.host().isEmpty() || url.path().isEmpty() ||
url.protocol().compare("recoll"))
return false;
QString path = url.path(); QString path = url.path();
KIO::UDSEntry entry; if (!path.startsWith("/"))
if (!path.compare("/")) return false;
entry.insert(KIO::UDSEntry::UDS_NAME, "/welcome"); // Look for the last '/' and check if it is followed by
else // resultBaseName (riiiight...)
entry.insert(KIO::UDSEntry::UDS_NAME, url.path()); int slashpos = path.lastIndexOf("/");
entry.insert(KIO::UDSEntry::UDS_TARGET_URL, url.url()); if (slashpos == -1 || slashpos == 0 || slashpos == path.length() -1)
entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG); return false;
statEntry(entry); slashpos++;
finished(); kDebug() << "Comparing " << path.mid(slashpos, resultBaseName.length()) <<
"and " << resultBaseName;
if (path.mid(slashpos, resultBaseName.length()).compare(resultBaseName))
return false;
QString snum = path.mid(slashpos + resultBaseName.length());
sscanf(snum.toAscii(), "%d", num);
if (*num == -1)
return false;
kDebug() << "URL analysis ok, num:" << *num;
// We do have something that ressembles a recoll result locator. Check if
// this matches the current search, else have to run the requested one
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;
}
return true;
} }
static const UDSEntry resultToUDSEntry(const Rcl::Doc& doc, int num)
const UDSEntry resultToUDSEntry(Rcl::Doc doc)
{ {
UDSEntry entry; UDSEntry entry;
KUrl url(doc.url.c_str()); KUrl url(doc.url.c_str());
kDebug() << doc.url.c_str(); kDebug() << doc.url.c_str();
entry.insert(KIO::UDSEntry::UDS_NAME, url.fileName()); entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, url.fileName());
char cnum[30];sprintf(cnum, "%d", num);
entry.insert(KIO::UDSEntry::UDS_NAME, resultBaseName + cnum);
if (!doc.mimetype.compare("application/x-fsdirectory")) { if (!doc.mimetype.compare("application/x-fsdirectory")) {
entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, "inode/directory"); entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, "inode/directory");
entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
@ -87,17 +120,16 @@ const UDSEntry resultToUDSEntry(Rcl::Doc doc)
entry.insert( KIO::UDSEntry::UDS_ACCESS_TIME, info.st_atime); entry.insert( KIO::UDSEntry::UDS_ACCESS_TIME, info.st_atime);
entry.insert( KIO::UDSEntry::UDS_CREATION_TIME, info.st_ctime); entry.insert( KIO::UDSEntry::UDS_CREATION_TIME, info.st_ctime);
} }
kDebug() << "entry URL: " << doc.url.c_str();
entry.insert(KIO::UDSEntry::UDS_TARGET_URL, doc.url.c_str()); entry.insert(KIO::UDSEntry::UDS_TARGET_URL, doc.url.c_str());
// entry.insert(KIO::UDSEntry::UDS_URL, "recoll://search/query/1");
return entry; return entry;
} }
// From kio_beagle // From kio_beagle
void RecollProtocol::createRootEntry(KIO::UDSEntry& entry) static void createRootEntry(KIO::UDSEntry& entry)
{ {
// home directory
entry.clear(); entry.clear();
entry.insert( KIO::UDSEntry::UDS_NAME, "."); entry.insert( KIO::UDSEntry::UDS_NAME, ".");
entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
@ -105,11 +137,12 @@ void RecollProtocol::createRootEntry(KIO::UDSEntry& entry)
entry.insert( KIO::UDSEntry::UDS_MIME_TYPE, "inode/directory"); entry.insert( KIO::UDSEntry::UDS_MIME_TYPE, "inode/directory");
} }
void RecollProtocol::createGoHomeEntry(KIO::UDSEntry& entry) // Points to html query screen
static void createGoHomeEntry(KIO::UDSEntry& entry)
{ {
// status file
entry.clear(); entry.clear();
entry.insert(KIO::UDSEntry::UDS_NAME, "Recoll home (click me)"); entry.insert(KIO::UDSEntry::UDS_NAME, "search");
entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, "Recoll search (click me)");
entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG); entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
entry.insert(KIO::UDSEntry::UDS_TARGET_URL, "recoll:///welcome"); entry.insert(KIO::UDSEntry::UDS_TARGET_URL, "recoll:///welcome");
entry.insert(KIO::UDSEntry::UDS_ACCESS, 0500); entry.insert(KIO::UDSEntry::UDS_ACCESS, 0500);
@ -117,6 +150,49 @@ void RecollProtocol::createGoHomeEntry(KIO::UDSEntry& entry)
entry.insert(KIO::UDSEntry::UDS_ICON_NAME, "recoll"); entry.insert(KIO::UDSEntry::UDS_ICON_NAME, "recoll");
} }
// Points to help file
static void createGoHelpEntry(KIO::UDSEntry& entry)
{
QString location =
KStandardDirs::locate("data", "kio_recoll/help.html");
entry.clear();
entry.insert(KIO::UDSEntry::UDS_NAME, "help");
entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, "Recoll help (click me first)");
entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
entry.insert(KIO::UDSEntry::UDS_TARGET_URL, QString("file://") +
location);
entry.insert(KIO::UDSEntry::UDS_ACCESS, 0500);
entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, "text/html");
entry.insert(KIO::UDSEntry::UDS_ICON_NAME, "help");
}
void RecollProtocol::stat(const KUrl & url)
{
kDebug() << url << endl ;
int num = -1;
QString path = url.path();
KIO::UDSEntry entry;
if (!path.compare("/")) {
createRootEntry(entry);
} else if (!path.compare("/help")) {
createGoHelpEntry(entry);
} else if (!path.compare("/search")) {
createGoHomeEntry(entry);
} else if (isRecollResult(url, &num)) {
// If this url starts with the current search url appended with a
// result name appended, let's stat said result.
Rcl::Doc doc;
if (num >= 0 && !m_source.isNull() && m_source->getDoc(num, doc)) {
entry = resultToUDSEntry(doc, num);
}
} else {
// ??
}
entry.insert(KIO::UDSEntry::UDS_TARGET_URL, url.url());
statEntry(entry);
finished();
}
void RecollProtocol::listDir(const KUrl& url) void RecollProtocol::listDir(const KUrl& url)
{ {
@ -136,6 +212,7 @@ void RecollProtocol::listDir(const KUrl& url)
error(KIO::ERR_SLAVE_DEFINED, reason.c_str()); error(KIO::ERR_SLAVE_DEFINED, reason.c_str());
return; return;
} }
if (url.path().isEmpty() || url.path() == "/") { if (url.path().isEmpty() || url.path() == "/") {
kDebug() << "list /" << endl; kDebug() << "list /" << endl;
@ -144,12 +221,11 @@ void RecollProtocol::listDir(const KUrl& url)
// entry for '/' // entry for '/'
createRootEntry(entry); createRootEntry(entry);
// listEntry(entry, false);
entries.append(entry); entries.append(entry);
// entry for 'Information'
createGoHomeEntry(entry); createGoHomeEntry(entry);
// listEntry(entry, false); entries.append(entry);
createGoHelpEntry(entry);
entries.append(entry); entries.append(entry);
listEntries(entries); listEntries(entries);
@ -157,23 +233,32 @@ void RecollProtocol::listDir(const KUrl& url)
return; return;
} }
QString query, opt; QString query, opt;
URLToQuery(url, query, opt); URLToQuery(url, query, opt);
kDebug() << "Query: " << query; kDebug() << "Query: " << query;
if (!query.isEmpty()) { if (!query.isEmpty()) {
if (!doSearch(query, opt.toUtf8().at(0))) if (!doSearch(query, opt))
return; return;
} else { } else {
finished(); finished();
return; return;
} }
static int numentries = -1;
if (numentries == -1) {
if (o_rclconfig)
o_rclconfig->getConfParam("kio_max_direntries", &numentries);
if (numentries == -1)
numentries = 100;
}
vector<ResListEntry> page; vector<ResListEntry> page;
int pagelen = m_source->getSeqSlice(0, 100, page); int pagelen = m_source->getSeqSlice(0, numentries, page);
kDebug() << "Got " << pagelen << " results."; kDebug() << "Got " << pagelen << " results.";
UDSEntryList entries; UDSEntryList entries;
for (int i = 0; i < pagelen; i++) { for (int i = 0; i < pagelen; i++) {
entries.append(resultToUDSEntry(page[i].doc)); entries.append(resultToUDSEntry(page[i].doc, i));
} }
listEntries(entries); listEntries(entries);
finished(); finished();

View File

@ -1,5 +1,5 @@
#ifndef lint #ifndef lint
static char rcsid[] = "@(#$Id: htmlif.cpp,v 1.2 2008-11-27 17:48:43 dockes Exp $ (C) 2005 J.F.Dockes"; static char rcsid[] = "@(#$Id: htmlif.cpp,v 1.3 2008-12-01 15:36:52 dockes Exp $ (C) 2005 J.F.Dockes";
#endif #endif
/* /*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -75,6 +75,15 @@ string RecollKioPager::pageTop()
return "<p align=\"center\"><a href=\"recoll:///welcome\">New Search</a></p>"; return "<p align=\"center\"><a href=\"recoll:///welcome\">New Search</a></p>";
} }
string RecollProtocol::makeQueryUrl(int page)
{
char buf[100];
sprintf(buf, "recoll://search/query?q=%s&qtp=%s&p=%d",
(const char*)m_srchStr.toUtf8(), (const char*)m_opt.toUtf8(),
page);
return string(buf);
}
string RecollKioPager::nextUrl() string RecollKioPager::nextUrl()
{ {
int pagenum = pageNumber(); int pagenum = pageNumber();
@ -82,10 +91,9 @@ string RecollKioPager::nextUrl()
pagenum = 0; pagenum = 0;
else else
pagenum++; pagenum++;
char buf[100]; return m_parent->makeQueryUrl(pagenum);
sprintf(buf, "recoll://command/Page%d", pagenum);
return buf;
} }
string RecollKioPager::prevUrl() string RecollKioPager::prevUrl()
{ {
int pagenum = pageNumber(); int pagenum = pageNumber();
@ -93,9 +101,7 @@ string RecollKioPager::prevUrl()
pagenum = 0; pagenum = 0;
else else
pagenum--; pagenum--;
char buf[100]; return m_parent->makeQueryUrl(pagenum);
sprintf(buf, "recoll://command/Page%d", pagenum);
return buf;
} }
static string welcomedata; static string welcomedata;
@ -139,21 +145,37 @@ void RecollProtocol::queryDetails()
os << "</head>" << endl; os << "</head>" << endl;
os << "<body><h3>Query details:</h3>" << endl; os << "<body><h3>Query details:</h3>" << endl;
os << "<p>" << m_pager.queryDescription().c_str() <<"</p>"<< endl; os << "<p>" << m_pager.queryDescription().c_str() <<"</p>"<< endl;
os << "<p><a href=\"recoll://command/Page" << os << "<p><a href=\"" << makeQueryUrl(m_pager.pageNumber()).c_str() <<
m_pager.pageNumber() << "\">Return to results</a>" << endl; "\">Return to results</a>" << endl;
os << "</body></html>" << endl; os << "</body></html>" << endl;
data(array); data(array);
kDebug() << "done" << endl; kDebug() << "done" << endl;
} }
void RecollProtocol::htmlDoSearch(const QString& q, char opt) void RecollProtocol::htmlDoSearch(const QString& q, const QString &opt, int page)
{ {
kDebug() << "htmlDoSearch" << endl; kDebug();
if (!doSearch(q, opt)) // Check if same search or need to start new
return; if (q.compare(m_srchStr) || opt.compare(m_opt)) {
if (!doSearch(q, opt))
return;
m_pager.setDocSource(m_source);
// goto page 0
m_pager.resultPageNext();
}
// Check / adjust page number
if (page > m_pager.pageNumber()) {
int npages = page - m_pager.pageNumber();
for (int i = 0; i < npages; i++)
m_pager.resultPageNext();
} else if (page < m_pager.pageNumber()) {
int npages = m_pager.pageNumber() - page;
for (int i = 0; i < npages; i++)
m_pager.resultPageBack();
}
// Display
mimeType("text/html"); mimeType("text/html");
m_pager.setDocSource(m_source);
m_pager.resultPageNext();
m_pager.displayPage(); m_pager.displayPage();
kDebug() << "done" << endl; kDebug() << "done" << endl;
} }

View File

@ -1,5 +1,5 @@
#ifndef lint #ifndef lint
static char rcsid[] = "@(#$Id: kio_recoll.cpp,v 1.18 2008-11-28 09:14:42 dockes Exp $ (C) 2005 J.F.Dockes"; static char rcsid[] = "@(#$Id: kio_recoll.cpp,v 1.19 2008-12-01 15:36:52 dockes Exp $ (C) 2005 J.F.Dockes";
#endif #endif
/* /*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -66,7 +66,7 @@ RclConfig *RclConfig::getMainConfig()
} }
RecollProtocol::RecollProtocol(const QByteArray &pool, const QByteArray &app) RecollProtocol::RecollProtocol(const QByteArray &pool, const QByteArray &app)
: SlaveBase("recoll", pool, app), m_initok(false), m_rcldb(0) : SlaveBase("recoll", pool, app), m_initok(false), m_rcldb(0), m_opt("l")
{ {
kDebug() << endl; kDebug() << endl;
if (o_rclconfig == 0) { if (o_rclconfig == 0) {
@ -123,11 +123,14 @@ void RecollProtocol::mimetype(const KUrl &url)
finished(); finished();
} }
bool RecollProtocol::URLToQuery(const KUrl &url, QString& q, QString& opt) bool RecollProtocol::URLToQuery(const KUrl &url, QString& q, QString& opt,
int *page)
{ {
if (url.host().isEmpty()) { if (url.host().isEmpty()) {
q = url.path(); q = url.path();
opt = "l"; opt = "l";
if (page)
*page = 0;
} else { } else {
// Decode the forms' arguments // Decode the forms' arguments
q = url.queryItem("q"); q = url.queryItem("q");
@ -135,6 +138,14 @@ bool RecollProtocol::URLToQuery(const KUrl &url, QString& q, QString& opt)
if (opt.isEmpty()) { if (opt.isEmpty()) {
opt = "l"; opt = "l";
} }
if (page) {
QString p = url.queryItem("p");
if (p.isEmpty()) {
page = 0;
} else {
sscanf(p.toAscii(), "%d", page);
}
}
} }
if (q.startsWith("/")) if (q.startsWith("/"))
q.remove(0,1); q.remove(0,1);
@ -146,7 +157,7 @@ void RecollProtocol::get(const KUrl & url)
kDebug() << url << endl; kDebug() << url << endl;
if (!m_initok || !maybeOpenDb(m_reason)) { if (!m_initok || !maybeOpenDb(m_reason)) {
string reason = "RecollProtocol::get:Init error: " + m_reason; string reason = "Recoll: init error: " + m_reason;
error(KIO::ERR_SLAVE_DEFINED, reason.c_str()); error(KIO::ERR_SLAVE_DEFINED, reason.c_str());
return; return;
} }
@ -154,56 +165,53 @@ void RecollProtocol::get(const KUrl & url)
QString host = url.host(); QString host = url.host();
QString path = url.path(); QString path = url.path();
kDebug() << "host:" << host << " path:" << path; int docnum = -1;
if (host.isEmpty() && if (host.isEmpty() &&
(path.isEmpty() || !path.compare("/")||!path.compare("/welcome"))) { (path.isEmpty() || !path.compare("/")||!path.compare("/welcome"))) {
// recoll:/ // recoll:/ : print the html form page
welcomePage(); welcomePage();
goto out; goto out;
} else if ((!host.compare("search") && !path.compare("/query")) } else if (host.isEmpty() && isRecollResult(url, &docnum)) {
|| host.isEmpty()) { // Matched an url generated by konqueror out of a directory listing:
// ie: recoll:/some search string/recollResultxx
// Redirect to the result document URL
Rcl::Doc doc;
if (docnum >= 0 && !m_source.isNull() && m_source->getDoc(docnum, doc)) {
mimeType(doc.mimetype.c_str());
redirection(KUrl::fromLocalFile((const char *)(doc.url.c_str()+7)));
goto out;
}
} else if (host.isEmpty() ||
(!host.compare("search") && !path.compare("/query"))) {
// Either "recoll://search/query?query args" // Either "recoll://search/query?query args"
// Or "recoll: some search string" // Or "recoll:[/]some search string"
// HTML style query, maybe initial or request for other page
QString query, opt; QString query, opt;
URLToQuery(url, query, opt); int page;
URLToQuery(url, query, opt, &page);
if (!query.isEmpty()) { if (!query.isEmpty()) {
htmlDoSearch(query, opt.toUtf8().at(0)); htmlDoSearch(query, opt, page);
goto out; goto out;
} }
} else if (!host.compare("command")) { } else if (!host.compare("command")) {
if (!path.isEmpty()) { if (path.indexOf("/QueryDetails") == 0) {
if (path.indexOf("/Page") == 0) { queryDetails();
int newpage = 0; goto out;
sscanf(path.toUtf8(), "/Page%d", &newpage);
if (newpage > m_pager.pageNumber()) {
int npages = newpage - m_pager.pageNumber();
for (int i = 0; i < npages; i++)
m_pager.resultPageNext();
} else if (newpage < m_pager.pageNumber()) {
int npages = m_pager.pageNumber() - newpage;
for (int i = 0; i < npages; i++)
m_pager.resultPageBack();
}
mimeType("text/html");
m_pager.displayPage();
goto out;
} else if (path.indexOf("/QueryDetails") == 0) {
queryDetails();
goto out;
}
} }
} }
kDebug() << "Unrecognized URL" << endl; kDebug() << "Unrecognized URL: " << url << endl;
outputError("unrecognized URL"); error(KIO::ERR_SLAVE_DEFINED, "Unrecognized URL");
out: out:
finished(); finished();
kDebug() << "done" << endl; kDebug() << "done" << endl;
} }
bool RecollProtocol::doSearch(const QString& q, char opt) bool RecollProtocol::doSearch(const QString& q, const QString &qopt)
{ {
kDebug() << q << endl; kDebug() << "query" << q << "opt" << qopt;
m_srchStr = q;
m_opt = qopt;
char opt = qopt.isEmpty() ? 'l' : qopt.toUtf8().at(0);
string qs = (const char *)q.toUtf8(); string qs = (const char *)q.toUtf8();
Rcl::SearchData *sd = 0; Rcl::SearchData *sd = 0;
if (opt != 'l') { if (opt != 'l') {
@ -232,7 +240,7 @@ bool RecollProtocol::doSearch(const QString& q, char opt)
if (!sd) { if (!sd) {
kDebug() << "Could not build search data from user string"; kDebug() << "Could not build search data from user string";
m_reason = "Internal Error: cant build search"; m_reason = "Internal Error: cant build search";
error(-1, m_reason.c_str()); error(KIO::ERR_SLAVE_DEFINED, m_reason.c_str());
finished(); finished();
return false; return false;
} }
@ -242,8 +250,8 @@ bool RecollProtocol::doSearch(const QString& q, char opt)
kDebug() << "Executing query"; kDebug() << "Executing query";
RefCntr<Rcl::Query>query(new Rcl::Query(m_rcldb)); RefCntr<Rcl::Query>query(new Rcl::Query(m_rcldb));
if (!query->setQuery(sdata)) { if (!query->setQuery(sdata)) {
m_reason = "Internal Error: query execute failed"; m_reason = "Query execute failed. Invalid query or syntax error?";
error(-1, m_reason.c_str()); error(KIO::ERR_SLAVE_DEFINED, m_reason.c_str());
finished(); finished();
kDebug() << "setQuery failed, returning"; kDebug() << "setQuery failed, returning";
return false; return false;
@ -254,7 +262,7 @@ bool RecollProtocol::doSearch(const QString& q, char opt)
new DocSequenceDb(RefCntr<Rcl::Query>(query), "Query results", sdata); new DocSequenceDb(RefCntr<Rcl::Query>(query), "Query results", sdata);
if (src == 0) { if (src == 0) {
kDebug() << "Cant' build result sequence"; kDebug() << "Cant' build result sequence";
error(-1, "Can't build result sequence"); error(KIO::ERR_SLAVE_DEFINED, "Can't build result sequence");
finished(); finished();
return false; return false;
} }

View File

@ -1,5 +1,5 @@
#ifndef _RECOLL_H #ifndef _RECOLL_H
/* @(#$Id: kio_recoll.h,v 1.9 2008-11-28 09:14:42 dockes Exp $ (C) 2005 J.F.Dockes */ /* @(#$Id: kio_recoll.h,v 1.10 2008-12-01 15:36:52 dockes Exp $ (C) 2005 J.F.Dockes */
#define _RECOLL_H #define _RECOLL_H
/* /*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -70,23 +70,36 @@ class RecollProtocol : public KIO::SlaveBase {
static RclConfig *o_rclconfig; static RclConfig *o_rclconfig;
friend class RecollKioPager;
private: private:
bool maybeOpenDb(string &reason); bool maybeOpenDb(string &reason);
void outputError(const QString& errmsg); void outputError(const QString& errmsg);
bool doSearch(const QString& q, char opt = 'l'); bool doSearch(const QString& q, const QString& opt = "l");
void welcomePage(); void welcomePage();
void queryDetails(); void queryDetails();
void htmlDoSearch(const QString& q, char opt); void htmlDoSearch(const QString& q, const QString& opt, int page);
bool URLToQuery(const KUrl &url, QString& q, QString& opt); bool URLToQuery(const KUrl &url, QString& q, QString& opt, int *page=0);
void createRootEntry(KIO::UDSEntry& entry); bool isRecollResult(const KUrl &url, int *num);
void createGoHomeEntry(KIO::UDSEntry& entry); string makeQueryUrl(int page);
bool m_initok; bool m_initok;
Rcl::Db *m_rcldb; Rcl::Db *m_rcldb;
std::string m_reason; std::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.
RecollKioPager m_pager; RecollKioPager m_pager;
RefCntr<DocSequence> m_source; RefCntr<DocSequence> m_source;
QString m_srchStr;
QString m_opt;
}; };
extern "C" {int kdemain(int, char**);} extern "C" {int kdemain(int, char**);}
#endif // _RECOLL_H #endif // _RECOLL_H

View File

@ -34,3 +34,23 @@ le changement ne s'opere pas toujours immediatement quand on change le
fichier .proto, y compris apres avoir tue tous les process kde (changement fichier .proto, y compris apres avoir tue tous les process kde (changement
à la deuxieme execution de konqueror sur kde4.0). Sur kde4.0 il faut que le à la deuxieme execution de konqueror sur kde4.0). Sur kde4.0 il faut que le
.proto soit sans entree "listing" .proto soit sans entree "listing"
Les KIO slaves ne sont pas associes a une fenetre ! ils sont
reutilises au hasard, et leur etat n'a aucune raison de correspondre a
celui de l'affichage. On peut tres bien avoir 1 fenetre 2 kio ou 1 kio
deux fenetres, et le next d'un search peut arriver au kio qui a
l'autre search, donc n'importenaouak. Il faudrait que l'etat soit
partage et accede par un identifiant uniquement determine par l'url de
la fenetre.
Meme pour une fenetre unique, au bout d'un moment le kio timeout et exite.
En fait les slaves ne peuvent pas stocker d'etat du tout. Donc:
- soit un serveur central auquel ils parlent
- soit ils relancent dynamiquement les recherches si pas de match
C'est vrai aussi bien pour les dirlists que pour la version html.
J'ai essaye de mettre une boucle timeout callback callspecial() mais
ca ne sert a rien, c'est gere dans le process kio_slave, ca ne
maintient pas l'association avec un konqueror.