From 31f704f564e29a2a27d80bdb09c4272634697472 Mon Sep 17 00:00:00 2001
From: dockes
Date: Thu, 20 Nov 2008 13:10:23 +0000
Subject: [PATCH] kioslave sort of works
---
src/kde/kioslave/recoll/00README.txt | 35 ++-
src/kde/kioslave/recoll/CMakeLists.txt | 42 +--
src/kde/kioslave/recoll/data/welcome.html | 20 ++
src/kde/kioslave/recoll/kio_recoll.cpp | 295 +++++++++++++++-------
src/kde/kioslave/recoll/kio_recoll.h | 36 ++-
src/query/reslistpager.cpp | 99 +++++---
src/query/reslistpager.h | 35 ++-
7 files changed, 396 insertions(+), 166 deletions(-)
create mode 100644 src/kde/kioslave/recoll/data/welcome.html
diff --git a/src/kde/kioslave/recoll/00README.txt b/src/kde/kioslave/recoll/00README.txt
index 7e7c8c7e..c9064d84 100644
--- a/src/kde/kioslave/recoll/00README.txt
+++ b/src/kde/kioslave/recoll/00README.txt
@@ -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
diff --git a/src/kde/kioslave/recoll/CMakeLists.txt b/src/kde/kioslave/recoll/CMakeLists.txt
index 07a50677..f67c9c84 100644
--- a/src/kde/kioslave/recoll/CMakeLists.txt
+++ b/src/kde/kioslave/recoll/CMakeLists.txt
@@ -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)
diff --git a/src/kde/kioslave/recoll/data/welcome.html b/src/kde/kioslave/recoll/data/welcome.html
new file mode 100644
index 00000000..b13ff2b7
--- /dev/null
+++ b/src/kde/kioslave/recoll/data/welcome.html
@@ -0,0 +1,20 @@
+
+
+
+ Recoll Search
+
+
+
+ Recoll search
+
+
+
+
+
diff --git a/src/kde/kioslave/recoll/kio_recoll.cpp b/src/kde/kioslave/recoll/kio_recoll.cpp
index 989a547d..ba71ebc7 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.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
@@ -26,6 +26,7 @@ using namespace std;
//#include
#include
+#include
#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 = "";
+ chunk += tr("(show query)") + "";
+ return chunk;
+}
+
+const static string parformat =
+ "
"
+ "%R %S "
+ "Open %T
"
+ "%M %D %U
"
+ "%A %K";
+const string &RecollKioPager::parFormat()
+{
+ return parformat;
+}
+
+string RecollKioPager::pageTop()
+{
+ return "New Search
";
+}
+
+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 = "Recoll Error"
+ "Could not locate Recoll welcome.html file: ";
+ welcomedata += reason;
+ welcomedata += "
";
+ }
+ }
+ string tmp;
+ map 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 sdata(sd);
+ sdata->setStemlang("english");
+ RefCntrquery(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(query), "Query results",
+ sdata);
+
+ m_pager.setDocSource(RefCntr(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 sdata = wasaStringToRcl((const char*)u8, m_reason);
- sdata->setStemlang("english");
-
- RefCntrquery(new Rcl::Query(m_rcldb));
- if (!query->setQuery(sdata)) {
- m_reason = "Internal Error: setQuery failed";
- outputError(m_reason.c_str());
- finished();
- return;
+ os << "" << endl;
+ os << "" << "Recoll query details" << "\n" << endl;
+ os << "" << endl;
+ os << "Query details:
" << endl;
+ os << "" << m_pager.queryDescription().c_str() <<"
"<< endl;
+ os << "Return to results" << endl;
+ os << "" << 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 << "" << endl;
- os << "
" << endl;
- os << "" << endl;
- os << "" << endl;
- os << "Recoll: query results" << endl;
- os << "" << endl;
-
- os << "Actual query performed: " << endl;
- os << explain.c_str() << "
";
-
- 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("") + sh + "
\n";
- else
- result = "
";
-
- 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,
- "Modified: %Y-%m-%d %H:%M:%S", tm);
- }
- result += "" +
- "
" + "";
- string abst = escapeHtml(doc.meta[Rcl::Doc::keyabs]);
- result += string(perbuf) + " " + doc.meta[Rcl::Doc::keytt] + "
" +
- doc.mimetype + " " +
- (datebuf[0] ? string(datebuf) + "
" : string("
")) +
- (!abst.empty() ? abst + "
" : string("")) +
- (!doc.meta[Rcl::Doc::keytt].empty() ? doc.meta[Rcl::Doc::keykw] +
- "
" : string("")) +
- "" + doc.url + "
\n";
-
- QString str = QString::fromUtf8(result.c_str(), result.length());
- os << str;
- }
-
- os << "";
-
- 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
diff --git a/src/kde/kioslave/recoll/kio_recoll.h b/src/kde/kioslave/recoll/kio_recoll.h
index 1ec47034..6c1e7a70 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.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
@@ -17,6 +17,25 @@ using std::string;
#include
#include
+#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**);}
diff --git a/src/query/reslistpager.cpp b/src/query/reslistpager.cpp
index c06bf07f..1b1668df 100644
--- a/src/query/reslistpager.cpp
+++ b/src/query/reslistpager.cpp
@@ -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
+#include
+#include
+
#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 = ""
- "";
- chunk += m_docSource->title();
- chunk += "";
- chunk += "";
- chunk += tr("Show query details");
- chunk += "
";
- append(chunk);
- return;
- }
// Display list header
// We could use a
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 = ""
- "";
+ chunk = ""
+ ""
+ "";
+ chunk += pageTop();
+ chunk += "";
chunk += m_docSource->title();
chunk += ""
" ";
@@ -121,9 +107,21 @@ void ResListPager::displayPage()
chunk += buf;
}
}
- chunk += "";
- chunk += tr("(show query)");
- chunk += "
";
+ chunk += detailsLink();
+ if (hasPrev() || hasNext()) {
+ chunk += " ";
+ if (hasPrev()) {
+ chunk += "";
+ chunk += tr("Previous");
+ chunk += " ";
+ }
+ if (hasNext()) {
+ chunk += "";
+ chunk += tr("Next");
+ chunk += "";
+ }
+ }
+ chunk += "
";
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 += "\n";
@@ -262,12 +261,12 @@ void ResListPager::displayPage()
chunk = "";
if (hasPrev() || hasNext()) {
if (hasPrev()) {
- chunk += "";
+ chunk += "";
chunk += tr("Previous");
chunk += " ";
}
if (hasNext()) {
- chunk += "";
+ chunk += "";
chunk += tr("Next");
chunk += "";
}
@@ -276,3 +275,41 @@ void ResListPager::displayPage()
chunk += "\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 = "";
+ chunk += tr("(show query)") + "";
+ return chunk;
+}
+
+const string &ResListPager::parFormat()
+{
+ const static string format("
"
+ "%R %S %L %T
"
+ "%M %D %U
"
+ "%A %K");
+ return format;
+}
+
diff --git a/src/query/reslistpager.h b/src/query/reslistpager.h
index 98f479ce..4811028b 100644
--- a/src/query/reslistpager.h
+++ b/src/query/reslistpager.h
@@ -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
using std::vector;
@@ -13,12 +13,25 @@ using std::vector;
*/
class ResListPager {
public:
- ResListPager(RefCntr 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 src)
+ {
+ m_winfirst = -1;
+ m_docSource = src;
+ m_hasNext = false;
+ m_respage.clear();
+ }
+ ResListPager(RefCntr 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 m_docSource;
int m_pagesize;
- string m_parformat;
bool m_hasNext;
vector m_respage;