From cd57031d449a18cfe56c72cd64d33f900b12ce7c Mon Sep 17 00:00:00 2001 From: Abs62 Date: Thu, 22 Dec 2022 17:57:43 +0300 Subject: [PATCH 01/10] Handle some media links without scheme in offline wikipedia/wiktionary via ArticleNetworkAccessManager --- article_netmgr.cc | 71 ++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/article_netmgr.cc b/article_netmgr.cc index 77602895..f4093903 100644 --- a/article_netmgr.cc +++ b/article_netmgr.cc @@ -238,35 +238,46 @@ QNetworkReply * ArticleNetworkAccessManager::createRequest( Operation op, QNetworkRequest const & req, QIODevice * outgoingData ) { + QNetworkRequest localReq( req ); + + if( localReq.url().scheme() == "gdlookup" && localReq.url().host() == "upload.wikimedia.org" ) + { + // Handle some requests from offline wikipedia/wiktionary without scheme + + QUrl newUrl( req.url() ); + newUrl.setScheme( "https" ); + localReq.setUrl( newUrl ); + } + + if ( op == GetOperation ) { - if ( req.url().scheme() == "qrcx" ) + if ( localReq.url().scheme() == "qrcx" ) { // We have to override the local load policy for the qrc scheme, hence // we use qrcx and redirect it here back to qrc - QUrl newUrl( req.url() ); + QUrl newUrl( localReq.url() ); newUrl.setScheme( "qrc" ); newUrl.setHost( "" ); - QNetworkRequest newReq( req ); - newReq.setUrl( newUrl ); + localReq.setUrl( newUrl ); - return QNetworkAccessManager::createRequest( op, newReq, outgoingData ); + return QNetworkAccessManager::createRequest( op, localReq, outgoingData ); } #if QT_VERSION >= 0x050300 // Qt 5.3+ // Workaround of same-origin policy - if( ( req.url().scheme().startsWith( "http" ) || req.url().scheme() == "ftp" ) - && req.hasRawHeader( "Referer" ) ) + if( ( localReq.url().scheme().startsWith( "http" ) || localReq.url().scheme() == "ftp" ) + && localReq.hasRawHeader( "Referer" ) ) { - QByteArray referer = req.rawHeader( "Referer" ); + QByteArray referer = localReq.rawHeader( "Referer" ); QUrl refererUrl = QUrl::fromEncoded( referer ); if( refererUrl.scheme().startsWith( "http") || refererUrl.scheme() == "ftp" ) { // Only for pages from network resources - if ( !req.url().host().endsWith( refererUrl.host() ) ) + if ( !localReq.url().host().endsWith( refererUrl.host() ) ) { QUrl frameUrl; frameUrl.setScheme( refererUrl.scheme() ); @@ -277,7 +288,7 @@ QNetworkReply * ArticleNetworkAccessManager::createRequest( Operation op, if( !value.origin ) value.setOrigin( frameUrl ); - QPair< QString, QString > target( req.url().scheme(), req.url().host() ); + QPair< QString, QString > target( localReq.url().scheme(), localReq.url().host() ); if( value.hostsToAccess.find( target ) == value.hostsToAccess.end() ) { value.hostsToAccess.insert( target ); @@ -291,68 +302,66 @@ QNetworkReply * ArticleNetworkAccessManager::createRequest( Operation op, QString contentType; - sptr< Dictionary::DataRequest > dr = getResource( req.url(), contentType ); + sptr< Dictionary::DataRequest > dr = getResource( localReq.url(), contentType ); if ( dr.get() ) - return new ArticleResourceReply( this, req, dr, contentType ); + return new ArticleResourceReply( this, localReq, dr, contentType ); } // Check the Referer. If the user has opted-in to block elements from external // pages, we block them. - if ( disallowContentFromOtherSites && req.hasRawHeader( "Referer" ) ) + if ( disallowContentFromOtherSites && localReq.hasRawHeader( "Referer" ) ) { - QByteArray referer = req.rawHeader( "Referer" ); + QByteArray referer = localReq.rawHeader( "Referer" ); //DPRINTF( "Referer: %s\n", referer.data() ); QUrl refererUrl = QUrl::fromEncoded( referer ); - //DPRINTF( "Considering %s vs %s\n", getHostBase( req.url() ).toUtf8().data(), + //DPRINTF( "Considering %s vs %s\n", getHostBase( localReq.url() ).toUtf8().data(), // getHostBase( refererUrl ).toUtf8().data() ); - if ( !req.url().host().endsWith( refererUrl.host() ) && - getHostBase( req.url() ) != getHostBase( refererUrl ) && !req.url().scheme().startsWith("data") ) + if ( !localReq.url().host().endsWith( refererUrl.host() ) && + getHostBase( localReq.url() ) != getHostBase( refererUrl ) && !localReq.url().scheme().startsWith("data") ) { - gdWarning( "Blocking element \"%s\"\n", req.url().toEncoded().data() ); + gdWarning( "Blocking element \"%s\"\n", localReq.url().toEncoded().data() ); return new BlockedNetworkReply( this ); } } - if( req.url().scheme() == "file" ) + if( localReq.url().scheme() == "file" ) { // Check file presence and adjust path if necessary - QString fileName = req.url().toLocalFile(); - if( req.url().host().isEmpty() && articleMaker.adjustFilePath( fileName ) ) + QString fileName = localReq.url().toLocalFile(); + if( localReq.url().host().isEmpty() && articleMaker.adjustFilePath( fileName ) ) { - QUrl newUrl( req.url() ); + QUrl newUrl( localReq.url() ); QUrl localUrl = QUrl::fromLocalFile( fileName ); newUrl.setHost( localUrl.host() ); newUrl.setPath( Qt4x5::Url::ensureLeadingSlash( localUrl.path() ) ); - QNetworkRequest newReq( req ); - newReq.setUrl( newUrl ); + localReq.setUrl( newUrl ); - return QNetworkAccessManager::createRequest( op, newReq, outgoingData ); + return QNetworkAccessManager::createRequest( op, localReq, outgoingData ); } } QNetworkReply *reply = 0; // spoof User-Agent - if ( hideGoldenDictHeader && req.url().scheme().startsWith("http", Qt::CaseInsensitive)) + if ( hideGoldenDictHeader && localReq.url().scheme().startsWith("http", Qt::CaseInsensitive)) { - QNetworkRequest newReq( req ); - newReq.setRawHeader("User-Agent", req.rawHeader("User-Agent").replace(qApp->applicationName(), "")); - reply = QNetworkAccessManager::createRequest( op, newReq, outgoingData ); + localReq.setRawHeader("User-Agent", localReq.rawHeader("User-Agent").replace(qApp->applicationName(), "")); + reply = QNetworkAccessManager::createRequest( op, localReq, outgoingData ); } if( !reply ) - reply = QNetworkAccessManager::createRequest( op, req, outgoingData ); + reply = QNetworkAccessManager::createRequest( op, localReq, outgoingData ); - if( req.url().scheme() == "https") + if( localReq.url().scheme() == "https") { #ifndef QT_NO_OPENSSL connect( reply, SIGNAL( sslErrors( QList< QSslError > ) ), From 79f05a23c8e204295b0378dc025b66ae70b8949f Mon Sep 17 00:00:00 2001 From: Abs62 Date: Thu, 22 Dec 2022 21:40:18 +0300 Subject: [PATCH 02/10] Websites: Fix loading some CSS (from url with query) --- article_netmgr.cc | 3 +-- mainwindow.cc | 12 +++++++++++- qt4x5.hh | 9 +++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/article_netmgr.cc b/article_netmgr.cc index f4093903..687535f9 100644 --- a/article_netmgr.cc +++ b/article_netmgr.cc @@ -249,7 +249,6 @@ QNetworkReply * ArticleNetworkAccessManager::createRequest( Operation op, localReq.setUrl( newUrl ); } - if ( op == GetOperation ) { if ( localReq.url().scheme() == "qrcx" ) @@ -472,7 +471,7 @@ sptr< Dictionary::DataRequest > ArticleNetworkAccessManager::getResource( } try { - return dictionaries[ x ]->getResource( Qt4x5::Url::path( url ).mid( 1 ).toUtf8().data() ); + return dictionaries[ x ]->getResource( Qt4x5::Url::fullPath( url ).mid( 1 ).toUtf8().data() ); } catch( std::exception & e ) { diff --git a/mainwindow.cc b/mainwindow.cc index 2ecc86b1..a016fa9f 100644 --- a/mainwindow.cc +++ b/mainwindow.cc @@ -3584,18 +3584,28 @@ static void filterAndCollectResources( QString & html, QRegExp & rx, const QStri vector< pair< QUrl, QString > > & downloadResources ) { int pos = 0; + int queryNom = 1; while ( ( pos = rx.indexIn( html, pos ) ) != -1 ) { QUrl url( rx.cap( 1 ) ); QString host = url.host(); - QString resourcePath = Qt4x5::Url::path( url ); + QString resourcePath = Qt4x5::Url::fullPath( url ); if ( !host.startsWith( '/' ) ) host.insert( 0, '/' ); if ( !resourcePath.startsWith( '/' ) ) resourcePath.insert( 0, '/' ); + // Replase query part of url (if exist) + int n = resourcePath.indexOf( QLatin1Char( '?' ) ); + if( n >= 0 ) + { + QString q_str = QString( "_q%1" ).arg( queryNom ); + resourcePath.replace( n, resourcePath.length() - n, q_str ); + queryNom += 1; + } + QCryptographicHash hash( QCryptographicHash::Md5 ); hash.addData( rx.cap().toUtf8() ); diff --git a/qt4x5.hh b/qt4x5.hh index fdc6ab44..5aa093fd 100644 --- a/qt4x5.hh +++ b/qt4x5.hh @@ -120,6 +120,15 @@ inline void removeQueryItem( QUrl & url, QString const & key ) #endif } +inline QString fullPath( QUrl const & url ) +{ +#if IS_QT_5 + return url.toString( QUrl::RemoveScheme | QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemovePort | QUrl::FullyDecoded ); +#else + return url.toString( QUrl::RemoveScheme | QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemovePort ); +#endif +} + inline void setQueryItems( QUrl & url, QList< QPair< QString, QString > > const & query ) { #if IS_QT_5 From 3bcd9cfe37dce502ef0aff928484f128b73fbb6e Mon Sep 17 00:00:00 2001 From: Abs62 Date: Thu, 22 Dec 2022 21:41:49 +0300 Subject: [PATCH 03/10] Websites: Fix some redirects --- website.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website.cc b/website.cc index b9952d0a..642b6d4e 100644 --- a/website.cc +++ b/website.cc @@ -200,9 +200,10 @@ void WebSiteArticleRequest::requestFinished( QNetworkReply * r ) QUrl redirectUrl = possibleRedirectUrl.toUrl(); if( !redirectUrl.isEmpty() ) { + QUrl newUrl = netReply->url().resolved( redirectUrl ); disconnect( netReply, 0, 0, 0 ); netReply->deleteLater(); - netReply = mgr.get( QNetworkRequest( redirectUrl ) ); + netReply = mgr.get( QNetworkRequest( newUrl ) ); #ifndef QT_NO_OPENSSL connect( netReply, SIGNAL( sslErrors( QList< QSslError > ) ), netReply, SLOT( ignoreSslErrors() ) ); From 9a5e1e891027e1a347369973ebd79d62b7922c61 Mon Sep 17 00:00:00 2001 From: Abs62 Date: Fri, 23 Dec 2022 01:12:28 +0300 Subject: [PATCH 04/10] Fix links decoding broken by #be22bb --- qt4x5.hh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/qt4x5.hh b/qt4x5.hh index 5aa093fd..8f524c0e 100644 --- a/qt4x5.hh +++ b/qt4x5.hh @@ -123,7 +123,13 @@ inline void removeQueryItem( QUrl & url, QString const & key ) inline QString fullPath( QUrl const & url ) { #if IS_QT_5 - return url.toString( QUrl::RemoveScheme | QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemovePort | QUrl::FullyDecoded ); + QString path = url.path( QUrl::FullyDecoded ); + if( url.hasQuery() ) + { + QUrlQuery urlQuery( url ); + path += QString::fromLatin1( "?" ) + urlQuery.toString( QUrl::FullyDecoded ); + } + return path; #else return url.toString( QUrl::RemoveScheme | QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemovePort ); #endif From 46a34e805cab4cf1456a6bb70e5ee04ae8d06aa6 Mon Sep 17 00:00:00 2001 From: Abs62 Date: Tue, 17 Jan 2023 20:59:13 +0300 Subject: [PATCH 05/10] Zim: One more check for Zim header --- zim.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/zim.cc b/zim.cc index 47d9d3fb..7fca1510 100644 --- a/zim.cc +++ b/zim.cc @@ -63,6 +63,7 @@ using BtreeIndexing::IndexInfo; DEF_EX_STR( exNotZimFile, "Not an Zim file", Dictionary::Ex ) DEF_EX_STR( exCantReadFile, "Can't read file", Dictionary::Ex ) +DEF_EX_STR( exInvalidZimHeader, "Invalid Zim header", Dictionary::Ex ) DEF_EX( exUserAbort, "User abort", Dictionary::Ex ) @@ -288,6 +289,9 @@ bool ZimFile::open() if( read( reinterpret_cast< char * >( &zimHeader ), sizeof( zimHeader ) ) != sizeof( zimHeader ) ) return false; + if( zimHeader.magicNumber != 0x44D495A || zimHeader.mimeListPos != sizeof( zimHeader ) ) + return false; + // Clusters in zim file may be placed in random order. // We create sorted offsets list to calculate clusters size. @@ -1694,11 +1698,15 @@ vector< sptr< Dictionary::Class > > makeDictionaries( df.open(); ZIM_header const & zh = df.header(); - bool new_namespaces = ( zh.majorVersion >= 6 && zh.minorVersion >= 1 ); if( zh.magicNumber != 0x44D495A ) throw exNotZimFile( i->c_str() ); + if( zh.mimeListPos != sizeof( ZIM_header ) ) + throw exInvalidZimHeader( i->c_str() ); + + bool new_namespaces = ( zh.majorVersion >= 6 && zh.minorVersion >= 1 ); + { int n = firstName.lastIndexOf( '/' ); initializing.indexingDictionary( firstName.mid( n + 1 ).toUtf8().constData() ); From 1921771bbdae49cd6905823d438d282059da5999 Mon Sep 17 00:00:00 2001 From: Abs62 Date: Wed, 18 Jan 2023 20:25:03 +0300 Subject: [PATCH 06/10] Remove 0xAD symbol (soft hyphen) for popup window search --- config.cc | 2 +- mouseover.cc | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config.cc b/config.cc index e0e6f1b7..81c5d936 100644 --- a/config.cc +++ b/config.cc @@ -193,7 +193,7 @@ InputPhrase Preferences::sanitizeInputPhrase( QString const & inputPhrase ) cons return result; } - const QString withPunct = inputPhrase.simplified(); + const QString withPunct = inputPhrase.simplified().remove( QChar( 0xAD ) ); // Simplify whitespaces and remove soft hyphens result.phrase = gd::toQString( Folding::trimWhitespaceOrPunct( gd::toWString( withPunct ) ) ); if ( !result.isValid() ) return result; // The suffix of an invalid input phrase must be empty. diff --git a/mouseover.cc b/mouseover.cc index 53c20f7d..3bec10c0 100644 --- a/mouseover.cc +++ b/mouseover.cc @@ -294,7 +294,7 @@ LRESULT CALLBACK MouseOver::eventHandler( HWND hwnd_, UINT msg, return 0; } else - if ( !wordSeq[ wordSeqPos ].isLetterOrNumber() ) + if ( !( wordSeq[ wordSeqPos ].isLetterOrNumber() || wordSeq[ wordSeqPos ] == QChar( 0xAD ) ) ) // Assume soft hyphen as letter { // Special case: the cursor points to something which doesn't look like a // middle of the word -- assume that it's something that joins two words @@ -303,13 +303,13 @@ LRESULT CALLBACK MouseOver::eventHandler( HWND hwnd_, UINT msg, int begin = wordSeqPos; for( ; begin; --begin ) - if ( !wordSeq[ begin - 1 ].isLetterOrNumber() ) + if ( !( wordSeq[ begin - 1 ].isLetterOrNumber() || wordSeq[ begin - 1 ] == QChar( 0xAD ) ) ) break; int end = wordSeqPos; while( ++end < wordSeq.size() ) - if ( !wordSeq[ end ].isLetterOrNumber() ) + if ( !( wordSeq[ end ].isLetterOrNumber() || wordSeq[ end ] == QChar( 0xAD ) ) ) break; if ( end - begin == 1 ) @@ -327,14 +327,14 @@ LRESULT CALLBACK MouseOver::eventHandler( HWND hwnd_, UINT msg, int begin = wordSeqPos; for( ; begin; --begin ) - if ( !wordSeq[ begin - 1 ].isLetterOrNumber() ) + if ( !( wordSeq[ begin - 1 ].isLetterOrNumber() || wordSeq[ begin - 1 ] == QChar( 0xAD ) ) ) break; int end = wordSeqPos; while( ++end < wordSeq.size() ) { - if ( !wordSeq[ end ].isLetterOrNumber() ) + if ( !( wordSeq[ end ].isLetterOrNumber() || wordSeq[ end ] == QChar( 0xAD ) ) ) break; } word = wordSeq.mid( begin, end - begin ); From 661dd4d1403d88ede7d0d7cdf2a9ec936059daef Mon Sep 17 00:00:00 2001 From: Abs62 Date: Thu, 19 Jan 2023 17:57:47 +0300 Subject: [PATCH 07/10] XDXF: Add support for draft revision 034 (issue #1600) --- xdxf.cc | 72 ++++++++++++++++++++++++++++++++++++++++++---------- xdxf.hh | 2 ++ xdxf2html.cc | 31 ++++++++++++++++++++-- 3 files changed, 90 insertions(+), 15 deletions(-) diff --git a/xdxf.cc b/xdxf.cc index b3010c44..141a7407 100644 --- a/xdxf.cc +++ b/xdxf.cc @@ -62,6 +62,22 @@ using BtreeIndexing::WordArticleLink; using BtreeIndexing::IndexedWords; using BtreeIndexing::IndexInfo; +quint32 getLanguageId( const QString & lang ) +{ + QString lstr = lang.left( 3 ); + + if( lstr.endsWith( QChar( '-' ) ) ) + lstr.chop( 1 ); + + switch( lstr.size() ) + { + case 2: return LangCoder::code2toInt( lstr.toLatin1().data() ); + case 3: return LangCoder::findIdForLanguageCode3( lstr.toLatin1().data() ); + } + + return 0; +} + namespace { DEF_EX_STR( exCantReadFile, "Can't read file", Dictionary::Ex ) @@ -72,7 +88,7 @@ DEF_EX_STR( exDictzipError, "DICTZIP error", Dictionary::Ex ) enum { Signature = 0x46584458, // XDXF on little-endian, FXDX on big-endian - CurrentFormatVersion = 5 + BtreeIndexing::FormatVersion + Folding::Version + CurrentFormatVersion = 6 + BtreeIndexing::FormatVersion + Folding::Version }; enum ArticleFormat @@ -1241,25 +1257,19 @@ vector< sptr< Dictionary::Class > > makeDictionaries( // Read the xdxf string str = stream.attributes().value( "lang_from" ).toString().toLatin1().data(); - - if ( str.size() > 3 ) - str.resize( 3 ); - - idxHeader.langFrom = LangCoder::findIdForLanguageCode3( str.c_str() ); + if( !str.empty() ) + idxHeader.langFrom = getLanguageId( str.c_str() ); str = stream.attributes().value( "lang_to" ).toString().toLatin1().data(); - - if ( str.size() > 3 ) - str.resize( 3 ); - - idxHeader.langTo = LangCoder::findIdForLanguageCode3( str.c_str() ); - - bool isLogical = ( stream.attributes().value( "format" ) == "logical" ); + if( !str.empty() ) + idxHeader.langTo = getLanguageId( str.c_str() ); QRegExp regNum( "\\d+" ); regNum.indexIn( stream.attributes().value( "revision" ).toString() ); idxHeader.revisionNumber = regNum.cap().toUInt(); + bool isLogical = ( stream.attributes().value( "format" ) == "logical" || idxHeader.revisionNumber >= 34 ); + idxHeader.articleFormat = isLogical ? Logical : Visual; unsigned articleCount = 0, wordCount = 0; @@ -1302,6 +1312,12 @@ vector< sptr< Dictionary::Class > > makeDictionaries( // todo implement adding other information to the description like , , , , , , , QString desc = readXhtmlData( stream ); + if( isLogical ) + { + desc = desc.simplified(); + desc.replace( QRegExp( "\\s*
" ), QChar( '\n' ) ); + } + if ( dictionaryDescription.isEmpty() ) { dictionaryDescription = desc; @@ -1319,6 +1335,36 @@ vector< sptr< Dictionary::Class > > makeDictionaries( } } else + if( stream.name() == "languages" ) + { + while( !( stream.isEndElement() && stream.name() == "languages" ) && !stream.atEnd() ) + { + if( !stream.readNext() ) + break; + if ( stream.isStartElement() ) + { + if( stream.name() == "from" ) + { + if( idxHeader.langFrom == 0 ) + { + QString lang = stream.attributes().value( "xml:lang" ).toString(); + idxHeader.langFrom = getLanguageId( lang ); + } + } + else if( stream.name() == "to" ) + { + if( idxHeader.langTo == 0 ) + { + QString lang = stream.attributes().value( "xml:lang" ).toString(); + idxHeader.langTo = getLanguageId( lang ); + } + } + } + else if ( stream.isEndElement() && stream.name() == "languages" ) + break; + } + } + else if ( stream.name() == "abbreviations" ) { QString s; diff --git a/xdxf.hh b/xdxf.hh index 880b2b50..e418d190 100644 --- a/xdxf.hh +++ b/xdxf.hh @@ -12,6 +12,8 @@ namespace Xdxf { using std::vector; using std::string; +quint32 getLanguageId( const QString & lang ); + vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & fileNames, string const & indicesDir, diff --git a/xdxf2html.cc b/xdxf2html.cc index 99724256..d2575654 100644 --- a/xdxf2html.cc +++ b/xdxf2html.cc @@ -14,6 +14,7 @@ #include "htmlescape.hh" #include "qt4x5.hh" #include +#include "xdxf.hh" #if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) #include @@ -233,8 +234,20 @@ string convert( string const & in, DICT_TYPE type, map < string, string > const el.setTagName( "div" ); el.setAttribute( "class", "xdxf_headwords" ); - if( dictPtr->isFromLanguageRTL() != dictPtr->isToLanguageRTL() ) - el.setAttribute( "dir", dictPtr->isFromLanguageRTL() ? "rtl" : "ltr" ); + bool isLanguageRtl = dictPtr->isFromLanguageRTL(); + if( el.hasAttribute( "xml:lang" ) ) + { + // Change xml-attribute "xml:lang" to html-attribute "lang" + QString lang = el.attribute( "xml:lang" ); + el.removeAttribute( "xml:lang" ); + el.setAttribute( "lang", lang ); + + quint32 langID = Xdxf::getLanguageId( lang ); + if( langID ) + isLanguageRtl = LangCoder::isLanguageRTL( langID ); + } + if( isLanguageRtl != dictPtr->isToLanguageRTL() ) + el.setAttribute( "dir", isLanguageRtl ? "rtl" : "ltr" ); } } @@ -329,6 +342,20 @@ string convert( string const & in, DICT_TYPE type, map < string, string > const QDomElement el = nodes.at( 0 ).toElement(); el.setTagName( "span" ); el.setAttribute( "class", "xdxf_def" ); + bool isLanguageRtl = dictPtr->isToLanguageRTL(); + if( el.hasAttribute( "xml:lang" ) ) + { + // Change xml-attribute "xml:lang" to html-attribute "lang" + QString lang = el.attribute( "xml:lang" ); + el.removeAttribute( "xml:lang" ); + el.setAttribute( "lang", lang ); + + quint32 langID = Xdxf::getLanguageId( lang ); + if( langID ) + isLanguageRtl = LangCoder::isLanguageRTL( langID ); + } + if( isLanguageRtl != dictPtr->isToLanguageRTL() ) + el.setAttribute( "dir", isLanguageRtl ? "rtl" : "ltr" ); } } From 7e1063f22ed0f8ff9a13284eed1d8279a2f2ad98 Mon Sep 17 00:00:00 2001 From: Abs62 Date: Sat, 4 Feb 2023 18:53:35 +0300 Subject: [PATCH 08/10] DSL: Fix freezes on some incorrect dictionaries --- dsl_details.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dsl_details.cc b/dsl_details.cc index ac0b1d91..f605f5e4 100644 --- a/dsl_details.cc +++ b/dsl_details.cc @@ -1286,6 +1286,13 @@ void processUnsortedParts( wstring & str, bool strip ) void expandOptionalParts( wstring & str, list< wstring > * result, size_t x, bool inside_recurse ) { + if( str.size() > 500 ) + { + // Don't expand too long headwords - it is highly likely incorrect dictionary + result->push_back( str ); + return; + } + list< wstring > expanded; list< wstring > * headwords; headwords = inside_recurse ? result : &expanded; From 62c92fce033307f10d9f70ca4eda8ff7ad86bb53 Mon Sep 17 00:00:00 2001 From: shenleban tongying Date: Sat, 4 Feb 2023 22:22:41 -0500 Subject: [PATCH 09/10] Fix styles of GroupComboBox and translateLine * fix GroupComboBox's drop down arrow isn't centered by correct padding * merge #translateLine of navToolbar and ScanPopup * special boarder handling when using #searchPane --- qt-style.css | 43 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/qt-style.css b/qt-style.css index 4b1c87ff..2be06574 100644 --- a/qt-style.css +++ b/qt-style.css @@ -1,9 +1,6 @@ MainWindow #translateLine, ScanPopup #translateLine, MainWindow #wordList, MainWindow #dictsPane #dictsList, MainWindow #historyPane #historyList, MainWindow #favoritesPane #favoritesTree { } -#translateLine { - color: palette(Text); /* ensure the text is inverse of the background, and also placehold text is grey */ -} #translateLine[noResults="true"] { background: #febb7d; @@ -13,19 +10,27 @@ MainWindow #translateLine, ScanPopup #translateLine, MainWindow #wordList, MainW image: none; } -#navToolbar #translateLine { +#translateLine { + color: palette(Text); /* ensure the text is inverse of the background, and also placehold text is grey */ + margin-left: 0; + padding: 1px 3px 1px 3px; + border: 1px solid gray; + border-left: 0; /* When not in #searchPane the border-left is provided by GroupComboBox */ + border-radius: 3px; - padding: 1px 3px 2px 3px; border-top-left-radius: 0; border-bottom-left-radius: 0; - margin-left: 0; +} + +#searchPane #translateLine { + border: 1px solid gray; + border-radius: 0; } GroupComboBox { margin-right: 0; border: 1px solid gray; - border-right: 1px transparent; border-radius: 3px; border-top-right-radius: 0; border-bottom-right-radius: 0; @@ -35,22 +40,20 @@ GroupComboBox { color: palette(Text); } -GroupComboBox:on { - padding: 3px 3px 1px 5px; +#searchPane GroupComboBox{ + border-radius: 3px; } GroupComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 15px; - border-left: 1px solid darkgray; + border-left: 1px solid gray; border-right: 1px transparent; - /* Hack: For unknown reason, if the padding right is unset, the drop-down won't show full content */ - padding-right: 4px; - border-right: 1px solid darkgray; - /* Hack: end*/ - + /* Hack: Padding must be >= 2px, or the drop-down won't show full content */ + padding-left: 2px; + padding-right: 2px; } GroupComboBox::down-arrow { @@ -79,16 +82,6 @@ MainStatusBar #icon { padding-right: 0; } -ScanPopup #translateLine { - margin: 0; - padding: 1px 3px 1px 3px; - border: 1px solid gray; - border-radius: 3px; - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - - .ScanPopup #outerFrame { border: 1px solid palette(dark); } From 1072adfad9985cd98626d1a9725845aff12648c6 Mon Sep 17 00:00:00 2001 From: Xiao YiFang Date: Sun, 5 Feb 2023 13:45:48 +0800 Subject: [PATCH 10/10] Revert "fix: mdx headword total count is incorrect" This reverts commit 66ec6b6d63926d389c0c618729624523597892de. --- mdx.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mdx.cc b/mdx.cc index 6e372e70..95f5c9c5 100644 --- a/mdx.cc +++ b/mdx.cc @@ -1603,8 +1603,8 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f idxHeader.formatVersion = kCurrentFormatVersion; idxHeader.parserVersion = MdictParser::kParserVersion; idxHeader.foldingVersion = Folding::Version; - idxHeader.articleCount = indexedWords.size(); - idxHeader.wordCount = indexedWords.size(); + idxHeader.articleCount = parser.wordCount(); + idxHeader.wordCount = parser.wordCount(); idx.rewind(); idx.write( &idxHeader, sizeof( idxHeader ) );