diff -Nru goldendict-1.5.0~rc2+git20210309/article_maker.cc goldendict-1.5.0~rc2+git20210630/article_maker.cc --- goldendict-1.5.0~rc2+git20210309/article_maker.cc 2020-11-05 20:39:20.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/article_maker.cc 2021-07-02 16:24:28.630231000 +0000 @@ -256,7 +256,8 @@ return result; } -sptr< Dictionary::DataRequest > ArticleMaker::makeDefinitionFor(QString const & inWord, unsigned groupId, +sptr< Dictionary::DataRequest > ArticleMaker::makeDefinitionFor( + Config::InputPhrase const & phrase, unsigned groupId, QMap< QString, QString > const & contexts, QSet< QString > const & mutedDicts, QStringList const & dictIDs , bool ignoreDiacritics ) const @@ -282,9 +283,9 @@ break; } - string header = makeHtmlHeader( inWord.trimmed(), QString(), true ); + string header = makeHtmlHeader( phrase.phrase, QString(), true ); - return new ArticleRequest( inWord.trimmed(), "", + return new ArticleRequest( phrase, "", contexts, ftsDicts, header, -1, true ); } @@ -292,9 +293,9 @@ if ( groupId == Instances::Group::HelpGroupId ) { // This is a special group containing internal welcome/help pages - string result = makeHtmlHeader( inWord, QString(), needExpandOptionalParts ); + string result = makeHtmlHeader( phrase.phrase, QString(), needExpandOptionalParts ); - if ( inWord == tr( "Welcome!" ) ) + if ( phrase.phrase == tr( "Welcome!" ) ) { result += tr( "

Welcome to GoldenDict!

" @@ -312,7 +313,7 @@ ).toUtf8().data(); } else - if ( inWord == tr( "Working with popup" ) ) + if ( phrase.phrase == tr( "Working with popup" ) ) { result += ( tr( "

Working with the popup

" @@ -333,7 +334,7 @@ else { // Not found - return makeNotFoundTextFor( inWord, "help" ); + return makeNotFoundTextFor( phrase.phrase, "help" ); } result += ""; @@ -362,7 +363,7 @@ std::vector< sptr< Dictionary::Class > > const & activeDicts = activeGroup ? activeGroup->dictionaries : dictionaries; - string header = makeHtmlHeader( inWord.trimmed(), + string header = makeHtmlHeader( phrase.phrase, activeGroup && activeGroup->icon.size() ? activeGroup->icon : QString(), needExpandOptionalParts ); @@ -378,13 +379,13 @@ QString::fromStdString( activeDicts[ x ]->getId() ) ) ) unmutedDicts.push_back( activeDicts[ x ] ); - return new ArticleRequest( inWord.trimmed(), activeGroup ? activeGroup->name : "", + return new ArticleRequest( phrase, activeGroup ? activeGroup->name : "", contexts, unmutedDicts, header, collapseBigArticles ? articleLimitSize : -1, needExpandOptionalParts, ignoreDiacritics ); } else - return new ArticleRequest( inWord.trimmed(), activeGroup ? activeGroup->name : "", + return new ArticleRequest( phrase, activeGroup ? activeGroup->name : "", contexts, activeDicts, header, collapseBigArticles ? articleLimitSize : -1, needExpandOptionalParts, ignoreDiacritics ); @@ -466,12 +467,12 @@ //////// ArticleRequest ArticleRequest::ArticleRequest( - QString const & word_, QString const & group_, + Config::InputPhrase const & phrase, QString const & group_, QMap< QString, QString > const & contexts_, vector< sptr< Dictionary::Class > > const & activeDicts_, string const & header, int sizeLimit, bool needExpandOptionalParts_, bool ignoreDiacritics_ ): - word( word_ ), group( group_ ), contexts( contexts_ ), + word( phrase.phrase ), group( group_ ), contexts( contexts_ ), activeDicts( activeDicts_ ), altsDone( false ), bodyDone( false ), foundAnyDefinitions( false ), closePrevSpan( false ) @@ -479,6 +480,9 @@ , needExpandOptionalParts( needExpandOptionalParts_ ) , ignoreDiacritics( ignoreDiacritics_ ) { + if ( !phrase.punctuationSuffix.isEmpty() ) + alts.insert( gd::toWString( phrase.phraseWithSuffix() ) ); + // No need to lock dataMutex on construction hasAnyData = true; diff -Nru goldendict-1.5.0~rc2+git20210309/article_maker.hh goldendict-1.5.0~rc2+git20210630/article_maker.hh --- goldendict-1.5.0~rc2+git20210309/article_maker.hh 2019-01-19 13:47:19.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/article_maker.hh 2021-07-02 16:24:28.630231000 +0000 @@ -8,6 +8,7 @@ #include #include #include +#include "config.hh" #include "dictionary.hh" #include "instances.hh" #include "wordfinder.hh" @@ -41,7 +42,7 @@ /// choice of the stylesheet file. void setDisplayStyle( QString const &, QString const & addonStyle ); - /// Looks up the given word within the given group, and creates a full html + /// Looks up the given phrase within the given group, and creates a full html /// page text containing its definition. /// The result is returned as Dictionary::DataRequest just like dictionaries /// themselves do. The difference is that the result is a complete html page @@ -50,7 +51,7 @@ /// the keys are dictionary ids. /// If mutedDicts is not empty, the search would be limited only to those /// dictionaries in group which aren't listed there. - sptr< Dictionary::DataRequest > makeDefinitionFor( QString const & word, unsigned groupId, + sptr< Dictionary::DataRequest > makeDefinitionFor( Config::InputPhrase const & phrase, unsigned groupId, QMap< QString, QString > const & contexts, QSet< QString > const & mutedDicts = QSet< QString >(), @@ -129,7 +130,7 @@ public: - ArticleRequest( QString const & word, QString const & group, + ArticleRequest( Config::InputPhrase const & phrase, QString const & group, QMap< QString, QString > const & contexts, std::vector< sptr< Dictionary::Class > > const & activeDicts, std::string const & header, diff -Nru goldendict-1.5.0~rc2+git20210309/article_netmgr.cc goldendict-1.5.0~rc2+git20210630/article_netmgr.cc --- goldendict-1.5.0~rc2+git20210309/article_netmgr.cc 2019-08-08 19:28:53.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/article_netmgr.cc 2021-07-02 16:24:28.630231000 +0000 @@ -388,9 +388,10 @@ if ( Qt4x5::Url::queryItemValue( url, "blank" ) == "1" ) return articleMaker.makeEmptyPage(); - bool groupIsValid = false; + Config::InputPhrase phrase ( Qt4x5::Url::queryItemValue( url, "word" ).trimmed(), + Qt4x5::Url::queryItemValue( url, "punctuation_suffix" ) ); - QString word = Qt4x5::Url::queryItemValue( url, "word" ); + bool groupIsValid = false; unsigned group = Qt4x5::Url::queryItemValue( url, "group" ).toUInt( &groupIsValid ); QString dictIDs = Qt4x5::Url::queryItemValue( url, "dictionaries" ); @@ -398,7 +399,7 @@ { // Individual dictionaries set from full-text search QStringList dictIDList = dictIDs.split( "," ); - return articleMaker.makeDefinitionFor( word, 0, QMap< QString, QString >(), QSet< QString >(), dictIDList ); + return articleMaker.makeDefinitionFor( phrase, 0, QMap< QString, QString >(), QSet< QString >(), dictIDList ); } // See if we have some dictionaries muted @@ -429,8 +430,8 @@ bool ignoreDiacritics = Qt4x5::Url::queryItemValue( url, "ignore_diacritics" ) == "1"; - if ( groupIsValid && word.size() ) // Require group and word to be passed - return articleMaker.makeDefinitionFor( word, group, contexts, mutedDicts, QStringList(), ignoreDiacritics ); + if ( groupIsValid && phrase.isValid() ) // Require group and phrase to be passed + return articleMaker.makeDefinitionFor( phrase, group, contexts, mutedDicts, QStringList(), ignoreDiacritics ); } if ( ( url.scheme() == "bres" || url.scheme() == "gdau" || url.scheme() == "gdvideo" || url.scheme() == "gico" ) && diff -Nru goldendict-1.5.0~rc2+git20210309/article-style.css goldendict-1.5.0~rc2+git20210630/article-style.css --- goldendict-1.5.0~rc2+git20210309/article-style.css 2019-04-13 05:07:33.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/article-style.css 2021-07-02 16:24:28.630231000 +0000 @@ -1624,6 +1624,7 @@ padding-right: 18px; } .mwiki #bodyContent a.external[href $=".ogg"], .mwiki #bodyContent a.external[href $=".OGG"], +.mwiki #bodyContent a.external[href $=".oga"], .mwiki #bodyContent a.external[href $=".OGA"], .mwiki #bodyContent a.external[href $=".mid"], .mwiki #bodyContent a.external[href $=".MID"], .mwiki #bodyContent a.external[href $=".midi"], .mwiki #bodyContent a.external[href $=".MIDI"], .mwiki #bodyContent a.external[href $=".mp3"], .mwiki #bodyContent a.external[href $=".MP3"], diff -Nru goldendict-1.5.0~rc2+git20210309/articleview.cc goldendict-1.5.0~rc2+git20210630/articleview.cc --- goldendict-1.5.0~rc2+git20210309/articleview.cc 2020-11-26 14:38:12.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/articleview.cc 2021-07-02 16:24:28.630231000 +0000 @@ -183,6 +183,30 @@ .arg( variable ) ); } +namespace { + +char const * const scrollToPrefix = "gdfrom-"; + +bool isScrollTo( QString const & id ) +{ + return id.startsWith( scrollToPrefix ); +} + +QString dictionaryIdFromScrollTo( QString const & scrollTo ) +{ + Q_ASSERT( isScrollTo( scrollTo ) ); + const int scrollToPrefixLength = 7; + return scrollTo.mid( scrollToPrefixLength ); +} + +} // unnamed namespace + +QString ArticleView::scrollToFromDictionaryId( QString const & dictionaryId ) +{ + Q_ASSERT( !isScrollTo( dictionaryId ) ); + return scrollToPrefix + dictionaryId; +} + ArticleView::ArticleView( QWidget * parent, ArticleNetworkAccessManager & nm, AudioPlayerPtr const & audioPlayer_, std::vector< sptr< Dictionary::Class > > const & allDictionaries_, @@ -352,7 +376,7 @@ #endif } -void ArticleView::showDefinition( QString const & word, unsigned group, +void ArticleView::showDefinition( Config::InputPhrase const & phrase, unsigned group, QString const & scrollTo, Contexts const & contexts_ ) { @@ -364,7 +388,9 @@ req.setScheme( "gdlookup" ); req.setHost( "localhost" ); - Qt4x5::Url::addQueryItem( req, "word", word ); + Qt4x5::Url::addQueryItem( req, "word", phrase.phrase ); + if ( !phrase.punctuationSuffix.isEmpty() ) + Qt4x5::Url::addQueryItem( req, "punctuation_suffix", phrase.punctuationSuffix ); Qt4x5::Url::addQueryItem( req, "group", QString::number( group ) ); if( cfg.preferences.ignoreDiacritics ) Qt4x5::Url::addQueryItem( req, "ignore_diacritics", "1" ); @@ -401,7 +427,7 @@ // Update both histories (pages history and headwords history) saveHistoryUserData(); - emit sendWordToHistory( word ); + emit sendWordToHistory( phrase.phrase ); // Any search opened is probably irrelevant now closeSearch(); @@ -417,6 +443,13 @@ ui.definition->setCursor( Qt::WaitCursor ); } +void ArticleView::showDefinition( QString const & word, unsigned group, + QString const & scrollTo, + Contexts const & contexts_ ) +{ + showDefinition( Config::InputPhrase::fromPhrase( word ), group, scrollTo, contexts_ ); +} + void ArticleView::showDefinition( QString const & word, QStringList const & dictIDs, QRegExp const & searchRegExp, unsigned group, bool ignoreDiacritics ) @@ -541,11 +574,14 @@ } } else - if ( Qt4x5::Url::queryItemValue( url, "scrollto" ).startsWith( "gdfrom-" ) ) { - // There is no active article saved in history, but we have it as a parameter. - // setCurrentArticle will save it and scroll there. - setCurrentArticle( Qt4x5::Url::queryItemValue( url, "scrollto" ), true ); + QString const scrollTo = Qt4x5::Url::queryItemValue( url, "scrollto" ); + if( isScrollTo( scrollTo ) ) + { + // There is no active article saved in history, but we have it as a parameter. + // setCurrentArticle will save it and scroll there. + setCurrentArticle( scrollTo, true ); + } } @@ -666,10 +702,10 @@ QString ArticleView::getActiveArticleId() { QString currentArticle = getCurrentArticle(); - if ( !currentArticle.startsWith( "gdfrom-" ) ) + if ( !isScrollTo( currentArticle ) ) return QString(); // Incorrect id - return currentArticle.mid( 7 ); + return dictionaryIdFromScrollTo( currentArticle ); } QString ArticleView::getCurrentArticle() @@ -684,7 +720,7 @@ void ArticleView::jumpToDictionary( QString const & id, bool force ) { - QString targetArticle = "gdfrom-" + id; + QString targetArticle = scrollToFromDictionaryId( id ); // jump only if neceessary, or when forced if ( force || targetArticle != getCurrentArticle() ) @@ -695,13 +731,14 @@ void ArticleView::setCurrentArticle( QString const & id, bool moveToIt ) { - if ( !id.startsWith( "gdfrom-" ) ) + if ( !isScrollTo( id ) ) return; // Incorrect id if ( !ui.definition->isVisible() ) return; // No action on background page, scrollIntoView there don't work - if ( getArticlesList().contains( id.mid( 7 ) ) ) + QString const dictionaryId = dictionaryIdFromScrollTo( id ); + if ( getArticlesList().contains( dictionaryId ) ) { if ( moveToIt ) ui.definition->page()->mainFrame()->evaluateJavaScript( QString( "document.getElementById('%1').scrollIntoView(true);" ).arg( id ) ); @@ -712,7 +749,7 @@ ui.definition->history()->currentItem().setUserData( userData ); ui.definition->page()->mainFrame()->evaluateJavaScript( - QString( "gdMakeArticleActive( '%1' );" ).arg( id.mid( 7 ) ) ); + QString( "gdMakeArticleActive( '%1' );" ).arg( dictionaryId ) ); } } @@ -728,7 +765,8 @@ return false; return ui.definition->page()->mainFrame()-> - evaluateJavaScript( QString( "!!document.getElementById('gdexpandframe-%1');" ).arg( ca.mid( 7 ) ) ).toBool(); + evaluateJavaScript( QString( "!!document.getElementById('gdexpandframe-%1');" ) + .arg( dictionaryIdFromScrollTo( ca ) ) ).toBool(); } bool ArticleView::isExternalLink( QUrl const & url ) @@ -756,8 +794,7 @@ if ( result.type() == QVariant::String ) { // Looks this way - - contexts[ ca.mid( 7 ) ] = QString::fromLatin1( url.toEncoded() ); + contexts[ dictionaryIdFromScrollTo( ca ) ] = QString::fromLatin1( url.toEncoded() ); QUrl target; @@ -789,7 +826,7 @@ if ( frameName.startsWith( "gdexpandframe-" ) ) { - QString newCurrent = "gdfrom-" + frameName.mid( 14 ); + QString newCurrent = scrollToFromDictionaryId( frameName.mid( 14 ) ); if ( getCurrentArticle() != newCurrent ) setCurrentArticle( newCurrent, false ); @@ -1181,7 +1218,7 @@ { if( dictName.compare( QString::fromUtf8( allDictionaries[ i ]->getName().c_str() ) ) == 0 ) { - newScrollTo = QString( "gdfrom-" ) + QString::fromUtf8( allDictionaries[ i ]->getId().c_str() ); + newScrollTo = scrollToFromDictionaryId( QString::fromUtf8( allDictionaries[ i ]->getId().c_str() ) ); break; } } @@ -1668,6 +1705,13 @@ return ui.definition->page()->mainFrame()->title(); } +Config::InputPhrase ArticleView::getPhrase() const +{ + const QUrl url = ui.definition->url(); + return Config::InputPhrase( Qt4x5::Url::queryItemValue( url, "word" ), + Qt4x5::Url::queryItemValue( url, "punctuation_suffix" ) ); +} + void ArticleView::print( QPrinter * printer ) const { ui.definition->print( printer ); @@ -1953,7 +1997,7 @@ fileName = savePath + "/" + name; fileName = QFileDialog::getSaveFileName( parentWidget(), tr( "Save sound" ), fileName, - tr( "Sound files (*.wav *.ogg *.mp3 *.mp4 *.aac *.flac *.mid *.wv *.ape);;All files (*.*)" ) ); + tr( "Sound files (*.wav *.ogg *.oga *.mp3 *.mp4 *.aac *.flac *.mid *.wv *.ape);;All files (*.*)" ) ); } else { @@ -1988,7 +2032,7 @@ QString id = tableOfContents[ result ]; if ( id.size() ) - setCurrentArticle( "gdfrom-" + id, true ); + setCurrentArticle( scrollToFromDictionaryId( id ), true ); } } #if 0 @@ -2085,9 +2129,9 @@ void ArticleView::pasteTriggered() { - QString text = cfg.preferences.sanitizeInputPhrase( QApplication::clipboard()->text() ); + Config::InputPhrase phrase = cfg.preferences.sanitizeInputPhrase( QApplication::clipboard()->text() ); - if ( text.size() ) + if ( phrase.isValid() ) { unsigned groupId = getGroup( ui.definition->url() ); if ( groupId == 0 ) @@ -2096,7 +2140,7 @@ // so let's try the currently selected group. groupId = groupComboBox->getCurrentGroup(); } - showDefinition( text, groupId, getCurrentArticle() ); + showDefinition( phrase, groupId, getCurrentArticle() ); } } @@ -2108,7 +2152,7 @@ { QStringList lst = getArticlesList(); - int idx = lst.indexOf( current.mid( 7 ) ); + int idx = lst.indexOf( dictionaryIdFromScrollTo( current ) ); if ( idx != -1 ) { @@ -2117,7 +2161,7 @@ if ( idx < 0 ) idx = lst.size() - 1; - setCurrentArticle( "gdfrom-" + lst[ idx ], true ); + setCurrentArticle( scrollToFromDictionaryId( lst[ idx ] ), true ); } } } @@ -2130,13 +2174,13 @@ { QStringList lst = getArticlesList(); - int idx = lst.indexOf( current.mid( 7 ) ); + int idx = lst.indexOf( dictionaryIdFromScrollTo( current ) ); if ( idx != -1 ) { idx = ( idx + 1 ) % lst.size(); - setCurrentArticle( "gdfrom-" + lst[ idx ], true ); + setCurrentArticle( scrollToFromDictionaryId( lst[ idx ] ), true ); } } } @@ -2214,10 +2258,10 @@ void ArticleView::onJsActiveArticleChanged(QString const & id) { - if ( !id.startsWith( "gdfrom-" ) ) + if ( !isScrollTo( id ) ) return; // Incorrect id - emit activeArticleChanged( this, id.mid( 7 ) ); + emit activeArticleChanged( this, dictionaryIdFromScrollTo( id ) ); } void ArticleView::doubleClicked( QPoint pos ) diff -Nru goldendict-1.5.0~rc2+git20210309/articleview.hh goldendict-1.5.0~rc2+git20210630/articleview.hh --- goldendict-1.5.0~rc2+git20210309/articleview.hh 2019-01-19 13:47:19.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/articleview.hh 2021-07-02 16:24:28.630231000 +0000 @@ -90,12 +90,19 @@ typedef QMap< QString, QString > Contexts; + /// Returns "gdfrom-" + dictionaryId. + static QString scrollToFromDictionaryId( QString const & dictionaryId ); + /// Shows the definition of the given word with the given group. /// scrollTo can be optionally set to a "gdfrom-xxxx" identifier to position /// the page to that article on load. /// contexts is an optional map of context values to be passed for dictionaries. /// The only values to pass here are ones obtained from showDefinitionInNewTab() /// signal or none at all. + void showDefinition( Config::InputPhrase const & phrase, unsigned group, + QString const & scrollTo = QString(), + Contexts const & contexts = Contexts() ); + void showDefinition( QString const & word, unsigned group, QString const & scrollTo = QString(), Contexts const & contexts = Contexts() ); @@ -161,6 +168,9 @@ /// Returns current article's title QString getTitle(); + /// Returns the phrase translated by the current article. + Config::InputPhrase getPhrase() const; + /// Prints current article void print( QPrinter * ) const; diff -Nru goldendict-1.5.0~rc2+git20210309/config.cc goldendict-1.5.0~rc2+git20210630/config.cc --- goldendict-1.5.0~rc2+git20210309/config.cc 2020-11-26 14:38:12.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/config.cc 2021-07-02 16:24:28.634230900 +0000 @@ -153,15 +153,31 @@ return SPWF_default; } -QString Preferences::sanitizeInputPhrase( QString const & inputPhrase ) const +InputPhrase Preferences::sanitizeInputPhrase( QString const & inputPhrase ) const { + InputPhrase result; + if( limitInputPhraseLength && inputPhrase.size() > inputPhraseLengthLimit ) { gdWarning( "Ignoring an input phrase %d symbols long. The configured maximum input phrase length is %d symbols.", inputPhrase.size(), inputPhraseLengthLimit ); - return QString(); + return result; } - return gd::toQString( Folding::trimWhitespaceOrPunct( gd::toWString( inputPhrase ) ) ).simplified(); + + const QString withPunct = inputPhrase.simplified(); + result.phrase = gd::toQString( Folding::trimWhitespaceOrPunct( gd::toWString( withPunct ) ) ); + if ( !result.isValid() ) + return result; // The suffix of an invalid input phrase must be empty. + + const int prefixSize = withPunct.indexOf( result.phrase.at(0) ); + const int suffixSize = withPunct.size() - prefixSize - result.phrase.size(); + Q_ASSERT( suffixSize >= 0 ); + Q_ASSERT( withPunct.size() - suffixSize - 1 + == withPunct.lastIndexOf( result.phrase.at( result.phrase.size() - 1 ) ) ); + if ( suffixSize != 0 ) + result.punctuationSuffix = withPunct.right( suffixSize ); + + return result; } Preferences::Preferences(): @@ -1084,6 +1100,11 @@ if ( !inspectorGeometry.isNull() ) c.inspectorGeometry = QByteArray::fromBase64( inspectorGeometry.toElement().text().toLatin1() ); + QDomNode dictionariesDialogGeometry = root.namedItem( "dictionariesDialogGeometry" ); + + if ( !dictionariesDialogGeometry.isNull() ) + c.dictionariesDialogGeometry = QByteArray::fromBase64( dictionariesDialogGeometry.toElement().text().toLatin1() ); + QDomNode timeForNewReleaseCheck = root.namedItem( "timeForNewReleaseCheck" ); if ( !timeForNewReleaseCheck.isNull() ) @@ -2078,6 +2099,10 @@ opt.appendChild( dd.createTextNode( QString::fromLatin1( c.inspectorGeometry.toBase64() ) ) ); root.appendChild( opt ); + opt = dd.createElement( "dictionariesDialogGeometry" ); + opt.appendChild( dd.createTextNode( QString::fromLatin1( c.dictionariesDialogGeometry.toBase64() ) ) ); + root.appendChild( opt ); + opt = dd.createElement( "timeForNewReleaseCheck" ); opt.appendChild( dd.createTextNode( c.timeForNewReleaseCheck.toString( Qt::ISODate ) ) ); root.appendChild( opt ); diff -Nru goldendict-1.5.0~rc2+git20210309/config.hh goldendict-1.5.0~rc2+git20210630/config.hh --- goldendict-1.5.0~rc2+git20210309/config.hh 2020-11-26 14:38:12.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/config.hh 2021-07-02 16:24:28.634230900 +0000 @@ -11,6 +11,7 @@ #include #include #include +#include #include "cpp_features.hh" #include "ex.hh" @@ -243,6 +244,38 @@ }; ScanPopupWindowFlags spwfFromInt( int id ); +struct InputPhrase +{ + InputPhrase() + {} + + InputPhrase( QString const & _phrase, QString const & _suffix ) : + phrase( _phrase ), + punctuationSuffix( _suffix ) + {} + + static InputPhrase fromPhrase( QString const & phrase ) + { + return InputPhrase( phrase, QString() ); + } + + bool isValid() const { return !phrase.isEmpty(); } + + QString phraseWithSuffix() const { return phrase + punctuationSuffix; } + + QString phrase; + QString punctuationSuffix; +}; + +inline bool operator == ( InputPhrase const & a, InputPhrase const & b ) +{ + return a.phrase == b.phrase && a.punctuationSuffix == b.punctuationSuffix; +} +inline bool operator != ( InputPhrase const & a, InputPhrase const & b ) +{ + return !( a == b ); +} + /// Various user preferences struct Preferences { @@ -323,7 +356,7 @@ bool limitInputPhraseLength; int inputPhraseLengthLimit; - QString sanitizeInputPhrase( QString const & inputPhrase ) const; + InputPhrase sanitizeInputPhrase( QString const & inputPhrase ) const; unsigned short maxDictionaryRefsInContextMenu; #ifndef Q_WS_X11 @@ -644,6 +677,7 @@ QByteArray popupWindowGeometry; // Geometry saved by QMainWindow QByteArray dictInfoGeometry; // Geometry of "Dictionary info" window QByteArray inspectorGeometry; // Geometry of WebKit inspector window + QByteArray dictionariesDialogGeometry; // Geometry of Dictionaries dialog QByteArray helpWindowGeometry; // Geometry of help window QByteArray helpSplitterState; // Geometry of help splitter @@ -802,5 +836,6 @@ } -#endif +Q_DECLARE_METATYPE( Config::InputPhrase ) +#endif diff -Nru goldendict-1.5.0~rc2+git20210309/debian/changelog goldendict-1.5.0~rc2+git20210630/debian/changelog --- goldendict-1.5.0~rc2+git20210309/debian/changelog 2021-03-21 19:30:49.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/debian/changelog 2021-07-05 20:30:11.000000000 +0000 @@ -1,8 +1,33 @@ -goldendict (1.5.0~rc2+git20210309-1ppa1~groovy1) groovy; urgency=medium +goldendict (1.5.0~rc2+git20210630-1ppa1~groovy1) groovy; urgency=medium * Automated backport upload; no source changes. - -- Alexander Pozdnyakov Sun, 21 Mar 2021 22:30:49 +0300 + -- Alexander Pozdnyakov Mon, 05 Jul 2021 23:30:11 +0300 + +goldendict (1.5.0~rc2+git20210630-1) unstable; urgency=medium + + * Compile + * URL: https://github.com/goldendict/goldendict.git + * Branch: master + * Commit: baff02a14b3f70f0d0a55bef550dbb74dcbf0ce8 + * Date: 1625072500 + * git changelog: + * baff02a - Make MainWindow::setTranslateBoxTextAnd*() harder to + misuse + * 9ff28e2 - Translate box: add missing wildcard symbol (un)escaping + * f919685 - Extract duplicated gdfrom- string manipulation into + functions + * bc7fe1a - Merge branch 'dictionaries-dialog-save-restore-geometry' + of https://github.com/vedgy/goldendict into Temp + * c3e4a99 - Dictionaries dialog: always show Maximize button + * fdf0464 - Save&restore the geometry of Dictionaries dialog + * e1c9a0d - Fix compilation without C++11 support + * df192bf - Don't show duplicate MediaWiki articles + * 99ddb76 - Don't add the same phrase to history twice in a row + * 60bc052 - Add input phrase's punctuation suffix to alts + * 57c4c33 - Add support for *.oga audio files + + -- Alexander Pozdnyakov Fri, 02 Jul 2021 19:24:48 +0300 goldendict (1.5.0~rc2+git20210309-1) unstable; urgency=medium diff -Nru goldendict-1.5.0~rc2+git20210309/editdictionaries.cc goldendict-1.5.0~rc2+git20210630/editdictionaries.cc --- goldendict-1.5.0~rc2+git20210309/editdictionaries.cc 2019-01-19 13:47:19.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/editdictionaries.cc 2021-07-02 16:24:28.634230900 +0000 @@ -13,7 +13,9 @@ vector< sptr< Dictionary::Class > > & dictionaries_, Instances::Groups & groupInstances_, QNetworkAccessManager & dictNetMgr_ ): - QDialog( parent ), cfg( cfg_ ), dictionaries( dictionaries_ ), + QDialog( parent, Qt::WindowSystemMenuHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint ), + cfg( cfg_ ), + dictionaries( dictionaries_ ), groupInstances( groupInstances_ ), dictNetMgr( dictNetMgr_ ), origCfg( cfg ), diff -Nru goldendict-1.5.0~rc2+git20210309/filetype.cc goldendict-1.5.0~rc2+git20210630/filetype.cc --- goldendict-1.5.0~rc2+git20210309/filetype.cc 2019-10-10 21:04:34.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/filetype.cc 2021-07-02 16:24:28.634230900 +0000 @@ -55,6 +55,7 @@ endsWith( s, ".au" ) || endsWith( s, ".voc" ) || endsWith( s, ".ogg" ) || + endsWith( s, ".oga" ) || endsWith( s, ".mp3" ) || endsWith( s, ".m4a") || endsWith( s, ".aac" ) || diff -Nru goldendict-1.5.0~rc2+git20210309/mainwindow.cc goldendict-1.5.0~rc2+git20210630/mainwindow.cc --- goldendict-1.5.0~rc2+git20210309/mainwindow.cc 2021-03-04 19:46:17.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/mainwindow.cc 2021-07-02 16:24:28.634230900 +0000 @@ -142,6 +142,8 @@ QThreadPool::globalInstance()->start( new InitSSLRunnable ); #endif + qRegisterMetaType< Config::InputPhrase >(); + #ifndef NO_EPWING_SUPPORT Epwing::initialize(); #endif @@ -957,11 +959,7 @@ updateGroupList(); applyWordsZoomLevel(); - if ( cfg.preferences.searchInDock ) - translateLine->setText( text ); - else - translateBox->setText( text, false ); - + setTranslateBoxTextAndKeepSuffix( text, WildcardsAreAlreadyEscaped, DisablePopup ); focusTranslateLine(); } @@ -981,7 +979,7 @@ QString str = QApplication::clipboard()->text(subtype, QClipboard::Selection); - translateLine->setText(str); + setTranslateBoxTextAndClearSuffix( str, EscapeWildcards, NoPopupChange ); QKeyEvent ev(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); @@ -1468,8 +1466,8 @@ connect( scanPopup.get(), SIGNAL(editGroupRequested( unsigned ) ), this, SLOT(editDictionaries( unsigned )), Qt::QueuedConnection ); - connect( scanPopup.get(), SIGNAL(sendWordToMainWindow( QString const & ) ), - this, SLOT(wordReceived( QString const & )), Qt::QueuedConnection ); + connect( scanPopup.get(), SIGNAL(sendPhraseToMainWindow( Config::InputPhrase const & ) ), + this, SLOT(phraseReceived( Config::InputPhrase const & )), Qt::QueuedConnection ); connect( this, SIGNAL( setExpandOptionalParts( bool ) ), scanPopup.get(), SIGNAL( setViewExpandMode( bool ) ) ); @@ -2037,7 +2035,9 @@ if ( editDictionaryGroup != Instances::Group::NoGroupId ) dicts.editGroup( editDictionaryGroup ); + dicts.restoreGeometry( cfg.dictionariesDialogGeometry ); dicts.exec(); + cfg.dictionariesDialogGeometry = newCfg.dictionariesDialogGeometry = dicts.saveGeometry(); if ( dicts.areDictionariesChanged() || dicts.areGroupsChanged() ) { @@ -2063,7 +2063,7 @@ Config::save( cfg ); - translateInputChanged( translateLine->text() ); + updateSuggestionList(); } } @@ -2244,7 +2244,7 @@ // Update word search results translateBox->setPopupEnabled( false ); - translateInputChanged( translateLine->text() ); + updateSuggestionList(); translateInputFinished( false ); updateCurrentGroupProperty(); @@ -2276,6 +2276,17 @@ void MainWindow::translateInputChanged( QString const & newValue ) { + updateSuggestionList( newValue ); + translateBoxSuffix = QString(); +} + +void MainWindow::updateSuggestionList() +{ + updateSuggestionList( translateLine->text() ); +} + +void MainWindow::updateSuggestionList( QString const & newValue ) +{ // If there's some status bar message present, clear it since it may be // about the previous search that has failed. if ( !mainStatusBar->currentMessage().isEmpty() ) @@ -2312,17 +2323,22 @@ wordFinder.prefixMatch( req, getActiveDicts() ); } -void MainWindow::translateInputFinished( bool checkModifiers, QString const & dictID ) +void MainWindow::translateInputFinished( bool checkModifiers ) { QString word = Folding::unescapeWildcardSymbols( translateLine->text() ); + respondToTranslationRequest( Config::InputPhrase( word, translateBoxSuffix ), checkModifiers ); +} - if ( word.size() ) +void MainWindow::respondToTranslationRequest( Config::InputPhrase const & phrase, + bool checkModifiers, QString const & scrollTo ) +{ + if ( phrase.isValid() ) { Qt::KeyboardModifiers mods = QApplication::keyboardModifiers(); if ( checkModifiers && ( mods & (Qt::ControlModifier | Qt::ShiftModifier) ) ) addNewTab(); - showTranslationFor( word, 0, dictID ); + showTranslationFor( phrase, 0, scrollTo ); if ( cfg.preferences.searchInDock ) { @@ -2334,6 +2350,25 @@ } } +void MainWindow::setTranslateBoxTextAndKeepSuffix( QString text, WildcardPolicy wildcardPolicy, + TranslateBoxPopup popupAction ) +{ + if( wildcardPolicy == EscapeWildcards ) + text = Folding::escapeWildcardSymbols( text ); + + if( popupAction == NoPopupChange || cfg.preferences.searchInDock ) + translateLine->setText( text ); + else + translateBox->setText( text, popupAction == EnablePopup ); +} + +void MainWindow::setTranslateBoxTextAndClearSuffix( QString const & text, WildcardPolicy wildcardPolicy, + TranslateBoxPopup popupAction ) +{ + setTranslateBoxTextAndKeepSuffix( text, wildcardPolicy, popupAction ); + translateBoxSuffix = QString(); +} + void MainWindow::handleEsc() { ArticleView *view = getCurrentArticleView(); @@ -2370,8 +2405,7 @@ { translateBox->setPopupEnabled( false ); - // Redo the current search request - translateInputChanged( translateLine->text() ); + updateSuggestionList(); ArticleView *view = getCurrentArticleView(); @@ -2724,10 +2758,8 @@ if( translateLine->isEnabled() ) { translateLine->setFocus(); - if ( cfg.preferences.searchInDock ) - translateLine->setText( t ); - else - translateBox->setText( t, true ); + // Escaping the typed-in characters is the user's responsibility. + setTranslateBoxTextAndClearSuffix( t, WildcardsAreAlreadyEscaped, EnablePopup ); translateLine->setCursorPosition( t.size() ); } } @@ -2745,19 +2777,15 @@ history.enableAdd( false ); - if ( cfg.preferences.searchInDock ) - translateLine->setText( Folding::escapeWildcardSymbols( word ) ); - else - translateBox->setText( Folding::escapeWildcardSymbols( word ), false ); - + setTranslateBoxTextAndClearSuffix( word, EscapeWildcards, DisablePopup ); showTranslationFor( word ); history.enableAdd( cfg.preferences.storeHistory ); } -void MainWindow::showTranslationFor( QString const & inWord, +void MainWindow::showTranslationFor( Config::InputPhrase const & phrase, unsigned inGroup, - QString const & dictID ) + QString const & scrollTo ) { ArticleView *view = getCurrentArticleView(); @@ -2767,15 +2795,11 @@ ( groupInstances.empty() ? 0 : groupInstances[ groupList->currentIndex() ].id ); - view->showDefinition( inWord, group, dictID ); + view->showDefinition( phrase, group, scrollTo ); updatePronounceAvailability(); updateFoundInDictsList(); - // Add to history - - addWordToHistory( inWord ); - updateBackForwardButtons(); #if 0 @@ -2867,6 +2891,11 @@ //ui.tabWidget->setTabText( ui.tabWidget->indexOf(ui.tab), inWord.trimmed() ); } +void MainWindow::showTranslationFor( QString const & word ) +{ + showTranslationFor( Config::InputPhrase::fromPhrase( word ) ); +} + void MainWindow::showTranslationFor( QString const & inWord, QStringList const & dictIDs, QRegExp const & searchRegExp, @@ -2883,10 +2912,6 @@ updatePronounceAvailability(); updateFoundInDictsList(); - // Add to history - - addWordToHistory( inWord ); - updateBackForwardButtons(); } @@ -3639,9 +3664,7 @@ makeScanPopup(); installHotKeys(); - // Reload suggestion list - QString word = translateLine->text(); - translateInputChanged( word ); + updateSuggestionList(); } void MainWindow::on_alwaysOnTop_triggered( bool checked ) @@ -3871,18 +3894,25 @@ return 0; } +void MainWindow::phraseReceived( Config::InputPhrase const & phrase ) +{ + toggleMainWindow( true ); + setTranslateBoxTextAndKeepSuffix( phrase.phrase, EscapeWildcards, NoPopupChange ); + translateBoxSuffix = phrase.punctuationSuffix; + respondToTranslationRequest( phrase, false ); +} + void MainWindow::wordReceived( const QString & word) { - toggleMainWindow( true ); - translateLine->setText( Folding::escapeWildcardSymbols( word ) ); - translateInputFinished( false ); + phraseReceived( Config::InputPhrase::fromPhrase( word ) ); } void MainWindow::headwordReceived( const QString & word, const QString & ID ) { - toggleMainWindow( true ); - translateLine->setText( Folding::escapeWildcardSymbols( word ) ); - translateInputFinished( false, QString( "gdfrom-" )+ ID ); + toggleMainWindow( true ); + setTranslateBoxTextAndClearSuffix( word, EscapeWildcards, NoPopupChange ); + respondToTranslationRequest( Config::InputPhrase::fromPhrase( word ), + false, ArticleView::scrollToFromDictionaryId( ID ) ); } void MainWindow::updateFavoritesMenu() @@ -4520,8 +4550,7 @@ void MainWindow::sendWordToInputLine( const QString & word ) { - translateLine->clear(); - translateLine->setText( word ); + setTranslateBoxTextAndClearSuffix( word, EscapeWildcards, NoPopupChange ); } void MainWindow::storeResourceSavePath( const QString & newPath ) @@ -4824,12 +4853,7 @@ } // Show headword without lost of focus on Favorites tree - - if ( cfg.preferences.searchInDock ) - translateLine->setText( Folding::escapeWildcardSymbols( headword ) ); - else - translateBox->setText( Folding::escapeWildcardSymbols( headword ), false ); - + setTranslateBoxTextAndClearSuffix( headword, EscapeWildcards, DisablePopup ); showTranslationFor(headword ); } diff -Nru goldendict-1.5.0~rc2+git20210309/mainwindow.hh goldendict-1.5.0~rc2+git20210630/mainwindow.hh --- goldendict-1.5.0~rc2+git20210309/mainwindow.hh 2020-11-26 14:38:12.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/mainwindow.hh 2021-07-02 16:24:28.634230900 +0000 @@ -82,6 +82,7 @@ void messageFromAnotherInstanceReceived( QString const & ); void showStatusBarMessage ( QString const &, int, QPixmap const & ); + void phraseReceived( Config::InputPhrase const & ); void wordReceived( QString const & ); void headwordReceived( QString const &, QString const & ); void setExpandMode( bool expand ); @@ -158,6 +159,7 @@ WordList * wordList; QLineEdit * translateLine; + QString translateBoxSuffix; ///< A punctuation suffix that corresponds to translateLine's text. WordFinder wordFinder; @@ -257,6 +259,19 @@ QString unescapeTabHeader( QString const & header ); + void respondToTranslationRequest( Config::InputPhrase const & phrase, + bool checkModifiers, QString const & scrollTo = QString() ); + + void updateSuggestionList(); + void updateSuggestionList( QString const & text ); + + enum WildcardPolicy { EscapeWildcards, WildcardsAreAlreadyEscaped }; + enum TranslateBoxPopup { NoPopupChange, EnablePopup, DisablePopup }; + void setTranslateBoxTextAndKeepSuffix( QString text, WildcardPolicy wildcardPolicy, + TranslateBoxPopup popupAction ); + void setTranslateBoxTextAndClearSuffix( QString const & text, WildcardPolicy wildcardPolicy, + TranslateBoxPopup popupAction ); + private slots: void hotKeyActivated( int ); @@ -358,7 +373,7 @@ void currentGroupChanged( QString const & ); void translateInputChanged( QString const & ); - void translateInputFinished( bool checkModifiers = true, QString const & dictID = QString() ); + void translateInputFinished( bool checkModifiers = true ); /// Closes any opened search in the article view, and focuses the translateLine/close main window to tray. void handleEsc(); @@ -393,8 +408,9 @@ void mutedDictionariesChanged(); - void showTranslationFor( QString const &, unsigned inGroup = 0, - QString const & dictID = QString() ); + void showTranslationFor( Config::InputPhrase const &, unsigned inGroup = 0, + QString const & scrollTo = QString() ); + void showTranslationFor( QString const & ); void showTranslationFor( QString const &, QStringList const & dictIDs, QRegExp const & searchRegExp, bool ignoreDiacritics ); diff -Nru goldendict-1.5.0~rc2+git20210309/mediawiki.cc goldendict-1.5.0~rc2+git20210630/mediawiki.cc --- goldendict-1.5.0~rc2+git20210309/mediawiki.cc 2020-12-10 20:46:23.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/mediawiki.cc 2021-07-02 16:24:28.634230900 +0000 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "gddebug.hh" #include "audiolink.hh" @@ -242,6 +243,26 @@ void addQuery( QNetworkAccessManager & mgr, wstring const & word ); virtual void requestFinished( QNetworkReply * ); + + /// This simple set implementation should be much more efficient than tree- + /// and hash-based standard/Qt containers when there are very few elements. + template< typename T > + class SmallSet { + public: + bool insert( T x ) + { + if( std::find( elements.begin(), elements.end(), x ) != elements.end() ) + return false; + elements.push_back( x ); + return true; + } + private: + std::vector< T > elements; + }; + + /// The page id set allows to filter out duplicate articles in case MediaWiki + /// redirects the main word and words in the alts collection to the same page. + SmallSet< long long > addedPageIds; Class * dictPtr; }; @@ -341,7 +362,9 @@ { QDomNode parseNode = dd.namedItem( "api" ).namedItem( "parse" ); - if ( !parseNode.isNull() && parseNode.toElement().attribute( "revid" ) != "0" ) + if ( !parseNode.isNull() && parseNode.toElement().attribute( "revid" ) != "0" + // Don't show the same article more than once: + && addedPageIds.insert( parseNode.toElement().attribute( "pageid" ).toLongLong() ) ) { QDomNode textNode = parseNode.namedItem( "text" ); @@ -480,9 +503,9 @@ #endif // audio url #if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) - articleString.replace( QRegularExpression( "dictPtr->getId() ) + "mid( 7, i->length() - 11 ); + QString loc = i->mid( 7, i->length() - 11 ); // e.g. *i == "gdhelp_en.qch" => loc == "en" QString lang = loc.mid( 0, 2 ); QString reg; if(loc.length() >= 5 ) diff -Nru goldendict-1.5.0~rc2+git20210309/scanpopup.cc goldendict-1.5.0~rc2+git20210630/scanpopup.cc --- goldendict-1.5.0~rc2+git20210309/scanpopup.cc 2020-11-26 14:38:12.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/scanpopup.cc 2021-07-02 16:24:28.634230900 +0000 @@ -2,6 +2,7 @@ * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */ #include "scanpopup.hh" +#include "folding.hh" #include #include #include @@ -492,9 +493,9 @@ void ScanPopup::translateWord( QString const & word ) { - QString str = pendingInputWord = cfg.preferences.sanitizeInputPhrase( word ); + pendingInputPhrase = cfg.preferences.sanitizeInputPhrase( word ); - if ( !str.size() ) + if ( !pendingInputPhrase.isValid() ) return; // Nothing there // In case we had any timers engaged before, cancel them now. @@ -505,7 +506,7 @@ emit hideScanFlag(); #endif - inputWord = str; + inputPhrase = pendingInputPhrase; engagePopup( false, #ifdef Q_OS_WIN true // We only focus popup under Windows when activated via Ctrl+C+C @@ -556,18 +557,18 @@ void ScanPopup::handleInputWord( QString const & str, bool forcePopup ) { - QString sanitizedStr = cfg.preferences.sanitizeInputPhrase( str ); + Config::InputPhrase sanitizedPhrase = cfg.preferences.sanitizeInputPhrase( str ); - if ( isVisible() && sanitizedStr == inputWord ) + if ( isVisible() && sanitizedPhrase == inputPhrase ) { // Attempt to translate the same word we already have shown in scan popup. // Ignore it, as it is probably a spurious mouseover event. return; } - pendingInputWord = sanitizedStr; + pendingInputPhrase = sanitizedPhrase; - if ( !pendingInputWord.size() ) + if ( !pendingInputPhrase.isValid() ) { if ( cfg.preferences.scanPopupAltMode ) { @@ -581,7 +582,7 @@ #ifdef HAVE_X11 if ( cfg.preferences.showScanFlag ) { - inputWord = pendingInputWord; + inputPhrase = pendingInputPhrase; emit showScanFlag( forcePopup ); return; } @@ -600,7 +601,7 @@ return; } - inputWord = pendingInputWord; + inputPhrase = pendingInputPhrase; engagePopup( forcePopup ); } @@ -616,7 +617,7 @@ if( cfg.preferences.scanToMainWindow && !forcePopup ) { // Send translated word to main window istead of show popup - emit sendWordToMainWindow( inputWord ); + emit sendPhraseToMainWindow( inputPhrase ); return; } @@ -712,13 +713,15 @@ /// Too large strings make window expand which is probably not what user /// wants - ui.translateBox->setText( inputWord, false ); + ui.translateBox->setText( Folding::escapeWildcardSymbols( inputPhrase.phrase ), false ); + translateBoxSuffix = inputPhrase.punctuationSuffix; - showTranslationFor( inputWord ); + showTranslationFor( inputPhrase ); } QString ScanPopup::elideInputWord() { + QString const & inputWord = inputPhrase.phrase; return inputWord.size() > 32 ? inputWord.mid( 0, 32 ) + "..." : inputWord; } @@ -749,7 +752,7 @@ if ( isVisible() ) { - translateInputChanged( ui.translateBox->translateLine()->text() ); + updateSuggestionList(); translateInputFinished(); } @@ -758,11 +761,22 @@ void ScanPopup::wordListItemActivated( QListWidgetItem * item ) { - showTranslationFor( item->text() ); + showTranslationFor( Config::InputPhrase::fromPhrase( item->text() ) ); } void ScanPopup::translateInputChanged( QString const & text ) { + updateSuggestionList( text ); + translateBoxSuffix = QString(); +} + +void ScanPopup::updateSuggestionList() +{ + updateSuggestionList( ui.translateBox->translateLine()->text() ); +} + +void ScanPopup::updateSuggestionList( QString const & text ) +{ mainStatusBar->clearMessage(); ui.translateBox->wordList()->setCurrentItem( 0, QItemSelectionModel::Clear ); @@ -791,20 +805,18 @@ void ScanPopup::translateInputFinished() { - inputWord = ui.translateBox->translateLine()->text().trimmed(); - showTranslationFor( inputWord ); + inputPhrase.phrase = Folding::unescapeWildcardSymbols( ui.translateBox->translateLine()->text().trimmed() ); + inputPhrase.punctuationSuffix = translateBoxSuffix; + showTranslationFor( inputPhrase ); } -void ScanPopup::showTranslationFor( QString const & inputWord ) +void ScanPopup::showTranslationFor( Config::InputPhrase const & inputPhrase ) { ui.pronounceButton->hide(); unsigned groupId = ui.groupList->getCurrentGroup(); - definition->showDefinition( inputWord, groupId ); + definition->showDefinition( inputPhrase, groupId ); definition->focus(); - - // Add to history - emit sendWordToHistory( inputWord.trimmed() ); } vector< sptr< Dictionary::Class > > const & ScanPopup::getActiveDicts() @@ -1124,7 +1136,7 @@ void ScanPopup::altModePoll() { - if ( !pendingInputWord.size() ) + if ( !pendingInputPhrase.isValid() ) { altModePollingTimer.stop(); altModeExpirationTimer.stop(); @@ -1135,7 +1147,7 @@ altModePollingTimer.stop(); altModeExpirationTimer.stop(); - inputWord = pendingInputWord; + inputPhrase = pendingInputPhrase; engagePopup( false ); } } @@ -1232,9 +1244,7 @@ void ScanPopup::mutedDictionariesChanged() { - // Update suggestion list - translateInputChanged( ui.translateBox->translateLine()->text() ); - + updateSuggestionList(); if ( dictionaryBar.toggleViewAction()->isChecked() ) definition->updateMutedContents(); } @@ -1248,7 +1258,7 @@ definition->closeSearch(); hideWindow(); } - emit sendWordToMainWindow( definition->getTitle() ); + emit sendPhraseToMainWindow( definition->getPhrase() ); } void ScanPopup::on_sendWordToFavoritesButton_clicked() diff -Nru goldendict-1.5.0~rc2+git20210309/scanpopup.hh goldendict-1.5.0~rc2+git20210630/scanpopup.hh --- goldendict-1.5.0~rc2+git20210309/scanpopup.hh 2019-02-02 00:45:31.000000000 +0000 +++ goldendict-1.5.0~rc2+git20210630/scanpopup.hh 2021-07-02 16:24:28.634230900 +0000 @@ -59,7 +59,7 @@ /// Forwarded from the dictionary bar, so that main window could act on this. void editGroupRequested( unsigned id ); /// Send word to main window - void sendWordToMainWindow( QString const & word ); + void sendPhraseToMainWindow( Config::InputPhrase const & phrase ); /// Close opened menus when window hide void closeMenu(); /// Signals to set expand optional parts mode (retranslation from/to MainWindow and dictionary bar) @@ -133,7 +133,8 @@ ArticleView * definition; QAction escapeAction, switchExpandModeAction, focusTranslateLineAction; QAction openSearchAction; - QString pendingInputWord, inputWord; + Config::InputPhrase pendingInputPhrase, inputPhrase; + QString translateBoxSuffix; ///< A punctuation suffix that corresponds to translateBox's text. WordFinder wordFinder; Config::Events configEvents; DictionaryBar dictionaryBar; @@ -183,7 +184,10 @@ void updateBackForwardButtons(); - void showTranslationFor( QString const & inputWord ); + void showTranslationFor( Config::InputPhrase const & inputPhrase ); + + void updateSuggestionList(); + void updateSuggestionList( QString const & text ); private slots: