diff --git a/README.md b/README.md index c6c4714f..21735eb9 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,6 @@ sudo dnf install git pkg-config libzstd-devel opencc-devel xz-devel xz-lzma-comp libao-devel ffmpeg-devel libtiff-devel eb-devel qt5-qtx11extras-devel libXtst-devel \ libxkbcommon-devel qt5-qtbase qt5-qttools qt5-qtsvg-devl qt5-qtwebengine-devel qt5-qtmultimedia-devl -qmake-qt5 CONFIG+=release CONFIG+=no_extra_tiff_handler CONFIG+=no_epwing_support -make - - ``` ## How to build @@ -48,11 +44,20 @@ First, clone this repository, e.g.: git clone https://github.com/xiaoyifang/goldendict.git -### Linux +### Linux (fedora) And then invoke `qmake-qt5` and `make`: cd goldendict && qmake-qt5 && make +### ArchLinux + +on archlinux based os, you can use `yay` to install the community goldendict-webengine-git . + + #(Manjaro distribution) + pacman -S --needed git base-devel yay + + yay -S goldendict-webengine-git + ### macOS ``` brew install qt # or use official offline installer diff --git a/btreeidx.cc b/btreeidx.cc index cb4355d2..3667abe1 100644 --- a/btreeidx.cc +++ b/btreeidx.cc @@ -1313,12 +1313,12 @@ void BtreeIndex::findSingleNodeHeadwords( uint32_t offsets, vector< char > extLeaf; - // A node + // A node readNode( currentNodeOffset, extLeaf ); - leaf = &extLeaf.front(); + leaf = &extLeaf.front(); leafEnd = leaf + extLeaf.size(); - // A leaf + // A leaf chainPtr = leaf + sizeof( uint32_t ); for( ;; ) @@ -1353,9 +1353,16 @@ QSet BtreeIndex::findNodes() } char const * leaf = &rootNode.front(); - - vector< char > extLeaf; QSet leafOffset; + + uint32_t leafEntries; + leafEntries = *(uint32_t *)leaf; + if ( leafEntries != 0xffffFFFF ) + { + leafOffset.insert(rootOffset); + return leafOffset; + } + // the current the btree's implementation has the height = 2. // A node offset diff --git a/config.cc b/config.cc index e028ad90..cf226dbc 100644 --- a/config.cc +++ b/config.cc @@ -184,8 +184,8 @@ InputPhrase Preferences::sanitizeInputPhrase( QString const & inputPhrase ) cons if( limitInputPhraseLength && inputPhrase.size() > inputPhraseLengthLimit ) { - gdWarning( "Ignoring an input phrase %d symbols long. The configured maximum input phrase length is %d symbols.", - inputPhrase.size(), inputPhraseLengthLimit ); + gdDebug( "Ignoring an input phrase %d symbols long. The configured maximum input phrase length is %d symbols.", + inputPhrase.size(), inputPhraseLengthLimit ); return result; } diff --git a/dsl_details.cc b/dsl_details.cc index 965ce1c6..569a2d55 100644 --- a/dsl_details.cc +++ b/dsl_details.cc @@ -12,6 +12,7 @@ #include #include + #include namespace Dsl { @@ -164,12 +165,37 @@ wstring ArticleDom::Node::renderAsText( bool stripTrsTag ) const return result; } -// Returns true if src == 'm' and dest is 'mX', where X is a digit -static inline bool checkM( wstring const & dest, wstring const & src ) +namespace { + +/// @return true if @p tagName equals "mN" where N is a digit +bool is_mN( wstring const & tagName ) { - return ( src == U"m" && dest.size() == 2 && dest[ 0 ] == L'm' && iswdigit( dest[ 1 ] ) ); + return tagName.size() == 2 && tagName[ 0 ] == U'm' && iswdigit( tagName[ 1 ] ); } +bool isAnyM( wstring const & tagName ) +{ + return tagName == U"m" || is_mN( tagName ); +} + +bool checkM( wstring const & dest, wstring const & src ) +{ + return src == U"m" && is_mN( dest ); +} + +/// Closing the [mN] tags is optional. Quote from https://documentation.help/ABBYY-Lingvo8/paragraph_form.htm: +/// Any paragraph from this tag until the end of card or until system meets an «[/m]» (margin shift toggle off) tag +struct MustTagBeClosed +{ + bool operator()( ArticleDom::Node const * tag ) const + { + Q_ASSERT( tag->isTag ); + return !isAnyM( tag->tagName ); + } +}; + +} // unnamed namespace + ArticleDom::ArticleDom( wstring const & str, string const & dictName, wstring const & headword_): root( Node::Tag(), wstring(), wstring() ), stringPos( str.c_str() ), @@ -375,7 +401,7 @@ ArticleDom::ArticleDom( wstring const & str, string const & dictName, if ( !isClosing ) { - if( name == U"m" || ( name.size() == 2 && name[ 0 ] == L'm' && iswdigit( name[ 1 ] ) ) ) + if( isAnyM( name ) ) { // Opening an 'mX' or 'm' tag closes any previous 'm' tag closeTag( U"m" , stack, false ); @@ -630,7 +656,24 @@ ArticleDom::ArticleDom( wstring const & str, string const & dictName, if ( stack.size() ) { - GD_FDPRINTF( stderr, "Warning: %u tags were unclosed.\n", (unsigned) stack.size() ); + list< Node * >::iterator it = std::find_if( stack.begin(), stack.end(), MustTagBeClosed() ); + if( it == stack.end() ) + return; // no unclosed tags that must be closed => nothing to warn about + QByteArray const firstTagName = gd::toQString( ( *it )->tagName ).toUtf8(); + ++it; + unsigned const unclosedTagCount = 1 + std::count_if( it, stack.end(), MustTagBeClosed() ); + + if( dictName.empty() ) + { + gdWarning( "Warning: %u tag(s) were unclosed, first tag name \"%s\".\n", + unclosedTagCount, firstTagName.constData() ); + } + else + { + gdWarning( "Warning: %u tag(s) were unclosed in \"%s\", article \"%s\", first tag name \"%s\".\n", + unclosedTagCount, dictName.c_str(), gd::toQString( headword ).toUtf8().constData(), + firstTagName.constData() ); + } } } @@ -640,7 +683,7 @@ void ArticleDom::openTag( wstring const & name, { list< Node > nodesToReopen; - if( name == U"m" || checkM( name, U"m" ) ) + if( isAnyM( name ) ) { // All tags above [m] tag will be closed and reopened after // to avoid break this tag by closing some other tag. diff --git a/favoritespanewidget.cc b/favoritespanewidget.cc index d97b2673..5eea16e0 100644 --- a/favoritespanewidget.cc +++ b/favoritespanewidget.cc @@ -208,12 +208,12 @@ void FavoritesPaneWidget::onSelectionChanged( QItemSelection const & selection ) return; itemSelectionChanged = true; - emitFavoritesItemRequested( selection.indexes().front() ); +// emitFavoritesItemRequested( selection.indexes().front() ); } void FavoritesPaneWidget::onItemClicked( QModelIndex const & idx ) { - if ( !itemSelectionChanged && m_favoritesTree->selectionModel()->selectedIndexes().size() == 1 ) +// if ( !itemSelectionChanged && m_favoritesTree->selectionModel()->selectedIndexes().size() == 1 ) { emitFavoritesItemRequested( idx ); } @@ -628,7 +628,7 @@ void FavoritesModel::readData() QFile favoritesFile( m_favoritesFilename ); if( !favoritesFile.open( QFile::ReadOnly ) ) { - gdWarning( "No favorities file found" ); + gdDebug( "No favorites file found" ); return; } diff --git a/ffmpegaudio.cc b/ffmpegaudio.cc index db83b79c..17bafd83 100644 --- a/ffmpegaudio.cc +++ b/ffmpegaudio.cc @@ -240,7 +240,7 @@ bool DecoderContext::openCodec( QString & errorString ) return false; } - av_log( NULL, AV_LOG_INFO, "Codec open: %s: channels: %d, rate: %d, format: %s\n", codec_->long_name, + gdDebug( "Codec open: %s: channels: %d, rate: %d, format: %s\n", codec_->long_name, codecContext_->channels, codecContext_->sample_rate, av_get_sample_fmt_name( codecContext_->sample_fmt ) ); if ( codecContext_->sample_fmt == AV_SAMPLE_FMT_S32 || @@ -341,7 +341,7 @@ bool DecoderContext::openOutputDevice( QString & errorString ) return false; } - av_log( NULL, AV_LOG_INFO, "ao_open_live(): %s: channels: %d, rate: %d, bits: %d\n", + gdDebug( "ao_open_live(): %s: channels: %d, rate: %d, bits: %d\n", aoDrvInfo->name, aoSampleFormat.channels, aoSampleFormat.rate, aoSampleFormat.bits ); aoDevice_ = ao_open_live( aoDriverId, &aoSampleFormat, NULL ); diff --git a/goldendict.pro b/goldendict.pro index 29e8914a..0ab34719 100644 --- a/goldendict.pro +++ b/goldendict.pro @@ -666,9 +666,10 @@ TS_OUT = $$TRANSLATIONS TS_OUT ~= s/.ts/.qm/g PRE_TARGETDEPS += $$TS_OUT -equals(QT_VERSION,6.4.0){ +equals(QT_VERSION,6.4.0) +{ #QTBUG-105984 - multimedia.files = $$[QT_INSTALL_PLUGINS]/multimedia/* + multimedia.files = $$[QT_PLUGIN_PATH]/multimedia/* multimedia.path = plugins/multimedia #multimedia.CONFIG += no_check_exist message("copy qt6.4.0 multimedia") diff --git a/historypanewidget.cc b/historypanewidget.cc index 81216b94..2a47fdd9 100644 --- a/historypanewidget.cc +++ b/historypanewidget.cc @@ -202,14 +202,14 @@ void HistoryPaneWidget::onSelectionChanged( QItemSelection const & selection ) return; itemSelectionChanged = true; - emitHistoryItemRequested( selection.front().topLeft() ); +// emitHistoryItemRequested( selection.front().topLeft() ); } void HistoryPaneWidget::onItemClicked( QModelIndex const & idx ) { // qDebug() << "clicked"; - if ( !itemSelectionChanged ) +// if ( !itemSelectionChanged ) { emitHistoryItemRequested( idx ); }