Compare commits

...

19 commits

Author SHA1 Message Date
xiaoyifang a51b590f86
Merge 3c5233f2a1 into fa9ad2fdf7 2024-11-20 00:14:54 -08:00
shenleban tongying fa9ad2fdf7
clean: delete useless fopen style mode char* API from File::Index
Some checks are pending
SonarCloud / Build and analyze (push) Waiting to run
2024-11-20 03:56:23 +00:00
shenleban tongying 8f42e2e073
refactor: port StarDict -> Ifo away from File::Index 2024-11-19 22:39:36 -05:00
shenleban tongying c892083b00
fix: stardict format's description HTML display (.ifo file) 2024-11-20 02:30:17 +00:00
atauzki 2d6e2a85ee
feat: Windows, use Fusion only when dark mode applied
Some checks are pending
SonarCloud / Build and analyze (push) Waiting to run
2024-11-19 12:41:13 +00:00
shenleban tongying 1fa0771716
fix: local audio files without extension are not added to dictAudioMap
Some checks are pending
SonarCloud / Build and analyze (push) Waiting to run
2024-11-19 02:35:15 +00:00
shenleban tongying bb87c55b1a
fix: manually deploy icu4c dylibs for macOS
Some checks are pending
SonarCloud / Build and analyze (push) Waiting to run
2024-11-18 09:43:19 +00:00
shenleban tongying 652da8e1ec
action: update brew before running macOS workflows
Some checks are pending
SonarCloud / Build and analyze (push) Waiting to run
2024-11-18 03:07:37 +00:00
xiaoyifang 3c5233f2a1 1 2024-11-11 09:19:29 +08:00
YiFang Xiao c5ca1b7d63 1 2024-11-11 09:16:14 +08:00
YiFang Xiao 5092ebe2ee 1 2024-11-11 09:16:14 +08:00
YiFang Xiao 5bef4cef22 1 2024-11-11 09:16:14 +08:00
xiaoyifang 59d01868da 1: do not update name 2024-11-11 09:16:14 +08:00
xiaoyifang 10b0496cce 1: do not update name 2024-11-11 09:16:14 +08:00
xiaoyifang 1cf495e7dd Revert "opt: update name should reflect the latest info"
This reverts commit 1272ea2d20a7908b9a69d6b551511916f97cc024.
2024-11-11 09:16:14 +08:00
xiaoyifang c2fc90801b opt: update name should reflect the latest info 2024-11-11 09:16:14 +08:00
autofix-ci[bot] 2de2141758 [autofix.ci] apply automated fixes 2024-11-11 09:16:14 +08:00
xiaoyifang db4c352d6c opt: erase the need to removeTabs 2024-11-11 09:16:14 +08:00
xiaoyifang 7c32cad65a opt: erase the need to removeTabs 2024-11-11 09:16:14 +08:00
32 changed files with 193 additions and 200 deletions

View file

@ -51,6 +51,9 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: false submodules: false
- name: Update brew
run: |
brew update
- name: Install dependencies - name: Install dependencies
run: | run: |
brew install \ brew install \
@ -66,11 +69,11 @@ jobs:
xapian \ xapian \
libzim \ libzim \
qt qt
- name: Install eb
run: |
wget https://github.com/mistydemeo/eb/releases/download/v4.4.3/eb-4.4.3.tar.bz2 wget https://github.com/mistydemeo/eb/releases/download/v4.4.3/eb-4.4.3.tar.bz2
tar xvjf eb-4.4.3.tar.bz2 tar xvjf eb-4.4.3.tar.bz2
cd eb-4.4.3 && ./configure && make -j 8 && sudo make install && cd .. cd eb-4.4.3 && ./configure && make -j 8 && sudo make install && cd ..
- name: Run build - name: Run build
run: | run: |
mkdir build_dir mkdir build_dir

View file

@ -26,6 +26,9 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- name: Update brew
run: |
brew update
- name: Install dependencies - name: Install dependencies
run: | run: |
brew install \ brew install \
@ -40,7 +43,8 @@ jobs:
ninja \ ninja \
opencc \ opencc \
xapian xapian
- name: Install eb
run: |
git clone https://github.com/xiaoyifang/eb.git git clone https://github.com/xiaoyifang/eb.git
cd eb && ./configure && make -j 8 && sudo make install && cd .. cd eb && ./configure && make -j 8 && sudo make install && cd ..
- uses: jurplel/install-qt-action@v4 - uses: jurplel/install-qt-action@v4
@ -61,6 +65,9 @@ jobs:
- name: Package - name: Package
run: | run: |
cmake --install build_dir/ cmake --install build_dir/
- name: Print package content
run: |
ls -Rl ./build_dir/redist
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: macOS-${{ matrix.os }}-Qt${{ matrix.qt_ver }} name: macOS-${{ matrix.os }}-Qt${{ matrix.qt_ver }}

View file

