Take advantage of text storage when possible to display preview data for an unaccessible document

This commit is contained in:
Jean-Francois Dockes 2019-06-16 11:49:18 +02:00
parent a647d1c344
commit be214c4a5a
6 changed files with 254 additions and 189 deletions

View File

@ -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()
{ {

View File

@ -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_ */

View File

@ -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,17 +683,30 @@ 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);
} }
} }
if (canGetRawText) {
lthr.fdoc = idoc;
if (!rcldb->getDocRawText(lthr.fdoc)) {
QMessageBox::warning(0, "Recoll",
tr("Could not fetch stored text"));
progress.close(); progress.close();
return false; 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,9 +980,11 @@ 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()));
if (canOpen(&m_dbdoc, theconfig)) {
popup->addAction(tr("Open document"), popup->addAction(tr("Open document"),
m_preview, SLOT(emitEditRequested())); m_preview, SLOT(emitEditRequested()));
} }
}
popup->popup(mapToGlobal(pos)); popup->popup(mapToGlobal(pos));
} }

View File

@ -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,12 +46,10 @@ 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;
} }
}; };
@ -250,17 +248,13 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
} }
} }
// 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>&nbsp;&nbsp;"; << trans("Preview") << "</a>&nbsp;&nbsp;";
} }
if (canOpen(&doc, config)) {
string apptag;
doc.getmeta(Rcl::Doc::keyapptg, &apptag);
if (!config->getMimeViewerDef(doc.mimetype, apptag, false).empty()) {
linksbuf << "<a href=\"" <<linkPrefix() + "E" <<docnumforlinks << "\">" linksbuf << "<a href=\"" <<linkPrefix() + "E" <<docnumforlinks << "\">"
<< trans("Open") << "</a>"; << trans("Open") << "</a>";
} }
@ -526,5 +520,3 @@ const string &ResListPager::dateFormat()
static const string cstr_format("&nbsp;%Y-%m-%d&nbsp;%H:%M:%S&nbsp;%z"); static const string cstr_format("&nbsp;%Y-%m-%d&nbsp;%H:%M:%S&nbsp;%z");
return cstr_format; return cstr_format;
} }

View File

@ -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()
{ {

View File

@ -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