17#include "ui_qgsstyleexportimportdialogbase.h"
33#include <QInputDialog>
35#include <QNetworkReply>
36#include <QProgressDialog>
38#include <QStandardItemModel>
40#include <QTemporaryFile>
43#include "moc_qgsstyleexportimportdialog.cpp"
45using namespace Qt::StringLiterals;
56 QPushButton *pb =
nullptr;
57 pb =
new QPushButton( tr(
"Select All" ) );
58 buttonBox->addButton( pb, QDialogButtonBox::ActionRole );
61 pb =
new QPushButton( tr(
"Clear Selection" ) );
62 buttonBox->addButton( pb, QDialogButtonBox::ActionRole );
65 mTempStyle = std::make_unique<QgsStyle>();
66 mTempStyle->createMemoryDatabase();
71 if ( mDialogMode ==
Import )
73 setWindowTitle( tr(
"Import Item(s)" ) );
75 importTypeCombo->addItem( tr(
"File" ), ImportSource::File );
77 importTypeCombo->addItem( tr(
"URL" ), ImportSource::Url );
81 mSymbolTags->setText( u
"imported"_s );
83 connect( mButtonFetch, &QAbstractButton::clicked,
this, &QgsStyleExportImportDialog::fetch );
86 mImportFileWidget->setDialogTitle( tr(
"Load Styles" ) );
87 mImportFileWidget->setFilter( tr(
"XML files (*.xml *.XML)" ) );
90 mImportFileWidget->setDefaultRoot( settings.
value( u
"StyleManager/lastImportDir"_s, QDir::homePath(),
QgsSettings::Gui ).toString() );
93 label->setText( tr(
"Select items to import" ) );
94 buttonBox->button( QDialogButtonBox::Ok )->setText( tr(
"Import" ) );
96 dialogStyle = mTempStyle.get();
100 setWindowTitle( tr(
"Export Item(s)" ) );
102 mLocationStackedEdit->setHidden(
true );
103 fromLabel->setHidden(
true );
104 importTypeCombo->setHidden(
true );
105 mLocationLabel->setHidden(
true );
107 mFavorite->setHidden(
true );
108 mIgnoreXMLTags->setHidden(
true );
110 pb =
new QPushButton( tr(
"Select by Group…" ) );
111 buttonBox->addButton( pb, QDialogButtonBox::ActionRole );
113 tagLabel->setHidden(
true );
114 mSymbolTags->setHidden(
true );
115 tagHintLabel->setHidden(
true );
117 buttonBox->button( QDialogButtonBox::Ok )->setText( tr(
"Export" ) );
119 dialogStyle = mStyle;
123 listItems->setIconSize( QSize(
static_cast<int>( iconSize ),
static_cast<int>( iconSize * 0.9 ) ) );
125 listItems->setGridSize( QSize(
static_cast<int>( listItems->iconSize().width() * 1.4 ),
static_cast<int>( listItems->iconSize().height() * 1.7 ) ) );
126 listItems->setTextElideMode( Qt::TextElideMode::ElideRight );
130 mModel->addDesiredIconSize( listItems->iconSize() );
133 listItems->setModel( mModel );
135 connect( listItems->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QgsStyleExportImportDialog::selectionChanged );
138 disconnect( buttonBox, &QDialogButtonBox::accepted,
this, &QDialog::accept );
140 buttonBox->button( QDialogButtonBox::Ok )->setEnabled(
false );
142 connect( buttonBox, &QDialogButtonBox::helpRequested,
this, &QgsStyleExportImportDialog::showHelp );
147 QModelIndexList selection = listItems->selectionModel()->selectedIndexes();
148 if ( selection.isEmpty() )
150 QMessageBox::warning(
this, tr(
"Export/import Item(s)" ), tr(
"You should select at least one symbol/color ramp." ) );
154 if ( mDialogMode ==
Export )
157 const QString lastUsedDir = settings.
value( u
"StyleManager/lastExportDir"_s, QDir::homePath(),
QgsSettings::Gui ).toString();
158 QString fileName = QFileDialog::getSaveFileName(
this, tr(
"Save Styles" ), lastUsedDir, tr(
"XML files (*.xml *.XML)" ) );
162 if ( fileName.isEmpty() )
169 if ( !fileName.endsWith(
".xml"_L1, Qt::CaseInsensitive ) )
171 fileName +=
".xml"_L1;
174 mFileName = fileName;
176 mCursorOverride = std::make_unique<QgsTemporaryCursorOverride>( Qt::WaitCursor );
177 moveStyles( &selection, mStyle, mTempStyle.get() );
178 if ( !mTempStyle->exportXml( mFileName ) )
180 mCursorOverride.reset();
181 QMessageBox::warning(
this, tr(
"Export Symbols" ), tr(
"Error when saving selected symbols to file:\n%1" ).arg( mTempStyle->errorString() ) );
186 mCursorOverride.reset();
187 QMessageBox::information(
this, tr(
"Export Symbols" ), tr(
"The selected symbols were successfully exported to file:\n%1" ).arg( mFileName ) );
192 mCursorOverride = std::make_unique<QgsTemporaryCursorOverride>( Qt::WaitCursor );
193 moveStyles( &selection, mTempStyle.get(), mStyle );
196 mCursorOverride.reset();
203bool QgsStyleExportImportDialog::populateStyles()
210 if ( !mTempStyle->importXml( mFileName ) )
213 QMessageBox::warning(
this, tr(
"Import Symbols or Color Ramps" ), tr(
"An error occurred during import:\n%1" ).arg( mTempStyle->errorString() ) );
219void QgsStyleExportImportDialog::moveStyles( QModelIndexList *selection,
QgsStyle *src,
QgsStyle *dst )
221 QList<QgsStyleManagerDialog::ItemDetails> items;
222 items.reserve( selection->size() );
223 for (
int i = 0; i < selection->size(); ++i )
225 const QModelIndex index = selection->at( i );
227 QgsStyleManagerDialog::ItemDetails details;
231 details.name = mModel->data( mModel->index( index.row(),
QgsStyleModel::Name, index.parent() ), Qt::DisplayRole ).toString();
235 QgsStyleManagerDialog::copyItems( items, src, dst,
this, mCursorOverride, mDialogMode ==
Import, mSymbolTags->text().split(
',' ), mFavorite->isChecked(), mIgnoreXMLTags->isChecked() );
243 mImportFileWidget->setFilePath( path );
248 listItems->selectAll();
253 listItems->clearSelection();
258 for (
int row = 0; row < listItems->model()->rowCount(); ++row )
260 const QModelIndex index = listItems->model()->index( row, 0 );
263 listItems->selectionModel()->select( index, QItemSelectionModel::Select );
270 for (
int row = 0; row < listItems->model()->rowCount(); ++row )
272 const QModelIndex index = listItems->model()->index( row, 0 );
275 const QItemSelection deselection( index, index );
276 listItems->selectionModel()->select( deselection, QItemSelectionModel::Deselect );
283 const auto constSymbolNames = symbolNames;
284 for (
const QString &symbolName : constSymbolNames )
286 const QModelIndexList indexes = listItems->model()->match( listItems->model()->index( 0,
QgsStyleModel::Name ), Qt::DisplayRole, symbolName, 1, Qt::MatchFixedString | Qt::MatchCaseSensitive );
287 const auto constIndexes = indexes;
288 for (
const QModelIndex &index : constIndexes )
290 listItems->selectionModel()->select( index, QItemSelectionModel::Select );
297 const auto constSymbolNames = symbolNames;
298 for (
const QString &symbolName : constSymbolNames )
300 const QModelIndexList indexes = listItems->model()->match( listItems->model()->index( 0,
QgsStyleModel::Name ), Qt::DisplayRole, symbolName, 1, Qt::MatchFixedString | Qt::MatchCaseSensitive );
301 const auto constIndexes = indexes;
302 for (
const QModelIndex &index : constIndexes )
304 const QItemSelection deselection( index, index );
305 listItems->selectionModel()->select( deselection, QItemSelectionModel::Deselect );
312 for (
int row = 0; row < listItems->model()->rowCount(); ++row )
314 const QModelIndex index = listItems->model()->index( row, 0 );
317 listItems->selectionModel()->select( index, QItemSelectionModel::Select );
324 for (
int row = 0; row < listItems->model()->rowCount(); ++row )
326 const QModelIndex index = listItems->model()->index( row, 0 );
329 const QItemSelection deselection( index, index );
330 listItems->selectionModel()->select( deselection, QItemSelectionModel::Deselect );
337 QStringList symbolNames = mStyle->symbolsOfSmartgroup(
QgsStyle::SymbolEntity, mStyle->smartgroupId( groupName ) );
347 QStringList symbolNames = mStyle->symbolsOfSmartgroup(
QgsStyle::SymbolEntity, mStyle->smartgroupId( groupName ) );
357 if ( !mGroupSelectionDlg )
360 mGroupSelectionDlg->setWindowTitle( tr(
"Select Item(s) by Group" ) );
370 mGroupSelectionDlg->show();
371 mGroupSelectionDlg->raise();
372 mGroupSelectionDlg->activateWindow();
377 const ImportSource source =
static_cast<ImportSource
>( importTypeCombo->itemData( index ).toInt() );
381 case ImportSource::File:
383 mLocationStackedEdit->setCurrentIndex( 0 );
384 mLocationLabel->setText( tr(
"File" ) );
388 case ImportSource::Official:
390 btnBrowse->setText( u
"Fetch Items"_s );
391 locationLineEdit->setEnabled(
false );
395 case ImportSource::Url:
397 mLocationStackedEdit->setCurrentIndex( 1 );
398 mLocationLabel->setText( tr(
"URL" ) );
404void QgsStyleExportImportDialog::fetch()
406 downloadStyleXml( QUrl( mUrlLineEdit->text() ) );
409void QgsStyleExportImportDialog::importFileChanged(
const QString &path )
411 if ( path.isEmpty() )
415 const QFileInfo pathInfo( mFileName );
416 const QString tag = pathInfo.fileName().remove( u
".xml"_s );
417 mSymbolTags->setText( tag );
418 if ( QFileInfo::exists( mFileName ) )
422 mImportFileWidget->setDefaultRoot( pathInfo.absolutePath() );
423 QgsSettings settings;
428void QgsStyleExportImportDialog::downloadStyleXml(
const QUrl &url )
430 mTempFile = std::make_unique<QTemporaryFile>();
431 if ( mTempFile->open() )
433 mFileName = mTempFile->fileName();
435 QProgressDialog *progressDlg =
new QProgressDialog(
this );
436 progressDlg->setLabelText( tr(
"Downloading style…" ) );
437 progressDlg->setAutoClose(
true );
440 QgsNetworkContentFetcherTask *fetcher =
new QgsNetworkContentFetcherTask( url );
445 QNetworkReply *reply = fetcher->
reply();
446 if ( !reply || reply->error() != QNetworkReply::NoError )
451 QMessageBox::information(
this, tr(
"Import from URL" ), tr(
"HTTP Error! Download failed: %1." ).arg( reply->errorString() ) );
455 mTempFile->write( reply->readAll() );
460 progressDlg->deleteLater();
467void QgsStyleExportImportDialog::selectionChanged(
const QItemSelection &selected,
const QItemSelection &deselected )
470 Q_UNUSED( deselected )
471 const bool nothingSelected = listItems->selectionModel()->selectedIndexes().empty();
472 buttonBox->button( QDialogButtonBox::Ok )->setDisabled( nothingSelected );
475void QgsStyleExportImportDialog::showHelp()
static const double UI_SCALE_FACTOR
UI scaling factor.
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
void fetched()
Emitted when the network content has been fetched, regardless of whether the fetch was successful or ...
QNetworkReply * reply()
Returns the network reply.
void cancel() override
Notifies the task that it should terminate.
Stores properties relating to a screen.
Stores settings for use within QGIS.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void clearSelection()
clearSelection deselects all symbols
void selectTag(const QString &tagName)
Select the symbols belonging to the given tag.
@ Export
Export existing symbols mode.
@ Import
Import xml file mode.
void deselectSymbols(const QStringList &symbolNames)
deselectSymbols deselect symbols by name
void importTypeChanged(int)
void selectAll()
selectAll selects all symbols
void selectSymbols(const QStringList &symbolNames)
selectSymbols select symbols by name
void selectSmartgroup(const QString &groupName)
selectSmartgroup selects all symbols from a smart group
void selectByGroup()
selectByGroup open select by group dialog
void deselectFavorites()
Deselects favorite symbols.
void setImportFilePath(const QString &path)
Sets the initial path to use for importing files, when the dialog is in a Import mode.
void deselectSmartgroup(const QString &groupName)
deselectSmartgroup deselects all symbols from a smart group
QgsStyleExportImportDialog(QgsStyle *style, QWidget *parent=nullptr, Mode mode=Export)
Constructor for QgsStyleExportImportDialog, with the specified parent widget.
void selectFavorites()
Selects favorite symbols.
~QgsStyleExportImportDialog() override
void deselectTag(const QString &tagName)
Deselect the symbols belonging to the given tag.
A dialog which presents available groups from a QgsStyle.
void favoritesDeselected()
Favorites has been deselected.
void allDeselected()
all deselected
void tagSelected(const QString &tagName)
tag with tagName has been selected
void tagDeselected(const QString &tagName)
tag with tagName has been deselected
void smartgroupDeselected(const QString &groupName)
smart group with groupName has been deselected
void favoritesSelected()
Favorites has need selected.
void smartgroupSelected(const QString &groupName)
smartgroup with groupName has been selected
void allSelected()
all selected
@ IsFavorite
Whether entity is flagged as a favorite.
@ SymbolType
Symbol type (for symbol or legend patch shape entities).
@ Type
Style entity type, see QgsStyle::StyleEntity.
@ Tag
String list of tags.
A QSortFilterProxyModel subclass for showing filtered symbol and color ramps entries from a QgsStyle ...
A database of saved style entities, including symbols, color ramps, text formats and others.
StyleEntity
Enum for Entities involved in a style.
@ TextFormatEntity
Text formats.
@ ColorrampEntity
Color ramps.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
void progressChanged(double progress)
Will be emitted by task when its progress changes.
void setDescription(const QString &description)
Sets the task's description.
Temporarily sets a cursor override for the QApplication for the lifetime of the object.