diff --git a/.github/workflows/release-windows-vcpkg-cmake.yml b/.github/workflows/release-windows-vcpkg-cmake.yml
index 29c68c120..a909a0fa5 100644
--- a/.github/workflows/release-windows-vcpkg-cmake.yml
+++ b/.github/workflows/release-windows-vcpkg-cmake.yml
@@ -21,7 +21,7 @@ jobs:
strategy:
matrix:
os: [windows-2022]
- qt_ver: [ 6.7.2 ]
+ qt_ver: [ 6.7.2, 6.6.3 ]
qt_arch: [win64_msvc2019_64]
env:
version: 24.05.13
@@ -133,6 +133,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
$tagName = "v$env:version-$env:versionSuffix.$(git rev-parse --short=8 HEAD)"
+ $releaseName = "v$env:version-$env:versionSuffix.$(date +'%y%m%d').$(git rev-parse --short=8 HEAD)"
Add-Content -Path ./change_note.txt -Value "
[Install instructions for Windows, macOS and Linux](https://xiaoyifang.github.io/goldendict-ng/install/).
@@ -153,9 +154,9 @@ jobs:
$tagExist = gh api --silent "repos/:owner/:repo/git/refs/tags/${tagName}"
if (-not $?) {
if ($env:prerelease -eq "true") {
- gh release create ${tagName} --target ${{github.ref_name}} --notes-file=./change_note.txt --latest=false --prerelease
+ gh release create ${tagName} -t ${releaseName} --target ${{github.ref_name}} --notes-file=./change_note.txt --latest=false --prerelease
} else {
- gh release create ${tagName} --target ${{github.ref_name}} --notes-file=./change_note.txt --latest=true
+ gh release create ${tagName} -t ${releaseName} --target ${{github.ref_name}} --notes-file=./change_note.txt --latest=true
}
}
@@ -167,8 +168,22 @@ jobs:
gh release upload "${tagName}" "${namePrefix}.7z#${namePrefix}-Windows.7z" --clobber
gh release upload "${tagName}" "${namePrefix}.exe#${namePrefix}-Windows-installer.exe" --clobber
- cd './goldendict'
- gh release upload "${tagName}" "goldendict.exe#${namePrefix}-Windows-main-exe-file-only.exe" --clobber
- gh release upload "${tagName}" "goldendict.pdb#${namePrefix}-Windows-debug-file.pdb" --clobber
- cd ..
+ - name: Upload Single packages
+ shell: bash
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ tagName="v${{env.version}}-${{env.versionSuffix}}.$(git rev-parse --short=8 HEAD)"
+ echo $tagName
+ namePrefix="GoldenDict-ng-${{env.version}}-Qt${{matrix.qt_ver}}"
+
+ cd ./build_dir/goldendict
+
+ # rename to avoid conflict with other packages
+ mv goldendict.exe goldendict-Qt${{matrix.qt_ver}}.exe
+ mv goldendict.pdb goldendict-Qt${{matrix.qt_ver}}.pdb
+
+ gh release upload "${tagName}" "goldendict-Qt${{matrix.qt_ver}}.exe#${namePrefix}-Windows-main-exe-file-only.exe" --clobber
+ gh release upload "${tagName}" "goldendict-Qt${{matrix.qt_ver}}.pdb#${namePrefix}-Windows-debug-file.pdb" --clobber
+ cd ..
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 29327d38b..267ad144b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -104,7 +104,7 @@ set(CMAKE_AUTOUIC_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/src/ui/")
# https://cmake.org/cmake/help/latest/command/file.html#filesystem
# ! Using GLOB_RECURSE is not recommended by cmake's documentation
# CONFIGURE_DEPENDS will trigger file tree recheck in every rebuilds.
-file(GLOB_RECURSE ALL_SOURCE_FILES CONFIGURE_DEPENDS src/*.cc src/*.hh src/*.c)
+file(GLOB_RECURSE ALL_SOURCE_FILES CONFIGURE_DEPENDS src/*.cc src/*.hh src/*.ui src/*.c)
if (APPLE)
file(GLOB_RECURSE MACOS_SOURCE_FILES CONFIGURE_DEPENDS src/macos/*.mm)
diff --git a/icons/lsasound.png b/icons/lsasound.png
new file mode 100644
index 000000000..2d73561b4
Binary files /dev/null and b/icons/lsasound.png differ
diff --git a/icons/lsasound.svg b/icons/lsasound.svg
index 58d761c67..f1a4a4be9 100644
--- a/icons/lsasound.svg
+++ b/icons/lsasound.svg
@@ -3,14 +3,14 @@
lsa
+ id="g1">lsa
diff --git a/resources.qrc b/resources.qrc
index 7c49291da..132967e43 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -68,7 +68,7 @@
icons/playsound_color.svgicons/sounddir.svgicons/zipsound.svg
- icons/lsasound.svg
+ icons/lsasound.pngicons/previous.svgicons/print.svgicons/programs.svg
diff --git a/src/btreeidx.cc b/src/btreeidx.cc
index 856ca3afb..efad109d3 100644
--- a/src/btreeidx.cc
+++ b/src/btreeidx.cc
@@ -1097,27 +1097,6 @@ void BtreeIndex::findArticleLinks( QVector< WordArticleLink > * articleLinks,
for ( ;; ) {
vector< WordArticleLink > result = readChain( chainPtr );
- if ( headwords
- && static_cast< vector< WordArticleLink >::size_type >( headwords->capacity() )
- < headwords->size() + result.size() ) {
- int n = headwords->capacity();
- headwords->reserve( n + n / 10 );
- }
-
- if ( offsets
- && static_cast< vector< WordArticleLink >::size_type >( offsets->capacity() )
- < offsets->size() + result.size() ) {
- int n = offsets->capacity();
- offsets->reserve( n + n / 10 );
- }
-
- if ( articleLinks
- && static_cast< vector< WordArticleLink >::size_type >( articleLinks->capacity() )
- < articleLinks->size() + result.size() ) {
- int n = articleLinks->capacity();
- articleLinks->reserve( n + n / 10 );
- }
-
for ( auto & i : result ) {
if ( isCancelled && Utils::AtomicInt::loadAcquire( *isCancelled ) )
return;
diff --git a/src/common/folding.cc b/src/common/folding.cc
index bf81b631c..5b4122bde 100644
--- a/src/common/folding.cc
+++ b/src/common/folding.cc
@@ -154,7 +154,7 @@ wstring applyWhitespaceAndPunctOnly( wstring const & in )
out.reserve( in.size() );
for ( size_t left = in.size(); left--; ++nextChar ) {
- if ( !isWhitespace( *nextChar ) && !isPunct( *nextChar ) )
+ if ( !isWhitespaceOrPunct( *nextChar ) )
out.push_back( *nextChar );
}
@@ -163,12 +163,13 @@ wstring applyWhitespaceAndPunctOnly( wstring const & in )
bool isWhitespace( wchar ch )
{
- return QChar::isSpace( ch );
+ //invisible character should be treated as whitespace as well.
+ return QChar::isSpace( ch ) || !QChar::isPrint( ch );
}
bool isWhitespaceOrPunct( wchar ch )
{
- return QChar::isSpace( ch ) || QChar::isPunct( ch );
+ return isWhitespace( ch ) || QChar::isPunct( ch );
}
bool isPunct( wchar ch )
@@ -182,14 +183,13 @@ wstring trimWhitespaceOrPunct( wstring const & in )
wstring::size_type wordSize = in.size();
// Skip any leading whitespace
- while ( *wordBegin && ( Folding::isWhitespace( *wordBegin ) || Folding::isPunct( *wordBegin ) ) ) {
+ while ( *wordBegin && Folding::isWhitespaceOrPunct( *wordBegin ) ) {
++wordBegin;
--wordSize;
}
// Skip any trailing whitespace
- while ( wordSize
- && ( Folding::isWhitespace( wordBegin[ wordSize - 1 ] ) || Folding::isPunct( wordBegin[ wordSize - 1 ] ) ) )
+ while ( wordSize && Folding::isWhitespaceOrPunct( wordBegin[ wordSize - 1 ] ) )
--wordSize;
return wstring( wordBegin, wordSize );
diff --git a/src/common/globalregex.hh b/src/common/globalregex.hh
index 7498e80e1..b3e1a1269 100644
--- a/src/common/globalregex.hh
+++ b/src/common/globalregex.hh
@@ -69,10 +69,11 @@ bool containHtmlEntity( std::string const & text );
} // namespace Html
const static QRegularExpression accentMark( R"(\p{M})", QRegularExpression::UseUnicodePropertiesOption );
-//contain unicode space mark and punctuation
-const static QRegularExpression markPuncSpace( R"([\p{M}\p{Z}\p{P}])", QRegularExpression::UseUnicodePropertiesOption );
-//contain unicode space and mark.
-const static QRegularExpression markSpace( R"([\p{M}\p{Z}])", QRegularExpression::UseUnicodePropertiesOption );
+//contain unicode space mark,invisible, and punctuation
+const static QRegularExpression markPuncSpace( R"([\p{M}\p{Z}\p{C}\p{P}])",
+ QRegularExpression::UseUnicodePropertiesOption );
+//contain unicode space and mark.invisible
+const static QRegularExpression markSpace( R"([\p{M}\p{Z}\p{C}])", QRegularExpression::UseUnicodePropertiesOption );
const static QRegularExpression whiteSpace( "\\s+" );
diff --git a/src/dict/dsl.cc b/src/dict/dsl.cc
index 83ae04dec..91d81f7a2 100644
--- a/src/dict/dsl.cc
+++ b/src/dict/dsl.cc
@@ -1565,7 +1565,7 @@ void DslResourceRequest::run()
string n = dict.getContainingFolder().toStdString() + Utils::Fs::separator() + resourceName;
- GD_DPRINTF( "n is %s\n", n.c_str() );
+ GD_DPRINTF( "dsl resource name is %s\n", n.c_str() );
try {
try {
diff --git a/src/dict/gls.cc b/src/dict/gls.cc
index 8f20a9154..2b96ae500 100644
--- a/src/dict/gls.cc
+++ b/src/dict/gls.cc
@@ -1069,7 +1069,7 @@ void GlsResourceRequest::run()
try {
string n = dict.getContainingFolder().toStdString() + Utils::Fs::separator() + resourceName;
- GD_DPRINTF( "n is %s\n", n.c_str() );
+ GD_DPRINTF( "gls resource name is %s\n", n.c_str() );
try {
QMutexLocker _( &dataMutex );
diff --git a/src/dict/lsa.cc b/src/dict/lsa.cc
index 644da7652..4874a97fe 100644
--- a/src/dict/lsa.cc
+++ b/src/dict/lsa.cc
@@ -483,7 +483,7 @@ void LsaDictionary::loadIcon() noexcept
if ( !loadIconFromFile( fileName ) ) {
// Load failed -- use default icons
- dictionaryIcon = QIcon( ":/icons/lsasound.svg" );
+ dictionaryIcon = QIcon( ":/icons/lsasound.png" );
}
dictionaryIconLoaded = true;
diff --git a/src/dict/stardict.cc b/src/dict/stardict.cc
index d2bfcbaf6..468626413 100644
--- a/src/dict/stardict.cc
+++ b/src/dict/stardict.cc
@@ -1517,7 +1517,7 @@ void StardictResourceRequest::run()
string n =
dict.getContainingFolder().toStdString() + Utils::Fs::separator() + "res" + Utils::Fs::separator() + resourceName;
- GD_DPRINTF( "n is %s\n", n.c_str() );
+ GD_DPRINTF( "startdict resource name is %s\n", n.c_str() );
try {
QMutexLocker _( &dataMutex );
diff --git a/src/dict/xdxf.cc b/src/dict/xdxf.cc
index 3c491a15c..79e01e218 100644
--- a/src/dict/xdxf.cc
+++ b/src/dict/xdxf.cc
@@ -942,7 +942,7 @@ void XdxfResourceRequest::run()
string n = dict.getContainingFolder().toStdString() + Utils::Fs::separator() + resourceName;
- GD_DPRINTF( "n is %s\n", n.c_str() );
+ GD_DPRINTF( "xdxf resource name is %s\n", n.c_str() );
try {
try {
diff --git a/src/indexedzip.cc b/src/indexedzip.cc
index 67e26c4df..4990d708f 100644
--- a/src/indexedzip.cc
+++ b/src/indexedzip.cc
@@ -13,6 +13,7 @@
#else
#include
#endif
+#include
using namespace BtreeIndexing;
using std::vector;
@@ -54,15 +55,23 @@ bool IndexedZip::loadFile( uint32_t offset, vector< char > & data )
if ( !zipIsOpen )
return false;
+ QMutexLocker _( &mutex );
// Now seek into the zip file and read its header
-
if ( !zip.seek( offset ) )
return false;
ZipFile::LocalFileHeader header;
if ( !ZipFile::readLocalHeader( zip, header ) ) {
+ vector< string > zipFileNames;
+ zip.getFilenames( zipFileNames );
GD_DPRINTF( "Failed to load header" );
+ string filename;
+ if ( zip.getCurrentFile() < zipFileNames.size() ) {
+ filename = zipFileNames.at( zip.getCurrentFile() );
+ }
+
+ qDebug() << "Current failed zip file:" << QString::fromStdString( filename );
return false;
}
@@ -123,6 +132,8 @@ bool IndexedZip::indexFile( BtreeIndexing::IndexedWords & zipFileNames, quint32
{
if ( !zipIsOpen )
return false;
+
+ QMutexLocker _( &mutex );
if ( !ZipFile::positionAtCentralDir( zip ) )
return false;
diff --git a/src/indexedzip.hh b/src/indexedzip.hh
index d904a1702..204667205 100644
--- a/src/indexedzip.hh
+++ b/src/indexedzip.hh
@@ -7,6 +7,7 @@
#include "btreeidx.hh"
#include
#include "zipfile.hh"
+#include
/// Allows using a btree index to read zip files. Basically built on top of
/// the base dictionary infrastructure adapted for zips.
@@ -14,6 +15,7 @@ class IndexedZip: public BtreeIndexing::BtreeIndex
{
ZipFile::SplitZipFile zip;
bool zipIsOpen;
+ QMutex mutex;
public:
diff --git a/src/splitfile.cc b/src/splitfile.cc
index 55ca3a699..e1ed0c0d2 100644
--- a/src/splitfile.cc
+++ b/src/splitfile.cc
@@ -44,6 +44,11 @@ void SplitFile::getFilenames( vector< string > & names ) const
names.push_back( ( *i )->fileName().toStdString() );
}
+int SplitFile::getCurrentFile() const
+{
+ return currentFile;
+}
+
bool SplitFile::open( QFile::OpenMode mode )
{
for ( QVector< QFile * >::iterator i = files.begin(); i != files.end(); ++i )
diff --git a/src/splitfile.hh b/src/splitfile.hh
index 2b308094f..3801e5f21 100644
--- a/src/splitfile.hh
+++ b/src/splitfile.hh
@@ -32,6 +32,7 @@ public:
virtual void setFileName( const QString & name ) = 0;
void getFilenames( vector< string > & names ) const;
+ int getCurrentFile() const;
bool open( QFile::OpenMode mode );
void close();
bool seek( quint64 pos );
diff --git a/src/ui/articleview.cc b/src/ui/articleview.cc
index 048fcc5a9..3c6d306ad 100644
--- a/src/ui/articleview.cc
+++ b/src/ui/articleview.cc
@@ -2026,8 +2026,13 @@ void ArticleView::performFindOperation( bool backwards )
f |= QWebEnginePage::FindBackward;
findText( text, f, [ text, this ]( bool match ) {
- bool setMark = !text.isEmpty() && !match;
- Utils::Widget::setNoResultColor( searchPanel->lineEdit, setMark );
+ bool nomatch = !text.isEmpty() && !match;
+ if ( nomatch ) {
+ //clear the previous findText results.
+ //when the results is empty, the highlight has not been removed.more likely a qt bug.
+ webview->findText( "" );
+ }
+ Utils::Widget::setNoResultColor( searchPanel->lineEdit, nomatch );
} );
}
@@ -2065,10 +2070,7 @@ bool ArticleView::closeSearch()
ftsSearchPanel->hide();
webview->setFocus();
- QWebEnginePage::FindFlags flags( 0 );
-
- webview->findText( "", flags );
-
+ webview->findText( "" );
return true;
}
return false;
diff --git a/src/ui/mainwindow.cc b/src/ui/mainwindow.cc
index 2e4a2af3e..e240d00c4 100644
--- a/src/ui/mainwindow.cc
+++ b/src/ui/mainwindow.cc
@@ -1535,7 +1535,7 @@ void MainWindow::makeDictionaries()
ftsIndexing.doIndexing();
updateStatusLine();
- updateGroupList();
+ updateGroupList( false );
}
void MainWindow::updateStatusLine()
@@ -1597,9 +1597,9 @@ void MainWindow::updateGroupList( bool reload )
updateDictionaryBar();
- qDebug() << "Reloading all the tabs...";
-
if ( reload ) {
+ qDebug() << "Reloading all the tabs...";
+
for ( int i = 0; i < ui.tabWidget->count(); ++i ) {
auto & view = dynamic_cast< ArticleView & >( *( ui.tabWidget->widget( i ) ) );
diff --git a/website/docs/topic_gd-tools.md b/website/docs/topic_gd-tools.md
new file mode 100644
index 000000000..f6a5146df
--- /dev/null
+++ b/website/docs/topic_gd-tools.md
@@ -0,0 +1,28 @@
+# GoldenDict tools
+
+A set of helpful programs to enhance goldendict for immersion learning.
+
+
+# prerequisite
+1. install [gd-tools](https://codeberg.org/hashirama/gd-tools) and configure it according to its README
+
+# features:
+- japanese sentence spliting, making each part of the sentence clickable
+![Alt](https://codeberg.org/hashirama/gd-tools/raw/branch/main/misc/marisa.gif)
+
+## How to setup:
+Open GoldenDict, press "Edit" > "Dictionaries" > "Programs" and add the installed executables. Set type to html. Command Line: gd-tools --word %GDWORD% --sentence %GDSEARCH%. Optionally add arguments, such as: gd-tools marisa --word %GDWORD% --sentence %GDSEARCH% . These programs are treated as dictionaries and you can add them under "Dictionaries" or "Groups".
+
+please notice that gd-tools does works in windows, and we have an [installer](https://www.mediafire.com/file/h1v7owj7np9j7wg/gd-tools_windows.zip/file) for it, you can install and then come back to the previous instruction.
+And if you're at Gnu Guix, install it from our [channel](https://codeberg.org/hashirama/ajattix)
+other features:
+- kanji stroke order: for those who want to know how to write a character
+- image searching
+and much more, please see our list [here](https://codeberg.org/hashirama/gd-tools/src/branch/main/README.md#table-of-contents)
+
+# Misc
+we have a mandarin version of gd-marisa, which relies on mecab (unix only) :
+![image](https://codeberg.org/hashirama/gd-tools/raw/branch/main/misc/mandarin.png)
+
+# Notes
+This article was written by 柱間(developer of gd-tools).
diff --git a/website/mkdocs.yml b/website/mkdocs.yml
index 3f6b6910e..ed69f8378 100644
--- a/website/mkdocs.yml
+++ b/website/mkdocs.yml
@@ -37,17 +37,19 @@ nav:
- Favorites: ui_favorites.md
- Shortcuts: ui_shortcuts.md
- Advanced Usages:
- - Anki Integration: topic_anki.md
- Program dictionary: howto/how to add a program as dictionary.md
- Command Lines: topic_commandline.md
- Custom Stylesheet & JavaScript: topic_userstyle.md
- Portable Mode: topic_portablemode.md
- Custom transliteration: topic_transliteration.md
- Customize Dictionary: custom_dictionary.md
- - OCR Integration: howto/ocr.md
- Wayland: topic_wayland.md
- Debug dictionary JS: howto/how to debug dictionary js.md
- Flatpak/FlatHub: topic_flatpak.md
+ - Related tools:
+ - Anki Integration: topic_anki.md
+ - OCR Integration: howto/ocr.md
+ - gd-tools: topic_gd-tools.md
- Report Bugs & Feedbacks: feedbacks.md
- Development Info:
- Start develop: developer.md