From be214c4a5aa1a41bb4c0057cfc764fc153453cfd Mon Sep 17 00:00:00 2001
From: Jean-Francois Dockes " << sh << " ";
+ chunk << " " << sh << " ";
else
- chunk << " ";
+ chunk << " ";
char xdocidbuf[100];
sprintf(xdocidbuf, "%lu", doc.xdocid);
@@ -299,7 +293,7 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
subs["I"] = iconurl;
subs["i"] = doc.ipath;
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["N"] = numbuf;
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:
for (const auto& entry : doc.meta) {
- if (!entry.first.empty())
- subs[entry.first] = maybeEscapeHtml(entry.second);
+ if (!entry.first.empty())
+ subs[entry.first] = maybeEscapeHtml(entry.second);
}
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
// anyway because of the paragraph's style), but we finally took
// the table approach for 1.15 for now (in guiutils.cpp)
-// chunk << " "
- << m_docSource->title()
- << " ";
+ << "" << endl
+ << headerContent()
+ << " "
+ << m_docSource->title()
+ << " ";
if (pageEmpty()) {
- chunk << trans(" No results found
") +
@@ -656,7 +660,7 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
if (progress.wasCanceled()) {
QMessageBox::warning(0, "Recoll", tr("Canceled"));
} else {
- progress.close();
+ progress.reset();
// Note that we can't easily check for a readable file
// because it's possible that only a region is locked
// (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;
switch (lthr.explain) {
case FileInterner::FetchMissing:
- msg = tr("Error loading the document: file missing");
+ msg = tr("Error loading the document: file missing.");
break;
case FileInterner::FetchPerm:
- msg = tr("Error loading the document: no permission");
+ msg = tr("Error loading the document: no permission.");
break;
case FileInterner::FetchNoBackend:
msg =
- tr("Error loading the document: backend not configured");
+ tr("Error loading: backend not configured.");
break;
case FileInterner::InternfileOther:
#ifdef _WIN32
@@ -679,16 +683,29 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
"other handler error
"
"Maybe the application is locking the file ?");
#else
- msg = tr("Error loading the document: other handler error");
+ msg = tr("Error loading the document: other handler error.");
#endif
break;
}
+ if (canGetRawText) {
+ msg += tr("
Attempting to display from stored text.");
+ }
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.
theconfig->setKeyDir("");
@@ -838,6 +855,7 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
lthr.fdoc.text.clear();
editor->m_fdoc = lthr.fdoc;
editor->m_dbdoc = idoc;
+ editPB->setEnabled(canOpen(&editor->m_dbdoc, theconfig));
if (textempty)
editor->displayFields();
@@ -962,8 +980,10 @@ void PreviewTextEdit::createPopupMenu(const QPoint& pos)
if (!m_dbdoc.url.empty()) {
popup->addAction(tr("Save document to file"),
m_preview, SLOT(emitSaveDocToFile()));
- popup->addAction(tr("Open document"),
- m_preview, SLOT(emitEditRequested()));
+ if (canOpen(&m_dbdoc, theconfig)) {
+ popup->addAction(tr("Open document"),
+ m_preview, SLOT(emitEditRequested()));
+ }
}
popup->popup(mapToGlobal(pos));
}
diff --git a/src/query/reslistpager.cpp b/src/query/reslistpager.cpp
index 95208444..a32d1864 100644
--- a/src/query/reslistpager.cpp
+++ b/src/query/reslistpager.cpp
@@ -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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -46,13 +46,11 @@ static const string cstr_hlfontcolor("");
static const string cstr_hlendfont("");
class PlainToRichHtReslist : public PlainToRich {
public:
- virtual string startMatch(unsigned int)
- {
- return cstr_hlfontcolor;
+ virtual string startMatch(unsigned int) {
+ return cstr_hlfontcolor;
}
- virtual string endMatch()
- {
- return cstr_hlendfont;
+ virtual string endMatch() {
+ return cstr_hlendfont;
}
};
static PlainToRichHtReslist g_hiliter;
@@ -70,8 +68,8 @@ ResListPager::ResListPager(int pagesize)
void ResListPager::resultPageNext()
{
if (!m_docSource) {
- LOGDEB("ResListPager::resultPageNext: null source\n");
- return;
+ LOGDEB("ResListPager::resultPageNext: null source\n");
+ return;
}
int resCnt = m_docSource->getResCnt();
@@ -79,9 +77,9 @@ void ResListPager::resultPageNext()
", winfirst " << m_winfirst << "\n");
if (m_winfirst < 0) {
- m_winfirst = 0;
+ m_winfirst = 0;
} 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
// determine if there is actually a next page
@@ -93,25 +91,25 @@ void ResListPager::resultPageNext()
// Get rid of the possible excess result
if (pagelen == m_pagesize + 1) {
- npage.resize(m_pagesize);
- pagelen--;
+ npage.resize(m_pagesize);
+ pagelen--;
}
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 -= int(m_respage.size());
- } else {
- // No results at all (on first page)
- m_winfirst = -1;
- }
- return;
+ // 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 -= int(m_respage.size());
+ } else {
+ // No results at all (on first page)
+ m_winfirst = -1;
+ }
+ return;
}
m_resultsInCurrentPage = pagelen;
m_respage = npage;
@@ -119,17 +117,17 @@ void ResListPager::resultPageNext()
static string maybeEscapeHtml(const string& fld)
{
if (fld.compare(0, cstr_fldhtm.size(), cstr_fldhtm))
- return escapeHtml(fld);
+ return escapeHtml(fld);
else
- return fld.substr(cstr_fldhtm.size());
+ return fld.substr(cstr_fldhtm.size());
}
void ResListPager::resultPageFor(int docnum)
{
if (!m_docSource) {
- LOGDEB("ResListPager::resultPageFor: null source\n");
- return;
+ LOGDEB("ResListPager::resultPageFor: null source\n");
+ return;
}
int resCnt = m_docSource->getResCnt();
@@ -145,14 +143,14 @@ void ResListPager::resultPageFor(int docnum)
m_hasNext = (pagelen == m_pagesize);
if (pagelen <= 0) {
- m_winfirst = -1;
- return;
+ m_winfirst = -1;
+ return;
}
m_respage = npage;
}
void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
- const HighlightData& hdata, const string& sh)
+ const HighlightData& hdata, const string& sh)
{
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::keyfn, &utf8fn);
if (utf8fn.empty()) {
- utf8fn = path_getsimple(url);
+ utf8fn = path_getsimple(url);
}
if (titleOrFilename.empty()) {
- titleOrFilename = utf8fn;
+ titleOrFilename = utf8fn;
}
// 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()) {
char cdate[100];
cdate[0] = 0;
- time_t mtime = doc.dmtime.empty() ?
- atoll(doc.fmtime.c_str()) : atoll(doc.dmtime.c_str());
- struct tm *tm = localtime(&mtime);
- strftime(cdate, 99, dateFormat().c_str(), tm);
+ time_t mtime = doc.dmtime.empty() ?
+ atoll(doc.fmtime.c_str()) : atoll(doc.dmtime.c_str());
+ struct tm *tm = localtime(&mtime);
+ strftime(cdate, 99, dateFormat().c_str(), tm);
transcode(cdate, datebuf, RclConfig::getLocaleCharset(), "UTF-8");
}
// Size information. We print both doc and file if they differ a lot
int64_t fsize = -1, dsize = -1;
if (!doc.dbytes.empty())
- dsize = static_cast
" << endl;
+// chunk << "
" << endl;
LOGDEB2("Chunk: [" << chunk.rdbuf()->str() << "]\n");
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)
{
if (m_winfirst < 0 || m_respage.size() == 0)
- return false;
+ return false;
if (num < m_winfirst || num >= m_winfirst + int(m_respage.size()))
- return false;
+ return false;
doc = m_respage[num-m_winfirst].doc;
return true;
}
@@ -346,12 +340,12 @@ void ResListPager::displayPage(RclConfig *config)
{
LOGDEB("ResListPager::displayPage. linkPrefix: " << linkPrefix() << "\n");
if (!m_docSource) {
- LOGDEB("ResListPager::displayPage: null source\n");
- return;
+ LOGDEB("ResListPager::displayPage: null source\n");
+ return;
}
if (m_winfirst < 0 && !pageEmpty()) {
- LOGDEB("ResListPager::displayPage: sequence error: winfirst < 0\n");
- return;
+ LOGDEB("ResListPager::displayPage: sequence error: winfirst < 0\n");
+ return;
}
ostringstream chunk;
@@ -365,84 +359,84 @@ void ResListPager::displayPage(RclConfig *config)
// accumulator
// Also note that there can be results beyond the estimated resCnt.
chunk << "
");
- string reason = m_docSource->getReason();
- if (!reason.empty()) {
- chunk << "" << escapeHtml(reason) <<
- "
Alternate spellings (accents suppressed): ")
- << "
"; - } else { - chunk << - trans("Alternate spellings: ") - << "
"; - - } + chunk << trans("No results found
"); + string reason = m_docSource->getReason(); + if (!reason.empty()) { + chunk << "" << escapeHtml(reason) << + ""; + } else { + HighlightData hldata; + m_docSource->getTerms(hldata); + vectoruterms(hldata.uterms.begin(), hldata.uterms.end()); + if (!uterms.empty()) { + map > spellings; + suggest(uterms, spellings); + if (!spellings.empty()) { + if (o_index_stripchars) { + chunk << + trans(" Alternate spellings (accents suppressed): ") + << "
"; + } else { + chunk << + trans(""; + } + } + } } else { - unsigned int resCnt = m_docSource->getResCnt(); - if (m_winfirst + m_respage.size() < resCnt) { - chunk << trans("Documents") << " " << m_winfirst + 1 - << "-" << m_winfirst + m_respage.size() << " " - << trans("out of at least") << " " - << resCnt << " " << trans("for") << " " ; - } else { - chunk << trans("Documents") << " " - << m_winfirst + 1 << "-" << m_winfirst + m_respage.size() - << " " << trans("for") << " "; - } + unsigned int resCnt = m_docSource->getResCnt(); + if (m_winfirst + m_respage.size() < resCnt) { + chunk << trans("Documents") << " " << m_winfirst + 1 + << "-" << m_winfirst + m_respage.size() << " " + << trans("out of at least") << " " + << resCnt << " " << trans("for") << " " ; + } else { + chunk << trans("Documents") << " " + << m_winfirst + 1 << "-" << m_winfirst + m_respage.size() + << " " << trans("for") << " "; + } } chunk << detailsLink(); if (hasPrev() || hasNext()) { - chunk << " "; - if (hasPrev()) { - chunk << "" - << trans("Previous") - << " "; - } - if (hasNext()) { - chunk << "" - << trans("Next") - << ""; - } + chunk << " "; + if (hasPrev()) { + chunk << "" + << trans("Previous") + << " "; + } + if (hasNext()) { + chunk << "" + << trans("Next") + << ""; + } } chunk << "" << endl; append(chunk.rdbuf()->str()); chunk.rdbuf()->str(""); if (pageEmpty()) - return; + return; HighlightData 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 // 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); - displayDoc(config, i, doc, hdata, sh); + Rcl::Doc& doc(m_respage[i].doc); + string& sh(m_respage[i].subHeader); + displayDoc(config, i, doc, hdata, sh); } // Footer chunk << "Alternate spellings: ") + << "
"; + + } - for (const auto& entry: spellings) { - chunk << "" << entry.first << " : "; + for (const auto& entry: spellings) { + chunk << "" << entry.first << " : "; for (const auto& spelling : entry.second) { - chunk << spelling << " "; - } - chunk << ""; - } - } - } + chunk << spelling << " "; + } + chunk << "
"; - } - chunk << "
"; + } + chunk << ""; if (hasPrev() || hasNext()) { - if (hasPrev()) { - chunk << "" - << trans("Previous") - << " "; - } - if (hasNext()) { - chunk << "" - << trans("Next") - << ""; - } + if (hasPrev()) { + chunk << "" + << trans("Previous") + << " "; + } + if (hasNext()) { + chunk << "" + << trans("Next") + << ""; + } } chunk << "
" << endl; chunk << "" << endl; @@ -515,9 +509,9 @@ string ResListPager::detailsLink() const string &ResListPager::parFormat() { static const string cstr_format("" - "%R %S %L %T
" - "%M %D %U
" - "%A %K"); + "%R %S %L %T
" + "%M %D %U
" + "%A %K"); return cstr_format; } @@ -526,5 +520,3 @@ const string &ResListPager::dateFormat() static const string cstr_format(" %Y-%m-%d %H:%M:%S %z"); return cstr_format; } - - diff --git a/src/rcldb/rcldb.cpp b/src/rcldb/rcldb.cpp index acfcee83..dbd6db53 100644 --- a/src/rcldb/rcldb.cpp +++ b/src/rcldb/rcldb.cpp @@ -992,6 +992,24 @@ bool Db::open(OpenMode mode, OpenError *error) 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 bool Db::close() { diff --git a/src/rcldb/rcldb.h b/src/rcldb/rcldb.h index 24e767e3..a234c319 100644 --- a/src/rcldb/rcldb.h +++ b/src/rcldb/rcldb.h @@ -189,6 +189,9 @@ public: /** Return existing stemming databases */ vectorgetStemLangs(); + /** Check if index stores the documents' texts. Only valid after open */ + bool storesDocText(); + /** Test word for spelling correction candidate: not too long, no * special chars... * @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 */ 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 * by the GUI document history feature for remembering where a * doc comes from and allowing later retrieval (if the ext index