Take advantage of text storage when possible to display preview data for an unaccessible document
This commit is contained in:
parent
a647d1c344
commit
be214c4a5a
@ -42,6 +42,7 @@ using namespace std;
|
|||||||
#include "mh_unknown.h"
|
#include "mh_unknown.h"
|
||||||
#include "mh_null.h"
|
#include "mh_null.h"
|
||||||
#include "mh_xslt.h"
|
#include "mh_xslt.h"
|
||||||
|
#include "rcldoc.h"
|
||||||
|
|
||||||
// Performance help: we use a pool of already known and created
|
// Performance help: we use a pool of already known and created
|
||||||
// handlers. There can be several instances for a given mime type
|
// handlers. There can be several instances for a given mime type
|
||||||
@ -381,6 +382,24 @@ bool canIntern(const std::string mtype, RclConfig *cfg)
|
|||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
/// Same, getting MIME from doc
|
||||||
|
bool canIntern(Rcl::Doc *doc, RclConfig *cfg)
|
||||||
|
{
|
||||||
|
if (doc) {
|
||||||
|
return canIntern(doc->mimetype, cfg);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Can this MIME type be opened (has viewer def) ?
|
||||||
|
bool canOpen(Rcl::Doc *doc, RclConfig *cfg) {
|
||||||
|
if (!doc) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
string apptag;
|
||||||
|
doc->getmeta(Rcl::Doc::keyapptg, &apptag);
|
||||||
|
return !cfg->getMimeViewerDef(doc->mimetype, apptag, false).empty();
|
||||||
|
}
|
||||||
|
|
||||||
string RecollFilter::metadataAsString()
|
string RecollFilter::metadataAsString()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -179,7 +179,14 @@ extern void returnMimeHandler(RecollFilter *);
|
|||||||
/// off recoll.
|
/// off recoll.
|
||||||
extern void clearMimeHandlerCache();
|
extern void clearMimeHandlerCache();
|
||||||
|
|
||||||
|
namespace Rcl {
|
||||||
|
class Doc;
|
||||||
|
}
|
||||||
/// Can this mime type be interned ?
|
/// Can this mime type be interned ?
|
||||||
extern bool canIntern(const std::string mimetype, RclConfig *cfg);
|
extern bool canIntern(const std::string mimetype, RclConfig *cfg);
|
||||||
|
/// Same, getting MIME from doc
|
||||||
|
extern bool canIntern(Rcl::Doc *doc, RclConfig *cfg);
|
||||||
|
/// Can this MIME type be opened (has viewer def) ?
|
||||||
|
extern bool canOpen(Rcl::Doc *doc, RclConfig *cfg);
|
||||||
|
|
||||||
#endif /* _MIMEHANDLER_H_INCLUDED_ */
|
#endif /* _MIMEHANDLER_H_INCLUDED_ */
|
||||||
|
|||||||
@ -406,6 +406,9 @@ void Preview::currentChanged(int index)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
edit->setFocus();
|
edit->setFocus();
|
||||||
|
|
||||||
|
editPB->setEnabled(canOpen(&edit->m_dbdoc, theconfig));
|
||||||
|
|
||||||
// Disconnect the print signal and reconnect it to the current editor
|
// Disconnect the print signal and reconnect it to the current editor
|
||||||
LOGDEB1("Disconnecting reconnecting print signal\n");
|
LOGDEB1("Disconnecting reconnecting print signal\n");
|
||||||
disconnect(this, SIGNAL(printCurrentPreviewRequest()), 0, 0);
|
disconnect(this, SIGNAL(printCurrentPreviewRequest()), 0, 0);
|
||||||
@ -643,6 +646,7 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
|
|||||||
if (CancelCheck::instance().cancelState())
|
if (CancelCheck::instance().cancelState())
|
||||||
return false;
|
return false;
|
||||||
if (lthr.status != 0) {
|
if (lthr.status != 0) {
|
||||||
|
bool canGetRawText = rcldb && rcldb->storesDocText();
|
||||||
QString explain;
|
QString explain;
|
||||||
if (!lthr.missing.empty()) {
|
if (!lthr.missing.empty()) {
|
||||||
explain = QString::fromUtf8("<br>") +
|
explain = QString::fromUtf8("<br>") +
|
||||||
@ -656,7 +660,7 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
|
|||||||
if (progress.wasCanceled()) {
|
if (progress.wasCanceled()) {
|
||||||
QMessageBox::warning(0, "Recoll", tr("Canceled"));
|
QMessageBox::warning(0, "Recoll", tr("Canceled"));
|
||||||
} else {
|
} else {
|
||||||
progress.close();
|
progress.reset();
|
||||||
// Note that we can't easily check for a readable file
|
// Note that we can't easily check for a readable file
|
||||||
// because it's possible that only a region is locked
|
// because it's possible that only a region is locked
|
||||||
// (e.g. on Windows for an ost file the first block is
|
// (e.g. on Windows for an ost file the first block is
|
||||||
@ -664,14 +668,14 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
|
|||||||
QString msg;
|
QString msg;
|
||||||
switch (lthr.explain) {
|
switch (lthr.explain) {
|
||||||
case FileInterner::FetchMissing:
|
case FileInterner::FetchMissing:
|
||||||
msg = tr("Error loading the document: file missing");
|
msg = tr("Error loading the document: file missing.");
|
||||||
break;
|
break;
|
||||||
case FileInterner::FetchPerm:
|
case FileInterner::FetchPerm:
|
||||||
msg = tr("Error loading the document: no permission");
|
msg = tr("Error loading the document: no permission.");
|
||||||
break;
|
break;
|
||||||
case FileInterner::FetchNoBackend:
|
case FileInterner::FetchNoBackend:
|
||||||
msg =
|
msg =
|
||||||
tr("Error loading the document: backend not configured");
|
tr("Error loading: backend not configured.");
|
||||||
break;
|
break;
|
||||||
case FileInterner::InternfileOther:
|
case FileInterner::InternfileOther:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -679,16 +683,29 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
|
|||||||
"other handler error<br>"
|
"other handler error<br>"
|
||||||
"Maybe the application is locking the file ?");
|
"Maybe the application is locking the file ?");
|
||||||
#else
|
#else
|
||||||
msg = tr("Error loading the document: other handler error");
|
msg = tr("Error loading the document: other handler error.");
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (canGetRawText) {
|
||||||
|
msg += tr("<br>Attempting to display from stored text.");
|
||||||
|
}
|
||||||
QMessageBox::warning(0, "Recoll", msg);
|
QMessageBox::warning(0, "Recoll", msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
progress.close();
|
|
||||||
return false;
|
if (canGetRawText) {
|
||||||
|
lthr.fdoc = idoc;
|
||||||
|
if (!rcldb->getDocRawText(lthr.fdoc)) {
|
||||||
|
QMessageBox::warning(0, "Recoll",
|
||||||
|
tr("Could not fetch stored text"));
|
||||||
|
progress.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
progress.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Reset config just in case.
|
// Reset config just in case.
|
||||||
theconfig->setKeyDir("");
|
theconfig->setKeyDir("");
|
||||||
@ -838,6 +855,7 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
|
|||||||
lthr.fdoc.text.clear();
|
lthr.fdoc.text.clear();
|
||||||
editor->m_fdoc = lthr.fdoc;
|
editor->m_fdoc = lthr.fdoc;
|
||||||
editor->m_dbdoc = idoc;
|
editor->m_dbdoc = idoc;
|
||||||
|
editPB->setEnabled(canOpen(&editor->m_dbdoc, theconfig));
|
||||||
if (textempty)
|
if (textempty)
|
||||||
editor->displayFields();
|
editor->displayFields();
|
||||||
|
|
||||||
@ -962,8 +980,10 @@ void PreviewTextEdit::createPopupMenu(const QPoint& pos)
|
|||||||
if (!m_dbdoc.url.empty()) {
|
if (!m_dbdoc.url.empty()) {
|
||||||
popup->addAction(tr("Save document to file"),
|
popup->addAction(tr("Save document to file"),
|
||||||
m_preview, SLOT(emitSaveDocToFile()));
|
m_preview, SLOT(emitSaveDocToFile()));
|
||||||
popup->addAction(tr("Open document"),
|
if (canOpen(&m_dbdoc, theconfig)) {
|
||||||
m_preview, SLOT(emitEditRequested()));
|
popup->addAction(tr("Open document"),
|
||||||
|
m_preview, SLOT(emitEditRequested()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
popup->popup(mapToGlobal(pos));
|
popup->popup(mapToGlobal(pos));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2007 J.F.Dockes
|
/* Copyright (C) 2007-2019 J.F.Dockes
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
@ -46,13 +46,11 @@ static const string cstr_hlfontcolor("<span style='color: blue;'>");
|
|||||||
static const string cstr_hlendfont("</span>");
|
static const string cstr_hlendfont("</span>");
|
||||||
class PlainToRichHtReslist : public PlainToRich {
|
class PlainToRichHtReslist : public PlainToRich {
|
||||||
public:
|
public:
|
||||||
virtual string startMatch(unsigned int)
|
virtual string startMatch(unsigned int) {
|
||||||
{
|
return cstr_hlfontcolor;
|
||||||
return cstr_hlfontcolor;
|
|
||||||
}
|
}
|
||||||
virtual string endMatch()
|
virtual string endMatch() {
|
||||||
{
|
return cstr_hlendfont;
|
||||||
return cstr_hlendfont;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static PlainToRichHtReslist g_hiliter;
|
static PlainToRichHtReslist g_hiliter;
|
||||||
@ -70,8 +68,8 @@ ResListPager::ResListPager(int pagesize)
|
|||||||
void ResListPager::resultPageNext()
|
void ResListPager::resultPageNext()
|
||||||
{
|
{
|
||||||
if (!m_docSource) {
|
if (!m_docSource) {
|
||||||
LOGDEB("ResListPager::resultPageNext: null source\n");
|
LOGDEB("ResListPager::resultPageNext: null source\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int resCnt = m_docSource->getResCnt();
|
int resCnt = m_docSource->getResCnt();
|
||||||
@ -79,9 +77,9 @@ void ResListPager::resultPageNext()
|
|||||||
", winfirst " << m_winfirst << "\n");
|
", winfirst " << m_winfirst << "\n");
|
||||||
|
|
||||||
if (m_winfirst < 0) {
|
if (m_winfirst < 0) {
|
||||||
m_winfirst = 0;
|
m_winfirst = 0;
|
||||||
} else {
|
} else {
|
||||||
m_winfirst += int(m_respage.size());
|
m_winfirst += int(m_respage.size());
|
||||||
}
|
}
|
||||||
// Get the next page of results. Note that we look ahead by one to
|
// Get the next page of results. Note that we look ahead by one to
|
||||||
// determine if there is actually a next page
|
// determine if there is actually a next page
|
||||||
@ -93,25 +91,25 @@ void ResListPager::resultPageNext()
|
|||||||
|
|
||||||
// Get rid of the possible excess result
|
// Get rid of the possible excess result
|
||||||
if (pagelen == m_pagesize + 1) {
|
if (pagelen == m_pagesize + 1) {
|
||||||
npage.resize(m_pagesize);
|
npage.resize(m_pagesize);
|
||||||
pagelen--;
|
pagelen--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pagelen <= 0) {
|
if (pagelen <= 0) {
|
||||||
// No results ? This can only happen on the first page or if the
|
// 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
|
// actual result list size is a multiple of the page pref (else
|
||||||
// there would have been no Next on the last page)
|
// there would have been no Next on the last page)
|
||||||
if (m_winfirst > 0) {
|
if (m_winfirst > 0) {
|
||||||
// Have already results. Let them show, just disable the
|
// Have already results. Let them show, just disable the
|
||||||
// Next button. We'd need to remove the Next link from the page
|
// Next button. We'd need to remove the Next link from the page
|
||||||
// too.
|
// too.
|
||||||
// Restore the m_winfirst value, let the current result vector alone
|
// Restore the m_winfirst value, let the current result vector alone
|
||||||
m_winfirst -= int(m_respage.size());
|
m_winfirst -= int(m_respage.size());
|
||||||
} else {
|
} else {
|
||||||
// No results at all (on first page)
|
// No results at all (on first page)
|
||||||
m_winfirst = -1;
|
m_winfirst = -1;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_resultsInCurrentPage = pagelen;
|
m_resultsInCurrentPage = pagelen;
|
||||||
m_respage = npage;
|
m_respage = npage;
|
||||||
@ -119,17 +117,17 @@ void ResListPager::resultPageNext()
|
|||||||
static string maybeEscapeHtml(const string& fld)
|
static string maybeEscapeHtml(const string& fld)
|
||||||
{
|
{
|
||||||
if (fld.compare(0, cstr_fldhtm.size(), cstr_fldhtm))
|
if (fld.compare(0, cstr_fldhtm.size(), cstr_fldhtm))
|
||||||
return escapeHtml(fld);
|
return escapeHtml(fld);
|
||||||
else
|
else
|
||||||
return fld.substr(cstr_fldhtm.size());
|
return fld.substr(cstr_fldhtm.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ResListPager::resultPageFor(int docnum)
|
void ResListPager::resultPageFor(int docnum)
|
||||||
{
|
{
|
||||||
if (!m_docSource) {
|
if (!m_docSource) {
|
||||||
LOGDEB("ResListPager::resultPageFor: null source\n");
|
LOGDEB("ResListPager::resultPageFor: null source\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int resCnt = m_docSource->getResCnt();
|
int resCnt = m_docSource->getResCnt();
|
||||||
@ -145,14 +143,14 @@ void ResListPager::resultPageFor(int docnum)
|
|||||||
m_hasNext = (pagelen == m_pagesize);
|
m_hasNext = (pagelen == m_pagesize);
|
||||||
|
|
||||||
if (pagelen <= 0) {
|
if (pagelen <= 0) {
|
||||||
m_winfirst = -1;
|
m_winfirst = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_respage = npage;
|
m_respage = npage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
|
void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
|
||||||
const HighlightData& hdata, const string& sh)
|
const HighlightData& hdata, const string& sh)
|
||||||
{
|
{
|
||||||
ostringstream chunk;
|
ostringstream chunk;
|
||||||
|
|
||||||
@ -176,10 +174,10 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
|
|||||||
doc.getmeta(Rcl::Doc::keytt, &titleOrFilename);
|
doc.getmeta(Rcl::Doc::keytt, &titleOrFilename);
|
||||||
doc.getmeta(Rcl::Doc::keyfn, &utf8fn);
|
doc.getmeta(Rcl::Doc::keyfn, &utf8fn);
|
||||||
if (utf8fn.empty()) {
|
if (utf8fn.empty()) {
|
||||||
utf8fn = path_getsimple(url);
|
utf8fn = path_getsimple(url);
|
||||||
}
|
}
|
||||||
if (titleOrFilename.empty()) {
|
if (titleOrFilename.empty()) {
|
||||||
titleOrFilename = utf8fn;
|
titleOrFilename = utf8fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Url for the parent directory. We strip the file:// part for local
|
// Url for the parent directory. We strip the file:// part for local
|
||||||
@ -201,92 +199,88 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
|
|||||||
if (!doc.dmtime.empty() || !doc.fmtime.empty()) {
|
if (!doc.dmtime.empty() || !doc.fmtime.empty()) {
|
||||||
char cdate[100];
|
char cdate[100];
|
||||||
cdate[0] = 0;
|
cdate[0] = 0;
|
||||||
time_t mtime = doc.dmtime.empty() ?
|
time_t mtime = doc.dmtime.empty() ?
|
||||||
atoll(doc.fmtime.c_str()) : atoll(doc.dmtime.c_str());
|
atoll(doc.fmtime.c_str()) : atoll(doc.dmtime.c_str());
|
||||||
struct tm *tm = localtime(&mtime);
|
struct tm *tm = localtime(&mtime);
|
||||||
strftime(cdate, 99, dateFormat().c_str(), tm);
|
strftime(cdate, 99, dateFormat().c_str(), tm);
|
||||||
transcode(cdate, datebuf, RclConfig::getLocaleCharset(), "UTF-8");
|
transcode(cdate, datebuf, RclConfig::getLocaleCharset(), "UTF-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size information. We print both doc and file if they differ a lot
|
// Size information. We print both doc and file if they differ a lot
|
||||||
int64_t fsize = -1, dsize = -1;
|
int64_t fsize = -1, dsize = -1;
|
||||||
if (!doc.dbytes.empty())
|
if (!doc.dbytes.empty())
|
||||||
dsize = static_cast<int64_t>(atoll(doc.dbytes.c_str()));
|
dsize = static_cast<int64_t>(atoll(doc.dbytes.c_str()));
|
||||||
if (!doc.fbytes.empty())
|
if (!doc.fbytes.empty())
|
||||||
fsize = static_cast<int64_t>(atoll(doc.fbytes.c_str()));
|
fsize = static_cast<int64_t>(atoll(doc.fbytes.c_str()));
|
||||||
string sizebuf;
|
string sizebuf;
|
||||||
if (dsize > 0) {
|
if (dsize > 0) {
|
||||||
sizebuf = displayableBytes(dsize);
|
sizebuf = displayableBytes(dsize);
|
||||||
if (fsize > 10 * dsize && fsize - dsize > 1000)
|
if (fsize > 10 * dsize && fsize - dsize > 1000)
|
||||||
sizebuf += string(" / ") + displayableBytes(fsize);
|
sizebuf += string(" / ") + displayableBytes(fsize);
|
||||||
} else if (fsize >= 0) {
|
} else if (fsize >= 0) {
|
||||||
sizebuf = displayableBytes(fsize);
|
sizebuf = displayableBytes(fsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
string richabst;
|
string richabst;
|
||||||
bool needabstract = parFormat().find("%A") != string::npos;
|
bool needabstract = parFormat().find("%A") != string::npos;
|
||||||
if (needabstract && m_docSource) {
|
if (needabstract && m_docSource) {
|
||||||
vector<string> vabs;
|
vector<string> vabs;
|
||||||
m_docSource->getAbstract(doc, vabs);
|
m_docSource->getAbstract(doc, vabs);
|
||||||
m_hiliter->set_inputhtml(false);
|
m_hiliter->set_inputhtml(false);
|
||||||
|
|
||||||
for (vector<string>::const_iterator it = vabs.begin();
|
for (vector<string>::const_iterator it = vabs.begin();
|
||||||
it != vabs.end(); it++) {
|
it != vabs.end(); it++) {
|
||||||
if (!it->empty()) {
|
if (!it->empty()) {
|
||||||
// No need to call escapeHtml(), plaintorich handles it
|
// No need to call escapeHtml(), plaintorich handles it
|
||||||
list<string> lr;
|
list<string> lr;
|
||||||
// There may be data like page numbers before the snippet text.
|
// There may be data like page numbers before the snippet text.
|
||||||
// will be in brackets.
|
// will be in brackets.
|
||||||
string::size_type bckt = it->find("]");
|
string::size_type bckt = it->find("]");
|
||||||
if (bckt == string::npos) {
|
if (bckt == string::npos) {
|
||||||
m_hiliter->plaintorich(*it, lr, hdata);
|
m_hiliter->plaintorich(*it, lr, hdata);
|
||||||
} else {
|
} else {
|
||||||
m_hiliter->plaintorich(it->substr(bckt), lr, hdata);
|
m_hiliter->plaintorich(it->substr(bckt), lr, hdata);
|
||||||
lr.front() = it->substr(0, bckt) + lr.front();
|
lr.front() = it->substr(0, bckt) + lr.front();
|
||||||
}
|
}
|
||||||
richabst += lr.front();
|
richabst += lr.front();
|
||||||
richabst += absSep();
|
richabst += absSep();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Links;
|
// Links; Uses utilities from mimehandler.h
|
||||||
ostringstream linksbuf;
|
ostringstream linksbuf;
|
||||||
if (canIntern(doc.mimetype, config)) {
|
if (canIntern(&doc, config)) {
|
||||||
linksbuf << "<a href=\""<< linkPrefix()<< "P" << docnumforlinks << "\">"
|
linksbuf << "<a href=\""<< linkPrefix()<< "P" << docnumforlinks << "\">"
|
||||||
<< trans("Preview") << "</a> ";
|
<< trans("Preview") << "</a> ";
|
||||||
}
|
}
|
||||||
|
if (canOpen(&doc, config)) {
|
||||||
string apptag;
|
linksbuf << "<a href=\"" <<linkPrefix() + "E" <<docnumforlinks << "\">"
|
||||||
doc.getmeta(Rcl::Doc::keyapptg, &apptag);
|
<< trans("Open") << "</a>";
|
||||||
|
|
||||||
if (!config->getMimeViewerDef(doc.mimetype, apptag, false).empty()) {
|
|
||||||
linksbuf << "<a href=\"" <<linkPrefix() + "E" <<docnumforlinks << "\">"
|
|
||||||
<< trans("Open") << "</a>";
|
|
||||||
}
|
}
|
||||||
ostringstream snipsbuf;
|
ostringstream snipsbuf;
|
||||||
if (doc.haspages) {
|
if (doc.haspages) {
|
||||||
snipsbuf << "<a href=\"" <<linkPrefix()<<"A" << docnumforlinks << "\">"
|
snipsbuf << "<a href=\"" <<linkPrefix()<<"A" << docnumforlinks << "\">"
|
||||||
<< trans("Snippets") << "</a> ";
|
<< trans("Snippets") << "</a> ";
|
||||||
linksbuf << " " << snipsbuf.str();
|
linksbuf << " " << snipsbuf.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
string collapscnt;
|
string collapscnt;
|
||||||
if (doc.getmeta(Rcl::Doc::keycc, &collapscnt) && !collapscnt.empty()) {
|
if (doc.getmeta(Rcl::Doc::keycc, &collapscnt) && !collapscnt.empty()) {
|
||||||
ostringstream collpsbuf;
|
ostringstream collpsbuf;
|
||||||
int clc = atoi(collapscnt.c_str()) + 1;
|
int clc = atoi(collapscnt.c_str()) + 1;
|
||||||
collpsbuf << "<a href=\""<<linkPrefix()<<"D" << docnumforlinks << "\">"
|
collpsbuf << "<a href=\""<<linkPrefix()<<"D" << docnumforlinks << "\">"
|
||||||
<< trans("Dups") << "(" << clc << ")" << "</a> ";
|
<< trans("Dups") << "(" << clc << ")" << "</a> ";
|
||||||
linksbuf << " " << collpsbuf.str();
|
linksbuf << " " << collpsbuf.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the result list paragraph:
|
// Build the result list paragraph:
|
||||||
|
|
||||||
// Subheader: this is used by history
|
// Subheader: this is used by history
|
||||||
if (!sh.empty())
|
if (!sh.empty())
|
||||||
chunk << "<p style='clear: both;'><b>" << sh << "</p>\n<p>";
|
chunk << "<p style='clear: both;'><b>" << sh << "</p>\n<p>";
|
||||||
else
|
else
|
||||||
chunk << "<p style='margin: 0px;padding: 0px;clear: both;'>";
|
chunk << "<p style='margin: 0px;padding: 0px;clear: both;'>";
|
||||||
|
|
||||||
char xdocidbuf[100];
|
char xdocidbuf[100];
|
||||||
sprintf(xdocidbuf, "%lu", doc.xdocid);
|
sprintf(xdocidbuf, "%lu", doc.xdocid);
|
||||||
@ -299,7 +293,7 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
|
|||||||
subs["I"] = iconurl;
|
subs["I"] = iconurl;
|
||||||
subs["i"] = doc.ipath;
|
subs["i"] = doc.ipath;
|
||||||
subs["K"] = !doc.meta[Rcl::Doc::keykw].empty() ?
|
subs["K"] = !doc.meta[Rcl::Doc::keykw].empty() ?
|
||||||
string("[") + maybeEscapeHtml(doc.meta[Rcl::Doc::keykw]) + "]" : "";
|
string("[") + maybeEscapeHtml(doc.meta[Rcl::Doc::keykw]) + "]" : "";
|
||||||
subs["L"] = linksbuf.str();
|
subs["L"] = linksbuf.str();
|
||||||
subs["N"] = numbuf;
|
subs["N"] = numbuf;
|
||||||
subs["M"] = doc.mimetype;
|
subs["M"] = doc.mimetype;
|
||||||
@ -314,8 +308,8 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
|
|||||||
|
|
||||||
// Let %(xx) access all metadata. HTML-neuter everything:
|
// Let %(xx) access all metadata. HTML-neuter everything:
|
||||||
for (const auto& entry : doc.meta) {
|
for (const auto& entry : doc.meta) {
|
||||||
if (!entry.first.empty())
|
if (!entry.first.empty())
|
||||||
subs[entry.first] = maybeEscapeHtml(entry.second);
|
subs[entry.first] = maybeEscapeHtml(entry.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
string formatted;
|
string formatted;
|
||||||
@ -326,7 +320,7 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
|
|||||||
// This was to force qt 4.x to clear the margins (which it should do
|
// This was to force qt 4.x to clear the margins (which it should do
|
||||||
// anyway because of the paragraph's style), but we finally took
|
// anyway because of the paragraph's style), but we finally took
|
||||||
// the table approach for 1.15 for now (in guiutils.cpp)
|
// the table approach for 1.15 for now (in guiutils.cpp)
|
||||||
// chunk << "<br style='clear:both;height:0;line-height:0;'>" << endl;
|
// chunk << "<br style='clear:both;height:0;line-height:0;'>" << endl;
|
||||||
|
|
||||||
LOGDEB2("Chunk: [" << chunk.rdbuf()->str() << "]\n");
|
LOGDEB2("Chunk: [" << chunk.rdbuf()->str() << "]\n");
|
||||||
append(chunk.rdbuf()->str(), i, doc);
|
append(chunk.rdbuf()->str(), i, doc);
|
||||||
@ -335,9 +329,9 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
|
|||||||
bool ResListPager::getDoc(int num, Rcl::Doc& doc)
|
bool ResListPager::getDoc(int num, Rcl::Doc& doc)
|
||||||
{
|
{
|
||||||
if (m_winfirst < 0 || m_respage.size() == 0)
|
if (m_winfirst < 0 || m_respage.size() == 0)
|
||||||
return false;
|
return false;
|
||||||
if (num < m_winfirst || num >= m_winfirst + int(m_respage.size()))
|
if (num < m_winfirst || num >= m_winfirst + int(m_respage.size()))
|
||||||
return false;
|
return false;
|
||||||
doc = m_respage[num-m_winfirst].doc;
|
doc = m_respage[num-m_winfirst].doc;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -346,12 +340,12 @@ void ResListPager::displayPage(RclConfig *config)
|
|||||||
{
|
{
|
||||||
LOGDEB("ResListPager::displayPage. linkPrefix: " << linkPrefix() << "\n");
|
LOGDEB("ResListPager::displayPage. linkPrefix: " << linkPrefix() << "\n");
|
||||||
if (!m_docSource) {
|
if (!m_docSource) {
|
||||||
LOGDEB("ResListPager::displayPage: null source\n");
|
LOGDEB("ResListPager::displayPage: null source\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_winfirst < 0 && !pageEmpty()) {
|
if (m_winfirst < 0 && !pageEmpty()) {
|
||||||
LOGDEB("ResListPager::displayPage: sequence error: winfirst < 0\n");
|
LOGDEB("ResListPager::displayPage: sequence error: winfirst < 0\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ostringstream chunk;
|
ostringstream chunk;
|
||||||
@ -365,84 +359,84 @@ void ResListPager::displayPage(RclConfig *config)
|
|||||||
// accumulator
|
// accumulator
|
||||||
// Also note that there can be results beyond the estimated resCnt.
|
// Also note that there can be results beyond the estimated resCnt.
|
||||||
chunk << "<html><head>" << endl
|
chunk << "<html><head>" << endl
|
||||||
<< "<meta http-equiv=\"content-type\""
|
<< "<meta http-equiv=\"content-type\""
|
||||||
<< " content=\"text/html; charset=utf-8\">" << endl
|
<< " content=\"text/html; charset=utf-8\">" << endl
|
||||||
<< headerContent()
|
<< headerContent()
|
||||||
<< "</head><body>" << endl
|
<< "</head><body>" << endl
|
||||||
<< pageTop()
|
<< pageTop()
|
||||||
<< "<p><span style=\"font-size:110%;\"><b>"
|
<< "<p><span style=\"font-size:110%;\"><b>"
|
||||||
<< m_docSource->title()
|
<< m_docSource->title()
|
||||||
<< "</b></span> ";
|
<< "</b></span> ";
|
||||||
|
|
||||||
if (pageEmpty()) {
|
if (pageEmpty()) {
|
||||||
chunk << trans("<p><b>No results found</b><br>");
|
chunk << trans("<p><b>No results found</b><br>");
|
||||||
string reason = m_docSource->getReason();
|
string reason = m_docSource->getReason();
|
||||||
if (!reason.empty()) {
|
if (!reason.empty()) {
|
||||||
chunk << "<blockquote>" << escapeHtml(reason) <<
|
chunk << "<blockquote>" << escapeHtml(reason) <<
|
||||||
"</blockquote></p>";
|
"</blockquote></p>";
|
||||||
} else {
|
} else {
|
||||||
HighlightData hldata;
|
HighlightData hldata;
|
||||||
m_docSource->getTerms(hldata);
|
m_docSource->getTerms(hldata);
|
||||||
vector<string> uterms(hldata.uterms.begin(), hldata.uterms.end());
|
vector<string> uterms(hldata.uterms.begin(), hldata.uterms.end());
|
||||||
if (!uterms.empty()) {
|
if (!uterms.empty()) {
|
||||||
map<string, vector<string> > spellings;
|
map<string, vector<string> > spellings;
|
||||||
suggest(uterms, spellings);
|
suggest(uterms, spellings);
|
||||||
if (!spellings.empty()) {
|
if (!spellings.empty()) {
|
||||||
if (o_index_stripchars) {
|
if (o_index_stripchars) {
|
||||||
chunk <<
|
chunk <<
|
||||||
trans("<p><i>Alternate spellings (accents suppressed): </i>")
|
trans("<p><i>Alternate spellings (accents suppressed): </i>")
|
||||||
<< "<br /><blockquote>";
|
<< "<br /><blockquote>";
|
||||||
} else {
|
} else {
|
||||||
chunk <<
|
chunk <<
|
||||||
trans("<p><i>Alternate spellings: </i>")
|
trans("<p><i>Alternate spellings: </i>")
|
||||||
<< "<br /><blockquote>";
|
<< "<br /><blockquote>";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& entry: spellings) {
|
for (const auto& entry: spellings) {
|
||||||
chunk << "<b>" << entry.first << "</b> : ";
|
chunk << "<b>" << entry.first << "</b> : ";
|
||||||
for (const auto& spelling : entry.second) {
|
for (const auto& spelling : entry.second) {
|
||||||
chunk << spelling << " ";
|
chunk << spelling << " ";
|
||||||
}
|
}
|
||||||
chunk << "<br />";
|
chunk << "<br />";
|
||||||
}
|
}
|
||||||
chunk << "</blockquote></p>";
|
chunk << "</blockquote></p>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned int resCnt = m_docSource->getResCnt();
|
unsigned int resCnt = m_docSource->getResCnt();
|
||||||
if (m_winfirst + m_respage.size() < resCnt) {
|
if (m_winfirst + m_respage.size() < resCnt) {
|
||||||
chunk << trans("Documents") << " <b>" << m_winfirst + 1
|
chunk << trans("Documents") << " <b>" << m_winfirst + 1
|
||||||
<< "-" << m_winfirst + m_respage.size() << "</b> "
|
<< "-" << m_winfirst + m_respage.size() << "</b> "
|
||||||
<< trans("out of at least") << " "
|
<< trans("out of at least") << " "
|
||||||
<< resCnt << " " << trans("for") << " " ;
|
<< resCnt << " " << trans("for") << " " ;
|
||||||
} else {
|
} else {
|
||||||
chunk << trans("Documents") << " <b>"
|
chunk << trans("Documents") << " <b>"
|
||||||
<< m_winfirst + 1 << "-" << m_winfirst + m_respage.size()
|
<< m_winfirst + 1 << "-" << m_winfirst + m_respage.size()
|
||||||
<< "</b> " << trans("for") << " ";
|
<< "</b> " << trans("for") << " ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chunk << detailsLink();
|
chunk << detailsLink();
|
||||||
if (hasPrev() || hasNext()) {
|
if (hasPrev() || hasNext()) {
|
||||||
chunk << " ";
|
chunk << " ";
|
||||||
if (hasPrev()) {
|
if (hasPrev()) {
|
||||||
chunk << "<a href=\"" << linkPrefix() + prevUrl() + "\"><b>"
|
chunk << "<a href=\"" << linkPrefix() + prevUrl() + "\"><b>"
|
||||||
<< trans("Previous")
|
<< trans("Previous")
|
||||||
<< "</b></a> ";
|
<< "</b></a> ";
|
||||||
}
|
}
|
||||||
if (hasNext()) {
|
if (hasNext()) {
|
||||||
chunk << "<a href=\"" << linkPrefix() + nextUrl() + "\"><b>"
|
chunk << "<a href=\"" << linkPrefix() + nextUrl() + "\"><b>"
|
||||||
<< trans("Next")
|
<< trans("Next")
|
||||||
<< "</b></a>";
|
<< "</b></a>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chunk << "</p>" << endl;
|
chunk << "</p>" << endl;
|
||||||
|
|
||||||
append(chunk.rdbuf()->str());
|
append(chunk.rdbuf()->str());
|
||||||
chunk.rdbuf()->str("");
|
chunk.rdbuf()->str("");
|
||||||
if (pageEmpty())
|
if (pageEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
HighlightData hdata;
|
HighlightData hdata;
|
||||||
m_docSource->getTerms(hdata);
|
m_docSource->getTerms(hdata);
|
||||||
@ -450,24 +444,24 @@ void ResListPager::displayPage(RclConfig *config)
|
|||||||
// Emit data for result entry paragraph. Do it in chunks that make sense
|
// Emit data for result entry paragraph. Do it in chunks that make sense
|
||||||
// html-wise, else our client may get confused
|
// html-wise, else our client may get confused
|
||||||
for (int i = 0; i < (int)m_respage.size(); i++) {
|
for (int i = 0; i < (int)m_respage.size(); i++) {
|
||||||
Rcl::Doc& doc(m_respage[i].doc);
|
Rcl::Doc& doc(m_respage[i].doc);
|
||||||
string& sh(m_respage[i].subHeader);
|
string& sh(m_respage[i].subHeader);
|
||||||
displayDoc(config, i, doc, hdata, sh);
|
displayDoc(config, i, doc, hdata, sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
chunk << "<p align=\"center\">";
|
chunk << "<p align=\"center\">";
|
||||||
if (hasPrev() || hasNext()) {
|
if (hasPrev() || hasNext()) {
|
||||||
if (hasPrev()) {
|
if (hasPrev()) {
|
||||||
chunk << "<a href=\"" + linkPrefix() + prevUrl() + "\"><b>"
|
chunk << "<a href=\"" + linkPrefix() + prevUrl() + "\"><b>"
|
||||||
<< trans("Previous")
|
<< trans("Previous")
|
||||||
<< "</b></a> ";
|
<< "</b></a> ";
|
||||||
}
|
}
|
||||||
if (hasNext()) {
|
if (hasNext()) {
|
||||||
chunk << "<a href=\"" << linkPrefix() + nextUrl() + "\"><b>"
|
chunk << "<a href=\"" << linkPrefix() + nextUrl() + "\"><b>"
|
||||||
<< trans("Next")
|
<< trans("Next")
|
||||||
<< "</b></a>";
|
<< "</b></a>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chunk << "</p>" << endl;
|
chunk << "</p>" << endl;
|
||||||
chunk << "</body></html>" << endl;
|
chunk << "</body></html>" << endl;
|
||||||
@ -515,9 +509,9 @@ string ResListPager::detailsLink()
|
|||||||
const string &ResListPager::parFormat()
|
const string &ResListPager::parFormat()
|
||||||
{
|
{
|
||||||
static const string cstr_format("<img src=\"%I\" align=\"left\">"
|
static const string cstr_format("<img src=\"%I\" align=\"left\">"
|
||||||
"%R %S %L <b>%T</b><br>"
|
"%R %S %L <b>%T</b><br>"
|
||||||
"%M %D <i>%U</i><br>"
|
"%M %D <i>%U</i><br>"
|
||||||
"%A %K");
|
"%A %K");
|
||||||
return cstr_format;
|
return cstr_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,5 +520,3 @@ const string &ResListPager::dateFormat()
|
|||||||
static const string cstr_format(" %Y-%m-%d %H:%M:%S %z");
|
static const string cstr_format(" %Y-%m-%d %H:%M:%S %z");
|
||||||
return cstr_format;
|
return cstr_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -992,6 +992,24 @@ bool Db::open(OpenMode mode, OpenError *error)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Db::storesDocText()
|
||||||
|
{
|
||||||
|
if (!m_ndb || !m_ndb->m_isopen) {
|
||||||
|
LOGERR("Db::storesDocText: called on non-opened db\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return m_ndb->m_storetext;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Db::getDocRawText(Doc& doc)
|
||||||
|
{
|
||||||
|
if (!m_ndb || !m_ndb->m_isopen) {
|
||||||
|
LOGERR("Db::getDocRawText: called on non-opened db\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return m_ndb->getRawText(doc.xdocid, doc.text);
|
||||||
|
}
|
||||||
|
|
||||||
// Note: xapian has no close call, we delete and recreate the db
|
// Note: xapian has no close call, we delete and recreate the db
|
||||||
bool Db::close()
|
bool Db::close()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -189,6 +189,9 @@ public:
|
|||||||
/** Return existing stemming databases */
|
/** Return existing stemming databases */
|
||||||
vector<string> getStemLangs();
|
vector<string> getStemLangs();
|
||||||
|
|
||||||
|
/** Check if index stores the documents' texts. Only valid after open */
|
||||||
|
bool storesDocText();
|
||||||
|
|
||||||
/** Test word for spelling correction candidate: not too long, no
|
/** Test word for spelling correction candidate: not too long, no
|
||||||
* special chars...
|
* special chars...
|
||||||
* @param with_aspell test for use with aspell, else for xapian speller
|
* @param with_aspell test for use with aspell, else for xapian speller
|
||||||
@ -341,6 +344,12 @@ public:
|
|||||||
decide if we can update the index for it */
|
decide if we can update the index for it */
|
||||||
bool fromMainIndex(const Doc& doc);
|
bool fromMainIndex(const Doc& doc);
|
||||||
|
|
||||||
|
/** Retrieve the stored doc text. This returns false if the index does not
|
||||||
|
store raw text or other problems (discriminate with storesDocText().
|
||||||
|
On success, the data is stored in doc.text
|
||||||
|
*/
|
||||||
|
bool getDocRawText(Doc& doc);
|
||||||
|
|
||||||
/** Retrieve an index designator for the document result. This is used
|
/** Retrieve an index designator for the document result. This is used
|
||||||
* by the GUI document history feature for remembering where a
|
* by the GUI document history feature for remembering where a
|
||||||
* doc comes from and allowing later retrieval (if the ext index
|
* doc comes from and allowing later retrieval (if the ext index
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user