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 <QCryptographicHash>
#include <QDateTime>
#include "fsencoding.hh"
#include <QImage>
#include <QPainter>
#include <QRegularExpression>

View file

@ -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() )

View file

@ -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:

View file

@ -17,19 +17,19 @@
#include "wildcard.hh"
#include "help.hh"
#include <QMessageBox>
#include <QMutexLocker>
#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() )
@ -225,17 +225,35 @@ void DictHeadwords::filterChanged()
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()<<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->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()<<model->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" ) );
}
}

View file

@ -8,6 +8,7 @@
#include <QStringListModel>
#include <QSortFilterProxyModel>
#include <QAction>
#include <qprogressdialog.h>
#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: