GUI: implemented qt webengine compatibility. Default is still to use qt webkit

This commit is contained in:
Jean-Francois Dockes 2018-12-05 13:46:26 +01:00
parent 504705879b
commit 08bd33090c
8 changed files with 403 additions and 140 deletions

View File

@ -229,7 +229,21 @@ int main(int argc, char **argv)
} }
} }
#ifdef USING_WEBENGINE
// This is necessary for allowing webengine to load local resources (icons)
// It is not an issue because we never access remote sites.
char arg_disable_web_security[] = "--disable-web-security";
int appargc = argc + 1;
char** appargv = new char*[appargc+1];
for(int i = 0; i < argc; i++) {
appargv[i] = argv[i];
}
appargv[argc] = arg_disable_web_security;
appargv[argc+1] = nullptr;
QApplication app(appargc, appargv);
#else
QApplication app(argc, argv); QApplication app(argc, argv);
#endif
QCoreApplication::setOrganizationName("Recoll.org"); QCoreApplication::setOrganizationName("Recoll.org");
QCoreApplication::setApplicationName("recoll"); QCoreApplication::setApplicationName("recoll");

View File

@ -19,6 +19,7 @@ QT += xml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
@QMAKE_ENABLE_WEBKIT@ greaterThan(QT_MAJOR_VERSION, 4): QT += webkitwidgets @QMAKE_ENABLE_WEBKIT@ greaterThan(QT_MAJOR_VERSION, 4): QT += webkitwidgets
@QMAKE_ENABLE_WEBENGINE@ greaterThan(QT_MAJOR_VERSION, 4): QT += webenginewidgets
CONFIG += qt warn_on thread release CONFIG += qt warn_on thread release

View File

@ -61,11 +61,48 @@ static const QKeySequence quitKeySeq("Ctrl+q");
static const QKeySequence closeKeySeq("Ctrl+w"); static const QKeySequence closeKeySeq("Ctrl+w");
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT)
#include <QWebFrame> # include <QWebFrame>
#include <QWebElement> # include <QWebElement>
#include <QWebSettings> # include <QWebSettings>
# define QWEBSETTINGS QWebSettings
#elif defined(USING_WEBENGINE)
// Notes for WebEngine
// - All links must begin with http:// for acceptNavigationRequest to be
// called.
// - The links passed to acceptNav.. have the host part
// lowercased -> we change S0 to http://localhost/S0, not http://S0
# include <QWebEnginePage>
# include <QWebEngineSettings>
# include <QtWebEngineWidgets>
# define QWEBSETTINGS QWebEngineSettings
#endif #endif
#ifdef USING_WEBENGINE
// This script saves the location details when a mouse button is
// clicked. This is for replacing data provided by Webkit QWebElement
// on a right-click as QT WebEngine does not have an equivalent service.
static const string locdetailscript(R"raw(
var locDetails = '';
function saveLoc(ev)
{
el = ev.target;
locDetails = '';
while (el && el.attributes && !el.attributes.getNamedItem("rcldocnum")) {
el = el.parentNode;
}
rcldocnum = el.attributes.getNamedItem("rcldocnum");
if (rcldocnum) {
rcldocnumvalue = rcldocnum.value;
} else {
rcldocnumvalue = "";
}
if (el && el.attributes) {
locDetails = 'rcldocnum = ' + rcldocnumvalue
}
}
)raw");
#endif // webengine
// Decide if we set font family and style with a css section in the // Decide if we set font family and style with a css section in the
// html <head> or with qwebsettings setfont... calls. We currently do // html <head> or with qwebsettings setfont... calls. We currently do
// it with websettings because this gives an instant redisplay, and // it with websettings because this gives an instant redisplay, and
@ -91,6 +128,9 @@ public:
map<string, vector<string> >& sugg); map<string, vector<string> >& sugg);
virtual string absSep() {return (const char *)(prefs.abssep.toUtf8());} virtual string absSep() {return (const char *)(prefs.abssep.toUtf8());}
virtual string iconUrl(RclConfig *, Rcl::Doc& doc); virtual string iconUrl(RclConfig *, Rcl::Doc& doc);
#ifdef USING_WEBENGINE
virtual string linkPrefix() override {return "http://localhost/";}
#endif
private: private:
ResList *m_reslist; ResList *m_reslist;
}; };
@ -124,8 +164,9 @@ bool QtGuiResListPager::append(const string& data, int docnum,
LOGDEB2("QtGuiReslistPager::appendDoc: blockCount " << LOGDEB2("QtGuiReslistPager::appendDoc: blockCount " <<
m_reslist->document()->blockCount() << ", " << data << "\n"); m_reslist->document()->blockCount() << ", " << data << "\n");
logdata(data.c_str()); logdata(data.c_str());
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT) || defined(USING_WEBENGINE)
QString sdoc = QString("<div class=\"rclresult\" rcldocnum=\"%1\">").arg(docnum); QString sdoc = QString(
"<div class=\"rclresult\" id=\"%1\" rcldocnum=\"%1\">").arg(docnum);
m_reslist->append(sdoc); m_reslist->append(sdoc);
m_reslist->append(QString::fromUtf8(data.c_str())); m_reslist->append(QString::fromUtf8(data.c_str()));
m_reslist->append("</div>"); m_reslist->append("</div>");
@ -151,7 +192,7 @@ string QtGuiResListPager::trans(const string& in)
string QtGuiResListPager::detailsLink() string QtGuiResListPager::detailsLink()
{ {
string chunk = "<a href=\"H-1\">"; string chunk = string("<a href=\"") + linkPrefix() + "H-1\">";
chunk += trans("(show query)"); chunk += trans("(show query)");
chunk += "</a>"; chunk += "</a>";
return chunk; return chunk;
@ -190,6 +231,11 @@ string QtGuiResListPager::headerContent()
#endif #endif
out += string("color: ") + qs2utf8s(prefs.fontcolor) + ";\n"; out += string("color: ") + qs2utf8s(prefs.fontcolor) + ";\n";
out += string("}\n</style>\n"); out += string("}\n</style>\n");
#if defined(USING_WEBENGINE)
out += "<script type=\"text/javascript\">\n";
out += locdetailscript;
out += "</script>\n";
#endif
out += qs2utf8s(prefs.reslistheadertext); out += qs2utf8s(prefs.reslistheadertext);
return out; return out;
} }
@ -257,23 +303,22 @@ string QtGuiResListPager::iconUrl(RclConfig *config, Rcl::Doc& doc)
class PlainToRichQtReslist : public PlainToRich { class PlainToRichQtReslist : public PlainToRich {
public: public:
virtual string startMatch(unsigned int idx) virtual string startMatch(unsigned int idx) {
{ if (0 && m_hdata) {
if (0 && m_hdata) { string s1, s2;
string s1, s2; stringsToString<vector<string> >(m_hdata->groups[idx], s1);
stringsToString<vector<string> >(m_hdata->groups[idx], s1); stringsToString<vector<string> >(
stringsToString<vector<string> >(m_hdata->ugroups[m_hdata->grpsugidx[idx]], s2); m_hdata->ugroups[m_hdata->grpsugidx[idx]], s2);
LOGDEB2("Reslist startmatch: group " << s1 << " user group " << LOGDEB2("Reslist startmatch: group " << s1 << " user group " <<
s2 << "\n"); s2 << "\n");
} }
return string("<span class='rclmatch' style='") return string("<span class='rclmatch' style='")
+ qs2utf8s(prefs.qtermstyle) + string("'>"); + qs2utf8s(prefs.qtermstyle) + string("'>");
} }
virtual string endMatch() virtual string endMatch() {
{ return string("</span>");
return string("</span>"); }
}
}; };
static PlainToRichQtReslist g_hiliter; static PlainToRichQtReslist g_hiliter;
@ -286,13 +331,19 @@ ResList::ResList(QWidget* parent, const char* name)
setObjectName("resList"); setObjectName("resList");
else else
setObjectName(name); setObjectName(name);
#if defined(USING_WEBKIT)
#if defined(USING_WEBKIT) || defined(USING_WEBENGINE)
setPage(new RclWebPage(this));
#ifdef USING_WEBKIT
LOGDEB("Reslist: using Webkit\n"); LOGDEB("Reslist: using Webkit\n");
page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
// signals and slots connections // signals and slots connections
connect(this, SIGNAL(linkClicked(const QUrl &)), connect(this, SIGNAL(linkClicked(const QUrl &)),
this, SLOT(linkWasClicked(const QUrl &))); this, SLOT(onLinkClicked(const QUrl &)));
page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); #else
settings()->setAttribute(QWebSettings::JavascriptEnabled, true); LOGDEB("Reslist: using Webengine\n");
#endif
settings()->setAttribute(QWEBSETTINGS::JavascriptEnabled, true);
#else #else
LOGDEB("Reslist: using QTextBrowser\n"); LOGDEB("Reslist: using QTextBrowser\n");
setReadOnly(true); setReadOnly(true);
@ -301,7 +352,7 @@ ResList::ResList(QWidget* parent, const char* name)
setTabChangesFocus(true); setTabChangesFocus(true);
// signals and slots connections // signals and slots connections
connect(this, SIGNAL(anchorClicked(const QUrl &)), connect(this, SIGNAL(anchorClicked(const QUrl &)),
this, SLOT(linkWasClicked(const QUrl &))); this, SLOT(onLinkClicked(const QUrl &)));
#endif #endif
setFont(); setFont();
@ -366,23 +417,39 @@ void ResList::setRclMain(RclMain *m, bool ismain)
} }
} }
void ResList::setFont() void ResList::runStoredJS()
{
runJS(m_js);
m_js.clear();
}
void ResList::runJS(const QString& js)
{ {
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT)
#ifndef SETFONT_WITH_HEADSTYLE page()->mainFrame()->evaluateJavaScript(js);
QWebSettings *websettings = settings(); #elif defined(USING_WEBENGINE)
page()->runJavaScript(js);
#else
Q_UNUSED(js);
#endif
}
void ResList::setFont()
{
#if defined(USING_WEBKIT) || defined(USING_WEBENGINE)
# ifndef SETFONT_WITH_HEADSTYLE
if (prefs.reslistfontfamily.length()) { if (prefs.reslistfontfamily.length()) {
// For some reason there is (12-2014) an offset of 3 between what // For some reason there is (12-2014) an offset of 3 between what
// we request from webkit and what we get. // we request from webkit and what we get.
websettings->setFontSize(QWebSettings::DefaultFontSize, settings()->setFontSize(QWEBSETTINGS::DefaultFontSize,
prefs.reslistfontsize + 3); prefs.reslistfontsize + 3);
websettings->setFontFamily(QWebSettings::StandardFont, settings()->setFontFamily(QWEBSETTINGS::StandardFont,
prefs.reslistfontfamily); prefs.reslistfontfamily);
} else { } else {
websettings->resetFontSize(QWebSettings::DefaultFontSize); settings()->resetFontSize(QWEBSETTINGS::DefaultFontSize);
websettings->resetFontFamily(QWebSettings::StandardFont); settings()->resetFontFamily(QWEBSETTINGS::StandardFont);
} }
#endif # endif
#else #else
if (prefs.reslistfontfamily.length()) { if (prefs.reslistfontfamily.length()) {
QFont nfont(prefs.reslistfontfamily, prefs.reslistfontsize); QFont nfont(prefs.reslistfontfamily, prefs.reslistfontsize);
@ -399,8 +466,6 @@ int ResList::newListId()
return ++id; return ++id;
} }
extern "C" int XFlush(void *);
void ResList::setDocSource(std::shared_ptr<DocSequence> nsource) void ResList::setDocSource(std::shared_ptr<DocSequence> nsource)
{ {
LOGDEB("ResList::setDocSource()\n"); LOGDEB("ResList::setDocSource()\n");
@ -441,7 +506,7 @@ void ResList::resetView()
// slow search, the user will wonder if anything happened. The // slow search, the user will wonder if anything happened. The
// following helps making sure that the textedit is really // following helps making sure that the textedit is really
// blank. Else, there are often icons or text left around // blank. Else, there are often icons or text left around
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT) || defined(USING_WEBENGINE)
m_text = ""; m_text = "";
setHtml("<html><body></body></html>"); setHtml("<html><body></body></html>");
#else #else
@ -596,12 +661,21 @@ void ResList::highlighted(const QString& )
// fair enough, else we go to next/previous result page. // fair enough, else we go to next/previous result page.
void ResList::resPageUpOrBack() void ResList::resPageUpOrBack()
{ {
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT)
if (scrollIsAtTop()) { if (scrollIsAtTop()) {
resultPageBack(); resultPageBack();
} else { } else {
QWebFrame *frame = page()->mainFrame(); page()->mainFrame()->scroll(0, -int(0.9*geometry().height()));
frame->scroll(0, -int(0.9*geometry().height())); }
setupArrows();
#elif defined(USING_WEBENGINE)
if (scrollIsAtTop()) {
resultPageBack();
} else {
QString js = "window.scrollBy(" +
QString::number(0) + ", " +
QString::number(-int(0.9*geometry().height())) + ");";
runJS(js);
} }
setupArrows(); setupArrows();
#else #else
@ -618,8 +692,17 @@ void ResList::resPageDownOrNext()
if (scrollIsAtBottom()) { if (scrollIsAtBottom()) {
resultPageNext(); resultPageNext();
} else { } else {
QWebFrame *frame = page()->mainFrame(); page()->mainFrame()->scroll(0, int(0.9*geometry().height()));
frame->scroll(0, int(0.9*geometry().height())); }
setupArrows();
#elif defined(USING_WEBENGINE)
if (scrollIsAtBottom()) {
resultPageNext();
} else {
QString js = "window.scrollBy(" +
QString::number(0) + ", " +
QString::number(int(0.9*geometry().height())) + ");";
runJS(js);
} }
setupArrows(); setupArrows();
#else #else
@ -653,6 +736,16 @@ bool ResList::scrollIsAtBottom()
} }
LOGDEB2("scrollIsAtBottom: returning " << ret << "\n"); LOGDEB2("scrollIsAtBottom: returning " << ret << "\n");
return ret; return ret;
#elif defined(USING_WEBENGINE)
QSize css = page()->contentsSize().toSize();
QSize wss = size();
QPoint sp = page()->scrollPosition().toPoint();
LOGDEB1("atBottom: contents W " << css.width() << " H " << css.height() <<
" widget W " << wss.width() << " Y " << wss.height() <<
" scroll X " << sp.x() << " Y " << sp.y() << "\n");
// This seems to work but it's mysterious as points and pixels
// should not be the same
return wss.height() + sp.y() >= css.height() - 10;
#else #else
return false; return false;
#endif #endif
@ -673,6 +766,8 @@ bool ResList::scrollIsAtTop()
} }
LOGDEB2("scrollIsAtTop: returning " << ret << "\n"); LOGDEB2("scrollIsAtTop: returning " << ret << "\n");
return ret; return ret;
#elif defined(USING_WEBENGINE)
return page()->scrollPosition().toPoint().ry() == 0;
#else #else
return false; return false;
#endif #endif
@ -715,7 +810,7 @@ void ResList::resultPageFor(int docnum)
void ResList::append(const QString &text) void ResList::append(const QString &text)
{ {
LOGDEB2("QtGuiReslistPager::appendQString : " << qs2utf8s(text) << "\n"); LOGDEB2("QtGuiReslistPager::appendQString : " << qs2utf8s(text) << "\n");
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT) || defined(USING_WEBENGINE)
m_text += text; m_text += text;
#else #else
QTextBrowser::append(text); QTextBrowser::append(text);
@ -732,6 +827,15 @@ void ResList::displayPage()
setHtml(m_text); setHtml(m_text);
#endif #endif
#if defined(USING_WEBENGINE)
// Have to delay running this. Alternative would be to set it as
// onload on the body element in the html, like upplay does, but
// this would need an ennoying reslistpager modification.
m_js = "elt=document.getElementsByTagName('body')[0];"
"elt.addEventListener('contextmenu', saveLoc);";
QTimer::singleShot(200, this, SLOT(runStoredJS()));
#endif
LOGDEB0("ResList::displayPg: hasNext " << m_pager->hasNext() << LOGDEB0("ResList::displayPg: hasNext " << m_pager->hasNext() <<
" atBot " << scrollIsAtBottom() << " hasPrev " << " atBot " << scrollIsAtBottom() << " hasPrev " <<
m_pager->hasPrev() << " at Top " << scrollIsAtTop() << " \n"); m_pager->hasPrev() << " at Top " << scrollIsAtTop() << " \n");
@ -759,6 +863,12 @@ void ResList::previewExposed(int docnum)
} else { } else {
LOGDEB2("Not Found\n"); LOGDEB2("Not Found\n");
} }
#elif defined(USING_WEBENGINE)
QString js = QString(
"elt=document.getElementById('%1');"
"if (elt){elt.removeAttribute('style');}"
).arg(m_curPvDoc - pageFirstDocNum());
runJS(js);
#else #else
pair<int,int> blockrange = parnumfromdocnum(m_curPvDoc); pair<int,int> blockrange = parnumfromdocnum(m_curPvDoc);
if (blockrange.first != -1) { if (blockrange.first != -1) {
@ -789,6 +899,12 @@ void ResList::previewExposed(int docnum)
} else { } else {
LOGDEB2("Not Found\n"); LOGDEB2("Not Found\n");
} }
#elif defined(USING_WEBENGINE)
QString js = QString(
"elt=document.getElementById('%1');"
"if(elt){elt.setAttribute('style', 'background: LightBlue');}"
).arg(docnum - pageFirstDocNum());
runJS(js);
#else #else
pair<int,int> blockrange = parnumfromdocnum(docnum); pair<int,int> blockrange = parnumfromdocnum(docnum);
@ -816,6 +932,11 @@ void ResList::mouseDoubleClickEvent(QMouseEvent *event)
RESLIST_PARENTCLASS::mouseDoubleClickEvent(event); RESLIST_PARENTCLASS::mouseDoubleClickEvent(event);
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT)
emit(wordSelect(selectedText())); emit(wordSelect(selectedText()));
#elif defined(USING_WEBENGINE)
// webengineview does not have such an event function, and
// reimplementing event() itself is not useful (tried) as it does
// not get mouse clicks. We'd need javascript to do this, but it's
// not that useful, so left aside for now.
#else #else
if (textCursor().hasSelection()) if (textCursor().hasSelection())
emit(wordSelect(textCursor().selectedText())); emit(wordSelect(textCursor().selectedText()));
@ -834,14 +955,16 @@ void ResList::showQueryDetails()
QMessageBox::information(this, tr("Query details"), desc); QMessageBox::information(this, tr("Query details"), desc);
} }
void ResList::linkWasClicked(const QUrl &url) void ResList::onLinkClicked(const QUrl &qurl)
{ {
// qt5: url.toString() does not accept FullyDecoded, but that's what we // qt5: url.toString() does not accept FullyDecoded, but that's what we
// want. e.g. Suggestions links are like Sterm|spelling which we // want. e.g. Suggestions links are like Sterm|spelling which we
// receive as Sterm%7CSpelling // receive as Sterm%7CSpelling
string strurl = url_decode(qs2utf8s(url.toString())); string strurl = url_decode(qs2utf8s(qurl.toString()));
LOGDEB("ResList::linkWasClicked: [" << strurl << "]\n"); LOGDEB1("ResList::onLinkClicked: [" << strurl << "] prefix " <<
m_pager->linkPrefix() << "\n");
strurl = strurl.substr(m_pager->linkPrefix().size());
int what = strurl[0]; int what = strurl[0];
switch (what) { switch (what) {
@ -854,7 +977,7 @@ void ResList::linkWasClicked(const QUrl &url)
int i = atoi(strurl.c_str()+1) - 1; int i = atoi(strurl.c_str()+1) - 1;
Rcl::Doc doc; Rcl::Doc doc;
if (!getDoc(i, doc)) { if (!getDoc(i, doc)) {
LOGERR("ResList::linkWasClicked: can't get doc for " << i << "\n"); LOGERR("ResList::onLinkClicked: can't get doc for " << i << "\n");
return; return;
} }
emit(showSnippets(doc)); emit(showSnippets(doc));
@ -869,7 +992,7 @@ void ResList::linkWasClicked(const QUrl &url)
int i = atoi(strurl.c_str()+1) - 1; int i = atoi(strurl.c_str()+1) - 1;
Rcl::Doc doc; Rcl::Doc doc;
if (!getDoc(i, doc)) { if (!getDoc(i, doc)) {
LOGERR("ResList::linkWasClicked: can't get doc for " << i << "\n"); LOGERR("ResList::onLinkClicked: can't get doc for " << i << "\n");
return; return;
} }
vector<Rcl::Doc> dups; vector<Rcl::Doc> dups;
@ -885,7 +1008,7 @@ void ResList::linkWasClicked(const QUrl &url)
int i = atoi(strurl.c_str()+1) - 1; int i = atoi(strurl.c_str()+1) - 1;
Rcl::Doc doc; Rcl::Doc doc;
if (!getDoc(i, doc)) { if (!getDoc(i, doc)) {
LOGERR("ResList::linkWasClicked: can't get doc for " << i << "\n"); LOGERR("ResList::onLinkClicked: can't get doc for " << i << "\n");
return; return;
} }
emit editRequested(ResultPopup::getParent(std::shared_ptr<DocSequence>(), emit editRequested(ResultPopup::getParent(std::shared_ptr<DocSequence>(),
@ -894,6 +1017,7 @@ void ResList::linkWasClicked(const QUrl &url)
break; break;
// Show query details // Show query details
case 'h':
case 'H': case 'H':
{ {
showQueryDetails(); showQueryDetails();
@ -907,7 +1031,7 @@ void ResList::linkWasClicked(const QUrl &url)
int i = atoi(strurl.c_str()+1) - 1; int i = atoi(strurl.c_str()+1) - 1;
Rcl::Doc doc; Rcl::Doc doc;
if (!getDoc(i, doc)) { if (!getDoc(i, doc)) {
LOGERR("ResList::linkWasClicked: can't get doc for " << i << "\n"); LOGERR("ResList::onLinkClicked: can't get doc for " << i << "\n");
return; return;
} }
if (what == 'P') { if (what == 'P') {
@ -934,7 +1058,7 @@ void ResList::linkWasClicked(const QUrl &url)
case 'R': case 'R':
{ {
int i = atoi(strurl.c_str() + 1) - 1; int i = atoi(strurl.c_str() + 1) - 1;
QString s = url.toString(); QString s = qurl.toString();
int bar = s.indexOf("|"); int bar = s.indexOf("|");
if (bar == -1 || bar >= s.size()-1) if (bar == -1 || bar >= s.size()-1)
break; break;
@ -968,14 +1092,36 @@ void ResList::linkWasClicked(const QUrl &url)
break; break;
default: default:
LOGERR("ResList::linkWasClicked: bad link [" << strurl << "]\n"); LOGERR("ResList::onLinkClicked: bad link [" << strurl << "]\n");
break;// ?? break;// ??
} }
} }
void ResList::onPopupJsDone(const QVariant &jr)
{
QString qs(jr.toString());
LOGDEB("onPopupJsDone: parameter: " << qs2utf8s(qs) << "\n");
QStringList qsl = qs.split("\n", QString::SkipEmptyParts);
for (int i = 0 ; i < qsl.size(); i++) {
int eq = qsl[i].indexOf("=");
if (eq > 0) {
QString nm = qsl[i].left(eq).trimmed();
QString value = qsl[i].right(qsl[i].size() - (eq+1)).trimmed();
if (!nm.compare("rcldocnum")) {
m_popDoc = atoi(qs2utf8s(value).c_str());
} else {
LOGERR("onPopupJsDone: unknown key: " << qs2utf8s(nm) << "\n");
}
}
}
doCreatePopupMenu();
}
void ResList::createPopupMenu(const QPoint& pos) void ResList::createPopupMenu(const QPoint& pos)
{ {
LOGDEB("ResList::createPopupMenu(" << pos.x() << ", " << pos.y() << ")\n"); LOGDEB("ResList::createPopupMenu(" << pos.x() << ", " << pos.y() << ")\n");
m_popDoc = -1;
m_popPos = pos;
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT)
QWebHitTestResult htr = page()->mainFrame()->hitTestContent(pos); QWebHitTestResult htr = page()->mainFrame()->hitTestContent(pos);
if (htr.isNull()) if (htr.isNull())
@ -987,13 +1133,21 @@ void ResList::createPopupMenu(const QPoint& pos)
return; return;
QString snum = el.attribute("rcldocnum"); QString snum = el.attribute("rcldocnum");
m_popDoc = pageFirstDocNum() + snum.toInt(); m_popDoc = pageFirstDocNum() + snum.toInt();
#elif defined(USING_WEBENGINE)
QString js("window.locDetails;");
RclWebPage *mypage = dynamic_cast<RclWebPage*>(page());
mypage->runJavaScript(js, [this](const QVariant &v) {onPopupJsDone(v);});
#else #else
QTextCursor cursor = cursorForPosition(pos); QTextCursor cursor = cursorForPosition(pos);
int blocknum = cursor.blockNumber(); int blocknum = cursor.blockNumber();
LOGDEB("ResList::createPopupMenu(): block " << blocknum << "\n"); LOGDEB("ResList::createPopupMenu(): block " << blocknum << "\n");
m_popDoc = docnumfromparnum(blocknum); m_popDoc = docnumfromparnum(blocknum);
#endif #endif
doCreatePopupMenu();
}
void ResList::doCreatePopupMenu()
{
if (m_popDoc < 0) if (m_popDoc < 0)
return; return;
Rcl::Doc doc; Rcl::Doc doc;
@ -1004,7 +1158,7 @@ void ResList::createPopupMenu(const QPoint& pos)
if (m_ismainres) if (m_ismainres)
options |= ResultPopup::isMain; options |= ResultPopup::isMain;
QMenu *popup = ResultPopup::create(this, options, m_source, doc); QMenu *popup = ResultPopup::create(this, options, m_source, doc);
popup->popup(mapToGlobal(pos)); popup->popup(mapToGlobal(m_popPos));
} }
void ResList::menuPreview() void ResList::menuPreview()

View File

@ -20,6 +20,7 @@
#include "autoconfig.h" #include "autoconfig.h"
#include <map> #include <map>
#include <QPoint>
#if defined(USING_WEBENGINE) #if defined(USING_WEBENGINE)
# include <QWebEngineView> # include <QWebEngineView>
@ -34,6 +35,7 @@
class RclMain; class RclMain;
class QtGuiResListPager; class QtGuiResListPager;
class QEvent;
namespace Rcl { namespace Rcl {
class Doc; class Doc;
} }
@ -110,18 +112,22 @@ protected:
void mouseReleaseEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e);
void mouseDoubleClickEvent(QMouseEvent*); void mouseDoubleClickEvent(QMouseEvent*);
public slots:
virtual void onLinkClicked(const QUrl &);
virtual void onPopupJsDone(const QVariant&);
void runJS(const QString& js);
void runStoredJS();
protected slots: protected slots:
virtual void languageChange(); virtual void languageChange();
virtual void linkWasClicked(const QUrl &);
private: private:
QtGuiResListPager *m_pager{0}; QtGuiResListPager *m_pager{0};
std::shared_ptr<DocSequence> m_source; std::shared_ptr<DocSequence> m_source;
int m_popDoc{-1}; // Docnum for the popup menu. int m_popDoc{-1}; // Docnum for the popup menu.
QPoint m_popPos;
int m_curPvDoc{-1};// Docnum for current preview int m_curPvDoc{-1};// Docnum for current preview
int m_lstClckMod{0}; // Last click modifier. int m_lstClckMod{0}; // Last click modifier.
int m_listId{0}; // query Id for matching with preview windows int m_listId{0}; // query Id for matching with preview windows
#if defined(USING_WEBKIT) || defined(USING_WEBENGINE) #if defined(USING_WEBKIT) || defined(USING_WEBENGINE)
// Webview makes it more difficult to append text incrementally, // Webview makes it more difficult to append text incrementally,
// so we store the page and display it when done. // so we store the page and display it when done.
@ -133,10 +139,12 @@ private:
virtual int docnumfromparnum(int); virtual int docnumfromparnum(int);
virtual std::pair<int,int> parnumfromdocnum(int); virtual std::pair<int,int> parnumfromdocnum(int);
#endif #endif
QString m_js;
RclMain *m_rclmain{0}; RclMain *m_rclmain{0};
bool m_ismainres{true}; bool m_ismainres{true};
virtual void displayPage(); // Display current page void doCreatePopupMenu();
virtual void displayPage();
static int newListId(); static int newListId();
void resetView(); void resetView();
bool scrollIsAtTop(); bool scrollIsAtTop();
@ -144,5 +152,33 @@ private:
void setupArrows(); void setupArrows();
}; };
#ifdef USING_WEBENGINE
// Subclass the page to hijack the link clicks
class RclWebPage: public QWebEnginePage {
Q_OBJECT
public:
RclWebPage(ResList *parent)
: QWebEnginePage((QWidget *)parent), m_reslist(parent) {}
protected:
virtual bool acceptNavigationRequest(const QUrl& url,
NavigationType,
bool) {
m_reslist->onLinkClicked(url);
return false;
}
private:
ResList *m_reslist;
};
#else // Using Qt Webkit
#define RclWebPage QWebPage
#endif
#endif /* _RESLIST_H_INCLUDED_ */ #endif /* _RESLIST_H_INCLUDED_ */

View File

@ -21,15 +21,28 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <sstream> #include <sstream>
using namespace std;
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT)
#include <QWebSettings> # include <QWebSettings>
#include <QWebFrame> # include <QWebFrame>
#include <QUrl> # include <QUrl>
# define QWEBSETTINGS QWebSettings
# define QWEBPAGE QWebPage
#elif defined(USING_WEBENGINE)
// Notes for WebEngine
// - All links must begin with http:// for acceptNavigationRequest to be
// called.
// - The links passed to acceptNav.. have the host part
// lowercased -> we change S0 to http://h/S0, not http://S0
# include <QWebEnginePage>
# include <QWebEngineSettings>
# include <QtWebEngineWidgets>
# define QWEBSETTINGS QWebEngineSettings
# define QWEBPAGE QWebEnginePage
#else #else
#include <QTextBrowser> #include <QTextBrowser>
#endif #endif
#include <QShortcut> #include <QShortcut>
#include "log.h" #include "log.h"
@ -40,10 +53,12 @@ using namespace std;
#include "rclhelp.h" #include "rclhelp.h"
#include "plaintorich.h" #include "plaintorich.h"
// Note: the internal search currently does not work with QTextBrowser. To be using namespace std;
// fixed by looking at the preview code if someone asks for it...
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT)
#define browser ((QWebView*)browserw) #define browser ((QWebView*)browserw)
#elif defined(USING_WEBENGINE)
#define browser ((QWebEngineView*)browserw)
#else #else
#define browser ((QTextBrowser*)browserw) #define browser ((QTextBrowser*)browserw)
#endif #endif
@ -97,22 +112,32 @@ void SnippetsW::init()
verticalLayout->insertWidget(0, browserw); verticalLayout->insertWidget(0, browserw);
browser->setUrl(QUrl(QString::fromUtf8("about:blank"))); browser->setUrl(QUrl(QString::fromUtf8("about:blank")));
connect(browser, SIGNAL(linkClicked(const QUrl &)), connect(browser, SIGNAL(linkClicked(const QUrl &)),
this, SLOT(linkWasClicked(const QUrl &))); this, SLOT(onLinkClicked(const QUrl &)));
browser->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); browser->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
browser->page()->currentFrame()->setScrollBarPolicy(Qt::Horizontal, browser->page()->currentFrame()->setScrollBarPolicy(Qt::Horizontal,
Qt::ScrollBarAlwaysOff); Qt::ScrollBarAlwaysOff);
QWebSettings *ws = browser->page()->settings(); QWEBSETTINGS *ws = browser->page()->settings();
if (prefs.reslistfontfamily != "") { if (prefs.reslistfontfamily != "") {
ws->setFontFamily(QWebSettings::StandardFont, prefs.reslistfontfamily); ws->setFontFamily(QWEBSETTINGS::StandardFont, prefs.reslistfontfamily);
ws->setFontSize(QWebSettings::DefaultFontSize, prefs.reslistfontsize); ws->setFontSize(QWEBSETTINGS::DefaultFontSize, prefs.reslistfontsize);
} }
if (!prefs.snipCssFile.isEmpty()) if (!prefs.snipCssFile.isEmpty())
ws->setUserStyleSheetUrl(QUrl::fromLocalFile(prefs.snipCssFile)); ws->setUserStyleSheetUrl(QUrl::fromLocalFile(prefs.snipCssFile));
#elif defined(USING_WEBENGINE)
browserw = new QWebEngineView(this);
verticalLayout->insertWidget(0, browserw);
browser->setPage(new SnipWebPage(this));
QWEBSETTINGS *ws = browser->page()->settings();
if (prefs.reslistfontfamily != "") {
ws->setFontFamily(QWEBSETTINGS::StandardFont, prefs.reslistfontfamily);
ws->setFontSize(QWEBSETTINGS::DefaultFontSize, prefs.reslistfontsize);
}
// Stylesheet TBD
#else #else
browserw = new QTextBrowser(this); browserw = new QTextBrowser(this);
verticalLayout->insertWidget(0, browserw); verticalLayout->insertWidget(0, browserw);
connect(browser, SIGNAL(anchorClicked(const QUrl &)), connect(browser, SIGNAL(anchorClicked(const QUrl &)),
this, SLOT(linkWasClicked(const QUrl &))); this, SLOT(onLinkClicked(const QUrl &)));
browser->setReadOnly(true); browser->setReadOnly(true);
browser->setUndoRedoEnabled(false); browser->setUndoRedoEnabled(false);
browser->setOpenLinks(false); browser->setOpenLinks(false);
@ -165,23 +190,23 @@ void SnippetsW::init()
g_hiliter.set_inputhtml(false); g_hiliter.set_inputhtml(false);
bool nomatch = true; bool nomatch = true;
for (vector<Rcl::Snippet>::const_iterator it = vpabs.begin(); for (const auto& snippet : vpabs) {
it != vpabs.end(); it++) { if (snippet.page == -1) {
if (it->page == -1) {
oss << "<tr><td colspan=\"2\">" << oss << "<tr><td colspan=\"2\">" <<
it->snippet << "</td></tr>" << endl; snippet.snippet << "</td></tr>" << endl;
continue; continue;
} }
list<string> lr; list<string> lr;
if (!g_hiliter.plaintorich(it->snippet, lr, hdata)) { if (!g_hiliter.plaintorich(snippet.snippet, lr, hdata)) {
LOGDEB1("No match for [" << (it->snippet) << "]\n" ); LOGDEB1("No match for [" << snippet.snippet << "]\n");
continue; continue;
} }
nomatch = false; nomatch = false;
oss << "<tr><td>"; oss << "<tr><td>";
if (it->page > 0) { if (snippet.page > 0) {
oss << "<a href=\"P" << it->page << "T" << it->term << "\">" oss << "<a href=\"http://h/P" << snippet.page << "T" <<
<< "P.&nbsp;" << it->page << "</a>"; snippet.term << "\">"
<< "P.&nbsp;" << snippet.page << "</a>";
} }
oss << "</td><td>" << lr.front().c_str() << "</td></tr>" << endl; oss << "</td><td>" << lr.front().c_str() << "</td></tr>" << endl;
} }
@ -193,10 +218,12 @@ void SnippetsW::init()
"generator got lost in a maze...</p>")); "generator got lost in a maze...</p>"));
} }
oss << "\n</body></html>"; oss << "\n</body></html>";
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT) || defined(USING_WEBENGINE)
browser->setHtml(QString::fromUtf8(oss.str().c_str())); browser->setHtml(QString::fromUtf8(oss.str().c_str()));
#else #else
browser->insertHtml(QString::fromUtf8(oss.str().c_str())); browser->insertHtml(QString::fromUtf8(oss.str().c_str()));
browser->moveCursor (QTextCursor::Start);
browser->ensureCursorVisible();
#endif #endif
} }
@ -212,20 +239,21 @@ void SnippetsW::slotEditFindNext()
if (!searchFM->isVisible()) if (!searchFM->isVisible())
slotEditFind(); slotEditFind();
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT) || defined(USING_WEBENGINE)
browser->findText(searchLE->text()); browser->findText(searchLE->text());
#else #else
browser->find(searchLE->text(), 0); browser->find(searchLE->text());
#endif #endif
} }
void SnippetsW::slotEditFindPrevious() void SnippetsW::slotEditFindPrevious()
{ {
if (!searchFM->isVisible()) if (!searchFM->isVisible())
slotEditFind(); slotEditFind();
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT) || defined(USING_WEBENGINE)
browser->findText(searchLE->text(), QWebPage::FindBackward); browser->findText(searchLE->text(), QWEBPAGE::FindBackward);
#else #else
browser->find(searchLE->text(), QTextDocument::FindBackward); browser->find(searchLE->text(), QTextDocument::FindBackward);
#endif #endif
@ -233,17 +261,22 @@ void SnippetsW::slotEditFindPrevious()
void SnippetsW::slotSearchTextChanged(const QString& txt) void SnippetsW::slotSearchTextChanged(const QString& txt)
{ {
#if defined(USING_WEBKIT) #if defined(USING_WEBKIT) || defined(USING_WEBENGINE)
browser->findText(txt); browser->findText(txt);
#else #else
// Cursor thing is so that we don't go to the next occurrence with
// each character, but rather try to extend the current match
QTextCursor cursor = browser->textCursor();
cursor.setPosition(cursor.anchor(), QTextCursor::KeepAnchor);
browser->setTextCursor(cursor);
browser->find(txt, 0); browser->find(txt, 0);
#endif #endif
} }
void SnippetsW::linkWasClicked(const QUrl &url) void SnippetsW::onLinkClicked(const QUrl &url)
{ {
string ascurl = (const char *)url.toString().toUtf8(); string ascurl = qs2u8s(url.toString()).substr(9);
LOGDEB("Snippets::linkWasClicked: [" << (ascurl) << "]\n" ); LOGDEB("Snippets::onLinkClicked: [" << ascurl << "]\n");
if (ascurl.size() > 3) { if (ascurl.size() > 3) {
int what = ascurl[0]; int what = ascurl[0];
@ -264,7 +297,5 @@ void SnippetsW::linkWasClicked(const QUrl &url)
} }
} }
} }
LOGERR("Snippets::linkWasClicked: bad link [" << (ascurl) << "]\n" ); LOGERR("Snippets::onLinkClicked: bad link [" << ascurl << "]\n");
} }

