diff --git a/.clang-tidy b/.clang-tidy index ab1e45e00..e8a05ca4c 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -37,6 +37,7 @@ Checks: > -performance-enum-size, -readability-else-after-return, -readability-function-cognitive-complexity, + -readability-use-anyofallof, -readability-identifier-length, -readability-magic-numbers, CheckOptions: diff --git a/src/dict/aard.cc b/src/dict/aard.cc index 50b70aa12..554157ca6 100644 --- a/src/dict/aard.cc +++ b/src/dict/aard.cc @@ -306,10 +306,7 @@ void AardDictionary::loadIcon() noexcept QString fileName = QDir::fromNativeSeparators( QString::fromStdString( getDictionaryFilenames()[ 0 ] ) ); - // Remove the extension - fileName.chop( 3 ); - - if ( !loadIconFromFile( fileName ) ) { + if ( !loadIconFromFileName( fileName ) ) { // Load failed -- use default icons dictionaryIcon = QIcon( ":/icons/icon32_aard.png" ); } diff --git a/src/dict/bgl.cc b/src/dict/bgl.cc index 03457e6bc..b167ccfa4 100644 --- a/src/dict/bgl.cc +++ b/src/dict/bgl.cc @@ -263,10 +263,8 @@ void BglDictionary::loadIcon() noexcept QString fileName = QDir::fromNativeSeparators( QString::fromStdString( getDictionaryFilenames()[ 0 ] ) ); - // Remove the extension - fileName.chop( 3 ); - if ( !loadIconFromFile( fileName ) ) { + if ( !loadIconFromFileName( fileName ) ) { if ( idxHeader.iconSize ) { // Try loading icon now diff --git a/src/dict/dictdfiles.cc b/src/dict/dictdfiles.cc index 85f34138c..57f372639 100644 --- a/src/dict/dictdfiles.cc +++ b/src/dict/dictdfiles.cc @@ -205,10 +205,7 @@ void DictdDictionary::loadIcon() noexcept QString fileName = QDir::fromNativeSeparators( QString::fromStdString( getDictionaryFilenames()[ 0 ] ) ); - // Remove the extension - fileName.chop( 5 ); - - if ( !loadIconFromFile( fileName ) ) { + if ( !loadIconFromFileName( fileName ) ) { // Load failed -- use default icons dictionaryIcon = QIcon( ":/icons/icon32_dictd.png" ); } diff --git a/src/dict/dictionary.cc b/src/dict/dictionary.cc index ad57719c2..49d19236f 100644 --- a/src/dict/dictionary.cc +++ b/src/dict/dictionary.cc @@ -248,48 +248,45 @@ int Class::getOptimalIconSize() return 64 * qGuiApp->devicePixelRatio(); } -bool Class::loadIconFromFile( QString const & _filename, bool isFullName ) -{ - QFileInfo info; - QString fileName( _filename ); - - if ( isFullName ) { - info = QFileInfo( fileName ); - } - else { - fileName += "bmp"; - info = QFileInfo( fileName ); - if ( !info.isFile() ) { - fileName.chop( 3 ); - fileName += "png"; - info = QFileInfo( fileName ); - } - if ( !info.isFile() ) { - fileName.chop( 3 ); - fileName += "jpg"; - info = QFileInfo( fileName ); - } - if ( !info.isFile() ) { - fileName.chop( 3 ); - fileName += "ico"; - info = QFileInfo( fileName ); +bool Class::loadIconFromFileName( QString const & mainDictFileName ) +{ + const QFileInfo info( mainDictFileName ); + const QString basename = info.baseName(); + QDir dir = info.absoluteDir(); + + dir.setFilter( QDir::Files ); + dir.setNameFilters( QStringList() << basename + ".bmp" // + << basename + ".png" // + << basename + ".jpg" // + << basename + ".ico" // below are GD-ng only + << basename + ".jpeg" // + << basename + ".gif" // + << basename + ".webp" // + << basename + ".svgz" // + << basename + ".svg" ); + + for ( const auto & f : dir.entryInfoList() ) { + if ( loadIconFromFilePath( f.absoluteFilePath() ) ) { + return true; } } + return false; +} - if ( info.isFile() ) { - auto iconSize = getOptimalIconSize(); - QPixmap img( fileName ); - - if ( !img.isNull() ) { - // Load successful +bool Class::loadIconFromFilePath( QString const & filename ) +{ + auto iconSize = getOptimalIconSize(); + QImage img( filename ); - auto result = img.scaled( { iconSize, iconSize }, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation ); - dictionaryIcon = QIcon( result ); + if ( img.isNull() ) { + return false; + } + else { + auto result = img.scaled( { iconSize, iconSize }, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation ); + dictionaryIcon = QIcon( QPixmap::fromImage( result ) ); - return !dictionaryIcon.isNull(); - } + return !dictionaryIcon.isNull(); } - return false; } bool Class::loadIconFromText( const QString & iconUrl, QString const & text ) diff --git a/src/dict/dictionary.hh b/src/dict/dictionary.hh index 71e13eb1b..dad101c8c 100644 --- a/src/dict/dictionary.hh +++ b/src/dict/dictionary.hh @@ -315,9 +315,11 @@ protected: static int getOptimalIconSize(); - // Load icon from filename directly if isFullName == true - // else treat filename as name without extension - bool loadIconFromFile( QString const & filename, bool isFullName = false ); + /// Try load icon based on the main dict file name + bool loadIconFromFileName( QString const & mainDictFileName ); + /// Load an icon using a full image file path + bool loadIconFromFilePath( QString const & filename ); + /// Generate icon based on a text bool loadIconFromText( const QString & iconUrl, QString const & text ); static QString getAbbrName( QString const & text ); diff --git a/src/dict/dictserver.cc b/src/dict/dictserver.cc index a38976c28..f241111f1 100644 --- a/src/dict/dictserver.cc +++ b/src/dict/dictserver.cc @@ -351,7 +351,7 @@ void DictServerDictionary::loadIcon() noexcept if ( !icon.isEmpty() ) { QFileInfo fInfo( QDir( Config::getConfigDir() ), icon ); if ( fInfo.isFile() ) { - loadIconFromFile( fInfo.absoluteFilePath(), true ); + loadIconFromFilePath( fInfo.absoluteFilePath() ); } } if ( dictionaryIcon.isNull() ) { diff --git a/src/dict/dsl.cc b/src/dict/dsl.cc index 114bf946f..798dee931 100644 --- a/src/dict/dsl.cc +++ b/src/dict/dsl.cc @@ -435,7 +435,7 @@ void DslDictionary::loadIcon() noexcept fileName.chop( 3 ); } - if ( !loadIconFromFile( fileName ) ) { + if ( !loadIconFromFileName( fileName ) ) { // Load failed -- use default icons dictionaryIcon = QIcon( ":/icons/icon32_dsl.png" ); } diff --git a/src/dict/epwing.cc b/src/dict/epwing.cc index f70f85148..23ba84d7b 100644 --- a/src/dict/epwing.cc +++ b/src/dict/epwing.cc @@ -235,11 +235,11 @@ void EpwingDictionary::loadIcon() noexcept if ( dictionaryIconLoaded ) return; - QString fileName = QString::fromStdString( getDictionaryFilenames()[ 0 ] ) + QDir::separator() - + eBook.getCurrentSubBookDirectory() + "."; + QString fileName = + QString::fromStdString( getDictionaryFilenames()[ 0 ] ) + QDir::separator() + eBook.getCurrentSubBookDirectory(); if ( !fileName.isEmpty() ) - loadIconFromFile( fileName ); + loadIconFromFileName( fileName ); if ( dictionaryIcon.isNull() ) { // Load failed -- use default icons diff --git a/src/dict/gls.cc b/src/dict/gls.cc index df26e7c34..b19cc0531 100644 --- a/src/dict/gls.cc +++ b/src/dict/gls.cc @@ -476,15 +476,7 @@ void GlsDictionary::loadIcon() noexcept QString fileName = QDir::fromNativeSeparators( getDictionaryFilenames()[ 0 ].c_str() ); - // Remove the extension - if ( fileName.endsWith( ".gls.dz", Qt::CaseInsensitive ) ) { - fileName.chop( 6 ); - } - else { - fileName.chop( 3 ); - } - - if ( !loadIconFromFile( fileName ) ) { + if ( !loadIconFromFileName( fileName ) ) { // Load failed -- use default icon dictionaryIcon = QIcon( ":/icons/icon32_gls.png" ); } diff --git a/src/dict/hunspell.cc b/src/dict/hunspell.cc index 7f8a183a1..36093265d 100644 --- a/src/dict/hunspell.cc +++ b/src/dict/hunspell.cc @@ -127,10 +127,7 @@ void HunspellDictionary::loadIcon() noexcept QString fileName = QDir::fromNativeSeparators( getDictionaryFilenames()[ 0 ].c_str() ); - // Remove the extension - fileName.chop( 3 ); - - if ( !loadIconFromFile( fileName ) ) { + if ( !loadIconFromFileName( fileName ) ) { // Load failed -- use default icons dictionaryIcon = QIcon( ":/icons/icon32_hunspell.png" ); } diff --git a/src/dict/lsa.cc b/src/dict/lsa.cc index fb9f2b39c..da717ac07 100644 --- a/src/dict/lsa.cc +++ b/src/dict/lsa.cc @@ -488,10 +488,7 @@ void LsaDictionary::loadIcon() noexcept QString fileName = QDir::fromNativeSeparators( getDictionaryFilenames()[ 0 ].c_str() ); - // Remove the extension - fileName.chop( 3 ); - - if ( !loadIconFromFile( fileName ) ) { + if ( !loadIconFromFileName( fileName ) ) { // Load failed -- use default icons dictionaryIcon = QIcon( ":/icons/lsasound.png" ); } diff --git a/src/dict/mdx.cc b/src/dict/mdx.cc index 530ef2b1a..02fe57de8 100644 --- a/src/dict/mdx.cc +++ b/src/dict/mdx.cc @@ -816,11 +816,9 @@ void MdxDictionary::loadIcon() noexcept QString fileName = QDir::fromNativeSeparators( getDictionaryFilenames()[ 0 ].c_str() ); - // Remove the extension - fileName.chop( 3 ); QString text = QString::fromStdString( dictionaryName ); - if ( !loadIconFromFile( fileName ) && !loadIconFromText( ":/icons/mdict-bg.png", text ) ) { + if ( !loadIconFromFileName( fileName ) && !loadIconFromText( ":/icons/mdict-bg.png", text ) ) { // Use default icons dictionaryIcon = QIcon( ":/icons/mdict.png" ); } diff --git a/src/dict/mediawiki.cc b/src/dict/mediawiki.cc index 5f8b64b0f..671c267bf 100644 --- a/src/dict/mediawiki.cc +++ b/src/dict/mediawiki.cc @@ -113,7 +113,7 @@ void MediaWikiDictionary::loadIcon() noexcept if ( !icon.isEmpty() ) { QFileInfo fInfo( QDir( Config::getConfigDir() ), icon ); if ( fInfo.isFile() ) { - loadIconFromFile( fInfo.absoluteFilePath(), true ); + loadIconFromFilePath( fInfo.absoluteFilePath() ); } } if ( dictionaryIcon.isNull() ) { diff --git a/src/dict/programs.cc b/src/dict/programs.cc index 38980b851..4abb4e2f3 100644 --- a/src/dict/programs.cc +++ b/src/dict/programs.cc @@ -121,7 +121,7 @@ void ProgramsDictionary::loadIcon() noexcept if ( !prg.iconFilename.isEmpty() ) { QFileInfo fInfo( QDir( Config::getConfigDir() ), prg.iconFilename ); if ( fInfo.isFile() ) { - loadIconFromFile( fInfo.absoluteFilePath(), true ); + loadIconFromFilePath( fInfo.absoluteFilePath() ); } } if ( dictionaryIcon.isNull() ) { diff --git a/src/dict/sdict.cc b/src/dict/sdict.cc index 3be85a32c..1fd594e07 100644 --- a/src/dict/sdict.cc +++ b/src/dict/sdict.cc @@ -205,10 +205,7 @@ void SdictDictionary::loadIcon() noexcept QString fileName = QDir::fromNativeSeparators( getDictionaryFilenames()[ 0 ].c_str() ); - // Remove the extension - fileName.chop( 3 ); - - if ( !loadIconFromFile( fileName ) ) { + if ( !loadIconFromFileName( fileName ) ) { // Load failed -- use default icons dictionaryIcon = QIcon( ":/icons/icon32_sdict.png" ); } diff --git a/src/dict/slob.cc b/src/dict/slob.cc index 6f7102ab8..613b4fd4d 100644 --- a/src/dict/slob.cc +++ b/src/dict/slob.cc @@ -721,10 +721,8 @@ void SlobDictionary::loadIcon() noexcept QString fileName = QDir::fromNativeSeparators( getDictionaryFilenames()[ 0 ].c_str() ); - // Remove the extension - fileName.chop( 4 ); - if ( !loadIconFromFile( fileName ) ) { + if ( !loadIconFromFileName( fileName ) ) { // Load failed -- use default icons dictionaryIcon = QIcon( ":/icons/icon32_slob.png" ); } diff --git a/src/dict/sounddir.cc b/src/dict/sounddir.cc index 6f66320ed..e7ba66982 100644 --- a/src/dict/sounddir.cc +++ b/src/dict/sounddir.cc @@ -292,7 +292,7 @@ void SoundDirDictionary::loadIcon() noexcept if ( !iconFilename.isEmpty() ) { const QFileInfo fInfo( QDir( Config::getConfigDir() ), iconFilename ); if ( fInfo.isFile() ) { - loadIconFromFile( fInfo.absoluteFilePath(), true ); + loadIconFromFilePath( fInfo.absoluteFilePath() ); } } if ( dictionaryIcon.isNull() ) { diff --git a/src/dict/stardict.cc b/src/dict/stardict.cc index c1cdf131b..71ed6a14c 100644 --- a/src/dict/stardict.cc +++ b/src/dict/stardict.cc @@ -266,10 +266,7 @@ void StardictDictionary::loadIcon() noexcept QString fileName = QDir::fromNativeSeparators( getDictionaryFilenames()[ 0 ].c_str() ); - // Remove the extension - fileName.chop( 3 ); - - if ( !loadIconFromFile( fileName ) ) { + if ( !loadIconFromFileName( fileName ) ) { // Load failed -- use default icons dictionaryIcon = QIcon( ":/icons/icon32_stardict.png" ); } diff --git a/src/dict/voiceengines.cc b/src/dict/voiceengines.cc index 71b36bf08..c00a9682e 100644 --- a/src/dict/voiceengines.cc +++ b/src/dict/voiceengines.cc @@ -115,7 +115,7 @@ void VoiceEnginesDictionary::loadIcon() noexcept if ( !voiceEngine.iconFilename.isEmpty() ) { QFileInfo fInfo( QDir( Config::getConfigDir() ), voiceEngine.iconFilename ); if ( fInfo.isFile() ) - loadIconFromFile( fInfo.absoluteFilePath(), true ); + loadIconFromFilePath( fInfo.absoluteFilePath() ); } if ( dictionaryIcon.isNull() ) dictionaryIcon = QIcon( ":/icons/text2speech.svg" ); diff --git a/src/dict/website.cc b/src/dict/website.cc index abadad1bd..8b776e663 100644 --- a/src/dict/website.cc +++ b/src/dict/website.cc @@ -459,7 +459,7 @@ void WebSiteDictionary::loadIcon() noexcept if ( !iconFilename.isEmpty() ) { QFileInfo fInfo( QDir( Config::getConfigDir() ), iconFilename ); if ( fInfo.isFile() ) { - loadIconFromFile( fInfo.absoluteFilePath(), true ); + loadIconFromFilePath( fInfo.absoluteFilePath() ); } } if ( dictionaryIcon.isNull() diff --git a/src/dict/xdxf.cc b/src/dict/xdxf.cc index 69fb88518..8b150dc24 100644 --- a/src/dict/xdxf.cc +++ b/src/dict/xdxf.cc @@ -313,7 +313,11 @@ void XdxfDictionary::loadIcon() noexcept } if ( info.isFile() ) { - loadIconFromFile( fileName, true ); + loadIconFromFilePath( fileName ); + } + + if ( dictionaryIcon.isNull() ) { + loadIconFromFileName( fileName ); } if ( dictionaryIcon.isNull() ) { diff --git a/src/dict/zim.cc b/src/dict/zim.cc index e25f4f76f..59300fafb 100644 --- a/src/dict/zim.cc +++ b/src/dict/zim.cc @@ -252,9 +252,8 @@ void ZimDictionary::loadIcon() noexcept // Try to load Original GD's user provided icon QString fileName = QDir::fromNativeSeparators( getDictionaryFilenames()[ 0 ].c_str() ); - // Remove the extension - fileName.chop( 3 ); - if ( loadIconFromFile( fileName ) ) { + + if ( loadIconFromFileName( fileName ) ) { dictionaryIconLoaded = true; return; } diff --git a/src/dict/zipsounds.cc b/src/dict/zipsounds.cc index 946be049b..5c2b8a3fb 100644 --- a/src/dict/zipsounds.cc +++ b/src/dict/zipsounds.cc @@ -363,10 +363,7 @@ void ZipSoundsDictionary::loadIcon() noexcept QString fileName = QDir::fromNativeSeparators( getDictionaryFilenames()[ 0 ].c_str() ); - // Remove the extension - fileName.chop( 4 ); - - if ( !loadIconFromFile( fileName ) ) { + if ( !loadIconFromFileName( fileName ) ) { // Load failed -- use default icons dictionaryIcon = QIcon( ":/icons/zipsound.svg" ); } diff --git a/website/docs/dictformats.md b/website/docs/dictformats.md index b833554b4..95a621125 100644 --- a/website/docs/dictformats.md +++ b/website/docs/dictformats.md @@ -38,17 +38,23 @@ GoldenDict-ng does not provide any dictionary modification functionality. To convert between formats, try tools like [pyglossary](https://github.com/ilius/pyglossary). -### Individual Dictionary Icons +### Custom Dictionary Icon -Every local dictionary can have individual icon. BMP, PNG, JPG or ICO files can be used for this icon. +Every local dictionary can have a custom icon. +Supported formats are PNG, JPEG, GIF, SVG, WebP, ICO and BMP. -For Babylon, StarDict, DictD, ABBYY Lingvo, AardDictionary, SDictionary, Zim, MDict, Lsa, Zips, Slob, Gls dictionaries such graphics file must be named by main dictionary file name and places beside one. That is if main file of your dictionary, for example, named "My_best_dictionary.dsl" therefore icon file must be named "My_best_dictionary.bmp" (.png, .jpg etc.). +For most dictionary formats, a dictionary's icon file should have the same basename as the main dictionary file and be placed beside the main dictionary file. For example: -For XDXF dictionaries, the icon file must be named "icon16.png" (for 16х16 images) or "icon32.png" (for 32х32 images) or "dict.bmp" and placed into the dictionary folder. +``` +. +├── My_best_dictionary.mdx <- the main dictionary file +└── My_best_dictionary.svg <- the icon +``` -For Epwing dictionaries icon file must be named by name of folder with dictionary data beside "catalogs" file (a few folders can be presented, every folder is separate dictionary) and placed beside "catalogs" file. +For XDXF, GD will prioritize to use `icon16.png`, `icon32.png` or `dict.bmp` in the dictionary folder as icon. + +For Epwing, the icon file should be placed beside the `catalogs` file and have the same name as the parent folder that contains `catalogs` file. -If individual icon is not presented the default icon for this type of dictionaries will be used. ### Stardict