2014-02-28 12:36:28 +00:00
|
|
|
/* This file is (c) 2014 Abs62
|
|
|
|
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
|
|
|
|
|
|
|
#include "dictheadwords.hh"
|
|
|
|
#include "gddebug.hh"
|
2023-05-27 09:50:41 +00:00
|
|
|
#include "headwordsmodel.hh"
|
2014-02-28 12:36:28 +00:00
|
|
|
#include <QDir>
|
|
|
|
#include <QFileDialog>
|
|
|
|
#include <QTimer>
|
|
|
|
#include <QProgressDialog>
|
|
|
|
|
2019-03-25 15:08:52 +00:00
|
|
|
#include <QRegularExpression>
|
|
|
|
#include "wildcard.hh"
|
2023-04-22 00:43:50 +00:00
|
|
|
#include "help.hh"
|
2022-12-31 06:01:48 +00:00
|
|
|
#include <QMessageBox>
|
2023-04-22 04:03:53 +00:00
|
|
|
#include <QMutexLocker>
|
2023-05-27 09:50:41 +00:00
|
|
|
#include <memory>
|
2019-03-25 15:08:52 +00:00
|
|
|
|
2014-02-28 12:36:28 +00:00
|
|
|
|
2024-06-22 11:34:09 +00:00
|
|
|
enum SearchType {
|
|
|
|
FixedString,
|
|
|
|
Wildcard,
|
|
|
|
Regex
|
|
|
|
};
|
2023-04-22 04:03:53 +00:00
|
|
|
DictHeadwords::DictHeadwords( QWidget * parent, Config::Class & cfg_, Dictionary::Class * dict_ ):
|
|
|
|
QDialog( parent ),
|
|
|
|
cfg( cfg_ ),
|
|
|
|
dict( dict_ ),
|
|
|
|
helpAction( this )
|
2014-02-28 12:36:28 +00:00
|
|
|
{
|
|
|
|
ui.setupUi( this );
|
|
|
|
|
2023-04-22 04:03:53 +00:00
|
|
|
const bool fromMainWindow = parent->objectName() == "MainWindow";
|
2015-03-23 15:58:49 +00:00
|
|
|
|
|
|
|
if ( fromMainWindow )
|
|
|
|
setAttribute( Qt::WA_DeleteOnClose, false );
|
|
|
|
|
2014-03-03 13:46:41 +00:00
|
|
|
setWindowFlags( windowFlags() & ~Qt::WindowContextHelpButtonHint );
|
2014-02-28 12:36:28 +00:00
|
|
|
|
2019-03-19 14:36:07 +00:00
|
|
|
if ( cfg.headwordsDialog.headwordsDialogGeometry.size() > 0 )
|
|
|
|
restoreGeometry( cfg.headwordsDialog.headwordsDialogGeometry );
|
|
|
|
|
2024-06-22 11:34:09 +00:00
|
|
|
ui.searchModeCombo->addItem( tr( "Text" ), SearchType::FixedString );
|
|
|
|
ui.searchModeCombo->addItem( tr( "Wildcards" ), SearchType::Wildcard );
|
|
|
|
ui.searchModeCombo->addItem( tr( "RegExp" ), SearchType::Regex );
|
2014-02-28 12:36:28 +00:00
|
|
|
ui.searchModeCombo->setCurrentIndex( cfg.headwordsDialog.searchMode );
|
|
|
|
|
|
|
|
ui.exportButton->setAutoDefault( false );
|
|
|
|
ui.OKButton->setAutoDefault( false );
|
|
|
|
ui.applyButton->setAutoDefault( true );
|
|
|
|
ui.applyButton->setDefault( true );
|
|
|
|
|
|
|
|
ui.matchCase->setChecked( cfg.headwordsDialog.matchCase );
|
|
|
|
|
2023-05-27 09:50:41 +00:00
|
|
|
model = std::make_shared< HeadwordListModel >();
|
2024-06-25 07:24:33 +00:00
|
|
|
model->setMaxFilterResults( ui.filterMaxResult->value() );
|
2014-02-28 12:36:28 +00:00
|
|
|
proxy = new QSortFilterProxyModel( this );
|
|
|
|
|
2023-05-27 09:50:41 +00:00
|
|
|
proxy->setSourceModel( model.get() );
|
2014-03-01 13:41:05 +00:00
|
|
|
|
|
|
|
proxy->setSortCaseSensitivity( Qt::CaseInsensitive );
|
|
|
|
proxy->setSortLocaleAware( true );
|
2014-03-18 13:44:41 +00:00
|
|
|
proxy->setDynamicSortFilter( false );
|
2014-02-28 12:36:28 +00:00
|
|
|
|
|
|
|
ui.headersListView->setModel( proxy );
|
2014-03-01 13:11:14 +00:00
|
|
|
ui.headersListView->setEditTriggers( QAbstractItemView::NoEditTriggers );
|
2014-02-28 12:36:28 +00:00
|
|
|
|
|
|
|
// very important call, for performance reasons:
|
|
|
|
ui.headersListView->setUniformItemSizes( true );
|
|
|
|
|
|
|
|
delegate = new WordListItemDelegate( ui.headersListView->itemDelegate() );
|
|
|
|
if ( delegate )
|
|
|
|
ui.headersListView->setItemDelegate( delegate );
|
|
|
|
|
2014-03-14 12:38:59 +00:00
|
|
|
ui.autoApply->setChecked( cfg.headwordsDialog.autoApply );
|
2014-02-28 12:36:28 +00:00
|
|
|
|
2024-06-25 07:24:33 +00:00
|
|
|
//arbitrary number.
|
|
|
|
bool exceedLimit = model->totalCount() > HEADWORDS_MAX_LIMIT;
|
|
|
|
ui.filterMaxResult->setEnabled( exceedLimit );
|
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( this, &QDialog::finished, this, &DictHeadwords::savePos );
|
2014-02-28 12:36:28 +00:00
|
|
|
|
2015-03-23 15:58:49 +00:00
|
|
|
if ( !fromMainWindow ) {
|
|
|
|
ui.helpButton->hide();
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( this, &DictHeadwords::closeDialog, this, &QDialog::accept );
|
2015-03-23 15:58:49 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
helpAction.setShortcut( QKeySequence( "F1" ) );
|
|
|
|
helpAction.setShortcutContext( Qt::WidgetWithChildrenShortcut );
|
|
|
|
|
2023-04-17 02:23:39 +00:00
|
|
|
connect( ui.helpButton, &QAbstractButton::clicked, &helpAction, &QAction::trigger );
|
|
|
|
connect( &helpAction, &QAction::triggered, []() {
|
2023-04-22 00:43:50 +00:00
|
|
|
Help::openHelpWebpage( Help::section::ui_headwords );
|
2023-04-17 02:23:39 +00:00
|
|
|
} );
|
2015-03-23 15:58:49 +00:00
|
|
|
|
|
|
|
addAction( &helpAction );
|
|
|
|
}
|
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( ui.OKButton, &QAbstractButton::clicked, this, &DictHeadwords::okButtonClicked );
|
|
|
|
connect( ui.exportButton, &QAbstractButton::clicked, this, &DictHeadwords::exportButtonClicked );
|
|
|
|
connect( ui.applyButton, &QAbstractButton::clicked, this, &DictHeadwords::filterChanged );
|
2014-02-28 12:36:28 +00:00
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( ui.autoApply, &QCheckBox::stateChanged, this, &DictHeadwords::autoApplyStateChanged );
|
2014-02-28 12:36:28 +00:00
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( ui.filterLine, &QLineEdit::textChanged, this, &DictHeadwords::filterChangedInternal );
|
|
|
|
connect( ui.searchModeCombo, &QComboBox::currentIndexChanged, this, &DictHeadwords::filterChangedInternal );
|
|
|
|
connect( ui.matchCase, &QCheckBox::stateChanged, this, &DictHeadwords::filterChangedInternal );
|
2014-02-28 12:36:28 +00:00
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( ui.headersListView, &QAbstractItemView::clicked, this, &DictHeadwords::itemClicked );
|
2014-02-28 12:36:28 +00:00
|
|
|
|
|
|
|
|
2014-03-04 17:38:47 +00:00
|
|
|
ui.headersListView->installEventFilter( this );
|
|
|
|
|
2014-03-03 13:46:41 +00:00
|
|
|
setup( dict_ );
|
2014-02-28 12:36:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DictHeadwords::~DictHeadwords()
|
|
|
|
{
|
|
|
|
if ( delegate )
|
2019-03-20 14:49:39 +00:00
|
|
|
delegate->deleteLater();
|
2014-02-28 12:36:28 +00:00
|
|
|
}
|
|
|
|
|
2014-03-03 13:46:41 +00:00
|
|
|
void DictHeadwords::setup( Dictionary::Class * dict_ )
|
|
|
|
{
|
|
|
|
QApplication::setOverrideCursor( Qt::WaitCursor );
|
|
|
|
|
|
|
|
dict = dict_;
|
|
|
|
|
|
|
|
setWindowTitle( QString::fromUtf8( dict->getName().c_str() ) );
|
|
|
|
|
2023-05-27 09:50:41 +00:00
|
|
|
const auto size = dict->getWordCount();
|
|
|
|
std::shared_ptr< HeadwordListModel > other = std::make_shared< HeadwordListModel >();
|
|
|
|
model.swap( other );
|
2024-06-25 07:24:33 +00:00
|
|
|
model->setMaxFilterResults( ui.filterMaxResult->value() );
|
2023-05-27 09:50:41 +00:00
|
|
|
model->setDict( dict );
|
|
|
|
proxy->setSourceModel( model.get() );
|
2014-03-03 13:46:41 +00:00
|
|
|
proxy->sort( 0 );
|
|
|
|
filterChanged();
|
|
|
|
|
2024-06-25 07:24:33 +00:00
|
|
|
ui.autoApply->setEnabled( true );
|
|
|
|
ui.autoApply->setChecked( cfg.headwordsDialog.autoApply );
|
2014-03-14 12:38:59 +00:00
|
|
|
|
|
|
|
ui.applyButton->setEnabled( !ui.autoApply->isChecked() );
|
|
|
|
|
2024-06-25 07:24:33 +00:00
|
|
|
//arbitrary number.
|
|
|
|
bool exceedLimit = model->totalCount() > HEADWORDS_MAX_LIMIT;
|
|
|
|
ui.filterMaxResult->setEnabled( exceedLimit );
|
|
|
|
|
2014-11-14 16:45:06 +00:00
|
|
|
setWindowIcon( dict->getIcon() );
|
|
|
|
|
2014-11-17 14:37:19 +00:00
|
|
|
dictId = QString( dict->getId().c_str() );
|
|
|
|
|
2014-03-03 13:46:41 +00:00
|
|
|
QApplication::restoreOverrideCursor();
|
2024-06-25 07:24:33 +00:00
|
|
|
connect( model.get(), &HeadwordListModel::numberPopulated, this, [ this ]( int _ ) {
|
|
|
|
showHeadwordsNumber();
|
|
|
|
} );
|
|
|
|
connect( proxy, &QAbstractItemModel::dataChanged, this, &DictHeadwords::showHeadwordsNumber );
|
|
|
|
connect( ui.filterMaxResult, &QSpinBox::valueChanged, this, [ this ]( int _value ) {
|
|
|
|
model->setMaxFilterResults( _value );
|
|
|
|
} );
|
2014-03-03 13:46:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DictHeadwords::savePos()
|
2014-02-28 12:36:28 +00:00
|
|
|
{
|
|
|
|
cfg.headwordsDialog.searchMode = ui.searchModeCombo->currentIndex();
|
|
|
|
cfg.headwordsDialog.matchCase = ui.matchCase->isChecked();
|
2024-06-25 07:24:33 +00:00
|
|
|
cfg.headwordsDialog.autoApply = ui.autoApply->isChecked();
|
2014-02-28 12:36:28 +00:00
|
|
|
cfg.headwordsDialog.headwordsDialogGeometry = saveGeometry();
|
|
|
|
}
|
|
|
|
|
2014-03-04 17:38:47 +00:00
|
|
|
bool DictHeadwords::eventFilter( QObject * obj, QEvent * ev )
|
|
|
|
{
|
|
|
|
if ( obj == ui.headersListView && ev->type() == QEvent::KeyPress ) {
|
2024-01-22 09:04:30 +00:00
|
|
|
auto * kev = dynamic_cast< QKeyEvent * >( ev );
|
2014-03-04 17:38:47 +00:00
|
|
|
if ( kev->key() == Qt::Key_Return || kev->key() == Qt::Key_Enter ) {
|
|
|
|
itemClicked( ui.headersListView->currentIndex() );
|
|
|
|
return true;
|
|
|
|
}
|
2024-01-22 09:04:30 +00:00
|
|
|
else if ( kev->key() == Qt::Key_Up ) {
|
|
|
|
auto index = ui.headersListView->currentIndex();
|
|
|
|
if ( index.row() == 0 )
|
|
|
|
return true;
|
|
|
|
auto preIndex = ui.headersListView->model()->index( index.row() - 1, index.column() );
|
|
|
|
ui.headersListView->setCurrentIndex( preIndex );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if ( kev->key() == Qt::Key_Down ) {
|
|
|
|
auto index = ui.headersListView->currentIndex();
|
|
|
|
//last row.
|
|
|
|
if ( index.row() == ui.headersListView->model()->rowCount() - 1 )
|
|
|
|
return true;
|
|
|
|
auto preIndex = ui.headersListView->model()->index( index.row() + 1, index.column() );
|
|
|
|
ui.headersListView->setCurrentIndex( preIndex );
|
|
|
|
return true;
|
|
|
|
}
|
2014-03-04 17:38:47 +00:00
|
|
|
}
|
|
|
|
return QDialog::eventFilter( obj, ev );
|
|
|
|
}
|
|
|
|
|
2014-02-28 12:36:28 +00:00
|
|
|
void DictHeadwords::okButtonClicked()
|
|
|
|
{
|
2014-03-03 13:46:41 +00:00
|
|
|
savePos();
|
2023-04-22 04:03:53 +00:00
|
|
|
emit closeDialog();
|
2014-03-03 13:46:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DictHeadwords::reject()
|
|
|
|
{
|
|
|
|
savePos();
|
2023-04-22 04:03:53 +00:00
|
|
|
emit closeDialog();
|
2014-02-28 12:36:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DictHeadwords::exportButtonClicked()
|
|
|
|
{
|
|
|
|
saveHeadersToFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DictHeadwords::filterChangedInternal()
|
|
|
|
{
|
|
|
|
// emit signal in async manner, to avoid UI slowdown
|
|
|
|
if ( ui.autoApply->isChecked() )
|
2022-12-26 02:08:17 +00:00
|
|
|
QTimer::singleShot( 100, this, &DictHeadwords::filterChanged );
|
2014-02-28 12:36:28 +00:00
|
|
|
}
|
|
|
|
|
2023-04-22 05:32:10 +00:00
|
|
|
QRegularExpression DictHeadwords::getFilterRegex() const
|
2014-02-28 12:36:28 +00:00
|
|
|
{
|
2024-06-22 11:34:09 +00:00
|
|
|
const SearchType syntax =
|
|
|
|
static_cast< SearchType >( ui.searchModeCombo->itemData( ui.searchModeCombo->currentIndex() ).toInt() );
|
2014-02-28 12:36:28 +00:00
|
|
|
|
2019-03-25 15:08:52 +00:00
|
|
|
QRegularExpression::PatternOptions options = QRegularExpression::UseUnicodePropertiesOption;
|
|
|
|
if ( !ui.matchCase->isChecked() )
|
|
|
|
options |= QRegularExpression::CaseInsensitiveOption;
|
|
|
|
|
|
|
|
QString pattern;
|
|
|
|
switch ( syntax ) {
|
2024-06-22 11:34:09 +00:00
|
|
|
case SearchType::FixedString:
|
2023-04-22 04:03:53 +00:00
|
|
|
pattern = QRegularExpression::escape( ui.filterLine->text() );
|
|
|
|
break;
|
2024-06-22 11:34:09 +00:00
|
|
|
case SearchType::Wildcard:
|
2023-04-22 04:03:53 +00:00
|
|
|
pattern = wildcardsToRegexp( ui.filterLine->text() );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pattern = ui.filterLine->text();
|
|
|
|
break;
|
2019-03-25 15:08:52 +00:00
|
|
|
}
|
|
|
|
|
2023-04-22 04:03:53 +00:00
|
|
|
QRegularExpression regExp = QRegularExpression( pattern, options );
|
2014-02-28 12:36:28 +00:00
|
|
|
|
2019-03-25 15:08:52 +00:00
|
|
|
if ( !regExp.isValid() ) {
|
|
|
|
gdWarning( "Invalid regexp pattern: %s\n", pattern.toUtf8().data() );
|
|
|
|
}
|
2023-04-22 04:03:53 +00:00
|
|
|
return regExp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DictHeadwords::filterChanged()
|
|
|
|
{
|
2023-04-22 09:04:03 +00:00
|
|
|
const QRegularExpression regExp = getFilterRegex();
|
2019-03-25 15:08:52 +00:00
|
|
|
|
|
|
|
QApplication::setOverrideCursor( Qt::WaitCursor );
|
|
|
|
|
2024-06-25 07:24:33 +00:00
|
|
|
model->setFilter( regExp );
|
2022-05-05 12:59:50 +00:00
|
|
|
|
2022-09-19 14:19:22 +00:00
|
|
|
proxy->setFilterRegularExpression( regExp );
|
2014-03-18 13:44:41 +00:00
|
|
|
proxy->sort( 0 );
|
2014-02-28 12:36:28 +00:00
|
|
|
|
2014-03-01 18:43:31 +00:00
|
|
|
QApplication::restoreOverrideCursor();
|
2014-02-28 12:36:28 +00:00
|
|
|
|
|
|
|
showHeadwordsNumber();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DictHeadwords::itemClicked( const QModelIndex & index )
|
|
|
|
{
|
|
|
|
QVariant value = proxy->data( index, Qt::DisplayRole );
|
|
|
|
if ( value.canConvert< QString >() ) {
|
2014-03-17 17:23:36 +00:00
|
|
|
QString headword = value.toString();
|
2014-11-17 14:37:19 +00:00
|
|
|
emit headwordSelected( headword, dictId );
|
2014-03-17 17:23:36 +00:00
|
|
|
}
|
2014-02-28 12:36:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DictHeadwords::autoApplyStateChanged( int state )
|
|
|
|
{
|
|
|
|
ui.applyButton->setEnabled( state == Qt::Unchecked );
|
|
|
|
}
|
|
|
|
|
|
|
|
void DictHeadwords::showHeadwordsNumber()
|
|
|
|
{
|
2024-06-25 07:24:33 +00:00
|
|
|
if ( ui.filterLine->text().isEmpty() ) {
|
|
|
|
ui.headersNumber->setText( tr( "Unique headwords total: %1." ).arg( QString::number( model->totalCount() ) ) );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ui.headersNumber->setText( tr( "Unique headwords total: %1, filtered(limited): %2" )
|
|
|
|
.arg( QString::number( model->totalCount() ), QString::number( proxy->rowCount() ) ) );
|
|
|
|
}
|
2014-02-28 12:36:28 +00:00
|
|
|
}
|
|
|
|
|
2024-06-25 07:24:33 +00:00
|
|
|
void DictHeadwords::exportAllWords( QProgressDialog & progress, QTextStream & out )
|
2023-04-22 04:03:53 +00:00
|
|
|
{
|
2024-06-25 07:24:33 +00:00
|
|
|
if ( const QRegularExpression regExp = getFilterRegex(); regExp.isValid() && !regExp.pattern().isEmpty() ) {
|
|
|
|
loadRegex( progress, out );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-04-22 04:03:53 +00:00
|
|
|
const int headwordsNumber = model->totalCount();
|
|
|
|
|
2024-01-22 09:04:30 +00:00
|
|
|
QMutexLocker const _( &mutex );
|
2024-06-25 07:24:33 +00:00
|
|
|
QSet< QString > allHeadwords;
|
2023-04-22 04:03:53 +00:00
|
|
|
|
2024-06-25 07:24:33 +00:00
|
|
|
int totalCount = 0;
|
|
|
|
for ( int i = 0; i < headwordsNumber && i < model->wordCount(); ++i ) {
|
|
|
|
if ( progress.wasCanceled() )
|
|
|
|
break;
|
2023-04-22 04:03:53 +00:00
|
|
|
|
2024-06-25 07:24:33 +00:00
|
|
|
QVariant value = model->getRow( i );
|
|
|
|
if ( !value.canConvert< QString >() )
|
|
|
|
continue;
|
2023-04-22 04:03:53 +00:00
|
|
|
|
2024-06-25 07:24:33 +00:00
|
|
|
allHeadwords.insert( value.toString() );
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( const auto & item : allHeadwords ) {
|
|
|
|
progress.setValue( totalCount++ );
|
|
|
|
|
|
|
|
writeWordToFile( out, item );
|
|
|
|
}
|
2023-04-22 04:03:53 +00:00
|
|
|
|
|
|
|
// continue to write the remaining headword
|
|
|
|
int nodeIndex = model->getCurrentIndex();
|
|
|
|
auto headwords = model->getRemainRows( nodeIndex );
|
|
|
|
while ( !headwords.isEmpty() ) {
|
|
|
|
if ( progress.wasCanceled() )
|
|
|
|
break;
|
|
|
|
|
2024-06-25 07:24:33 +00:00
|
|
|
for ( const auto & item : headwords ) {
|
|
|
|
progress.setValue( totalCount++ );
|
|
|
|
|
|
|
|
writeWordToFile( out, item );
|
|
|
|
}
|
|
|
|
|
2023-04-22 04:03:53 +00:00
|
|
|
|
|
|
|
headwords = model->getRemainRows( nodeIndex );
|
|
|
|
}
|
2024-06-25 07:24:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DictHeadwords::loadRegex( QProgressDialog & progress, QTextStream & out )
|
|
|
|
{
|
|
|
|
const int headwordsNumber = model->totalCount();
|
|
|
|
|
|
|
|
QMutexLocker const _( &mutex );
|
|
|
|
QSet< QString > allHeadwords;
|
|
|
|
|
|
|
|
int totalCount = 0;
|
|
|
|
for ( int i = 0; i < model->wordCount(); ++i ) {
|
|
|
|
if ( progress.wasCanceled() )
|
|
|
|
break;
|
|
|
|
|
|
|
|
QVariant value = model->getRow( i );
|
|
|
|
if ( !value.canConvert< QString >() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
allHeadwords.insert( value.toString() );
|
|
|
|
}
|
|
|
|
|
|
|
|
progress.setMaximum( allHeadwords.size() );
|
|
|
|
for ( const auto & item : allHeadwords ) {
|
|
|
|
progress.setValue( totalCount++ );
|
2023-04-22 04:03:53 +00:00
|
|
|
|
2024-06-25 07:24:33 +00:00
|
|
|
writeWordToFile( out, item );
|
2023-04-22 04:03:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-28 12:36:28 +00:00
|
|
|
void DictHeadwords::saveHeadersToFile()
|
|
|
|
{
|
|
|
|
QString exportPath;
|
|
|
|
if ( cfg.headwordsDialog.headwordsExportPath.isEmpty() )
|
|
|
|
exportPath = QDir::homePath();
|
|
|
|
else {
|
|
|
|
exportPath = QDir::fromNativeSeparators( cfg.headwordsDialog.headwordsExportPath );
|
|
|
|
if ( !QDir( exportPath ).exists() )
|
|
|
|
exportPath = QDir::homePath();
|
|
|
|
}
|
|
|
|
|
2024-01-22 09:04:30 +00:00
|
|
|
QString const fileName = QFileDialog::getSaveFileName( this,
|
|
|
|
tr( "Save headwords to file" ),
|
|
|
|
exportPath,
|
|
|
|
tr( "Text files (*.txt);;All files (*.*)" ) );
|
2014-02-28 12:36:28 +00:00
|
|
|
if ( fileName.size() == 0 )
|
|
|
|
return;
|
|
|
|
|
2022-12-31 06:01:48 +00:00
|
|
|
QFile file( fileName );
|
|
|
|
|
|
|
|
if ( !file.open( QFile::WriteOnly | QIODevice::Text ) ) {
|
|
|
|
QMessageBox::critical( this, "GoldenDict", tr( "Can not open exported file" ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-28 12:36:28 +00:00
|
|
|
cfg.headwordsDialog.headwordsExportPath =
|
|
|
|
QDir::toNativeSeparators( QFileInfo( fileName ).absoluteDir().absolutePath() );
|
|
|
|
|
2023-04-22 04:03:53 +00:00
|
|
|
const int headwordsNumber = model->totalCount();
|
2022-12-31 06:01:48 +00:00
|
|
|
|
2024-06-25 07:24:33 +00:00
|
|
|
QProgressDialog progress( tr( "Export headwords..." ), tr( "Cancel" ), 0, headwordsNumber, this );
|
2022-12-31 06:01:48 +00:00
|
|
|
progress.setWindowModality( Qt::WindowModal );
|
|
|
|
|
|
|
|
// Write UTF-8 BOM
|
2023-04-22 04:42:10 +00:00
|
|
|
QTextStream out( &file );
|
|
|
|
out.setGenerateByteOrderMark( true );
|
|
|
|
//qt 6 will use utf-8 default.
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
|
|
|
out.setCodec( "UTF-8" );
|
|
|
|
#endif
|
2014-02-28 12:36:28 +00:00
|
|
|
|
2024-06-25 07:24:33 +00:00
|
|
|
exportAllWords( progress, out );
|
2014-02-28 12:36:28 +00:00
|
|
|
|
|
|
|
file.close();
|
2022-12-31 06:01:48 +00:00
|
|
|
|
2023-04-22 04:03:53 +00:00
|
|
|
progress.setValue( progress.maximum() );
|
2022-12-31 06:01:48 +00:00
|
|
|
if ( progress.wasCanceled() ) {
|
|
|
|
QMessageBox::warning( this, "GoldenDict", tr( "Export process is interrupted" ) );
|
|
|
|
gdWarning( "Headers export error: %s", file.errorString().toUtf8().data() );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
//completed.
|
2023-04-22 04:03:53 +00:00
|
|
|
progress.close();
|
2022-12-31 06:01:48 +00:00
|
|
|
QMessageBox::information( this, "GoldenDict", tr( "Export finished" ) );
|
|
|
|
}
|
2014-02-28 12:36:28 +00:00
|
|
|
}
|
2024-06-25 07:24:33 +00:00
|
|
|
void DictHeadwords::writeWordToFile( QTextStream & out, const QString & word )
|
|
|
|
{
|
|
|
|
QByteArray line = word.toUtf8();
|
|
|
|
|
|
|
|
//usually the headword should not contain \r \n;
|
|
|
|
line.replace( '\n', ' ' );
|
|
|
|
line.replace( '\r', ' ' );
|
|
|
|
|
|
|
|
//write one line
|
|
|
|
out << line << Qt::endl;
|
|
|
|
}
|