View File

@ -33,15 +33,17 @@ class SnippetsW : public QWidget, public Ui::Snippets
{ {
Q_OBJECT Q_OBJECT
public: public:
SnippetsW(Rcl::Doc doc, std::shared_ptr<DocSequence> source, QWidget* parent = 0) SnippetsW(Rcl::Doc doc, std::shared_ptr<DocSequence> source,
: QWidget(parent), m_doc(doc), m_source(source) QWidget* parent = 0)
{ : QWidget(parent), m_doc(doc), m_source(source) {
setupUi((QDialog*)this); setupUi((QDialog*)this);
init(); init();
} }
public slots:
virtual void onLinkClicked(const QUrl &);
protected slots: protected slots:
virtual void linkWasClicked(const QUrl &);
virtual void slotEditFind(); virtual void slotEditFind();
virtual void slotEditFindNext(); virtual void slotEditFindNext();
virtual void slotEditFindPrevious(); virtual void slotEditFindPrevious();
@ -55,4 +57,25 @@ private:
std::shared_ptr<DocSequence> m_source; std::shared_ptr<DocSequence> m_source;
}; };
#ifdef USING_WEBENGINE
#include <QWebEnginePage>
// Subclass the page to hijack the link clicks
class SnipWebPage: public QWebEnginePage {
Q_OBJECT
public:
SnipWebPage(SnippetsW *parent)
: QWebEnginePage((QWidget *)parent), m_parent(parent) {}
protected:
virtual bool acceptNavigationRequest(const QUrl& url,
NavigationType,
bool) {
m_parent->onLinkClicked(url);
return false;
}
private:
SnippetsW *m_parent;
};
#endif
#endif /* _SNIPPETS_W_H_INCLUDED_ */ #endif /* _SNIPPETS_W_H_INCLUDED_ */