@ -284,6 +284,7 @@ if (APPLE)
set(QT_DEPLOY_TRANSLATIONS_DIR \"Contents/Resources/translations\") set(QT_DEPLOY_TRANSLATIONS_DIR \"Contents/Resources/translations\")
qt_deploy_runtime_dependencies( qt_deploy_runtime_dependencies(
EXECUTABLE \"${Redistributable_APP}\" EXECUTABLE \"${Redistributable_APP}\"
ADDITIONAL_LIBRARIES ${BREW_ICU_ADDITIONAL_DYLIBS}
GENERATE_QT_CONF GENERATE_QT_CONF
NO_APP_STORE_COMPLIANCE) NO_APP_STORE_COMPLIANCE)
qt_deploy_translations() qt_deploy_translations()

View file

@ -79,30 +79,25 @@ endif ()
if (WITH_ZIM) if (WITH_ZIM)
if (APPLE) if (APPLE)
# ICU from homebrew is "key-only", we need to manually prioritize it -> see `brew info icu4c` # ICU from homebrew is "key-only", we need to manually prioritize it -> see `brew info icu4c`
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/opt/icu4c@76/lib/pkgconfig:/opt/homebrew/opt/icu4c@76/lib/pkgconfig:/usr/local/opt/icu4c/lib/pkgconfig:/opt/homebrew/opt/icu4c/lib/pkgconfig") # And we needs to find the correct one if multiple versions co exists.
set(ENV{PATH} "$ENV{PATH}:/usr/local/bin/:/opt/homebrew/bin") # add brew command into PATH
execute_process(
COMMAND sh -c [=[brew --prefix $(brew deps libzim | grep icu4c)]=]
OUTPUT_VARIABLE ICU_REQUIRED_BY_ZIM_PREFIX
OUTPUT_STRIP_TRAILING_WHITESPACE
COMMAND_ERROR_IS_FATAL ANY)
message(STATUS "Found correct homebrew icu path -> ${ICU_REQUIRED_BY_ZIM_PREFIX}")
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${ICU_REQUIRED_BY_ZIM_PREFIX}/lib/pkgconfig")
message(STATUS "Updated pkg_config_path -> $ENV{PKG_CONFIG_PATH}:${ICU_REQUIRED_BY_ZIM_PREFIX}/lib/pkgconfig")
# icu4c as transitive dependency of libzim may not be automatically copied into app bundle
# so we manually discover the icu4c from homebrew, then find the relevent dylibs
set(BREW_ICU_ADDITIONAL_DYLIBS "${ICU_REQUIRED_BY_ZIM_PREFIX}/lib/libicudata.dylib ${ICU_REQUIRED_BY_ZIM_PREFIX}/lib/libicui18n.dylib ${ICU_REQUIRED_BY_ZIM_PREFIX}/lib/libicuuc.dylib")
message(STATUS "Additional ICU `.dylib`s -> ${BREW_ICU_ADDITIONAL_DYLIBS}")
endif () endif ()
pkg_check_modules(ZIM REQUIRED IMPORTED_TARGET libzim) pkg_check_modules(ZIM REQUIRED IMPORTED_TARGET libzim)
target_link_libraries(${GOLDENDICT} PRIVATE PkgConfig::ZIM) target_link_libraries(${GOLDENDICT} PRIVATE PkgConfig::ZIM)
if (APPLE)
# icu4c as transitive dependency of libzim may not be copied into app bundle, so we directly depends on it to assist macdeployqt
# Why such complexities: 1) System or XCode SDKS's icu exists 2) icu itself is depended by various stuffs and homebrew may need multiple versions of it
pkg_check_modules(BREW_ICU REQUIRED IMPORTED_TARGET icu-i18n icu-uc)
target_link_libraries(${GOLDENDICT} PUBLIC PkgConfig::BREW_ICU)
# Verify icu <-> zim matches
message("Zim include dirs -> ${ZIM_INCLUDE_DIRS}")
message("Homebrew icu include dirs-> ${BREW_ICU_INCLUDE_DIRS}")
list(GET BREW_ICU_INCLUDE_DIRS 0 ONE_OF_BREW_ICU_INCLUDE_DIR)
if (ONE_OF_BREW_ICU_INCLUDE_DIR IN_LIST ZIM_INCLUDE_DIRS)
message("ZIM OK!")
else ()
message(FATAL_ERROR "!!!! ZIM <-> icu error -> check `brew info libzim` and `brew list libzim`")
endif ()
# TODO: get rid of these 💩, how?
endif ()
endif () endif ()
if (USE_SYSTEM_FMT) if (USE_SYSTEM_FMT)

View file

@ -257,9 +257,14 @@ inline bool isAudioUrl( QUrl const & url )
{ {
if ( !url.isValid() ) if ( !url.isValid() )
return false; return false;
// Note: we check for forvo sound links explicitly, as they don't have extensions
return ( url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "gdau" ) // gdau links are known to be audios, (sometimes they may not have file extension).
if ( url.scheme() == "gdau" ) {
return true;
}
// Note: we check for forvo sound links explicitly, as they don't have extensions
return ( url.scheme() == "http" || url.scheme() == "https" )
&& ( Filetype::isNameOfSound( url.path().toUtf8().data() ) || url.host() == "apifree.forvo.com" ); && ( Filetype::isNameOfSound( url.path().toUtf8().data() ) || url.host() == "apifree.forvo.com" );
} }

View file

@ -103,7 +103,7 @@ static_assert( alignof( IdxHeader ) == 1 );
bool indexIsOldOrBad( string const & indexFile ) bool indexIsOldOrBad( string const & indexFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -287,10 +287,10 @@ private:
AardDictionary::AardDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ): AardDictionary::AardDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ), idxHeader( idx.read< IdxHeader >() ),
chunks( idx, idxHeader.chunksOffset ), chunks( idx, idxHeader.chunksOffset ),
df( dictionaryFiles[ 0 ], "rb" ) df( dictionaryFiles[ 0 ], QIODevice::ReadOnly )
{ {
// Read dictionary name // Read dictionary name
@ -802,7 +802,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
} }
} }
File::Index df( fileName, "rb" ); File::Index df( fileName, QIODevice::ReadOnly );
AAR_header dictHeader; AAR_header dictHeader;
@ -871,7 +871,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
initializing.indexingDictionary( dictName ); initializing.indexingDictionary( dictName );
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;
memset( &idxHeader, 0, sizeof( idxHeader ) ); memset( &idxHeader, 0, sizeof( idxHeader ) );

View file

