diff --git a/src/lib/Makefile b/src/lib/Makefile index 1f80b9ea..51e726a8 100644 --- a/src/lib/Makefile +++ b/src/lib/Makefile @@ -8,8 +8,8 @@ LIBS = librcl.a all: $(LIBS) -OBJS = rclaspell.o rclconfig.o rclinit.o textsplit.o unacpp.o csguess.o indexer.o mimetype.o htmlparse.o myhtmlparse.o mimehandler.o internfile.o mh_exec.o mh_html.o mh_mail.o mh_mbox.o mh_text.o docseq.o docseqdb.o docseqhist.o history.o recollq.o sortseq.o filtseq.o wasastringtoquery.o wasatorcl.o pathhash.o rcldb.o rcldoc.o rclquery.o searchdata.o stemdb.o stoplist.o base64.o conftree.o copyfile.o debuglog.o execmd.o fstreewalk.o idfile.o fileudi.o md5.o mimeparse.o pathut.o readfile.o smallut.o transcode.o wipedir.o x11mon.o -DEPS = rclaspell.dep.stamp rclconfig.dep.stamp rclinit.dep.stamp textsplit.dep.stamp unacpp.dep.stamp csguess.dep.stamp indexer.dep.stamp mimetype.dep.stamp htmlparse.dep.stamp myhtmlparse.dep.stamp mimehandler.dep.stamp internfile.dep.stamp mh_exec.dep.stamp mh_html.dep.stamp mh_mail.dep.stamp mh_mbox.dep.stamp mh_text.dep.stamp docseq.dep.stamp docseqdb.dep.stamp docseqhist.dep.stamp history.dep.stamp recollq.dep.stamp sortseq.dep.stamp filtseq.dep.stamp wasastringtoquery.dep.stamp wasatorcl.dep.stamp pathhash.dep.stamp rcldb.dep.stamp rcldoc.dep.stamp rclquery.dep.stamp searchdata.dep.stamp stemdb.dep.stamp stoplist.dep.stamp base64.dep.stamp conftree.dep.stamp copyfile.dep.stamp debuglog.dep.stamp execmd.dep.stamp fstreewalk.dep.stamp idfile.dep.stamp fileudi.dep.stamp md5.dep.stamp mimeparse.dep.stamp pathut.dep.stamp readfile.dep.stamp smallut.dep.stamp transcode.dep.stamp wipedir.dep.stamp x11mon.dep.stamp +OBJS = rclaspell.o rclconfig.o rclinit.o textsplit.o unacpp.o csguess.o indexer.o mimetype.o htmlparse.o myhtmlparse.o mimehandler.o internfile.o mh_exec.o mh_html.o mh_mail.o mh_mbox.o mh_text.o docseq.o docseqdb.o docseqhist.o filtseq.o history.o plaintorich.o recollq.o reslistpager.o sortseq.o wasastringtoquery.o wasatorcl.o pathhash.o rcldb.o rcldoc.o rclquery.o searchdata.o stemdb.o stoplist.o base64.o conftree.o copyfile.o debuglog.o execmd.o fstreewalk.o idfile.o fileudi.o md5.o mimeparse.o pathut.o readfile.o smallut.o transcode.o wipedir.o x11mon.o +DEPS = rclaspell.dep.stamp rclconfig.dep.stamp rclinit.dep.stamp textsplit.dep.stamp unacpp.dep.stamp csguess.dep.stamp indexer.dep.stamp mimetype.dep.stamp htmlparse.dep.stamp myhtmlparse.dep.stamp mimehandler.dep.stamp internfile.dep.stamp mh_exec.dep.stamp mh_html.dep.stamp mh_mail.dep.stamp mh_mbox.dep.stamp mh_text.dep.stamp docseq.dep.stamp docseqdb.dep.stamp docseqhist.dep.stamp filtseq.dep.stamp history.dep.stamp plaintorich.dep.stamp recollq.dep.stamp reslistpager.dep.stamp sortseq.dep.stamp wasastringtoquery.dep.stamp wasatorcl.dep.stamp pathhash.dep.stamp rcldb.dep.stamp rcldoc.dep.stamp rclquery.dep.stamp searchdata.dep.stamp stemdb.dep.stamp stoplist.dep.stamp base64.dep.stamp conftree.dep.stamp copyfile.dep.stamp debuglog.dep.stamp execmd.dep.stamp fstreewalk.dep.stamp idfile.dep.stamp fileudi.dep.stamp md5.dep.stamp mimeparse.dep.stamp pathut.dep.stamp readfile.dep.stamp smallut.dep.stamp transcode.dep.stamp wipedir.dep.stamp x11mon.dep.stamp librcl.a : $(DEPS) $(OBJS) unac.o ar ru librcl.a $(OBJS) unac.o @@ -57,14 +57,18 @@ docseqdb.o : ../query/docseqdb.cpp $(CXX) $(ALL_CXXFLAGS) -c ../query/docseqdb.cpp docseqhist.o : ../query/docseqhist.cpp $(CXX) $(ALL_CXXFLAGS) -c ../query/docseqhist.cpp -history.o : ../query/history.cpp - $(CXX) $(ALL_CXXFLAGS) -c ../query/history.cpp -recollq.o : ../query/recollq.cpp - $(CXX) $(ALL_CXXFLAGS) -c ../query/recollq.cpp -sortseq.o : ../query/sortseq.cpp - $(CXX) $(ALL_CXXFLAGS) -c ../query/sortseq.cpp filtseq.o : ../query/filtseq.cpp $(CXX) $(ALL_CXXFLAGS) -c ../query/filtseq.cpp +history.o : ../query/history.cpp + $(CXX) $(ALL_CXXFLAGS) -c ../query/history.cpp +plaintorich.o : ../query/plaintorich.cpp + $(CXX) $(ALL_CXXFLAGS) -c ../query/plaintorich.cpp +recollq.o : ../query/recollq.cpp + $(CXX) $(ALL_CXXFLAGS) -c ../query/recollq.cpp +reslistpager.o : ../query/reslistpager.cpp + $(CXX) $(ALL_CXXFLAGS) -c ../query/reslistpager.cpp +sortseq.o : ../query/sortseq.cpp + $(CXX) $(ALL_CXXFLAGS) -c ../query/sortseq.cpp wasastringtoquery.o : ../query/wasastringtoquery.cpp $(CXX) $(ALL_CXXFLAGS) -c ../query/wasastringtoquery.cpp wasatorcl.o : ../query/wasatorcl.cpp @@ -181,18 +185,24 @@ docseqdb.dep.stamp : ../query/docseqdb.cpp docseqhist.dep.stamp : ../query/docseqhist.cpp $(CXX) -M $(ALL_CXXFLAGS) ../query/docseqhist.cpp > docseqhist.dep touch docseqhist.dep.stamp -history.dep.stamp : ../query/history.cpp - $(CXX) -M $(ALL_CXXFLAGS) ../query/history.cpp > history.dep - touch history.dep.stamp -recollq.dep.stamp : ../query/recollq.cpp - $(CXX) -M $(ALL_CXXFLAGS) ../query/recollq.cpp > recollq.dep - touch recollq.dep.stamp -sortseq.dep.stamp : ../query/sortseq.cpp - $(CXX) -M $(ALL_CXXFLAGS) ../query/sortseq.cpp > sortseq.dep - touch sortseq.dep.stamp filtseq.dep.stamp : ../query/filtseq.cpp $(CXX) -M $(ALL_CXXFLAGS) ../query/filtseq.cpp > filtseq.dep touch filtseq.dep.stamp +history.dep.stamp : ../query/history.cpp + $(CXX) -M $(ALL_CXXFLAGS) ../query/history.cpp > history.dep + touch history.dep.stamp +plaintorich.dep.stamp : ../query/plaintorich.cpp + $(CXX) -M $(ALL_CXXFLAGS) ../query/plaintorich.cpp > plaintorich.dep + touch plaintorich.dep.stamp +recollq.dep.stamp : ../query/recollq.cpp + $(CXX) -M $(ALL_CXXFLAGS) ../query/recollq.cpp > recollq.dep + touch recollq.dep.stamp +reslistpager.dep.stamp : ../query/reslistpager.cpp + $(CXX) -M $(ALL_CXXFLAGS) ../query/reslistpager.cpp > reslistpager.dep + touch reslistpager.dep.stamp +sortseq.dep.stamp : ../query/sortseq.cpp + $(CXX) -M $(ALL_CXXFLAGS) ../query/sortseq.cpp > sortseq.dep + touch sortseq.dep.stamp wasastringtoquery.dep.stamp : ../query/wasastringtoquery.cpp $(CXX) -M $(ALL_CXXFLAGS) ../query/wasastringtoquery.cpp > wasastringtoquery.dep touch wasastringtoquery.dep.stamp @@ -288,10 +298,12 @@ include mh_text.dep include docseq.dep include docseqdb.dep include docseqhist.dep -include history.dep -include recollq.dep -include sortseq.dep include filtseq.dep +include history.dep +include plaintorich.dep +include recollq.dep +include reslistpager.dep +include sortseq.dep include wasastringtoquery.dep include wasatorcl.dep include pathhash.dep diff --git a/src/lib/mkMake b/src/lib/mkMake index 38acc06e..3e5e6690 100755 --- a/src/lib/mkMake +++ b/src/lib/mkMake @@ -24,10 +24,12 @@ ${depth}/internfile/mh_text.cpp \ ${depth}/query/docseq.cpp \ ${depth}/query/docseqdb.cpp \ ${depth}/query/docseqhist.cpp \ -${depth}/query/history.cpp \ -${depth}/query/recollq.cpp \ -${depth}/query/sortseq.cpp \ ${depth}/query/filtseq.cpp \ +${depth}/query/history.cpp \ +${depth}/query/plaintorich.cpp \ +${depth}/query/recollq.cpp \ +${depth}/query/reslistpager.cpp \ +${depth}/query/sortseq.cpp \ ${depth}/query/wasastringtoquery.cpp \ ${depth}/query/wasatorcl.cpp \ ${depth}/rcldb/pathhash.cpp \ diff --git a/src/qt4gui/recoll.pro.in b/src/qt4gui/recoll.pro.in index 12c41290..59525151 100644 --- a/src/qt4gui/recoll.pro.in +++ b/src/qt4gui/recoll.pro.in @@ -22,7 +22,6 @@ SOURCES += \ ../qtgui/guiutils.cpp \ ../qtgui/idxthread.cpp \ ../qtgui/main.cpp \ - ../qtgui/plaintorich.cpp \ ../qtgui/rclmain_w.cpp \ ../qtgui/reslist.cpp \ ../qtgui/advsearch_w.cpp \ diff --git a/src/qtgui/recoll.pro.in b/src/qtgui/recoll.pro.in index 244e7a33..6b39e743 100644 --- a/src/qtgui/recoll.pro.in +++ b/src/qtgui/recoll.pro.in @@ -22,7 +22,6 @@ SOURCES += \ guiutils.cpp \ idxthread.cpp \ main.cpp \ - plaintorich.cpp \ rclmain_w.cpp \ reslist.cpp \ advsearch_w.cpp \ diff --git a/src/qtgui/plaintorich.cpp b/src/query/plaintorich.cpp similarity index 99% rename from src/qtgui/plaintorich.cpp rename to src/query/plaintorich.cpp index 5085a377..c8b90aaa 100644 --- a/src/qtgui/plaintorich.cpp +++ b/src/query/plaintorich.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: plaintorich.cpp,v 1.34 2008-10-13 11:44:17 dockes Exp $ (C) 2005 J.F.Dockes"; +static char rcsid[] = "@(#$Id: plaintorich.cpp,v 1.1 2008-11-19 12:19:40 dockes Exp $ (C) 2005 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify diff --git a/src/qtgui/plaintorich.h b/src/query/plaintorich.h similarity index 97% rename from src/qtgui/plaintorich.h rename to src/query/plaintorich.h index 2caccb59..2686b05f 100644 --- a/src/qtgui/plaintorich.h +++ b/src/query/plaintorich.h @@ -16,7 +16,7 @@ */ #ifndef _PLAINTORICH_H_INCLUDED_ #define _PLAINTORICH_H_INCLUDED_ -/* @(#$Id: plaintorich.h,v 1.18 2008-10-03 08:09:35 dockes Exp $ (C) 2004 J.F.Dockes */ +/* @(#$Id: plaintorich.h,v 1.1 2008-11-19 12:19:40 dockes Exp $ (C) 2004 J.F.Dockes */ #include #include diff --git a/src/query/reslistpager.cpp b/src/query/reslistpager.cpp new file mode 100644 index 00000000..c06bf07f --- /dev/null +++ b/src/query/reslistpager.cpp @@ -0,0 +1,278 @@ +#ifndef lint +static char rcsid[] = "@(#$Id: reslistpager.cpp,v 1.1 2008-11-19 12:19:40 dockes Exp $ (C) 2007 J.F.Dockes"; +#endif + +#include "reslistpager.h" +#include "debuglog.h" +#include "rclconfig.h" +#include "smallut.h" +#include "plaintorich.h" +#include "mimehandler.h" + +// This should be passed as an input object to the pager instead +class PlainToRichHtReslist : public PlainToRich { +public: + virtual ~PlainToRichHtReslist() {} + virtual string startMatch() {return string("");} + virtual string endMatch() {return string("");} +}; +// IDEM +struct Prefs { + bool queryBuildAbstract; + bool queryReplaceAbstract; +}; +Prefs prefs = {true, true}; + +void ResListPager::resultPageNext() +{ + if (m_docSource.isNull()) + return; + + int resCnt = m_docSource->getResCnt(); + LOGDEB(("ResListPager::resultPageNext: rescnt %d, winfirst %d\n", + resCnt, m_winfirst)); + + if (m_winfirst < 0) { + m_winfirst = 0; + } else { + m_winfirst += m_pagesize; + } + // Get the next page of results. + vector npage; + int pagelen = m_docSource->getSeqSlice(m_winfirst, m_pagesize, npage); + + // If page was truncated, there is no next + m_hasNext = (pagelen == m_pagesize); + + if (pagelen <= 0) { + // No results ? This can only happen on the first page or if the + // actual result list size is a multiple of the page pref (else + // there would have been no Next on the last page) + if (m_winfirst > 0) { + // Have already results. Let them show, just disable the + // Next button. We'd need to remove the Next link from the page + // too. + // Restore the m_winfirst value, let the current result vector alone + m_winfirst -= m_pagesize; + } else { + // No results at all (on first page) + m_winfirst = -1; + } + return; + } + 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 + // it prominently + // Note: have to append text in chunks that make sense + // html-wise. If we break things up too much, the editor + // 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 += m_docSource->title(); + chunk += "</b></font>" + "   "; + + if (pageEmpty()) { + chunk += tr("<p><b>No results found</b> for "); + } else { + unsigned int resCnt = m_docSource->getResCnt(); + if (m_winfirst + m_respage.size() < resCnt) { + string f1 = tr("Documents <b>%d-%d</b> out of at least <b>%d</b> for "); + char buf[1024]; + snprintf(buf, 1023, f1.c_str(), m_winfirst+1, + m_winfirst + m_respage.size(), resCnt); + chunk += buf; + } else { + string f1 = tr("Documents <b>%d-%d</b> for "); + char buf[1024]; + snprintf(buf, 1023, f1.c_str(), m_winfirst + 1, + m_winfirst + m_respage.size()); + chunk += buf; + } + } + chunk += "<a href=\"H-1\">"; + chunk += tr("(show query)"); + chunk += "</a></p>"; + + append(chunk); + if (pageEmpty()) + return; + + + HiliteData hdata; + m_docSource->getTerms(hdata.terms, hdata.groups, hdata.gslks); + + // Emit data for result entry paragraph. Do it in chunks that make sense + // html-wise, else our client may get confused + for (int i = 0; i < (int)m_respage.size(); i++) { + + Rcl::Doc &doc(m_respage[i].doc); + string& sh(m_respage[i].subHeader); + int percent; + if (doc.pc == -1) { + percent = 0; + // Document not available, maybe other further, will go on. + doc.meta[Rcl::Doc::keyabs] = string(tr("Unavailable document")); + } else { + percent = doc.pc; + } + // Percentage of 'relevance' + char perbuf[10]; + sprintf(perbuf, "%3d%% ", percent); + + // Determine icon to display if any + string iconpath; + RclConfig::getMainConfig()->getMimeIconName(doc.mimetype, &iconpath); + + // Printable url: either utf-8 if transcoding succeeds, or url-encoded + string url; + printableUrl(RclConfig::getMainConfig()->getDefCharset(), doc.url, url); + + // Make title out of file name if none yet + if (doc.meta[Rcl::Doc::keytt].empty()) { + doc.meta[Rcl::Doc::keytt] = path_getsimple(url); + } + + // Result number + char numbuf[20]; + int docnumforlinks = m_winfirst + 1 + i; + sprintf(numbuf, "%d", docnumforlinks); + + // Document date: either doc or file modification time + 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); +#ifndef sun + strftime(datebuf, 99, " %Y-%m-%d %H:%M:%S %z", tm); +#else + strftime(datebuf, 99, " %Y-%m-%d %H:%M:%S %Z", tm); +#endif + } + + // Size information. We print both doc and file if they differ a lot + long fsize = -1, dsize = -1; + if (!doc.dbytes.empty()) + dsize = atol(doc.dbytes.c_str()); + if (!doc.fbytes.empty()) + fsize = atol(doc.fbytes.c_str()); + string sizebuf; + if (dsize > 0) { + sizebuf = displayableBytes(dsize); + if (fsize > 10 * dsize && fsize - dsize > 1000) + sizebuf += string(" / ") + displayableBytes(fsize); + } else if (fsize >= 0) { + sizebuf = displayableBytes(fsize); + } + + string abstract; + if (prefs.queryBuildAbstract && + (doc.syntabs || prefs.queryReplaceAbstract)) { + abstract = m_docSource->getAbstract(doc); + } else { + abstract = doc.meta[Rcl::Doc::keyabs]; + } + // No need to call escapeHtml(), plaintorich handles it + list<string> lr; + PlainToRichHtReslist ptr; + ptr.plaintorich(abstract, lr, hdata); + string richabst = lr.front(); + + // Links; + string linksbuf; + char vlbuf[100]; + if (canIntern(doc.mimetype, RclConfig::getMainConfig())) { + sprintf(vlbuf, "\"P%d\"", docnumforlinks); + linksbuf += string("<a href=") + vlbuf + ">" + "Preview" + "</a>" + + "  "; + } + if (!RclConfig::getMainConfig()->getMimeViewerDef(doc.mimetype).empty()) { + sprintf(vlbuf, "E%d", docnumforlinks); + linksbuf += string("<a href=") + vlbuf + ">" + "Open" + "</a>"; + } + + // Build the result list paragraph: + chunk = ""; + + // Subheader: this is used by history + if (!sh.empty()) + chunk += "<p><b>" + sh + "</p>\n<p>"; + else + chunk += "<p>"; + + // Configurable stuff + map<char,string> subs; + subs['A'] = !richabst.empty() ? richabst + "<br>" : ""; + subs['D'] = datebuf; + subs['I'] = iconpath; + subs['K'] = !doc.meta[Rcl::Doc::keykw].empty() ? + escapeHtml(doc.meta[Rcl::Doc::keykw]) + "<br>" : ""; + subs['L'] = linksbuf; + subs['N'] = numbuf; + subs['M'] = doc.mimetype; + subs['R'] = perbuf; + subs['S'] = sizebuf; + subs['T'] = escapeHtml(doc.meta[Rcl::Doc::keytt]); + subs['U'] = url; + + string formatted; + pcSubst(m_parformat, formatted, subs); + chunk += formatted; + + chunk += "</p>\n"; + + LOGDEB2(("Chunk: [%s]\n", (const char *)chunk.c_str())); + append(chunk); + } + + // Footer + chunk = "<p align=\"center\">"; + if (hasPrev() || hasNext()) { + if (hasPrev()) { + chunk += "<a href=\"p-1\"><b>"; + chunk += tr("Previous"); + chunk += "</b></a>   "; + } + if (hasNext()) { + chunk += "<a href=\"n-1\"><b>"; + chunk += tr("Next"); + chunk += "</b></a>"; + } + } + chunk += "</p>\n"; + chunk += "</body></html>\n"; + append(chunk); +} diff --git a/src/query/reslistpager.h b/src/query/reslistpager.h new file mode 100644 index 00000000..98f479ce --- /dev/null +++ b/src/query/reslistpager.h @@ -0,0 +1,51 @@ +#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 */ + +#include <vector> +using std::vector; + +#include "refcntr.h" +#include "docseq.h" + +/** + * Produces html text for a paged result list. + */ +class ResListPager { +public: + ResListPager(RefCntr<DocSequence> src, int pagesize, + const string& parformat) + : m_docSource(src), m_pagesize(pagesize), m_parformat(parformat), + m_hasNext(false) + {} + virtual ~ResListPager() {} + void pageNext(); + bool hasNext() {return m_hasNext;} + bool hasPrev() {return m_winfirst > 0;} + bool atBot() {return m_winfirst <= 0;} + void resultPageBack() { + if (m_winfirst <= 0) return; + m_winfirst -= 2 * m_pagesize; + resultPageNext(); + } + void resultPageFirst() { + m_winfirst = -1; + resultPageNext(); + } + void resultPageNext(); + void displayPage(); + bool pageEmpty() {return m_respage.size() == 0;} + virtual bool append(const string& data); + virtual string tr(const string& in); +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; +}; + +#endif /* _reslistpager_h_included_ */