View File

@ -25,6 +25,7 @@
#include <stdint.h> #include <stdint.h>
#include <sstream> #include <sstream>
#include <iostream>
#include <list> #include <list>
using std::ostringstream; using std::ostringstream;
using std::endl; using std::endl;
@ -69,12 +70,13 @@ 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();
LOGDEB("ResListPager::resultPageNext: rescnt " << (resCnt) << ", winfirst " << (m_winfirst) << "\n" ); LOGDEB("ResListPager::resultPageNext: rescnt " << resCnt <<
", winfirst " << m_winfirst << "\n");
if (m_winfirst < 0) { if (m_winfirst < 0) {
m_winfirst = 0; m_winfirst = 0;
@ -126,12 +128,13 @@ static string maybeEscapeHtml(const string& fld)
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();
LOGDEB("ResListPager::resultPageFor(" << (docnum) << "): rescnt " << (resCnt) << ", winfirst " << (m_winfirst) << "\n" ); LOGDEB("ResListPager::resultPageFor(" << docnum << "): rescnt " <<
resCnt << ", winfirst " << m_winfirst << "\n");
m_winfirst = (docnum / m_pagesize) * m_pagesize; m_winfirst = (docnum / m_pagesize) * m_pagesize;
// Get the next page of results. // Get the next page of results.
@ -250,7 +253,7 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
// Links; // Links;
ostringstream linksbuf; ostringstream linksbuf;
if (canIntern(doc.mimetype, config)) { if (canIntern(doc.mimetype, config)) {
linksbuf << "<a href=\"P" << docnumforlinks << "\">" linksbuf << "<a href=\""<< linkPrefix()<< "P" << docnumforlinks << "\">"
<< trans("Preview") << "</a>&nbsp;&nbsp;"; << trans("Preview") << "</a>&nbsp;&nbsp;";
} }
@ -258,12 +261,12 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
doc.getmeta(Rcl::Doc::keyapptg, &apptag); doc.getmeta(Rcl::Doc::keyapptg, &apptag);
if (!config->getMimeViewerDef(doc.mimetype, apptag, false).empty()) { if (!config->getMimeViewerDef(doc.mimetype, apptag, false).empty()) {
linksbuf << "<a href=\"E" << docnumforlinks << "\">" linksbuf << "<a href=\"" <<linkPrefix() + "E" <<docnumforlinks << "\">"
<< trans("Open") << "</a>"; << trans("Open") << "</a>";
} }
ostringstream snipsbuf; ostringstream snipsbuf;
if (doc.haspages) { if (doc.haspages) {
snipsbuf << "<a href=\"A" << docnumforlinks << "\">" snipsbuf << "<a href=\"" <<linkPrefix()<<"A" << docnumforlinks << "\">"
<< trans("Snippets") << "</a>&nbsp;&nbsp;"; << trans("Snippets") << "</a>&nbsp;&nbsp;";
linksbuf << "&nbsp;&nbsp;" << snipsbuf.str(); linksbuf << "&nbsp;&nbsp;" << snipsbuf.str();
} }
@ -272,8 +275,8 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
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=\"D" << docnumforlinks << "\">" collpsbuf << "<a href=\""<<linkPrefix()<<"D" << docnumforlinks << "\">"
<< trans("Dups") << "(" << clc << ")" << "</a>&nbsp;&nbsp;"; << trans("Dups") << "(" << clc << ")" << "</a>&nbsp;&nbsp;";
linksbuf << "&nbsp;&nbsp;" << collpsbuf.str(); linksbuf << "&nbsp;&nbsp;" << collpsbuf.str();
} }
@ -326,7 +329,7 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
// 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: [" << ((const char *)chunk.rdbuf()->str()) << "]\n" ); LOGDEB2("Chunk: [" << chunk.rdbuf()->str() << "]\n");
append(chunk.rdbuf()->str(), i, doc); append(chunk.rdbuf()->str(), i, doc);
} }
@ -342,13 +345,13 @@ bool ResListPager::getDoc(int num, Rcl::Doc& doc)
void ResListPager::displayPage(RclConfig *config) void ResListPager::displayPage(RclConfig *config)
{ {
LOGDEB("ResListPager::displayPage\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;
} }
@ -363,14 +366,14 @@ 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>&nbsp;&nbsp;&nbsp;"; << "</b></span>&nbsp;&nbsp;&nbsp;";
if (pageEmpty()) { if (pageEmpty()) {
chunk << trans("<p><b>No results found</b><br>"); chunk << trans("<p><b>No results found</b><br>");
@ -389,11 +392,11 @@ void ResListPager::displayPage(RclConfig *config)
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>";
} }
@ -412,27 +415,27 @@ void ResListPager::displayPage(RclConfig *config)
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 << "&nbsp;&nbsp;"; chunk << "&nbsp;&nbsp;";
if (hasPrev()) { if (hasPrev()) {
chunk << "<a href=\"" + prevUrl() + "\"><b>" chunk << "<a href=\"" << linkPrefix() + prevUrl() + "\"><b>"
<< trans("Previous") << trans("Previous")
<< "</b></a>&nbsp;&nbsp;&nbsp;"; << "</b></a>&nbsp;&nbsp;&nbsp;";
} }
if (hasNext()) { if (hasNext()) {
chunk << "<a href=\""+ nextUrl() + "\"><b>" chunk << "<a href=\"" << linkPrefix() + nextUrl() + "\"><b>"
<< trans("Next") << trans("Next")
<< "</b></a>"; << "</b></a>";
} }
} }
chunk << "</p>" << endl; chunk << "</p>" << endl;
@ -457,14 +460,14 @@ void ResListPager::displayPage(RclConfig *config)
chunk << "<p align=\"center\">"; chunk << "<p align=\"center\">";
if (hasPrev() || hasNext()) { if (hasPrev() || hasNext()) {
if (hasPrev()) { if (hasPrev()) {
chunk << "<a href=\"" + prevUrl() + "\"><b>" chunk << "<a href=\"" + linkPrefix() + prevUrl() + "\"><b>"
<< trans("Previous") << trans("Previous")
<< "</b></a>&nbsp;&nbsp;&nbsp;"; << "</b></a>&nbsp;&nbsp;&nbsp;";
} }
if (hasNext()) { if (hasNext()) {
chunk << "<a href=\""+ nextUrl() + "\"><b>" chunk << "<a href=\"" << linkPrefix() + nextUrl() + "\"><b>"
<< trans("Next") << trans("Next")
<< "</b></a>"; << "</b></a>";
} }
} }
chunk << "</p>" << endl; chunk << "</p>" << endl;
@ -505,7 +508,7 @@ string ResListPager::trans(const string& in)
string ResListPager::detailsLink() string ResListPager::detailsLink()
{ {
string chunk = "<a href=\"H-1\">"; string chunk = string("<a href=\"") + linkPrefix() + "H-1\">";
chunk += trans("(show query)") + "</a>"; chunk += trans("(show query)") + "</a>";
return chunk; return chunk;
} }

View File

@ -121,6 +121,7 @@ public:
sugg.clear(); sugg.clear();
} }
virtual string absSep() {return "&hellip;";} virtual string absSep() {return "&hellip;";}
virtual string linkPrefix() {return "";}
private: private:
int m_pagesize; int m_pagesize;
int m_newpagesize; int m_newpagesize;