diff --git a/src/dict/dictionary.cc b/src/dict/dictionary.cc index 21433ad4..678e1471 100644 --- a/src/dict/dictionary.cc +++ b/src/dict/dictionary.cc @@ -17,7 +17,6 @@ #include #include #include -#include "fsencoding.hh" #include #include #include diff --git a/src/headwordsmodel.cc b/src/headwordsmodel.cc index e6b3ebad..c7a999f3 100644 --- a/src/headwordsmodel.cc +++ b/src/headwordsmodel.cc @@ -46,10 +46,29 @@ void HeadwordListModel::setFilter( QRegularExpression reg ) queuedRequests.push_back( sr ); } +void HeadwordListModel::addMatches( QStringList matches) +{ + QStringList filtered; + for ( auto & w : matches ) { + if ( !words.contains( w ) ) { + filtered << w; + } + } + + if ( filtered.isEmpty() ) + return; + + beginInsertRows( QModelIndex(), words.size(), words.size() + filtered.count() - 1 ); + for ( const auto & word : filtered ) { + words.append( word ); + } + endInsertRows(); +} + void HeadwordListModel::requestFinished() { // See how many new requests have finished, and if we have any new results - for( std::list< sptr< Dictionary::WordSearchRequest > >::iterator i = queuedRequests.begin(); + for( auto i = queuedRequests.begin(); i != queuedRequests.end(); ) { if( ( *i )->isFinished() ) diff --git a/src/headwordsmodel.hh b/src/headwordsmodel.hh index b227f235..7c7d76f8 100644 --- a/src/headwordsmodel.hh +++ b/src/headwordsmodel.hh @@ -20,6 +20,7 @@ public: QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const override; QString getRow( int row ); void setFilter( QRegularExpression ); + void addMatches( QStringList matches ); int getCurrentIndex(); QSet< QString > getRemainRows( int & nodeIndex ); signals: diff --git a/src/ui/dictheadwords.cc b/src/ui/dictheadwords.cc index aa43c89a..931cbd50 100644 --- a/src/ui/dictheadwords.cc +++ b/src/ui/dictheadwords.cc @@ -17,19 +17,19 @@ #include "wildcard.hh" #include "help.hh" #include +#include #define AUTO_APPLY_LIMIT 150000 -DictHeadwords::DictHeadwords( QWidget *parent, Config::Class & cfg_, - Dictionary::Class * dict_ ) : - QDialog(parent) -, cfg( cfg_ ) -, dict( dict_ ) -, helpAction( this ) +DictHeadwords::DictHeadwords( QWidget * parent, Config::Class & cfg_, Dictionary::Class * dict_ ): + QDialog( parent ), + cfg( cfg_ ), + dict( dict_ ), + helpAction( this ) { ui.setupUi( this ); - bool fromMainWindow = parent->objectName() == "MainWindow"; + const bool fromMainWindow = parent->objectName() == "MainWindow"; if( fromMainWindow ) setAttribute( Qt::WA_DeleteOnClose, false ); @@ -126,7 +126,7 @@ void DictHeadwords::setup( Dictionary::Class *dict_ ) setWindowTitle( QString::fromUtf8( dict->getName().c_str() ) ); - auto size = dict->getWordCount(); + const auto size = dict->getWordCount(); model->setDict(dict); proxy->sort( 0 ); filterChanged(); @@ -180,13 +180,13 @@ bool DictHeadwords::eventFilter( QObject * obj, QEvent * ev ) void DictHeadwords::okButtonClicked() { savePos(); - closeDialog(); + emit closeDialog(); } void DictHeadwords::reject() { savePos(); - closeDialog(); + emit closeDialog(); } void DictHeadwords::exportButtonClicked() @@ -201,11 +201,11 @@ void DictHeadwords::filterChangedInternal() QTimer::singleShot( 100, this, &DictHeadwords::filterChanged ); } -void DictHeadwords::filterChanged() +QRegularExpression DictHeadwords::getFilterRegex( ) { - QRegExp::PatternSyntax syntax = - QRegExp::PatternSyntax( ui.searchModeCombo->itemData( - ui.searchModeCombo->currentIndex()).toInt() ); + const QRegExp::PatternSyntax syntax = + static_cast< QRegExp::PatternSyntax >(ui.searchModeCombo->itemData( + ui.searchModeCombo->currentIndex() ).toInt()); QRegularExpression::PatternOptions options = QRegularExpression::UseUnicodePropertiesOption; if( !ui.matchCase->isChecked() ) @@ -214,28 +214,46 @@ void DictHeadwords::filterChanged() QString pattern; switch( syntax ) { - case QRegExp::FixedString: - pattern = QRegularExpression::escape( ui.filterLine->text() ); - break; - case QRegExp::WildcardUnix: - pattern = wildcardsToRegexp( ui.filterLine->text() ); - break; - default: - pattern = ui.filterLine->text(); - break; + case QRegExp::FixedString: + pattern = QRegularExpression::escape( ui.filterLine->text() ); + break; + case QRegExp::WildcardUnix: + pattern = wildcardsToRegexp( ui.filterLine->text() ); + break; + default: + pattern = ui.filterLine->text(); + break; } - QRegularExpression regExp( pattern, options ); + QRegularExpression regExp = QRegularExpression( pattern, options ); if( !regExp.isValid() ) { gdWarning( "Invalid regexp pattern: %s\n", pattern.toUtf8().data() ); - regExp.setPattern( QString::fromLatin1( "\1" ) ); } + return regExp; +} + +void DictHeadwords::filterChanged() +{ + const QRegularExpression regExp= getFilterRegex(); QApplication::setOverrideCursor( Qt::WaitCursor ); - model->setFilter(regExp); + qDebug()<totalCount(); + + QProgressDialog progress( tr( "Loading headwords..." ), tr( "Cancel" ), 0, headwordsNumber, this ); + progress.setWindowModality( Qt::WindowModal ); + loadAllSortedWords( progress ); + progress.close(); + } + + const auto filtered = sortedWords.filter( regExp ); + model->addMatches( filtered ); + + // model->setFilter(regExp); proxy->setFilterRegularExpression( regExp ); proxy->sort( 0 ); @@ -266,6 +284,47 @@ void DictHeadwords::showHeadwordsNumber() .arg( QString::number( model->totalCount() ), QString::number( proxy->rowCount() ) ) ); } +// TODO , the ui and the code mixed together , this is not the right way to do this. need future refactor +void DictHeadwords::loadAllSortedWords( QProgressDialog & progress ) +{ + const int headwordsNumber = model->totalCount(); + + QMutexLocker _( &mutex ); + if ( sortedWords.isEmpty() ) { + QSet< QString > allHeadwords; + + int totalCount = 0; + for ( int i = 0; i < headwordsNumber && i < model->wordCount(); ++i ) { + if ( progress.wasCanceled() ) + break; + progress.setValue( totalCount++ ); + + QVariant value = model->getRow( i ); + if ( !value.canConvert< QString >() ) + continue; + + allHeadwords.insert( value.toString() ); + } + + // continue to write the remaining headword + int nodeIndex = model->getCurrentIndex(); + auto headwords = model->getRemainRows( nodeIndex ); + while ( !headwords.isEmpty() ) { + if ( progress.wasCanceled() ) + break; + allHeadwords.unite( headwords ); + + totalCount += headwords.size(); + progress.setValue( totalCount ); + + headwords = model->getRemainRows( nodeIndex ); + } + + sortedWords = allHeadwords.values(); + sortedWords.sort(); + } +} + void DictHeadwords::saveHeadersToFile() { QString exportPath; @@ -295,59 +354,34 @@ void DictHeadwords::saveHeadersToFile() cfg.headwordsDialog.headwordsExportPath = QDir::toNativeSeparators( QFileInfo( fileName ).absoluteDir().absolutePath() ); - QSet< QString > allHeadwords; - int headwordsNumber = model->totalCount(); + const int headwordsNumber = model->totalCount(); - //headwordsNumber*2 , read + write QProgressDialog progress( tr( "Export headwords..." ), tr( "Cancel" ), 0, headwordsNumber*2, this ); progress.setWindowModality( Qt::WindowModal ); - int totalCount=0; - for( int i = 0; i < headwordsNumber && i < model->wordCount(); ++i ) - { - if( progress.wasCanceled() ) - break; - progress.setValue( totalCount++ ); - - QVariant value = model->getRow( i ); - if( !value.canConvert< QString >() ) - continue; - - allHeadwords.insert( value.toString() ); - } - - // continue to write the remaining headword - int nodeIndex = model->getCurrentIndex(); - auto headwords = model->getRemainRows( nodeIndex ); - while( !headwords.isEmpty() ) - { - if( progress.wasCanceled() ) - break; - allHeadwords.unite(headwords); - - totalCount += headwords.size(); - progress.setValue( totalCount ); - - headwords = model->getRemainRows( nodeIndex ); - } - - qDebug()<getCurrentIndex(); + loadAllSortedWords( progress ); // Write UTF-8 BOM QByteArray line; line.append( 0xEF ).append( 0xBB ).append( 0xBF ); file.write( line ); - QList< QString > sortedWords = allHeadwords.values(); - sortedWords.sort(); + QStringList filtered; + const QRegularExpression regExp = getFilterRegex(); + if(regExp.isValid() && !regExp.pattern().isEmpty()){ + filtered = sortedWords.filter( regExp ); + } + else{ + filtered = sortedWords; + } + auto currentValue = progress.value(); // Write headwords - for( auto const & word : sortedWords ) + for ( auto const & word : filtered ) { if( progress.wasCanceled() ) break; - progress.setValue( totalCount++ ); - + progress.setValue( currentValue++ ); line = word.toUtf8(); line.replace( '\n', ' ' ); @@ -361,6 +395,7 @@ void DictHeadwords::saveHeadersToFile() file.close(); + progress.setValue( progress.maximum() ); if( progress.wasCanceled() ) { QMessageBox::warning( this, "GoldenDict", tr( "Export process is interrupted" ) ); @@ -370,7 +405,7 @@ void DictHeadwords::saveHeadersToFile() { //completed. progress.setValue(headwordsNumber*2); - progress.hide(); + progress.close(); QMessageBox::information( this, "GoldenDict", tr( "Export finished" ) ); } } diff --git a/src/ui/dictheadwords.hh b/src/ui/dictheadwords.hh index 1c789bce..5bc1a26e 100644 --- a/src/ui/dictheadwords.hh +++ b/src/ui/dictheadwords.hh @@ -8,6 +8,7 @@ #include #include #include +#include #include "config.hh" #include "ui_dictheadwords.h" @@ -42,15 +43,19 @@ protected: private: Ui::DictHeadwords ui; + QStringList sortedWords; + QMutex mutex; private slots: void savePos(); void filterChangedInternal(); + QRegularExpression getFilterRegex(); void filterChanged(); void exportButtonClicked(); void okButtonClicked(); void itemClicked( const QModelIndex & index ); void autoApplyStateChanged( int state ); void showHeadwordsNumber(); + void loadAllSortedWords( QProgressDialog & progress ); virtual void reject(); signals: