diff --git a/.clang-tidy b/.clang-tidy
index 2ef34ab55..6b2fd3721 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -27,6 +27,7 @@ Checks: >
-google-readability-casting,
-hicpp-deprecated-headers,
-misc-const-correctness,
+ -misc-include-cleaner,
-misc-non-private-member-variables-in-classes,
-modernize-avoid-c-arrays,
-modernize-deprecated-headers,
diff --git a/.github/workflows/PR-check-cmake.yml b/.github/workflows/PR-check-cmake.yml
index f2614626b..b42bc7943 100644
--- a/.github/workflows/PR-check-cmake.yml
+++ b/.github/workflows/PR-check-cmake.yml
@@ -45,7 +45,7 @@ jobs:
cmake --build ./build_dir
job_macos_build_check:
name: macos Build and analyze
- runs-on: macos-12
+ runs-on: macos-13
steps:
- uses: actions/checkout@v4
with:
diff --git a/.github/workflows/release-macos-homebrew.yml b/.github/workflows/release-macos-homebrew.yml
index dea137b92..ab6907d2e 100644
--- a/.github/workflows/release-macos-homebrew.yml
+++ b/.github/workflows/release-macos-homebrew.yml
@@ -22,7 +22,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
- os: [macos-12,macos-14]
+ os: [macos-13,macos-14]
qt_ver: [ 6.7.3,6.6.3 ]
qt_arch: [clang_64]
env:
diff --git a/src/config.cc b/src/config.cc
index 045d8130a..c523d83a4 100644
--- a/src/config.cc
+++ b/src/config.cc
@@ -1157,8 +1157,10 @@ Class load()
c.showingDictBarNames = ( root.namedItem( "showingDictBarNames" ).toElement().text() == "1" );
- c.usingToolbarsIconSize =
- ( static_cast< ToolbarsIconSize >( root.namedItem( "usingToolbarsIconSize" ).toElement().text().toInt() ) );
+ QDomNode usingToolbarsIconSize = root.namedItem( "usingToolbarsIconSize" );
+ if ( !usingToolbarsIconSize.isNull() ) {
+ c.usingToolbarsIconSize = static_cast< ToolbarsIconSize >( usingToolbarsIconSize.toElement().text().toInt() );
+ }
if ( !root.namedItem( "historyExportPath" ).isNull() )
c.historyExportPath = root.namedItem( "historyExportPath" ).toElement().text();
@@ -1169,9 +1171,6 @@ Class load()
if ( !root.namedItem( "articleSavePath" ).isNull() )
c.articleSavePath = root.namedItem( "articleSavePath" ).toElement().text();
- if ( !root.namedItem( "editDictionaryCommandLine" ).isNull() )
- c.editDictionaryCommandLine = root.namedItem( "editDictionaryCommandLine" ).toElement().text();
-
if ( !root.namedItem( "maxHeadwordSize" ).isNull() ) {
unsigned int value = root.namedItem( "maxHeadwordSize" ).toElement().text().toUInt();
if ( value != 0 ) // 0 is invalid value for our purposes
@@ -2174,10 +2173,6 @@ void save( Class const & c )
root.appendChild( opt );
}
- opt = dd.createElement( "editDictionaryCommandLine" );
- opt.appendChild( dd.createTextNode( c.editDictionaryCommandLine ) );
- root.appendChild( opt );
-
opt = dd.createElement( "maxHeadwordSize" );
opt.appendChild( dd.createTextNode( QString::number( c.maxHeadwordSize ) ) );
root.appendChild( opt );
diff --git a/src/config.hh b/src/config.hh
index 6c870fb17..2dc1568c4 100644
--- a/src/config.hh
+++ b/src/config.hh
@@ -885,8 +885,6 @@ struct Class
HeadwordsDialog headwordsDialog;
- QString editDictionaryCommandLine; // Command line to call external editor for dictionary
-
Class():
lastMainGroupId( 0 ),
lastPopupGroupId( 0 ),
diff --git a/src/dict/dictdfiles.cc b/src/dict/dictdfiles.cc
index 2199d8a17..b7869dc27 100644
--- a/src/dict/dictdfiles.cc
+++ b/src/dict/dictdfiles.cc
@@ -426,8 +426,7 @@ QString const & DictdDictionary::getDescription()
sptr< Dictionary::DataRequest > req = getArticle( U"00databaseinfo", vector< wstring >(), wstring(), false );
if ( req->dataSize() > 0 ) {
- dictionaryDescription = Html::unescape( QString::fromUtf8( req->getFullData().data(), req->getFullData().size() ),
- Html::HtmlOption::Keep );
+ dictionaryDescription = QString::fromUtf8( req->getFullData().data(), req->getFullData().size() );
}
else {
dictionaryDescription = "NONE";
diff --git a/src/dict/dictionary.cc b/src/dict/dictionary.cc
index 1cd646f87..2e3f6fbd4 100644
--- a/src/dict/dictionary.cc
+++ b/src/dict/dictionary.cc
@@ -516,7 +516,8 @@ string makeDictionaryId( vector< string > const & dictionaryFiles ) noexcept
QCryptographicHash hash( QCryptographicHash::Md5 );
for ( const auto & i : sortedList ) {
- hash.addData( i.c_str(), i.size() + 1 );
+ // Note: a null byte at the end is a must
+ hash.addData( { i.c_str(), static_cast< qsizetype >( i.size() + 1 ) } );
}
return hash.result().toHex().data();
diff --git a/src/dict/dsl_details.cc b/src/dict/dsl_details.cc
index c09eb8e14..3c1976915 100644
--- a/src/dict/dsl_details.cc
+++ b/src/dict/dsl_details.cc
@@ -807,7 +807,7 @@ bool ArticleDom::atSignFirstInLine()
/////////////// DslScanner
DslScanner::DslScanner( string const & fileName ):
- encoding( Utf8::Windows1252 ),
+ encoding( Utf8::Utf8 ),
readBufferPtr( readBuffer ),
readBufferLeft( 0 ),
linesRead( 0 )
@@ -819,11 +819,12 @@ DslScanner::DslScanner( string const & fileName ):
if ( !f )
throw exCantOpen( fileName );
- // Now try guessing the encoding by reading the first two bytes
+ // Now try guessing the encoding
- unsigned char firstBytes[ 50 ];
+ constexpr size_t firstBytesSize = 50;
+ unsigned char firstBytes[ firstBytesSize ];
- if ( gzread( f, firstBytes, sizeof( firstBytes ) ) != sizeof( firstBytes ) ) {
+ if ( gzread( f, firstBytes, firstBytesSize ) != firstBytesSize ) {
// Apparently the file's too short
gzclose( f );
throw exMalformedDslFile( fileName );
@@ -831,37 +832,33 @@ DslScanner::DslScanner( string const & fileName ):
bool needExactEncoding = false;
- QByteArray ba = QByteArray::fromRawData( (const char *)firstBytes, 50 );
- codec = QTextCodec::codecForUtfText( ba, nullptr );
- if ( !codec ) {
- // the encoding has no bom.
- // check the first char # (0x23).
- auto hashTag = 0x0023;
-
- auto uci = qFromUnaligned< uint32_t >( firstBytes );
- if ( uci == qToBigEndian( hashTag ) ) {
- codec = QTextCodec::codecForMib( 1018 ); // utf-32 be
- }
- else if ( uci == qToLittleEndian( hashTag ) ) {
- codec = QTextCodec::codecForMib( 1019 ); // utf-32 le
- }
- else {
- auto uc = qFromUnaligned< uint16_t >( firstBytes );
- if ( uc == qToBigEndian( uint16_t( hashTag ) ) ) {
- codec = QTextCodec::codecForMib( 1013 ); // utf16 be
- }
- else if ( uc == qToLittleEndian( uint16_t( hashTag ) ) ) {
- codec = QTextCodec::codecForMib( 1014 ); // utf16 le
- }
- else {
- //default encoding
- codec = QTextCodec::codecForName( "UTF-8" );
- }
+ // Note that .dsl format always starts with "#NAME"
+ if ( auto guessedEncoding = QStringConverter::encodingForData( { firstBytes, firstBytesSize }, '#' );
+ guessedEncoding.has_value() ) {
+ switch ( guessedEncoding.value() ) {
+ case QStringConverter::Utf8:
+ encoding = Utf8::Utf8;
+ break;
+ case QStringConverter::Utf16LE:
+ encoding = Utf8::Utf16LE;
+ break;
+ case QStringConverter::Utf16BE:
+ encoding = Utf8::Utf16BE;
+ break;
+ case QStringConverter::Utf32LE:
+ encoding = Utf8::Utf16LE;
+ break;
+ case QStringConverter::Utf32BE:
+ encoding = Utf8::Utf32BE;
+ break;
+ default:
+ break;
}
}
- encoding = Utf8::getEncodingForName( codec->name() );
- qDebug() << codec->name();
+ codec = QTextCodec::codecForName( getEncodingNameFor( encoding ) );
+
+ qDebug() << "DSL encoding ->" << codec->name();
if ( gzrewind( f ) ) {
gzclose( f );
diff --git a/src/ui/articleview.cc b/src/ui/articleview.cc
index 45722dce1..0a99ad6f2 100644
--- a/src/ui/articleview.cc
+++ b/src/ui/articleview.cc
@@ -1389,7 +1389,7 @@ void ArticleView::playSound()
return link;})(); )";
webview->page()->runJavaScript( variable, [ this ]( const QVariant & result ) {
- if ( result.type() == QVariant::String ) {
+ if ( result.typeId() == qMetaTypeId< QString >() ) {
QString soundScript = result.toString();
if ( !soundScript.isEmpty() )
openLink( QUrl::fromEncoded( soundScript.toUtf8() ), webview->url() );
diff --git a/src/ui/dictinfo.cc b/src/ui/dictinfo.cc
index 73b06cf63..5b0490522 100644
--- a/src/ui/dictinfo.cc
+++ b/src/ui/dictinfo.cc
@@ -27,9 +27,6 @@ void DictInfo::showInfo( sptr< Dictionary::Class > dict )
ui.dictionaryTranslatesTo->setText( Language::localizedStringForId( dict->getLangTo() ) );
ui.openFolder->setVisible( dict->isLocalDictionary() );
- ui.editDictionary->setVisible( dict->isLocalDictionary() && !dict->getMainFilename().isEmpty()
- && !cfg.editDictionaryCommandLine.isEmpty() );
- ui.editDictionary->setToolTip( tr( "Edit the dictionary via command:\n%1" ).arg( cfg.editDictionaryCommandLine ) );
if ( dict->getWordCount() == 0 )
ui.headwordsButton->setVisible( false );
@@ -63,11 +60,6 @@ void DictInfo::savePos( int )
cfg.dictInfoGeometry = saveGeometry();
}
-void DictInfo::on_editDictionary_clicked()
-{
- done( EDIT_DICTIONARY );
-}
-
void DictInfo::on_openFolder_clicked()
{
done( OPEN_FOLDER );
diff --git a/src/ui/dictinfo.hh b/src/ui/dictinfo.hh
index 74a15b6af..13a7e205e 100644
--- a/src/ui/dictinfo.hh
+++ b/src/ui/dictinfo.hh
@@ -16,7 +16,6 @@ public:
REJECTED,
ACCEPTED,
OPEN_FOLDER,
- EDIT_DICTIONARY,
SHOW_HEADWORDS
};
@@ -28,7 +27,6 @@ private:
Config::Class & cfg;
private slots:
void savePos( int );
- void on_editDictionary_clicked();
void on_openFolder_clicked();
void on_OKButton_clicked();
void on_headwordsButton_clicked();
diff --git a/src/ui/dictinfo.ui b/src/ui/dictinfo.ui
index 1e73f5dd4..d799a6f9b 100644
--- a/src/ui/dictinfo.ui
+++ b/src/ui/dictinfo.ui
@@ -23,16 +23,6 @@
- -
-
-
- true
-
-
- Edit dictionary
-
-
-
-
diff --git a/src/ui/dictionarybar.cc b/src/ui/dictionarybar.cc
index 52bd13d71..1230fada9 100644
--- a/src/ui/dictionarybar.cc
+++ b/src/ui/dictionarybar.cc
@@ -11,12 +11,10 @@ using std::vector;
DictionaryBar::DictionaryBar( QWidget * parent,
Config::Events & events,
- QString const & _editDictionaryCommand,
unsigned short const & maxDictionaryRefsInContextMenu_ ):
QToolBar( tr( "&Dictionary Bar" ), parent ),
mutedDictionaries( nullptr ),
configEvents( events ),
- editDictionaryCommand( _editDictionaryCommand ),
maxDictionaryRefsInContextMenu( maxDictionaryRefsInContextMenu_ )
{
normalIconSize = { this->iconSize().height(), this->iconSize().height() };
@@ -115,7 +113,6 @@ void DictionaryBar::showContextMenu( QContextMenuEvent * event, bool extended )
const QAction * infoAction = nullptr;
const QAction * headwordsAction = nullptr;
- const QAction * editDictAction = nullptr;
const QAction * openDictFolderAction = nullptr;
QString dictFilename;
@@ -138,13 +135,6 @@ void DictionaryBar::showContextMenu( QContextMenuEvent * event, bool extended )
headwordsAction = menu.addAction( tr( "Dictionary headwords" ) );
openDictFolderAction = menu.addAction( tr( "Open dictionary folder" ) );
-
- if ( !editDictionaryCommand.isEmpty() ) {
- if ( !pDict->getMainFilename().isEmpty() ) {
- dictFilename = pDict->getMainFilename();
- editDictAction = menu.addAction( tr( "Edit dictionary" ) );
- }
- }
}
}
}
@@ -201,13 +191,6 @@ void DictionaryBar::showContextMenu( QContextMenuEvent * event, bool extended )
return;
}
- if ( result && result == editDictAction ) {
- QString command( editDictionaryCommand );
- command.replace( "%GDDICT%", QString( R"("%1")" ).arg( dictFilename ) );
- if ( !QProcess::startDetached( command, QStringList() ) )
- QApplication::beep();
- }
-
if ( result && result == maxDictionaryRefsAction ) {
showContextMenu( event, true );
}
diff --git a/src/ui/dictionarybar.hh b/src/ui/dictionarybar.hh
index 8a8ebe4fc..9f38f942b 100644
--- a/src/ui/dictionarybar.hh
+++ b/src/ui/dictionarybar.hh
@@ -18,10 +18,7 @@ class DictionaryBar: public QToolBar
public:
/// Constructs an empty dictionary bar
- DictionaryBar( QWidget * parent,
- Config::Events &,
- QString const & _editDictionaryCommand,
- unsigned short const & maxDictionaryRefsInContextMenu_ );
+ DictionaryBar( QWidget * parent, Config::Events &, unsigned short const & maxDictionaryRefsInContextMenu_ );
/// Sets dictionaries to be displayed in the bar. Their statuses (enabled/
/// disabled) are taken from the configuration data.
@@ -68,7 +65,7 @@ private:
Config::MutedDictionaries storedMutedSet;
bool enterSoloMode = false;
- QString editDictionaryCommand;
+
// how many dictionaries should be shown in the context menu:
unsigned short const & maxDictionaryRefsInContextMenu;
std::vector< sptr< Dictionary::Class > > allDictionaries;
diff --git a/src/ui/mainwindow.cc b/src/ui/mainwindow.cc
index 0ccdc5120..a1639c6e7 100644
--- a/src/ui/mainwindow.cc
+++ b/src/ui/mainwindow.cc
@@ -155,7 +155,7 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
addTab( this ),
cfg( cfg_ ),
history( History::Load(), cfg_.preferences.maxStringsInHistory, cfg_.maxHeadwordSize ),
- dictionaryBar( this, configEvents, cfg.editDictionaryCommandLine, cfg.preferences.maxDictionaryRefsInContextMenu ),
+ dictionaryBar( this, configEvents, cfg.preferences.maxDictionaryRefsInContextMenu ),
articleMaker( dictionaries, groupInstances, cfg.preferences ),
articleNetMgr( this,
dictionaries,
@@ -4021,9 +4021,6 @@ void MainWindow::showDictionaryInfo( const QString & id )
if ( result == DictInfo::OPEN_FOLDER ) {
openDictionaryFolder( id );
}
- else if ( result == DictInfo::EDIT_DICTIONARY ) {
- editDictionary( dictionaries[ x ].get() );
- }
else if ( result == DictInfo::SHOW_HEADWORDS ) {
showDictionaryHeadwords( dictionaries[ x ].get() );
}
@@ -4100,21 +4097,6 @@ void MainWindow::stopAudio()
}
}
-void MainWindow::editDictionary( Dictionary::Class * dict )
-{
- QString dictFilename = dict->getMainFilename();
- if ( !cfg.editDictionaryCommandLine.isEmpty() && !dictFilename.isEmpty() ) {
- QString command( cfg.editDictionaryCommandLine );
- command.replace( "%GDDICT%", "\"" + dictFilename + "\"" );
- if ( command.contains( "%GDWORD%" ) ) {
- QString headword = unescapeTabHeader( ui.tabWidget->tabText( ui.tabWidget->currentIndex() ) );
- command.replace( "%GDWORD%", headword );
- }
- if ( !QProcess::startDetached( command, QStringList() ) )
- QApplication::beep();
- }
-}
-
void MainWindow::openDictionaryFolder( const QString & id )
{
for ( unsigned x = 0; x < dictionaries.size(); x++ ) {
@@ -4161,12 +4143,6 @@ void MainWindow::foundDictsContextMenuRequested( const QPoint & pos )
QAction * openDictFolderAction = menu.addAction( tr( "Open dictionary folder" ) );
- QAction * editAction = nullptr;
-
- QString dictFilename = pDict->getMainFilename();
- if ( !cfg.editDictionaryCommandLine.isEmpty() && !dictFilename.isEmpty() )
- editAction = menu.addAction( tr( "Edit dictionary" ) );
-
QAction * result = menu.exec( ui.dictsList->mapToGlobal( pos ) );
if ( result && result == infoAction ) {
@@ -4186,9 +4162,6 @@ void MainWindow::foundDictsContextMenuRequested( const QPoint & pos )
else if ( result && result == openDictFolderAction ) {
openDictionaryFolder( id );
}
- else if ( result && result == editAction ) {
- editDictionary( pDict );
- }
}
}
}
diff --git a/src/ui/mainwindow.hh b/src/ui/mainwindow.hh
index 4be69adbe..9e6aa2fa8 100644
--- a/src/ui/mainwindow.hh
+++ b/src/ui/mainwindow.hh
@@ -290,8 +290,6 @@ private slots:
void openDictionaryFolder( QString const & id );
- void editDictionary( Dictionary::Class * dict );
-
void showFTSIndexingName( QString const & name );
void handleAddToFavoritesButton();
diff --git a/src/ui/scanpopup.cc b/src/ui/scanpopup.cc
index f88d872cd..cb5158f35 100644
--- a/src/ui/scanpopup.cc
+++ b/src/ui/scanpopup.cc
@@ -80,7 +80,7 @@ ScanPopup::ScanPopup( QWidget * parent,
stopAudioAction( this ),
openSearchAction( this ),
wordFinder( this ),
- dictionaryBar( this, configEvents, cfg.editDictionaryCommandLine, cfg.preferences.maxDictionaryRefsInContextMenu ),
+ dictionaryBar( this, configEvents, cfg.preferences.maxDictionaryRefsInContextMenu ),
hideTimer( this )
{
ui.setupUi( this );