@ -85,7 +85,7 @@ static_assert( alignof( IdxHeader ) == 1 );
bool indexIsOldOrBad( string const & indexFile ) bool indexIsOldOrBad( string const & indexFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -250,7 +250,7 @@ private:
BglDictionary::BglDictionary( string const & id, string const & indexFile, string const & dictionaryFile ): BglDictionary::BglDictionary( string const & id, string const & indexFile, string const & dictionaryFile ):
BtreeDictionary( id, vector< string >( 1, dictionaryFile ) ), BtreeDictionary( id, vector< string >( 1, dictionaryFile ) ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ), idxHeader( idx.read< IdxHeader >() ),
chunks( idx, idxHeader.chunksOffset ) chunks( idx, idxHeader.chunksOffset )
{ {
@ -1083,7 +1083,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
initializing.indexingDictionary( b.title() ); initializing.indexingDictionary( b.title() );
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;

View file

@ -74,7 +74,7 @@ static_assert( alignof( IdxHeader ) == 1 );
bool indexIsOldOrBad( string const & indexFile ) bool indexIsOldOrBad( string const & indexFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -155,8 +155,8 @@ DictdDictionary::DictdDictionary( string const & id,
string const & indexFile, string const & indexFile,
vector< string > const & dictionaryFiles ): vector< string > const & dictionaryFiles ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
indexFile( dictionaryFiles[ 0 ], "rb" ), indexFile( dictionaryFiles[ 0 ], QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ) idxHeader( idx.read< IdxHeader >() )
{ {
@ -606,7 +606,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
initializing.indexingDictionary( dictionaryName ); initializing.indexingDictionary( dictionaryName );
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;
@ -619,7 +619,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
IndexedWords indexedWords; IndexedWords indexedWords;
File::Index indexFile( dictFiles[ 0 ], "rb" ); File::Index indexFile( dictFiles[ 0 ], QIODevice::ReadOnly );
// Read words from index until none's left. // Read words from index until none's left.

View file

@ -132,7 +132,7 @@ struct InsidedCard
bool indexIsOldOrBad( string const & indexFile, bool hasZipFile ) bool indexIsOldOrBad( string const & indexFile, bool hasZipFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -289,7 +289,7 @@ private:
DslDictionary::DslDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ): DslDictionary::DslDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ), idxHeader( idx.read< IdxHeader >() ),
dz( 0 ), dz( 0 ),
deferredInitRunnableStarted( false ), deferredInitRunnableStarted( false ),
@ -1807,7 +1807,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
gdDebug( "Dsl: Building the index for dictionary: %s\n", gdDebug( "Dsl: Building the index for dictionary: %s\n",
QString::fromStdU32String( scanner.getDictionaryName() ).toUtf8().data() ); QString::fromStdU32String( scanner.getDictionaryName() ).toUtf8().data() );
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;

View file

@ -66,7 +66,7 @@ static_assert( alignof( IdxHeader ) == 1 );
bool indexIsOldOrBad( string const & indexFile ) bool indexIsOldOrBad( string const & indexFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -219,7 +219,7 @@ EpwingDictionary::EpwingDictionary( string const & id,
vector< string > const & dictionaryFiles, vector< string > const & dictionaryFiles,
int subBook ): int subBook ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ), idxHeader( idx.read< IdxHeader >() ),
chunks( idx, idxHeader.chunksOffset ) chunks( idx, idxHeader.chunksOffset )
{ {
@ -1197,7 +1197,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
QByteArray nameData = str.toUtf8(); QByteArray nameData = str.toUtf8();
initializing.indexingDictionary( nameData.data() ); initializing.indexingDictionary( nameData.data() );
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader{}; IdxHeader idxHeader{};

View file

@ -335,7 +335,7 @@ static_assert( alignof( IdxHeader ) == 1 );
bool indexIsOldOrBad( string const & indexFile, bool hasZipFile ) bool indexIsOldOrBad( string const & indexFile, bool hasZipFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -443,7 +443,7 @@ private:
GlsDictionary::GlsDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ): GlsDictionary::GlsDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ), idxHeader( idx.read< IdxHeader >() ),
dz( 0 ), dz( 0 ),
chunks( idx, idxHeader.chunksOffset ) chunks( idx, idxHeader.chunksOffset )
@ -1270,7 +1270,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
gdDebug( "Gls: Building the index for dictionary: %s\n", gdDebug( "Gls: Building the index for dictionary: %s\n",
QString::fromStdU32String( scanner.getDictionaryName() ).toUtf8().data() ); QString::fromStdU32String( scanner.getDictionaryName() ).toUtf8().data() );
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;

View file

@ -224,7 +224,7 @@ void loadDictionaries( QWidget * parent,
loadDicts.wait(); loadDicts.wait();
if ( loadDicts.getExceptionText().size() ) { if ( !loadDicts.getExceptionText().empty() ) {
QMessageBox::critical( parent, QMessageBox::critical( parent,
QCoreApplication::translate( "LoadDictionaries", "Error loading dictionaries" ), QCoreApplication::translate( "LoadDictionaries", "Error loading dictionaries" ),
QString::fromUtf8( loadDicts.getExceptionText().c_str() ) ); QString::fromUtf8( loadDicts.getExceptionText().c_str() ) );

View file

@ -65,7 +65,7 @@ static_assert( alignof( IdxHeader ) == 1 );
bool indexIsOldOrBad( string const & indexFile ) bool indexIsOldOrBad( string const & indexFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -201,7 +201,7 @@ string LsaDictionary::getName() noexcept
LsaDictionary::LsaDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ): LsaDictionary::LsaDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ) idxHeader( idx.read< IdxHeader >() )
{ {
// Initialize the index // Initialize the index
@ -405,7 +405,7 @@ sptr< Dictionary::DataRequest > LsaDictionary::getResource( string const & name
return std::make_shared< Dictionary::DataRequestInstant >( false ); // No such resource return std::make_shared< Dictionary::DataRequestInstant >( false ); // No such resource
} }
File::Index f( getDictionaryFilenames()[ 0 ], "rb" ); File::Index f( getDictionaryFilenames()[ 0 ], QIODevice::ReadOnly );
f.seek( chain[ 0 ].articleOffset ); f.seek( chain[ 0 ].articleOffset );
Entry e( f ); Entry e( f );
@ -522,7 +522,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
} }
try { try {
File::Index f( *i, "rb" ); File::Index f( *i, QIODevice::ReadOnly );
/// Check the signature /// Check the signature
@ -547,7 +547,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
initializing.indexingDictionary( Utils::Fs::basename( *i ) ); initializing.indexingDictionary( Utils::Fs::basename( *i ) );
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;

View file

@ -302,7 +302,7 @@ private:
MdxDictionary::MdxDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ): MdxDictionary::MdxDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxFileName( indexFile ), idxFileName( indexFile ),
idxHeader( idx.read< IdxHeader >() ), idxHeader( idx.read< IdxHeader >() ),
chunks( idx, idxHeader.chunksOffset ), chunks( idx, idxHeader.chunksOffset ),
@ -1307,7 +1307,7 @@ private:
static bool indexIsOldOrBad( vector< string > const & dictFiles, string const & indexFile ) static bool indexIsOldOrBad( vector< string > const & dictFiles, string const & indexFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
return idx.readRecords( &header, sizeof( header ), 1 ) != 1 || header.signature != kSignature return idx.readRecords( &header, sizeof( header ), 1 ) != 1 || header.signature != kSignature
@ -1385,7 +1385,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
} }
} }
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;
memset( &idxHeader, 0, sizeof( idxHeader ) ); memset( &idxHeader, 0, sizeof( idxHeader ) );
// We write a dummy header first. At the end of the process the header // We write a dummy header first. At the end of the process the header

View file

@ -97,7 +97,7 @@ static_assert( alignof( IdxHeader ) == 1 );
bool indexIsOldOrBad( string const & indexFile ) bool indexIsOldOrBad( string const & indexFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -188,10 +188,10 @@ SdictDictionary::SdictDictionary( string const & id,
string const & indexFile, string const & indexFile,
vector< string > const & dictionaryFiles ): vector< string > const & dictionaryFiles ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ), idxHeader( idx.read< IdxHeader >() ),
chunks( idx, idxHeader.chunksOffset ), chunks( idx, idxHeader.chunksOffset ),
df( dictionaryFiles[ 0 ], "rb" ) df( dictionaryFiles[ 0 ], QIODevice::ReadOnly )
{ {
// Read dictionary name // Read dictionary name
@ -689,7 +689,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
try { try {
gdDebug( "SDict: Building the index for dictionary: %s\n", fileName.c_str() ); gdDebug( "SDict: Building the index for dictionary: %s\n", fileName.c_str() );
File::Index df( fileName, "rb" ); File::Index df( fileName, QIODevice::ReadOnly );
DCT_header dictHeader; DCT_header dictHeader;
@ -722,7 +722,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
initializing.indexingDictionary( dictName ); initializing.indexingDictionary( dictName );
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;
memset( &idxHeader, 0, sizeof( idxHeader ) ); memset( &idxHeader, 0, sizeof( idxHeader ) );

View file

@ -97,7 +97,7 @@ struct RefEntry
bool indexIsOldOrBad( string const & indexFile ) bool indexIsOldOrBad( string const & indexFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -702,7 +702,7 @@ private:
SlobDictionary::SlobDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ): SlobDictionary::SlobDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
idxFileName( indexFile ), idxFileName( indexFile ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ) idxHeader( idx.read< IdxHeader >() )
{ {
// Open data file // Open data file
@ -1285,7 +1285,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
initializing.indexingDictionary( sf.getDictionaryName().toUtf8().constData() ); initializing.indexingDictionary( sf.getDictionaryName().toUtf8().constData() );
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;
memset( &idxHeader, 0, sizeof( idxHeader ) ); memset( &idxHeader, 0, sizeof( idxHeader ) );

View file

@ -51,7 +51,7 @@ static_assert( alignof( IdxHeader ) == 1 );
bool indexIsOldOrBad( string const & indexFile ) bool indexIsOldOrBad( string const & indexFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -114,7 +114,7 @@ SoundDirDictionary::SoundDirDictionary( string const & id,
QString const & iconFilename_ ): QString const & iconFilename_ ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
name( name_ ), name( name_ ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ), idxHeader( idx.read< IdxHeader >() ),
chunks( idx, idxHeader.chunksOffset ), chunks( idx, idxHeader.chunksOffset ),
iconFilename( iconFilename_ ) iconFilename( iconFilename_ )
@ -370,7 +370,7 @@ sptr< Dictionary::DataRequest > SoundDirDictionary::getResource( string const &
// Now try loading that file // Now try loading that file
try { try {
File::Index f( fileName.toStdString(), "rb" ); File::Index f( fileName.toStdString(), QIODevice::ReadOnly );
sptr< Dictionary::DataRequestInstant > dr = std::make_shared< Dictionary::DataRequestInstant >( true ); sptr< Dictionary::DataRequestInstant > dr = std::make_shared< Dictionary::DataRequestInstant >( true );
@ -479,7 +479,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( Config::SoundDirs const &
initializing.indexingDictionary( soundDir.name.toUtf8().data() ); initializing.indexingDictionary( soundDir.name.toUtf8().data() );
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;

View file

@ -76,13 +76,15 @@ DEF_EX_STR( exIncorrectOffset, "Incorrect offset encountered in file", Dictionar
/// Contents of an ifo file /// Contents of an ifo file
struct Ifo struct Ifo
{ {
string version;
string bookname; string bookname;
uint32_t wordcount, synwordcount, idxfilesize, idxoffsetbits; uint32_t wordcount = 0;
uint32_t synwordcount = 0;
uint32_t idxfilesize = 0;
uint32_t idxoffsetbits = 32;
string sametypesequence, dicttype, description; string sametypesequence, dicttype, description;
string copyright, author, email, website, date; string copyright, author, email, website, date;
explicit Ifo( File::Index & ); explicit Ifo( const QString & fileName );
}; };
enum { enum {
@ -116,7 +118,7 @@ static_assert( alignof( IdxHeader ) == 1 );
bool indexIsOldOrBad( string const & indexFile ) bool indexIsOldOrBad( string const & indexFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -235,7 +237,7 @@ StardictDictionary::StardictDictionary( string const & id,
string const & indexFile, string const & indexFile,
vector< string > const & dictionaryFiles ): vector< string > const & dictionaryFiles ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ), idxHeader( idx.read< IdxHeader >() ),
bookName( loadString( idxHeader.bookNameSize ) ), bookName( loadString( idxHeader.bookNameSize ) ),
sameTypeSequence( loadString( idxHeader.sameTypeSequenceSize ) ), sameTypeSequence( loadString( idxHeader.sameTypeSequenceSize ) ),
@ -1085,40 +1087,36 @@ QString const & StardictDictionary::getDescription()
return dictionaryDescription; return dictionaryDescription;
} }
File::Index ifoFile( getDictionaryFilenames()[ 0 ], "r" ); Ifo ifo( QString::fromStdString( getDictionaryFilenames()[ 0 ] ) );
Ifo ifo( ifoFile );
if ( !ifo.copyright.empty() ) { if ( !ifo.copyright.empty() ) {
QString copyright = QString::fromUtf8( ifo.copyright.c_str() ).replace( "<br>", "\n", Qt::CaseInsensitive ); QString copyright = QString::fromUtf8( ifo.copyright.c_str() );
dictionaryDescription += QObject::tr( "Copyright: %1%2" ).arg( copyright ).arg( "\n\n" ); dictionaryDescription += QObject::tr( "Copyright: %1%2" ).arg( copyright ).arg( "<br><br>" );
} }
if ( !ifo.author.empty() ) { if ( !ifo.author.empty() ) {
QString author = QString::fromUtf8( ifo.author.c_str() ); QString author = QString::fromUtf8( ifo.author.c_str() );
dictionaryDescription += QObject::tr( "Author: %1%2" ).arg( author ).arg( "\n\n" ); dictionaryDescription += QObject::tr( "Author: %1%2" ).arg( author ).arg( "<br><br>" );
} }
if ( !ifo.email.empty() ) { if ( !ifo.email.empty() ) {
QString email = QString::fromUtf8( ifo.email.c_str() ); QString email = QString::fromUtf8( ifo.email.c_str() );
dictionaryDescription += QObject::tr( "E-mail: %1%2" ).arg( email ).arg( "\n\n" ); dictionaryDescription += QObject::tr( "E-mail: %1%2" ).arg( email ).arg( "<br><br>" );
} }
if ( !ifo.website.empty() ) { if ( !ifo.website.empty() ) {
QString website = QString::fromUtf8( ifo.website.c_str() ); QString website = QString::fromUtf8( ifo.website.c_str() );
dictionaryDescription += QObject::tr( "Website: %1%2" ).arg( website ).arg( "\n\n" ); dictionaryDescription += QObject::tr( "Website: %1%2" ).arg( website ).arg( "<br><br>" );
} }
if ( !ifo.date.empty() ) { if ( !ifo.date.empty() ) {
QString date = QString::fromUtf8( ifo.date.c_str() ); QString date = QString::fromUtf8( ifo.date.c_str() );
dictionaryDescription += QObject::tr( "Date: %1%2" ).arg( date ).arg( "\n\n" ); dictionaryDescription += QObject::tr( "Date: %1%2" ).arg( date ).arg( "<br><br>" );
} }
if ( !ifo.description.empty() ) { if ( !ifo.description.empty() ) {
QString desc = QString::fromUtf8( ifo.description.c_str() ); QString desc = QString::fromUtf8( ifo.description.c_str() );
desc.replace( "\t", "<br/>" ); dictionaryDescription += desc;
desc.replace( "\\n", "<br/>" );
desc.replace( "<br>", "<br/>", Qt::CaseInsensitive );
dictionaryDescription += Html::unescape( desc, Html::HtmlOption::Keep );
} }
if ( dictionaryDescription.isEmpty() ) { if ( dictionaryDescription.isEmpty() ) {
@ -1457,85 +1455,77 @@ static char const * beginsWith( char const * substr, char const * str )
return strncmp( str, substr, len ) == 0 ? str + len : 0; return strncmp( str, substr, len ) == 0 ? str + len : 0;
} }
Ifo::Ifo( File::Index & f ): Ifo::Ifo( const QString & fileName )
wordcount( 0 ),
synwordcount( 0 ),
idxfilesize( 0 ),
idxoffsetbits( 32 )
{ {
static string const versionEq( "version=" ); QFile f( fileName );
if ( !f.open( QIODevice::ReadOnly ) ) {
throw exCantReadFile( "Cannot open IFO file -> " + fileName.toStdString() );
};
static string const booknameEq( "bookname=" ); if ( !f.readLine().startsWith( "StarDict's dict ifo file" ) || !f.readLine().startsWith( "version=" ) ) {
//GD_DPRINTF( "%s<\n", f.gets().c_str() );
//GD_DPRINTF( "%s<\n", f.gets().c_str() );
if ( QString::fromUtf8( f.gets().c_str() ) != "StarDict's dict ifo file"
|| f.gets().compare( 0, versionEq.size(), versionEq ) ) {
throw exNotAnIfoFile(); throw exNotAnIfoFile();
} }
/// Now go through the file and parse options /// Now go through the file and parse options
{
while ( !f.atEnd() ) {
auto line = f.readLine();
auto option = QByteArrayView( line ).trimmed();
// Empty lines are allowed in .ifo file
try { if ( option.isEmpty() ) {
char option[ 16384 ]; continue;
for ( ;; ) {
if ( !f.gets( option, sizeof( option ), true ) ) {
break;
} }
if ( char const * val = beginsWith( "bookname=", option ) ) { if ( char const * val = beginsWith( "bookname=", option.data() ) ) {
bookname = val; bookname = val;
} }
else if ( char const * val = beginsWith( "wordcount=", option ) ) { else if ( char const * val = beginsWith( "wordcount=", option.data() ) ) {
if ( sscanf( val, "%u", &wordcount ) != 1 ) { if ( sscanf( val, "%u", &wordcount ) != 1 ) {
throw exBadFieldInIfo( option ); throw exBadFieldInIfo( option.data() );
} }
} }
else if ( char const * val = beginsWith( "synwordcount=", option ) ) { else if ( char const * val = beginsWith( "synwordcount=", option.data() ) ) {
if ( sscanf( val, "%u", &synwordcount ) != 1 ) { if ( sscanf( val, "%u", &synwordcount ) != 1 ) {
throw exBadFieldInIfo( option ); throw exBadFieldInIfo( option.data() );
} }
} }
else if ( char const * val = beginsWith( "idxfilesize=", option ) ) { else if ( char const * val = beginsWith( "idxfilesize=", option.data() ) ) {
if ( sscanf( val, "%u", &idxfilesize ) != 1 ) { if ( sscanf( val, "%u", &idxfilesize ) != 1 ) {
throw exBadFieldInIfo( option ); throw exBadFieldInIfo( option.data() );
} }
} }
else if ( char const * val = beginsWith( "idxoffsetbits=", option ) ) { else if ( char const * val = beginsWith( "idxoffsetbits=", option.data() ) ) {
if ( sscanf( val, "%u", &idxoffsetbits ) != 1 || ( idxoffsetbits != 32 && idxoffsetbits != 64 ) ) { if ( sscanf( val, "%u", &idxoffsetbits ) != 1 || ( idxoffsetbits != 32 && idxoffsetbits != 64 ) ) {
throw exBadFieldInIfo( option ); throw exBadFieldInIfo( option.data() );
} }
} }
else if ( char const * val = beginsWith( "sametypesequence=", option ) ) { else if ( char const * val = beginsWith( "sametypesequence=", option.data() ) ) {
sametypesequence = val; sametypesequence = val;
} }
else if ( char const * val = beginsWith( "dicttype=", option ) ) { else if ( char const * val = beginsWith( "dicttype=", option.data() ) ) {
dicttype = val; dicttype = val;
} }
else if ( char const * val = beginsWith( "description=", option ) ) { else if ( char const * val = beginsWith( "description=", option.data() ) ) {
description = val; description = val;
} }
else if ( char const * val = beginsWith( "copyright=", option ) ) { else if ( char const * val = beginsWith( "copyright=", option.data() ) ) {
copyright = val; copyright = val;
} }
else if ( char const * val = beginsWith( "author=", option ) ) { else if ( char const * val = beginsWith( "author=", option.data() ) ) {
author = val; author = val;
} }
else if ( char const * val = beginsWith( "email=", option ) ) { else if ( char const * val = beginsWith( "email=", option.data() ) ) {
email = val; email = val;
} }
else if ( char const * val = beginsWith( "website=", option ) ) { else if ( char const * val = beginsWith( "website=", option.data() ) ) {
website = val; website = val;
} }
else if ( char const * val = beginsWith( "date=", option ) ) { else if ( char const * val = beginsWith( "date=", option.data() ) ) {
date = val; date = val;
} }
} }
} }
catch ( File::exReadError & ) {
}
} }
//// StardictDictionary::getResource() //// StardictDictionary::getResource()
@ -1897,9 +1887,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
if ( Dictionary::needToRebuildIndex( dictFiles, indexFile ) || indexIsOldOrBad( indexFile ) ) { if ( Dictionary::needToRebuildIndex( dictFiles, indexFile ) || indexIsOldOrBad( indexFile ) ) {
// Building the index // Building the index
File::Index ifoFile( fileName, "r" ); Ifo ifo( QString::fromStdString( fileName ) );
Ifo ifo( ifoFile );
gdDebug( "Stardict: Building the index for dictionary: %s\n", ifo.bookname.c_str() ); gdDebug( "Stardict: Building the index for dictionary: %s\n", ifo.bookname.c_str() );
@ -1930,7 +1918,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
initializing.indexingDictionary( ifo.bookname ); initializing.indexingDictionary( ifo.bookname );
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;

View file

@ -37,50 +37,18 @@ bool tryPossibleZipName( std::string const & name, std::string & copyTo )
void loadFromFile( std::string const & filename, std::vector< char > & data ) void loadFromFile( std::string const & filename, std::vector< char > & data )
{ {
File::Index f( filename, "rb" ); File::Index f( filename, QIODevice::ReadOnly );
auto size = f.file().size(); // QFile::size() obtains size via statx on Linux auto size = f.file().size(); // QFile::size() obtains size via statx on Linux
data.resize( size ); data.resize( size );
f.read( data.data(), size ); f.read( data.data(), size );
} }
void Index::open( char const * mode ) Index::Index( std::string_view filename, QIODevice::OpenMode mode )
{
QFile::OpenMode openMode = QIODevice::Text;
const char * pch = mode;
while ( *pch ) {
switch ( *pch ) {
case 'r':
openMode |= QIODevice::ReadOnly;
break;
case 'w':
openMode |= QIODevice::WriteOnly;
break;
case '+':
openMode &= ~( QIODevice::ReadOnly | QIODevice::WriteOnly );
openMode |= QIODevice::ReadWrite;
break;
case 'a':
openMode |= QIODevice::Append;
break;
case 'b':
openMode &= ~QIODevice::Text;
break;
default:
break;
}
++pch;
}
if ( !f.open( openMode ) ) {
throw exCantOpen( f.fileName().toStdString() + ": " + f.errorString().toUtf8().data() );
}
}
Index::Index( std::string_view filename, char const * mode )
{ {
f.setFileName( QString::fromUtf8( filename.data(), filename.size() ) ); f.setFileName( QString::fromUtf8( filename.data(), filename.size() ) );
open( mode ); if ( !f.open( mode ) ) {
throw exCantOpen( ( f.fileName() + ": " + f.errorString() ).toStdString() );
}
} }
void Index::read( void * buf, qint64 size ) void Index::read( void * buf, qint64 size )

View file

@ -43,7 +43,7 @@ public:
QMutex lock; QMutex lock;
// Create QFile Object and open() it. // Create QFile Object and open() it.
Index( std::string_view filename, char const * mode ); Index( std::string_view filename, QIODevice::OpenMode mode );
/// QFile::read & QFile::write , but with exception throwing /// QFile::read & QFile::write , but with exception throwing
void read( void * buf, qint64 size ); void read( void * buf, qint64 size );
@ -113,8 +113,6 @@ public:
~Index() noexcept; ~Index() noexcept;
private: private:
// QFile::open but with fopen-like mode settings.
void open( char const * mode );
template< typename T > template< typename T >
void readType( T & value ) void readType( T & value )

View file

@ -125,7 +125,7 @@ static_assert( alignof( IdxHeader ) == 1 );
bool indexIsOldOrBad( string const & indexFile ) bool indexIsOldOrBad( string const & indexFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -228,7 +228,7 @@ private:
XdxfDictionary::XdxfDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ): XdxfDictionary::XdxfDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ) idxHeader( idx.read< IdxHeader >() )
{ {
// Read the dictionary name // Read the dictionary name
@ -1077,7 +1077,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
//initializing.indexingDictionary( nameFromFileName( dictFiles[ 0 ] ) ); //initializing.indexingDictionary( nameFromFileName( dictFiles[ 0 ] ) );
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;
map< string, string > abrv; map< string, string > abrv;

View file

@ -93,7 +93,7 @@ static_assert( alignof( IdxHeader ) == 1 );
// Some supporting functions // Some supporting functions
bool indexIsOldOrBad( string const & indexFile ) bool indexIsOldOrBad( string const & indexFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -241,7 +241,7 @@ private:
ZimDictionary::ZimDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ): ZimDictionary::ZimDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ), idxHeader( idx.read< IdxHeader >() ),
df( dictionaryFiles[ 0 ] ) df( dictionaryFiles[ 0 ] )
{ {
@ -832,7 +832,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
initializing.indexingDictionary( firstName.mid( n + 1 ).toUtf8().constData() ); initializing.indexingDictionary( firstName.mid( n + 1 ).toUtf8().constData() );
} }
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;
memset( &idxHeader, 0, sizeof( idxHeader ) ); memset( &idxHeader, 0, sizeof( idxHeader ) );
idxHeader.namePtr = 0xFFFFFFFF; idxHeader.namePtr = 0xFFFFFFFF;

View file

@ -60,7 +60,7 @@ static_assert( alignof( IdxHeader ) == 1 );
bool indexIsOldOrBad( string const & indexFile ) bool indexIsOldOrBad( string const & indexFile )
{ {
File::Index idx( indexFile, "rb" ); File::Index idx( indexFile, QIODevice::ReadOnly );
IdxHeader header; IdxHeader header;
@ -140,7 +140,7 @@ ZipSoundsDictionary::ZipSoundsDictionary( string const & id,
string const & indexFile, string const & indexFile,
vector< string > const & dictionaryFiles ): vector< string > const & dictionaryFiles ):
BtreeDictionary( id, dictionaryFiles ), BtreeDictionary( id, dictionaryFiles ),
idx( indexFile, "rb" ), idx( indexFile, QIODevice::ReadOnly ),
idxHeader( idx.read< IdxHeader >() ) idxHeader( idx.read< IdxHeader >() )
{ {
chunks = std::shared_ptr< ChunkedStorage::Reader >( new ChunkedStorage::Reader( idx, idxHeader.chunksOffset ) ); chunks = std::shared_ptr< ChunkedStorage::Reader >( new ChunkedStorage::Reader( idx, idxHeader.chunksOffset ) );
@ -405,7 +405,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
if ( Dictionary::needToRebuildIndex( dictFiles, indexFile ) || indexIsOldOrBad( indexFile ) ) { if ( Dictionary::needToRebuildIndex( dictFiles, indexFile ) || indexIsOldOrBad( indexFile ) ) {
gdDebug( "Zips: Building the index for dictionary: %s\n", fileName.c_str() ); gdDebug( "Zips: Building the index for dictionary: %s\n", fileName.c_str() );
File::Index idx( indexFile, "wb" ); File::Index idx( indexFile, QIODevice::WriteOnly );
IdxHeader idxHeader; IdxHeader idxHeader;
memset( &idxHeader, 0, sizeof( idxHeader ) ); memset( &idxHeader, 0, sizeof( idxHeader ) );

View file

@ -368,7 +368,7 @@ int main( int argc, char ** argv )
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
// TODO: Force fusion because Qt6.7's "ModernStyle"'s dark theme have problems, need to test / reconsider in future // TODO: Force fusion because Qt6.7's "ModernStyle"'s dark theme have problems, need to test / reconsider in future
QHotkeyApplication::setStyle( QStyleFactory::create( "Fusion" ) ); QHotkeyApplication::setStyle( QStyleFactory::create( "WindowsVista" ) );
#endif #endif

View file

@ -17,7 +17,7 @@ void PronounceEngine::reset()
} }
void PronounceEngine::sendAudio( std::string dictId, QString audioLink ) void PronounceEngine::sendAudio( const std::string & dictId, const QString & audioLink )
{ {
if ( state == PronounceState::OCCUPIED ) { if ( state == PronounceState::OCCUPIED ) {
return; return;
@ -29,7 +29,7 @@ void PronounceEngine::sendAudio( std::string dictId, QString audioLink )
QMutexLocker _( &mutex ); QMutexLocker _( &mutex );
dictAudioMap.operator[]( dictId ).push_back( audioLink ); dictAudioMap[ dictId ].append( audioLink );
} }
void PronounceEngine::finishDictionary( std::string dictId ) void PronounceEngine::finishDictionary( std::string dictId )

View file

@ -21,7 +21,7 @@ class PronounceEngine: public QObject
public: public:
explicit PronounceEngine( QObject * parent = nullptr ); explicit PronounceEngine( QObject * parent = nullptr );
void reset(); void reset();
void sendAudio( std::string dictId, QString audioLink ); void sendAudio( const std::string & dictId, const QString & audioLink );
void finishDictionary( std::string dictId ); void finishDictionary( std::string dictId );
signals: signals:
void emitAudio( QString audioLink ); void emitAudio( QString audioLink );

View file

@ -204,26 +204,11 @@ void EditDictionaries::acceptChangedSources( bool rebuildGroups )
// Those hold pointers to dictionaries, we need to free them. // Those hold pointers to dictionaries, we need to free them.
groupInstances.clear(); groupInstances.clear();
groups.clear();
orderAndProps.clear();
loadDictionaries( this, cfg, dictionaries, dictNetMgr ); loadDictionaries( this, cfg, dictionaries, dictNetMgr );
Instances::updateNames( savedGroups, dictionaries );
Instances::updateNames( savedOrder, dictionaries );
Instances::updateNames( savedInactive, dictionaries );
if ( rebuildGroups ) { if ( rebuildGroups ) {
ui.tabs->removeTab( 1 ); orderAndProps->rebuild( savedOrder, savedInactive, dictionaries );
ui.tabs->removeTab( 1 ); groups->rebuild( dictionaries, savedGroups, orderAndProps->getCurrentDictionaryOrder() );
orderAndProps = new OrderAndProps( this, savedOrder, savedInactive, dictionaries );
groups = new Groups( this, dictionaries, savedGroups, orderAndProps->getCurrentDictionaryOrder() );
ui.tabs->insertTab( 1, orderAndProps, QIcon( ":/icons/book.svg" ), tr( "&Dictionaries" ) );
ui.tabs->insertTab( 2, groups, QIcon( ":/icons/bookcase.svg" ), tr( "&Groups" ) );
connect( groups, &Groups::showDictionaryInfo, this, &EditDictionaries::showDictionaryInfo );
connect( orderAndProps, &OrderAndProps::showDictionaryHeadwords, this, &EditDictionaries::showDictionaryHeadwords );
} }
setUpdatesEnabled( true ); setUpdatesEnabled( true );
} }

View file

@ -64,6 +64,24 @@ Groups::Groups( QWidget * parent,
countChanged(); countChanged();
} }
void Groups::rebuild( vector< sptr< Dictionary::Class > > const & dicts_,
Config::Groups const & groups_,
Config::Group const & order )
{
this->setUpdatesEnabled( false );
dicts = dicts_;
groups = groups_;
ui.dictionaries->setAsSource();
ui.dictionaries->populate( Instances::Group( order, dicts, Config::Group() ).dictionaries, dicts );
// Populate groups' widget
ui.groups->populate( groups, dicts, ui.dictionaries->getCurrentDictionaries() );
countChanged();
this->setUpdatesEnabled( true );
}
void Groups::editGroup( unsigned id ) void Groups::editGroup( unsigned id )
{ {
for ( int x = 0; x < groups.size(); ++x ) { for ( int x = 0; x < groups.size(); ++x ) {

View file

@ -18,7 +18,9 @@ public:
std::vector< sptr< Dictionary::Class > > const &, std::vector< sptr< Dictionary::Class > > const &,
Config::Groups const &, Config::Groups const &,
Config::Group const & order ); Config::Group const & order );
void rebuild( std::vector< sptr< Dictionary::Class > > const & dicts_,
Config::Groups const & groups_,
Config::Group const & order );
/// Instructs the dialog to position itself on editing the given group. /// Instructs the dialog to position itself on editing the given group.
void editGroup( unsigned id ); void editGroup( unsigned id );
@ -31,7 +33,7 @@ public:
private: private:
Ui::Groups ui; Ui::Groups ui;
std::vector< sptr< Dictionary::Class > > const & dicts; std::vector< sptr< Dictionary::Class > > dicts;
Config::Groups groups; Config::Groups groups;
QToolButton * groupsListButton; QToolButton * groupsListButton;

View file

@ -1356,8 +1356,10 @@ void MainWindow::updateAppearances( QString const & addonStyle,
darkPalette.setColor( QPalette::Disabled, QPalette::HighlightedText, disabledColor ); darkPalette.setColor( QPalette::Disabled, QPalette::HighlightedText, disabledColor );
qApp->setPalette( darkPalette ); qApp->setPalette( darkPalette );
qApp->setStyle( "Fusion" );
} }
else { else {
qApp->setStyle( "WindowsVista" );
qApp->setPalette( QPalette() ); qApp->setPalette( QPalette() );
} }
#endif #endif

View file

@ -133,6 +133,25 @@ OrderAndProps::OrderAndProps( QWidget * parent,
showDictNumbers(); showDictNumbers();
} }
void OrderAndProps::rebuild( Config::Group const & dictionaryOrder,
Config::Group const & inactiveDictionaries,
std::vector< sptr< Dictionary::Class > > const & allDictionaries )
{
Instances::Group order( dictionaryOrder, allDictionaries, Config::Group() );
Instances::Group inactive( inactiveDictionaries, allDictionaries, Config::Group() );
Instances::complementDictionaryOrder( order, inactive, allDictionaries );
setUpdatesEnabled( false );
ui.dictionaryOrder->populate( order.dictionaries, allDictionaries );
ui.inactiveDictionaries->populate( inactive.dictionaries, allDictionaries );
disableDictionaryDescription();
showDictNumbers();
setUpdatesEnabled( true );
}
Config::Group OrderAndProps::getCurrentDictionaryOrder() const Config::Group OrderAndProps::getCurrentDictionaryOrder() const
{ {
Instances::Group g; Instances::Group g;

View file

@ -17,7 +17,9 @@ public:
Config::Group const & dictionaryOrder, Config::Group const & dictionaryOrder,
Config::Group const & inactiveDictionaries, Config::Group const & inactiveDictionaries,
std::vector< sptr< Dictionary::Class > > const & allDictionaries ); std::vector< sptr< Dictionary::Class > > const & allDictionaries );
void rebuild( Config::Group const & dictionaryOrder,
Config::Group const & inactiveDictionaries,
std::vector< sptr< Dictionary::Class > > const & allDictionaries );
Config::Group getCurrentDictionaryOrder() const; Config::Group getCurrentDictionaryOrder() const;
Config::Group getCurrentInactiveDictionaries() const; Config::Group getCurrentInactiveDictionaries() const;