GUI reslist: fixed webengine image display issue, but failed with reliably getting scroll position for paging (cf QTBUG-105842)

This commit is contained in:
Jean-Francois Dockes 2022-08-20 12:29:06 +02:00
parent 426fee8a86
commit 8bd38a858d
2 changed files with 110 additions and 56 deletions

View File

@ -149,7 +149,7 @@ public:
// Now also set for webkit because, as we set baseURL to file://,
// the relative links we set in the list will also be prefixed (by
// the HTML engine)
virtual string linkPrefix() override {return "file:///";}
virtual string linkPrefix() override {return "file:///recoll-links/";}
virtual string bodyAttrs() override {
return "onload=\"addEventListener('contextmenu', saveLoc)\"";
}
@ -305,17 +305,21 @@ ResList::ResList(QWidget* parent, const char* name)
#if defined(USING_WEBKIT) || defined(USING_WEBENGINE)
setPage(new RclWebPage(this));
settings()->setAttribute(QWEBSETTINGS::JavascriptEnabled, true);
#ifdef USING_WEBKIT
LOGDEB("Reslist: using Webkit\n");
page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
// signals and slots connections
connect(this, SIGNAL(linkClicked(const QUrl &)),
this, SLOT(onLinkClicked(const QUrl &)));
connect(this, SIGNAL(linkClicked(const QUrl &)), this, SLOT(onLinkClicked(const QUrl &)));
#else
LOGDEB("Reslist: using Webengine\n");
connect(page(), SIGNAL(loadFinished(bool)), this, SLOT(runStoredJS(bool)));
// These appear to get randomly disconnected or never connected.
connect(page(), SIGNAL(scrollPositionChanged(const QPointF &)),
this, SLOT(onPageScrollPositionChanged(const QPointF &)));
connect(page(), SIGNAL(contentsSizeChanged(const QSizeF &)),
this, SLOT(onPageContentsSizeChanged(const QSizeF &)));
#endif
settings()->setAttribute(QWEBSETTINGS::JavascriptEnabled, true);
#else
LOGDEB("Reslist: using QTextBrowser\n");
setReadOnly(true);
@ -323,8 +327,7 @@ ResList::ResList(QWidget* parent, const char* name)
setOpenLinks(false);
setTabChangesFocus(true);
// signals and slots connections
connect(this, SIGNAL(anchorClicked(const QUrl &)),
this, SLOT(onLinkClicked(const QUrl &)));
connect(this, SIGNAL(anchorClicked(const QUrl &)), this, SLOT(onLinkClicked(const QUrl &)));
#endif
setFont();
@ -388,6 +391,20 @@ void ResList::setRclMain(RclMain *m, bool ismain)
}
}
#if defined(USING_WEBKIT) || defined(USING_WEBENGINE)
void ResList::runJS(const QString& js)
{
LOGDEB("runJS: " << qs2utf8s(js) << "\n");
#if defined(USING_WEBKIT)
page()->mainFrame()->evaluateJavaScript(js);
#elif defined(USING_WEBENGINE)
page()->runJavaScript(js);
// page()->runJavaScript(js, [](const QVariant &v) {qDebug() << v.toString();});
#endif
}
#if defined(USING_WEBENGINE)
void ResList::runStoredJS(bool res)
{
if (m_js.isEmpty()) {
@ -403,17 +420,39 @@ void ResList::runStoredJS(bool res)
m_js.clear();
}
void ResList::runJS(const QString& js)
void ResList::onPageScrollPositionChanged(const QPointF &position)
{
#if defined(USING_WEBKIT)
page()->mainFrame()->evaluateJavaScript(js);
#elif defined(USING_WEBENGINE)
page()->runJavaScript(js);
#else
Q_UNUSED(js);
#endif
LOGDEB0("ResList::onPageScrollPositionChanged: y : " << position.y() << "\n");
m_scrollpos = position;
}
void ResList::onPageContentsSizeChanged(const QSizeF &size)
{
LOGDEB0("ResList::onPageContentsSizeChanged: y : " << size.height() << "\n");
m_contentsize = size;
}
#endif // WEBENGINE
static void maybeDump(const QString& text)
{
std::string dumpfile;
if (!theconfig->getConfParam("reslisthtmldumpfile", dumpfile) || dumpfile.empty()) {
return;
}
dumpfile = path_tildexpand(dumpfile);
if (path_exists(dumpfile)) {
return;
}
auto fp = fopen(dumpfile.c_str(), "w");
if (fp) {
auto s = qs2utf8s(text);
fwrite(s.c_str(), 1, s.size(), fp);
fclose(fp);
}
}
#endif // WEBKIT or WEBENGINE
void ResList::onUiPrefsChanged()
{
setFont();
@ -454,7 +493,7 @@ void ResList::setDocSource(std::shared_ptr<DocSequence> nsource)
void ResList::readDocSource()
{
LOGDEB("ResList::readDocSource()\n");
resetView();
m_curPvDoc = -1;
if (!m_source)
return;
m_listId = newListId();
@ -648,9 +687,9 @@ void ResList::resPageUpOrBack()
setupArrows();
#elif defined(USING_WEBENGINE)
if (scrollIsAtTop()) {
// Displaypage first calls resetview() which causes a page load event. We want to run the js
// on the second event.
m_js_countdown = 1;
// Displaypage used to call resetview() which caused a page load event. We wanted to run the
// js on the second event, with countdown = 1. Not needed any more, but kept around.
m_js_countdown = 0;
m_js = "window.scrollBy(0,50000);";
resultPageBack();
} else {
@ -677,8 +716,10 @@ void ResList::resPageDownOrNext()
setupArrows();
#elif defined(USING_WEBENGINE)
if (scrollIsAtBottom()) {
LOGDEB0("downOrNext: at bottom: call resultPageNext\n");
resultPageNext();
} else {
LOGDEB0("downOrNext: scroll\n");
QString js = QString("window.scrollBy(%1, %2);").arg(0).arg(int(0.9*geometry().height()));
runJS(js);
}
@ -693,12 +734,6 @@ void ResList::resPageDownOrNext()
#endif
}
void ResList::setupArrows()
{
emit prevPageAvailable(m_pager->hasPrev() || !scrollIsAtTop());
emit nextPageAvailable(m_pager->hasNext() || !scrollIsAtBottom());
}
bool ResList::scrollIsAtBottom()
{
#if defined(USING_WEBKIT)
@ -715,10 +750,20 @@ bool ResList::scrollIsAtBottom()
LOGDEB2("scrollIsAtBottom: returning " << ret << "\n");
return ret;
#elif defined(USING_WEBENGINE)
QSize css = page()->contentsSize().toSize();
// TLDR: Could not find any way whatsoever to reliably get the page contents size or position
// with either signals or direct calls. No obvious way to get this from javascript either. This
// used to work, with direct calls and broke down around qt 5.15
QSize wss = size();
QPoint sp = page()->scrollPosition().toPoint();
LOGDEB1("atBottom: contents W " << css.width() << " H " << css.height() <<
//QSize css = page()->contentsSize().toSize();
QSize css = m_contentsize.toSize();
// Does not work with recent (2022) qt releases: always 0
//auto spf = page()->scrollPosition();
// Found no easy way to block waiting for the js output
//runJS("document.body.scrollTop", [](const QVariant &v) {qDebug() << v.toInt();});
QPoint sp = m_scrollpos.toPoint();
LOGDEB0("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
@ -729,6 +774,7 @@ bool ResList::scrollIsAtBottom()
#endif
}
bool ResList::scrollIsAtTop()
{
#if defined(USING_WEBKIT)
@ -745,12 +791,21 @@ bool ResList::scrollIsAtTop()
LOGDEB2("scrollIsAtTop: returning " << ret << "\n");
return ret;
#elif defined(USING_WEBENGINE)
return page()->scrollPosition().toPoint().ry() == 0;
//return page()->scrollPosition().toPoint().ry() == 0;
return m_scrollpos.y() == 0;
#else
return false;
#endif
}
void ResList::setupArrows()
{
emit prevPageAvailable(m_pager->hasPrev() || !scrollIsAtTop());
emit nextPageAvailable(m_pager->hasNext() || !scrollIsAtBottom());
}
// Show previous page of results. We just set the current number back
// 2 pages and show next page.
void ResList::resultPageBack()
@ -807,35 +862,18 @@ void ResList::append(const QString &text)
#endif
}
static void maybeDump(const QString& text)
{
std::string dumpfile;
if (!theconfig->getConfParam("reslisthtmldumpfile", dumpfile) || dumpfile.empty()) {
return;
}
dumpfile = path_tildexpand(dumpfile);
if (path_exists(dumpfile)) {
return;
}
auto fp = fopen(dumpfile.c_str(), "w");
if (fp) {
auto s = qs2utf8s(text);
fwrite(s.c_str(), 1, s.size(), fp);
fclose(fp);
}
}
void ResList::displayPage()
{
resetView();
#if defined(USING_WEBENGINE) || defined(USING_WEBKIT)
const static QUrl baseUrl("file:///");
QProgressDialog progress("Generating text snippets...", "", 0, prefs.respagesize, this);
m_residx = 0;
progress.setWindowModality(Qt::WindowModal);
progress.setCancelButton(nullptr);
progress.setMinimumDuration(2000);
m_progress = &progress;
m_text = "";
#endif
m_pager->displayPage(theconfig);
@ -847,9 +885,11 @@ void ResList::displayPage()
m_progress->close();
m_progress = nullptr;
}
const static QUrl baseUrl("file:///");
if (m_lasttext == m_text)
return;
maybeDump(m_text);
setHtml(m_text, baseUrl);
m_lasttext = m_text;
#endif
LOGDEB0("ResList::displayPg: hasNext " << m_pager->hasNext() <<
@ -867,7 +907,7 @@ void ResList::previewExposed(int docnum)
LOGDEB("ResList::previewExposed: doc " << docnum << "\n");
// Possibly erase old one to white
if (m_curPvDoc != -1) {
if (m_curPvDoc > -1) {
#if defined(USING_WEBKIT)
QString sel =
QString("div[rcldocnum=\"%1\"]").arg(m_curPvDoc - pageFirstDocNum());
@ -901,12 +941,14 @@ void ResList::previewExposed(int docnum)
m_curPvDoc = -1;
}
// Set background for active preview's doc entry
m_curPvDoc = docnum;
if ((m_curPvDoc = docnum) < 0) {
return;
}
// Set background for active preview's doc entry
#if defined(USING_WEBKIT)
QString sel =
QString("div[rcldocnum=\"%1\"]").arg(docnum - pageFirstDocNum());
QString sel = QString("div[rcldocnum=\"%1\"]").arg(docnum - pageFirstDocNum());
LOGDEB2("Searching for element, selector: [" << qs2utf8s(sel) << "]\n");
QWebElement elt = page()->mainFrame()->findFirstElement(sel);
if (!elt.isNull()) {

View File

@ -124,11 +124,15 @@ protected:
public slots:
virtual void onLinkClicked(const QUrl &);
virtual void onPopupJsDone(const QVariant&);
void runJS(const QString& js);
protected slots:
virtual void languageChange();
void runStoredJS(bool);
void setupArrows();
#if defined(USING_WEBENGINE)
void runStoredJS(bool);
void onPageScrollPositionChanged(const QPointF &position);
void onPageContentsSizeChanged(const QSizeF &size);
#endif // USING_WEBENGINE
private:
QtGuiResListPager *m_pager{0};
@ -144,6 +148,14 @@ private:
QString m_text;
QProgressDialog *m_progress{nullptr};
int m_residx{0}; // result index in page
void runJS(const QString& js);
#if defined(USING_WEBENGINE)
// Webengine local image display appears to break randomly (for some versions and platforms,
// circa 2022) when we display the same data multiple times. Detect and avoid.
QString m_lasttext;
QPointF m_scrollpos{0,0};
QSizeF m_contentsize{0,0};
#endif // WEBENGINE
#else
// Translate from textedit paragraph number to relative
// docnum. Built while we insert text into the qtextedit