fix: headword dialog filter and export

the wildcard and regex filter does not work as expected.

fix #556
This commit is contained in:
xiaoyifang 2023-04-22 12:03:53 +08:00
parent d0ae253c27
commit 72fca59a92
5 changed files with 126 additions and 67 deletions

View file

@ -17,7 +17,6 @@
#include <QFileInfo> #include <QFileInfo>
#include <QCryptographicHash> #include <QCryptographicHash>
#include <QDateTime> #include <QDateTime>
#include "fsencoding.hh"
#include <QImage> #include <QImage>
#include <QPainter> #include <QPainter>
#include <QRegularExpression> #include <QRegularExpression>

View file

@ -46,10 +46,29 @@ void HeadwordListModel::setFilter( QRegularExpression reg )
queuedRequests.push_back( sr ); 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() void HeadwordListModel::requestFinished()
{ {
// See how many new requests have finished, and if we have any new results // 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(); ) i != queuedRequests.end(); )
{ {
if( ( *i )->isFinished() ) if( ( *i )->isFinished() )

View file

@ -20,6 +20,7 @@ public:
QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const override; QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const override;
QString getRow( int row ); QString getRow( int row );
void setFilter( QRegularExpression ); void setFilter( QRegularExpression );
void addMatches( QStringList matches );
int getCurrentIndex(); int getCurrentIndex();
QSet< QString > getRemainRows( int & nodeIndex ); QSet< QString > getRemainRows( int & nodeIndex );
signals: signals:

View file

@ -17,19 +17,19 @@
#include "wildcard.hh" #include "wildcard.hh"
#include "help.hh" #include "help.hh"
#include <QMessageBox> #include <QMessageBox>
#include <QMutexLocker>
#define AUTO_APPLY_LIMIT 150000 #define AUTO_APPLY_LIMIT 150000
DictHeadwords::DictHeadwords( QWidget *parent, Config::Class & cfg_, DictHeadwords::DictHeadwords( QWidget * parent, Config::Class & cfg_, Dictionary::Class * dict_ ):
Dictionary::Class * dict_ ) : QDialog( parent ),
QDialog(parent) cfg( cfg_ ),
, cfg( cfg_ ) dict( dict_ ),
, dict( dict_ ) helpAction( this )
, helpAction( this )
{ {
ui.setupUi( this ); ui.setupUi( this );
bool fromMainWindow = parent->objectName() == "MainWindow"; const bool fromMainWindow = parent->objectName() == "MainWindow";
if( fromMainWindow ) if( fromMainWindow )
setAttribute( Qt::WA_DeleteOnClose, false ); setAttribute( Qt::WA_DeleteOnClose, false );
@ -126,7 +126,7 @@ void DictHeadwords::setup( Dictionary::Class *dict_ )
setWindowTitle( QString::fromUtf8( dict->getName().c_str() ) ); setWindowTitle( QString::fromUtf8( dict->getName().c_str() ) );
auto size = dict->getWordCount(); const auto size = dict->getWordCount();
model->setDict(dict); model->setDict(dict);
proxy->sort( 0 ); proxy->sort( 0 );
filterChanged(); filterChanged();
@ -180,13 +180,13 @@ bool DictHeadwords::eventFilter( QObject * obj, QEvent * ev )
void DictHeadwords::okButtonClicked() void DictHeadwords::okButtonClicked()
{ {
savePos(); savePos();
closeDialog(); emit closeDialog();
} }
void DictHeadwords::reject() void DictHeadwords::reject()
{ {
savePos(); savePos();
closeDialog(); emit closeDialog();
} }
void DictHeadwords::exportButtonClicked() void DictHeadwords::exportButtonClicked()
@ -201,10 +201,10 @@ void DictHeadwords::filterChangedInternal()
QTimer::singleShot( 100, this, &DictHeadwords::filterChanged ); QTimer::singleShot( 100, this, &DictHeadwords::filterChanged );
} }
void DictHeadwords::filterChanged() QRegularExpression DictHeadwords::getFilterRegex( )
{ {
QRegExp::PatternSyntax syntax = const QRegExp::PatternSyntax syntax =
QRegExp::PatternSyntax( ui.searchModeCombo->itemData( static_cast< QRegExp::PatternSyntax >(ui.searchModeCombo->itemData(
ui.searchModeCombo->currentIndex() ).toInt()); ui.searchModeCombo->currentIndex() ).toInt());
QRegularExpression::PatternOptions options = QRegularExpression::UseUnicodePropertiesOption; QRegularExpression::PatternOptions options = QRegularExpression::UseUnicodePropertiesOption;
@ -225,17 +225,35 @@ void DictHeadwords::filterChanged()
break; break;
} }
QRegularExpression regExp( pattern, options ); QRegularExpression regExp = QRegularExpression( pattern, options );
if( !regExp.isValid() ) if( !regExp.isValid() )
{ {
gdWarning( "Invalid regexp pattern: %s\n", pattern.toUtf8().data() ); 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 ); QApplication::setOverrideCursor( Qt::WaitCursor );
model->setFilter(regExp); qDebug()<<regExp.pattern();
if ( sortedWords.isEmpty() && regExp.isValid() && !regExp.pattern().isEmpty() ) {
const int headwordsNumber = model->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->setFilterRegularExpression( regExp );
proxy->sort( 0 ); proxy->sort( 0 );
@ -266,6 +284,47 @@ void DictHeadwords::showHeadwordsNumber()
.arg( QString::number( model->totalCount() ), QString::number( proxy->rowCount() ) ) ); .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() void DictHeadwords::saveHeadersToFile()
{ {
QString exportPath; QString exportPath;
@ -295,59 +354,34 @@ void DictHeadwords::saveHeadersToFile()
cfg.headwordsDialog.headwordsExportPath = QDir::toNativeSeparators( cfg.headwordsDialog.headwordsExportPath = QDir::toNativeSeparators(
QFileInfo( fileName ).absoluteDir().absolutePath() ); QFileInfo( fileName ).absoluteDir().absolutePath() );
QSet< QString > allHeadwords; const int headwordsNumber = model->totalCount();
int headwordsNumber = model->totalCount();
//headwordsNumber*2 , read + write
QProgressDialog progress( tr( "Export headwords..." ), tr( "Cancel" ), 0, headwordsNumber*2, this ); QProgressDialog progress( tr( "Export headwords..." ), tr( "Cancel" ), 0, headwordsNumber*2, this );
progress.setWindowModality( Qt::WindowModal ); progress.setWindowModality( Qt::WindowModal );
int totalCount=0; loadAllSortedWords( progress );
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()<<model->getCurrentIndex();
// Write UTF-8 BOM // Write UTF-8 BOM
QByteArray line; QByteArray line;
line.append( 0xEF ).append( 0xBB ).append( 0xBF ); line.append( 0xEF ).append( 0xBB ).append( 0xBF );
file.write( line ); file.write( line );
QList< QString > sortedWords = allHeadwords.values(); QStringList filtered;
sortedWords.sort();
const QRegularExpression regExp = getFilterRegex();
if(regExp.isValid() && !regExp.pattern().isEmpty()){
filtered = sortedWords.filter( regExp );
}
else{
filtered = sortedWords;
}
auto currentValue = progress.value();
// Write headwords // Write headwords
for( auto const & word : sortedWords ) for ( auto const & word : filtered )
{ {
if( progress.wasCanceled() ) if( progress.wasCanceled() )
break; break;
progress.setValue( totalCount++ ); progress.setValue( currentValue++ );
line = word.toUtf8(); line = word.toUtf8();
line.replace( '\n', ' ' ); line.replace( '\n', ' ' );
@ -361,6 +395,7 @@ void DictHeadwords::saveHeadersToFile()
file.close(); file.close();
progress.setValue( progress.maximum() );
if( progress.wasCanceled() ) if( progress.wasCanceled() )
{ {
QMessageBox::warning( this, "GoldenDict", tr( "Export process is interrupted" ) ); QMessageBox::warning( this, "GoldenDict", tr( "Export process is interrupted" ) );
@ -370,7 +405,7 @@ void DictHeadwords::saveHeadersToFile()
{ {
//completed. //completed.
progress.setValue(headwordsNumber*2); progress.setValue(headwordsNumber*2);
progress.hide(); progress.close();
QMessageBox::information( this, "GoldenDict", tr( "Export finished" ) ); QMessageBox::information( this, "GoldenDict", tr( "Export finished" ) );
} }
} }

View file

@ -8,6 +8,7 @@
#include <QStringListModel> #include <QStringListModel>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QAction> #include <QAction>
#include <qprogressdialog.h>
#include "config.hh" #include "config.hh"
#include "ui_dictheadwords.h" #include "ui_dictheadwords.h"
@ -42,15 +43,19 @@ protected:
private: private:
Ui::DictHeadwords ui; Ui::DictHeadwords ui;
QStringList sortedWords;
QMutex mutex;
private slots: private slots:
void savePos(); void savePos();
void filterChangedInternal(); void filterChangedInternal();
QRegularExpression getFilterRegex();
void filterChanged(); void filterChanged();
void exportButtonClicked(); void exportButtonClicked();
void okButtonClicked(); void okButtonClicked();
void itemClicked( const QModelIndex & index ); void itemClicked( const QModelIndex & index );
void autoApplyStateChanged( int state ); void autoApplyStateChanged( int state );
void showHeadwordsNumber(); void showHeadwordsNumber();
void loadAllSortedWords( QProgressDialog & progress );
virtual void reject(); virtual void reject();
signals: signals: