kioslave sort of works
This commit is contained in:
parent
be8f0a2b4e
commit
31f704f564
@ -1,6 +1,4 @@
|
||||
|
||||
(this used to work but last time I tried with konqueror (kde3, 11-2007), it failed with "protocol not authorized" or such. Didn't investigate more).
|
||||
|
||||
This is a small experiment with a recoll kio_slave
|
||||
|
||||
A kio_slave was implemented, supporting the "get" operation. Ie, you type
|
||||
@ -15,25 +13,38 @@ quite useful in this case.
|
||||
Implementation notes:
|
||||
-----------------------
|
||||
|
||||
- There are two main ways to do this:
|
||||
- a-la kio_beagle, using listDir() to list entries pointing to the
|
||||
different operations or objects (help, status, search result
|
||||
entries, bookmarks, whatever...). The nice thing is that the
|
||||
results really look like file object in a directory (probably,
|
||||
didn't try it actually), no need for look and feel, it's provided by kde
|
||||
|
||||
- Or a la strigi: all interactions are through html pages and get()
|
||||
operations. Looks less like a normal konqueror file-system
|
||||
listing, and needs more html coding but all in all probably
|
||||
simpler.
|
||||
|
||||
Recoll is currently doing the html thing. As far as I understand, the
|
||||
way to trigger a listdir is to have a inode/directory default mime
|
||||
type in the protocol file, and return inode/directory when
|
||||
appropriate in mimetype() (look at kio_beagle). Some kde daemon needs
|
||||
to be restarted when doing this (the protocol file is cached
|
||||
somewhere).
|
||||
|
||||
Also would need a page header, configuration polish etc... Not done for
|
||||
the same reason, this is a proof of concept.
|
||||
|
||||
KDE3 notes
|
||||
- Not using libtool. Probably should. compilation flags in the Makefile
|
||||
were copy-pasted from a kdebase compilation tree on FreeBSD (kio/man).
|
||||
|
||||
- You MUST install a kio_recoll.la in lib/kde3 along with kio_recoll.so,
|
||||
else kdeinit won't be able to load the lib (probably uses the libltdl
|
||||
thingy?). The one in this directory was duplicated/adjusted from
|
||||
kio_man.la. The contents don't seem too critical, just needs to exist.
|
||||
|
||||
- Currently retrieves all results on one page. Need to add state and
|
||||
previous/next buttons. As I didn't find this thing to be particularly
|
||||
useful, I didn't bothered to.
|
||||
|
||||
- Also would need a page header, configuration polish etc... Not done for
|
||||
the same reason, this is a proof of concept.
|
||||
|
||||
- If you want to try, compile, then install kio_recoll.la kio_recoll.so
|
||||
wherever kde keeps its plugins (ie: lib/kde3), and recoll.protocol in the
|
||||
services directory (share/services ? look for other .protocol file).
|
||||
|
||||
- I saw after doing the build/config mockup that kdevelop can generate a
|
||||
kio_slave project. This might be the next thing to do. otoh would need to
|
||||
separate the kio from the main source to avoid having to distribute 2megs
|
||||
|
||||
@ -7,40 +7,44 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/modules )
|
||||
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
#set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Recoll KIO Slave")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Recoll KIO Slave")
|
||||
#set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README")
|
||||
#set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
|
||||
#set(CPACK_PACKAGE_VERSION "${VERSION}")
|
||||
#set(CPACK_GENERATOR TGZ)
|
||||
#set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION}" CACHE INTERNAL "
|
||||
#tarball basename")
|
||||
#SET(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME} ${CPACK_PACKAGE_VERSION}")
|
||||
#include(CPack)
|
||||
set(CPACK_PACKAGE_VERSION "${VERSION}")
|
||||
set(CPACK_GENERATOR TGZ)
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION}" CACHE INTERNAL "tarball basename")
|
||||
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME} ${CPACK_PACKAGE_VERSION}")
|
||||
include(CPack)
|
||||
|
||||
# search packages used by KDE
|
||||
find_package(KDE4 REQUIRED)
|
||||
include (UsePkgConfig)
|
||||
include (KDE4Defaults)
|
||||
include (MacroLibrary)
|
||||
include(UsePkgConfig)
|
||||
include(KDE4Defaults)
|
||||
include(MacroLibrary)
|
||||
include(MacroOptionalAddSubdirectory)
|
||||
|
||||
add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
|
||||
add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
|
||||
add_definitions(-DKDE_DEFAULT_DEBUG_AREA=7130)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}")
|
||||
|
||||
set(depth ../../../)
|
||||
set(rcltop ${CMAKE_CURRENT_SOURCE_DIR}/${depth})
|
||||
|
||||
include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES}
|
||||
${depth}/utils ${depth}/rcldb ${depth}/query ${depth}/unac
|
||||
${depth}/common ${depth}/internfile ${depth}/index ${depth}/bincimapmime
|
||||
${rcltop}/utils ${rcltop}/rcldb ${rcltop}/query ${rcltop}/unac
|
||||
${rcltop}/common ${rcltop}/internfile ${rcltop}/index ${rcltop}/bincimapmime
|
||||
)
|
||||
|
||||
set(kio_recoll_SRCS
|
||||
kio_recoll.cpp
|
||||
)
|
||||
set(kio_recoll_SRCS kio_recoll.cpp)
|
||||
|
||||
kde4_add_plugin(kio_recoll ${kio_recoll_SRCS})
|
||||
link_directories(/home/dockes/projets/fulltext/recoll/src/lib)
|
||||
target_link_libraries(kio_recoll rcl xapian ${KDE4_KIO_LIBS})
|
||||
|
||||
target_link_libraries(kio_recoll
|
||||
${rcltop}/lib/librcl.a
|
||||
${rcltop}/bincimapmime/libmime.a
|
||||
xapian ${KDE4_KIO_LIBS})
|
||||
|
||||
install(TARGETS kio_recoll DESTINATION ${PLUGIN_INSTALL_DIR})
|
||||
install(FILES recoll.protocol DESTINATION ${SERVICES_INSTALL_DIR} )
|
||||
install(FILES recoll.protocol DESTINATION ${SERVICES_INSTALL_DIR})
|
||||
install(FILES data/welcome.html
|
||||
DESTINATION ${DATA_INSTALL_DIR}/kio_recoll)
|
||||
|
||||
20
src/kde/kioslave/recoll/data/welcome.html
Normal file
20
src/kde/kioslave/recoll/data/welcome.html
Normal file
@ -0,0 +1,20 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Recoll Search</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h3>Recoll search</h3>
|
||||
|
||||
<p><form method="get" action="recoll://search/query">
|
||||
Query type:<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="o">Any term<br>
|
||||
|
||||
Enter search string: <input type="text" name="q" size="40" value="%Q">
|
||||
<input type="submit" value="Search"></p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef lint
|
||||
static char rcsid[] = "@(#$Id: kio_recoll.cpp,v 1.14 2008-11-19 12:28:59 dockes Exp $ (C) 2005 J.F.Dockes";
|
||||
static char rcsid[] = "@(#$Id: kio_recoll.cpp,v 1.15 2008-11-20 13:10:23 dockes Exp $ (C) 2005 J.F.Dockes";
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
@ -26,6 +26,7 @@ using namespace std;
|
||||
|
||||
//#include <kinstance.h>
|
||||
#include <kcomponentdata.h>
|
||||
#include <kstandarddirs.h>
|
||||
|
||||
#include "rclconfig.h"
|
||||
#include "rcldb.h"
|
||||
@ -36,9 +37,65 @@ using namespace std;
|
||||
#include "wasastringtoquery.h"
|
||||
#include "wasatorcl.h"
|
||||
#include "kio_recoll.h"
|
||||
#include "docseqdb.h"
|
||||
#include "readfile.h"
|
||||
#include "smallut.h"
|
||||
|
||||
using namespace KIO;
|
||||
|
||||
bool RecollKioPager::append(const string& data)
|
||||
{
|
||||
if (!m_parent) return false;
|
||||
m_parent->data(QByteArray(data.c_str()));
|
||||
return true;
|
||||
}
|
||||
|
||||
string RecollKioPager::detailsLink()
|
||||
{
|
||||
string chunk = "<a href=\"recoll://command/QueryDetails\">";
|
||||
chunk += tr("(show query)") + "</a>";
|
||||
return chunk;
|
||||
}
|
||||
|
||||
const static string parformat =
|
||||
"<a href=\"%U\"><img src=\"%I\" align=\"left\"></a>"
|
||||
"%R %S "
|
||||
"<a href=\"%U\">Open</a> <b>%T</b><br>"
|
||||
"%M %D <i>%U</i><br>"
|
||||
"%A %K";
|
||||
const string &RecollKioPager::parFormat()
|
||||
{
|
||||
return parformat;
|
||||
}
|
||||
|
||||
string RecollKioPager::pageTop()
|
||||
{
|
||||
return "<p align=\"center\"><a href=\"recoll://welcome\">New Search</a></p>";
|
||||
}
|
||||
|
||||
string RecollKioPager::nextUrl()
|
||||
{
|
||||
int pagenum = pageNumber();
|
||||
if (pagenum < 0)
|
||||
pagenum = 0;
|
||||
else
|
||||
pagenum++;
|
||||
char buf[100];
|
||||
sprintf(buf, "recoll://command/Page%d", pagenum);
|
||||
return buf;
|
||||
}
|
||||
string RecollKioPager::prevUrl()
|
||||
{
|
||||
int pagenum = pageNumber();
|
||||
if (pagenum <= 0)
|
||||
pagenum = 0;
|
||||
else
|
||||
pagenum--;
|
||||
char buf[100];
|
||||
sprintf(buf, "recoll://command/Page%d", pagenum);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static RclConfig *rclconfig;
|
||||
RclConfig *RclConfig::getMainConfig()
|
||||
{
|
||||
@ -49,6 +106,7 @@ RecollProtocol::RecollProtocol(const QByteArray &pool, const QByteArray &app)
|
||||
: SlaveBase("recoll", pool, app), m_initok(false),
|
||||
m_rclconfig(0), m_rcldb(0)
|
||||
{
|
||||
m_pager.setParent(this);
|
||||
string reason;
|
||||
rclconfig = m_rclconfig = recollinit(0, 0, m_reason);
|
||||
if (!m_rclconfig || !m_rclconfig->ok()) {
|
||||
@ -99,9 +157,86 @@ bool RecollProtocol::maybeOpenDb(string &reason)
|
||||
return true;
|
||||
}
|
||||
|
||||
static string welcomedata;
|
||||
|
||||
void RecollProtocol::welcomePage()
|
||||
{
|
||||
kDebug() << endl;
|
||||
if (welcomedata.empty()) {
|
||||
QString location =
|
||||
KStandardDirs::locate("data", "kio_recoll/welcome.html");
|
||||
string reason;
|
||||
if (location.isEmpty() ||
|
||||
!file_to_string((const char *)location.toUtf8(),
|
||||
welcomedata, &reason)) {
|
||||
welcomedata = "<html><head><title>Recoll Error</title></head>"
|
||||
"<body><p>Could not locate Recoll welcome.html file: ";
|
||||
welcomedata += reason;
|
||||
welcomedata += "</p></body></html>";
|
||||
}
|
||||
}
|
||||
string tmp;
|
||||
map<char, string> subs;
|
||||
subs['Q'] = "";
|
||||
pcSubst(welcomedata, tmp, subs);
|
||||
data(tmp.c_str());
|
||||
kDebug() << "WelcomePage done" << endl;
|
||||
}
|
||||
|
||||
void RecollProtocol::doSearch(const QString& q, char opt)
|
||||
{
|
||||
string qs = (const char *)q.toUtf8();
|
||||
Rcl::SearchData *sd = 0;
|
||||
if (opt != 'l') {
|
||||
Rcl::SearchDataClause *clp = 0;
|
||||
if (opt == 'f') {
|
||||
clp = new Rcl::SearchDataClauseFilename(qs);
|
||||
} else {
|
||||
// If there is no white space inside the query, then the user
|
||||
// certainly means it as a phrase.
|
||||
bool isreallyaphrase = false;
|
||||
if (qs.find_first_of(" \t") == string::npos)
|
||||
isreallyaphrase = true;
|
||||
clp = isreallyaphrase ?
|
||||
new Rcl::SearchDataClauseDist(Rcl::SCLT_PHRASE, qs, 0) :
|
||||
new Rcl::SearchDataClauseSimple(opt == 'o' ?
|
||||
Rcl::SCLT_OR : Rcl::SCLT_AND,
|
||||
qs);
|
||||
}
|
||||
sd = new Rcl::SearchData(Rcl::SCLT_OR);
|
||||
if (sd && clp)
|
||||
sd->addClause(clp);
|
||||
} else {
|
||||
kDebug() << "Parsing query";
|
||||
sd = wasaStringToRcl(qs, m_reason);
|
||||
}
|
||||
if (!sd) {
|
||||
m_reason = "Internal Error: cant allocate new query";
|
||||
outputError(m_reason.c_str());
|
||||
finished();
|
||||
return;
|
||||
}
|
||||
|
||||
RefCntr<Rcl::SearchData> sdata(sd);
|
||||
sdata->setStemlang("english");
|
||||
RefCntr<Rcl::Query>query(new Rcl::Query(m_rcldb));
|
||||
if (!query->setQuery(sdata)) {
|
||||
m_reason = "Internal Error: setQuery failed";
|
||||
outputError(m_reason.c_str());
|
||||
finished();
|
||||
return;
|
||||
}
|
||||
DocSequenceDb *src =
|
||||
new DocSequenceDb(RefCntr<Rcl::Query>(query), "Query results",
|
||||
sdata);
|
||||
|
||||
m_pager.setDocSource(RefCntr<DocSequence>(src));
|
||||
m_pager.resultPageNext();
|
||||
}
|
||||
|
||||
void RecollProtocol::get(const KUrl & url)
|
||||
{
|
||||
kDebug() << "RecollProtocol::get:" << url << endl;
|
||||
kDebug() << url << endl;
|
||||
|
||||
mimeType("text/html");
|
||||
|
||||
@ -111,98 +246,75 @@ void RecollProtocol::get(const KUrl & url)
|
||||
return;
|
||||
}
|
||||
|
||||
string iconsdir;
|
||||
m_rclconfig->getConfParam("iconsdir", iconsdir);
|
||||
if (iconsdir.empty()) {
|
||||
iconsdir = path_cat("/usr/local/share/recoll", "images");
|
||||
} else {
|
||||
iconsdir = path_tildexpand(iconsdir);
|
||||
}
|
||||
|
||||
QString host = url.host();
|
||||
QString path = url.path();
|
||||
kDebug() << "RecollProtocol::get:path:" << path << endl;
|
||||
QByteArray u8 = path.toUtf8();
|
||||
kDebug() << "host:" << host << " path:" << path;
|
||||
if (host.isEmpty() || !host.compare("welcome")) {
|
||||
kDebug() << "Host is empty";
|
||||
if (path.isEmpty() || !path.compare("/")) {
|
||||
kDebug() << "Path is empty or strange";
|
||||
// Display welcome page
|
||||
welcomePage();
|
||||
finished();
|
||||
return;
|
||||
}
|
||||
// Ie: "recoll: some search string"
|
||||
doSearch(path);
|
||||
} else if (!host.compare("search")) {
|
||||
if (path.compare("/query")) {
|
||||
finished(); return;
|
||||
}
|
||||
// Decode the forms' arguments
|
||||
QString query = url.queryItem("q");
|
||||
if (query.isEmpty()) {
|
||||
finished(); return;
|
||||
}
|
||||
QString opt = url.queryItem("qtp");
|
||||
if (opt.isEmpty()) {
|
||||
opt = "l";
|
||||
}
|
||||
doSearch(query, opt.toUtf8().at(0));
|
||||
} else if (!host.compare("command")) {
|
||||
if (path.isEmpty()) {
|
||||
finished();return;
|
||||
} else if (path.indexOf("/Page") == 0) {
|
||||
int newpage = 0;
|
||||
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();
|
||||
}
|
||||
} else if (path.indexOf("/QueryDetails") == 0) {
|
||||
QByteArray array;
|
||||
QTextStream os(&array, QIODevice::WriteOnly);
|
||||
|
||||
RefCntr<Rcl::SearchData> sdata = wasaStringToRcl((const char*)u8, m_reason);
|
||||
sdata->setStemlang("english");
|
||||
|
||||
RefCntr<Rcl::Query>query(new Rcl::Query(m_rcldb));
|
||||
if (!query->setQuery(sdata)) {
|
||||
m_reason = "Internal Error: setQuery failed";
|
||||
outputError(m_reason.c_str());
|
||||
finished();
|
||||
return;
|
||||
os << "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">" << endl;
|
||||
os << "<title>" << "Recoll query details" << "</title>\n" << endl;
|
||||
os << "</head>" << endl;
|
||||
os << "<body><h3>Query details:</h3>" << endl;
|
||||
os << "<p>" << m_pager.queryDescription().c_str() <<"</p>"<< endl;
|
||||
os << "<p><a href=\"recoll://command/Page" <<
|
||||
m_pager.pageNumber() << "\">Return to results</a>" << endl;
|
||||
os << "</body></html>" << endl;
|
||||
data(array);
|
||||
finished();
|
||||
return;
|
||||
} else {
|
||||
// Unknown //command/???
|
||||
finished(); return;
|
||||
}
|
||||
} else {
|
||||
// Unknown 'host' //??? value
|
||||
finished(); return;
|
||||
}
|
||||
|
||||
string explain = sdata->getDescription();
|
||||
m_pager.displayPage();
|
||||
|
||||
QByteArray output;
|
||||
QTextStream os(&output, QIODevice::ReadWrite);
|
||||
|
||||
os << "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">" << endl;
|
||||
os << "<html><head>" << endl;
|
||||
os << "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">" << endl;
|
||||
os << "<meta http-equiv=\"Pragma\" content=\"no-cache\">" << endl;
|
||||
os << "<title>Recoll: query results</title>" << endl;
|
||||
os << "</head><body>" << endl;
|
||||
|
||||
os << "<p><b>Actual query performed: </b>" << endl;
|
||||
os << explain.c_str() << "</p>";
|
||||
|
||||
Rcl::Doc doc;
|
||||
int cnt = query->getResCnt();
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
string sh;
|
||||
doc.erase();
|
||||
|
||||
if (!query->getDoc(i, doc)) {
|
||||
// This may very well happen for history if the doc has
|
||||
// been removed since. So don't treat it as fatal.
|
||||
doc.meta[Rcl::Doc::keykw] = string("Unavailable document");
|
||||
}
|
||||
|
||||
string iconname = m_rclconfig->getMimeIconName(doc.mimetype);
|
||||
if (iconname.empty())
|
||||
iconname = "document";
|
||||
string imgfile = iconsdir + "/" + iconname + ".png";
|
||||
|
||||
string result;
|
||||
if (!sh.empty())
|
||||
result += string("<p><b>") + sh + "</p>\n<p>";
|
||||
else
|
||||
result = "<p>";
|
||||
|
||||
char perbuf[10];
|
||||
sprintf(perbuf, "%3d%%", doc.pc);
|
||||
if (doc.meta[Rcl::Doc::keytt].empty())
|
||||
doc.meta[Rcl::Doc::keytt] = path_getsimple(doc.url);
|
||||
char datebuf[100];
|
||||
datebuf[0] = 0;
|
||||
if (!doc.dmtime.empty() || !doc.fmtime.empty()) {
|
||||
time_t mtime = doc.dmtime.empty() ?
|
||||
atol(doc.fmtime.c_str()) : atol(doc.dmtime.c_str());
|
||||
struct tm *tm = localtime(&mtime);
|
||||
strftime(datebuf, 99,
|
||||
"<i>Modified:</i> %Y-%m-%d %H:%M:%S", tm);
|
||||
}
|
||||
result += "<a href=\"" + doc.url + "\">" +
|
||||
"<img src=\"file://" + imgfile + "\" align=\"left\">" + "</a>";
|
||||
string abst = escapeHtml(doc.meta[Rcl::Doc::keyabs]);
|
||||
result += string(perbuf) + " <b>" + doc.meta[Rcl::Doc::keytt] + "</b><br>" +
|
||||
doc.mimetype + " " +
|
||||
(datebuf[0] ? string(datebuf) + "<br>" : string("<br>")) +
|
||||
(!abst.empty() ? abst + "<br>" : string("")) +
|
||||
(!doc.meta[Rcl::Doc::keytt].empty() ? doc.meta[Rcl::Doc::keykw] +
|
||||
"<br>" : string("")) +
|
||||
"<a href=\"" + doc.url + "\">" + doc.url + "</a><br></p>\n";
|
||||
|
||||
QString str = QString::fromUtf8(result.c_str(), result.length());
|
||||
os << str;
|
||||
}
|
||||
|
||||
os << "</body></html>";
|
||||
|
||||
data(output);
|
||||
kDebug() << "call finished" << endl;
|
||||
finished();
|
||||
}
|
||||
@ -221,6 +333,8 @@ void RecollProtocol::outputError(const QString& errmsg)
|
||||
data(array);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Note: KDE_EXPORT is actually needed on Unix when building with
|
||||
// cmake. Says something like __attribute__(visibility(defautl))
|
||||
// (cmake apparently sets all symbols to not exported)
|
||||
@ -228,9 +342,6 @@ extern "C" {KDE_EXPORT int kdemain(int argc, char **argv);}
|
||||
|
||||
int kdemain(int argc, char **argv)
|
||||
{
|
||||
FILE*mf = fopen("/tmp/toto","w");
|
||||
fprintf(mf, "KIORECOLL\n");
|
||||
fclose(mf);
|
||||
#ifdef KDE_VERSION_3
|
||||
KInstance instance("kio_recoll");
|
||||
#else
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef _RECOLL_H
|
||||
/* @(#$Id: kio_recoll.h,v 1.5 2008-11-17 14:51:38 dockes Exp $ (C) 2005 J.F.Dockes */
|
||||
/* @(#$Id: kio_recoll.h,v 1.6 2008-11-20 13:10:23 dockes Exp $ (C) 2005 J.F.Dockes */
|
||||
#define _RECOLL_H
|
||||
|
||||
#include <string>
|
||||
@ -17,6 +17,25 @@ using std::string;
|
||||
#include <kio/global.h>
|
||||
#include <kio/slavebase.h>
|
||||
|
||||
#include "reslistpager.h"
|
||||
|
||||
class RecollProtocol;
|
||||
|
||||
class RecollKioPager : public ResListPager {
|
||||
public:
|
||||
RecollKioPager() : m_parent(0) {}
|
||||
void setParent(RecollProtocol *proto) {m_parent = proto;}
|
||||
|
||||
virtual bool append(const string& data);
|
||||
virtual string detailsLink();
|
||||
virtual const string &parFormat();
|
||||
virtual string nextUrl();
|
||||
virtual string prevUrl();
|
||||
virtual string pageTop();
|
||||
private:
|
||||
RecollProtocol *m_parent;
|
||||
};
|
||||
|
||||
class RecollProtocol : public KIO::SlaveBase {
|
||||
public:
|
||||
RecollProtocol(const QByteArray &pool, const QByteArray &app );
|
||||
@ -25,13 +44,18 @@ class RecollProtocol : public KIO::SlaveBase {
|
||||
virtual void get(const KUrl & url );
|
||||
|
||||
private:
|
||||
bool m_initok;
|
||||
RclConfig *m_rclconfig;
|
||||
Rcl::Db *m_rcldb;
|
||||
std::string m_dbdir;
|
||||
std::string m_reason;
|
||||
bool maybeOpenDb(string &reason);
|
||||
void outputError(const QString& errmsg);
|
||||
void doSearch(const QString& q, char opt = 'l');
|
||||
void welcomePage();
|
||||
|
||||
bool m_initok;
|
||||
RclConfig *m_rclconfig;
|
||||
Rcl::Db *m_rcldb;
|
||||
std::string m_dbdir;
|
||||
std::string m_reason;
|
||||
RecollKioPager m_pager;
|
||||
|
||||
};
|
||||
extern "C" {int kdemain(int, char**);}
|
||||
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
#ifndef lint
|
||||
static char rcsid[] = "@(#$Id: reslistpager.cpp,v 1.1 2008-11-19 12:19:40 dockes Exp $ (C) 2007 J.F.Dockes";
|
||||
static char rcsid[] = "@(#$Id: reslistpager.cpp,v 1.2 2008-11-20 13:10:23 dockes Exp $ (C) 2007 J.F.Dockes";
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "reslistpager.h"
|
||||
#include "debuglog.h"
|
||||
#include "rclconfig.h"
|
||||
@ -63,31 +67,9 @@ void ResListPager::resultPageNext()
|
||||
m_respage = npage;
|
||||
}
|
||||
|
||||
bool ResListPager::append(const string& data)
|
||||
{
|
||||
fprintf(stderr, "%s", data.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
string ResListPager::tr(const string& in)
|
||||
{
|
||||
return in;
|
||||
}
|
||||
|
||||
void ResListPager::displayPage()
|
||||
{
|
||||
string chunk;
|
||||
if (pageEmpty()) {
|
||||
chunk = "<html><head></head><body>"
|
||||
"<p><font size=+1><b>";
|
||||
chunk += m_docSource->title();
|
||||
chunk += "</b></font>";
|
||||
chunk += "<a href=\"H-1\">";
|
||||
chunk += tr("Show query details");
|
||||
chunk += "</a><br>";
|
||||
append(chunk);
|
||||
return;
|
||||
}
|
||||
|
||||
// Display list header
|
||||
// We could use a <title> but the textedit doesnt display
|
||||
@ -97,8 +79,12 @@ void ResListPager::displayPage()
|
||||
// gets confused. Hence the use of the 'chunk' text
|
||||
// accumulator
|
||||
// Also note that there can be results beyond the estimated resCnt.
|
||||
chunk = "<qt><head></head><body><p>"
|
||||
"<font size=+1><b>";
|
||||
chunk = "<html><head>"
|
||||
"<meta http-equiv=\"content-type\""
|
||||
"content=\"text/html; charset=utf-8\">"
|
||||
"</head><body>";
|
||||
chunk += pageTop();
|
||||
chunk += "<p><font size=+1><b>";
|
||||
chunk += m_docSource->title();
|
||||
chunk += "</b></font>"
|
||||
" ";
|
||||
@ -121,9 +107,21 @@ void ResListPager::displayPage()
|
||||
chunk += buf;
|
||||
}
|
||||
}
|
||||
chunk += "<a href=\"H-1\">";
|
||||
chunk += tr("(show query)");
|
||||
chunk += "</a></p>";
|
||||
chunk += detailsLink();
|
||||
if (hasPrev() || hasNext()) {
|
||||
chunk += " ";
|
||||
if (hasPrev()) {
|
||||
chunk += "<a href=\"" + prevUrl() + "\"><b>";
|
||||
chunk += tr("Previous");
|
||||
chunk += "</b></a> ";
|
||||
}
|
||||
if (hasNext()) {
|
||||
chunk += "<a href=\""+ nextUrl() + "\"><b>";
|
||||
chunk += tr("Next");
|
||||
chunk += "</b></a>";
|
||||
}
|
||||
}
|
||||
chunk += "</p>";
|
||||
|
||||
append(chunk);
|
||||
if (pageEmpty())
|
||||
@ -154,6 +152,7 @@ void ResListPager::displayPage()
|
||||
// Determine icon to display if any
|
||||
string iconpath;
|
||||
RclConfig::getMainConfig()->getMimeIconName(doc.mimetype, &iconpath);
|
||||
iconpath = string("file://") + iconpath;
|
||||
|
||||
// Printable url: either utf-8 if transcoding succeeds, or url-encoded
|
||||
string url;
|
||||
@ -249,7 +248,7 @@ void ResListPager::displayPage()
|
||||
subs['U'] = url;
|
||||
|
||||
string formatted;
|
||||
pcSubst(m_parformat, formatted, subs);
|
||||
pcSubst(parFormat(), formatted, subs);
|
||||
chunk += formatted;
|
||||
|
||||
chunk += "</p>\n";
|
||||
@ -262,12 +261,12 @@ void ResListPager::displayPage()
|
||||
chunk = "<p align=\"center\">";
|
||||
if (hasPrev() || hasNext()) {
|
||||
if (hasPrev()) {
|
||||
chunk += "<a href=\"p-1\"><b>";
|
||||
chunk += "<a href=\"" + prevUrl() + "\"><b>";
|
||||
chunk += tr("Previous");
|
||||
chunk += "</b></a> ";
|
||||
}
|
||||
if (hasNext()) {
|
||||
chunk += "<a href=\"n-1\"><b>";
|
||||
chunk += "<a href=\""+ nextUrl() + "\"><b>";
|
||||
chunk += tr("Next");
|
||||
chunk += "</b></a>";
|
||||
}
|
||||
@ -276,3 +275,41 @@ void ResListPager::displayPage()
|
||||
chunk += "</body></html>\n";
|
||||
append(chunk);
|
||||
}
|
||||
|
||||
string ResListPager::nextUrl()
|
||||
{
|
||||
return "n-1";
|
||||
}
|
||||
string ResListPager::prevUrl()
|
||||
{
|
||||
return "p-1";
|
||||
}
|
||||
|
||||
// Default implementations for things that should be re-implemented by our user.
|
||||
bool ResListPager::append(const string& data)
|
||||
{
|
||||
fprintf(stderr, "%s", data.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
string ResListPager::tr(const string& in)
|
||||
{
|
||||
return in;
|
||||
}
|
||||
|
||||
string ResListPager::detailsLink()
|
||||
{
|
||||
string chunk = "<a href=\"H-1\">";
|
||||
chunk += tr("(show query)") + "</a>";
|
||||
return chunk;
|
||||
}
|
||||
|
||||
const string &ResListPager::parFormat()
|
||||
{
|
||||
const static string format("<img src=\"%I\" align=\"left\">"
|
||||
"%R %S %L <b>%T</b><br>"
|
||||
"%M %D <i>%U</i><br>"
|
||||
"%A %K");
|
||||
return format;
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#ifndef _reslistpager_h_included_
|
||||
#define _reslistpager_h_included_
|
||||
/* @(#$Id: reslistpager.h,v 1.1 2008-11-19 12:19:40 dockes Exp $ (C) 2007 J.F.Dockes */
|
||||
/* @(#$Id: reslistpager.h,v 1.2 2008-11-20 13:10:23 dockes Exp $ (C) 2007 J.F.Dockes */
|
||||
|
||||
#include <vector>
|
||||
using std::vector;
|
||||
@ -13,12 +13,25 @@ using std::vector;
|
||||
*/
|
||||
class ResListPager {
|
||||
public:
|
||||
ResListPager(RefCntr<DocSequence> src, int pagesize,
|
||||
const string& parformat)
|
||||
: m_docSource(src), m_pagesize(pagesize), m_parformat(parformat),
|
||||
m_hasNext(false)
|
||||
ResListPager() : m_pagesize(10), m_hasNext(false) {}
|
||||
void setDocSource(RefCntr<DocSequence> src)
|
||||
{
|
||||
m_winfirst = -1;
|
||||
m_docSource = src;
|
||||
m_hasNext = false;
|
||||
m_respage.clear();
|
||||
}
|
||||
ResListPager(RefCntr<DocSequence> src, int pagesize)
|
||||
: m_winfirst(-1), m_docSource(src), m_pagesize(pagesize),
|
||||
m_hasNext(false)
|
||||
{}
|
||||
virtual ~ResListPager() {}
|
||||
int pageNumber()
|
||||
{
|
||||
if (m_winfirst < 0 || m_pagesize <= 0)
|
||||
return -1;
|
||||
return m_winfirst / m_pagesize;
|
||||
}
|
||||
void pageNext();
|
||||
bool hasNext() {return m_hasNext;}
|
||||
bool hasPrev() {return m_winfirst > 0;}
|
||||
@ -35,14 +48,24 @@ public:
|
||||
void resultPageNext();
|
||||
void displayPage();
|
||||
bool pageEmpty() {return m_respage.size() == 0;}
|
||||
|
||||
string queryDescription() {return m_docSource.isNull() ? "" :
|
||||
m_docSource->getDescription();}
|
||||
|
||||
// Things that need to be reimplemented in the subclass:
|
||||
virtual bool append(const string& data);
|
||||
virtual string tr(const string& in);
|
||||
virtual string detailsLink();
|
||||
virtual const string &parFormat();
|
||||
virtual string nextUrl();
|
||||
virtual string prevUrl();
|
||||
virtual string pageTop() {return string();}
|
||||
|
||||
private:
|
||||
// First docnum (from docseq) in current page
|
||||
int m_winfirst;
|
||||
RefCntr<DocSequence> m_docSource;
|
||||
int m_pagesize;
|
||||
string m_parformat;
|
||||
|
||||
bool m_hasNext;
|
||||
vector<ResListEntry> m_respage;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user