From f015ff555f9db5c535fafab40329122a35ac16af Mon Sep 17 00:00:00 2001 From: Xiao YiFang Date: Wed, 1 Jun 2022 23:11:41 +0800 Subject: [PATCH] feature: save bookmark to favorite panel reuse fulltext match to implement this bookmark feature --- articleview.cc | 81 +++++++++++++++++++++++++++++++++----------------- articleview.hh | 11 ++++++- mainwindow.cc | 28 +++++++++++++++-- mainwindow.hh | 2 ++ 4 files changed, 92 insertions(+), 30 deletions(-) diff --git a/articleview.cc b/articleview.cc index 4f997a8d..2df8b49e 100644 --- a/articleview.cc +++ b/articleview.cc @@ -402,6 +402,9 @@ void ArticleView::showDefinition( Config::InputPhrase const & phrase, unsigned g if ( scrollTo.size() ) Utils::Url::addQueryItem( req, "scrollto", scrollTo ); + if(delayedHighlightText.size()) + Utils::Url::addQueryItem( req, "regexp", delayedHighlightText ); + Contexts::Iterator pos = contexts.find( "gdanchor" ); if( pos != contexts.end() ) { @@ -579,6 +582,12 @@ void ArticleView::loadFinished( bool result ) } if( Utils::Url::hasQueryItem( ui.definition->url(), "regexp" ) ) highlightFTSResults(); + + if( !delayedHighlightText.isEmpty() ) + { + // findText( delayedHighlightText, QWebEnginePage::FindCaseSensitively ,[](bool){}); + delayedHighlightText.clear(); + } } void ArticleView::loadProgress(int ){ @@ -1592,6 +1601,11 @@ void ArticleView::setSelectionBySingleClick( bool set ) ui.definition->setSelectionBySingleClick( set ); } +void ArticleView::setDelayedHighlightText(QString const & text) +{ + delayedHighlightText = text; +} + void ArticleView::back() { // Don't allow navigating back to page 0, which is usually the initial @@ -1712,6 +1726,7 @@ void ArticleView::contextMenuRequested( QPoint const & pos ) QAction * sendWordToInputLineAction = 0; QAction * saveImageAction = 0; QAction * saveSoundAction = 0; + QAction * saveBookmark = 0; #if( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) ) const QWebEngineContextMenuData * menuData = &(r->contextMenuData()); @@ -1832,6 +1847,12 @@ void ArticleView::contextMenuRequested( QPoint const & pos ) } } + if(text.size()) + { + saveBookmark = new QAction( tr( "Save &Bookmark \"%1\"" ).arg( text.left( 60 ) ), &menu ); + menu.addAction( saveBookmark ); + } + // add anki menu if( !text.isEmpty() && cfg.preferences.ankiConnectServer.enabled ) { @@ -1932,6 +1953,10 @@ void ArticleView::contextMenuRequested( QPoint const & pos ) else if ( result == lookupSelection ) showDefinition( selectedText, getGroup( ui.definition->url() ), getCurrentArticle() ); + else if( result == saveBookmark ) + { + emit saveBookmarkSignal( selectedText ); + } else if( result == sendToAnkiAction ) { sendToAnki( ui.definition->title(), ui.definition->selectedText() ); @@ -2333,42 +2358,44 @@ void ArticleView::performFindOperation( bool restart, bool backwards, bool check if ( backwards ) f |= QWebEnginePage::FindBackward; - bool setMark = text.size() && !findText(text, f); + findText( text, + f, + [ &text, this ]( bool match ) + { + bool setMark = !text.isEmpty() && !match; - if ( ui.searchText->property( "noResults" ).toBool() != setMark ) - { - ui.searchText->setProperty( "noResults", setMark ); + if( ui.searchText->property( "noResults" ).toBool() != setMark ) + { + ui.searchText->setProperty( "noResults", setMark ); - // Reload stylesheet - reloadStyleSheet(); - } + // Reload stylesheet + reloadStyleSheet(); + } + } ); } -bool ArticleView::findText(QString& text, const QWebEnginePage::FindFlags& f) +void ArticleView::findText( QString & text, + const QWebEnginePage::FindFlags & f, + const std::function< void( bool match ) > & callback ) { - bool r; - // turn async to sync invoke. - QSharedPointer loop = QSharedPointer(new QEventLoop()); - QTimer::singleShot(1000, loop.data(), &QEventLoop::quit); -#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) - ui.definition->findText(text, f, [&](const QWebEngineFindTextResult& result) +#if( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) ) + ui.definition->findText( text, + f, + [ callback ]( const QWebEngineFindTextResult & result ) { - if(loop->isRunning()){ - r = result.numberOfMatches()>0; - loop->quit(); - } }); + auto r = result.numberOfMatches() > 0; + if( callback ) + callback( r ); + } ); #else - ui.definition->findText(text, f, [&](bool result) + ui.definition->findText( text, + f, + [ callback ]( bool result ) { - if(loop->isRunning()){ - r = result; - loop->quit(); - } }); + if( callback ) + callback( result ); + } ); #endif - - - loop->exec(); - return r; } void ArticleView::reloadStyleSheet() diff --git a/articleview.hh b/articleview.hh index 35aa99a1..e2a570d0 100644 --- a/articleview.hh +++ b/articleview.hh @@ -79,6 +79,8 @@ class ArticleView: public QFrame bool ftsSearchIsOpened, ftsSearchMatchCase; int ftsPosition; + QString delayedHighlightText; + void highlightFTSResults(); void highlightAllFtsOccurences( QWebEnginePage::FindFlags flags ); void performFtsFindOperation( bool backwards ); @@ -157,6 +159,8 @@ public: /// Called when preference changes void setSelectionBySingleClick( bool set ); + void setDelayedHighlightText(QString const & text); + public slots: /// Goes back in history @@ -227,6 +231,10 @@ public: ResourceToSaveHandler * saveResource( const QUrl & url, const QString & fileName ); ResourceToSaveHandler * saveResource( const QUrl & url, const QUrl & ref, const QString & fileName ); + void findText( QString & text, + const QWebEnginePage::FindFlags & f, + const std::function< void( bool match ) > & callback = nullptr ); + signals: void iconChanged( ArticleView *, QIcon const & icon ); @@ -285,6 +293,8 @@ signals: void inspectSignal(QWebEngineView * view); + void saveBookmarkSignal( const QString & bookmark ); + public slots: void on_searchPrevious_clicked(); @@ -391,7 +401,6 @@ private: void performFindOperation( bool restart, bool backwards, bool checkHighlight = false ); - bool findText(QString& text, const QWebEnginePage::FindFlags& f); void reloadStyleSheet(); diff --git a/mainwindow.cc b/mainwindow.cc index af84c699..f8103eae 100644 --- a/mainwindow.cc +++ b/mainwindow.cc @@ -1690,6 +1690,7 @@ ArticleView * MainWindow::createNewTab( bool switchToIt, connect( view, SIGNAL( zoomIn()), this, SLOT( zoomin() ) ); connect( view, SIGNAL( zoomOut()), this, SLOT( zoomout() ) ); + connect( view, &ArticleView::saveBookmarkSignal, this, &MainWindow::addBookmarkToFavorite ); view->setSelectionBySingleClick( cfg.preferences.selectWordBySingleClick ); @@ -4656,6 +4657,15 @@ void MainWindow::addWordToFavorites( QString const & word, unsigned groupId ) ui.favoritesPaneWidget->addHeadword( folder, word ); } +void MainWindow::addBookmarkToFavorite( QString const & text ) +{ + // get current tab word. + QString word = unescapeTabHeader( ui.tabWidget->tabText( ui.tabWidget->currentIndex() ) ); + const auto bookmark = QString( "%1~~~%2" ).arg( word, text ); + + ui.favoritesPaneWidget->addHeadword( nullptr, bookmark ); +} + void MainWindow::addAllTabsToFavorites() { QString folder; @@ -4728,8 +4738,22 @@ void MainWindow::headwordFromFavorites( QString const & headword, } // Show headword without lost of focus on Favorites tree - setTranslateBoxTextAndClearSuffix( headword, EscapeWildcards, DisablePopup ); - showTranslationFor(headword ); + // bookmark cases: the favorite item may like this "word~~~selectedtext" + auto words = headword.split( "~~~" ); + + setTranslateBoxTextAndClearSuffix( words[0], EscapeWildcards, DisablePopup ); + + //must be a bookmark. + if(words.size()>1) + { + auto view = getCurrentArticleView(); + if(view) + { + view->setDelayedHighlightText(words[1]);// findText( words[ 1 ], QWebEnginePage::FindCaseSensitively ); + } + } + + showTranslationFor( words[ 0 ] ); } #ifdef Q_OS_WIN32 diff --git a/mainwindow.hh b/mainwindow.hh index 4e3e4831..882dc1ae 100644 --- a/mainwindow.hh +++ b/mainwindow.hh @@ -462,6 +462,8 @@ private slots: void addWordToFavorites( QString const & word, unsigned groupId ); + void addBookmarkToFavorite( QString const & text ); + bool isWordPresentedInFavorites( QString const & word, unsigned groupId ); void sendWordToInputLine( QString const & word );