27 #include <QAbstractListModel> 30 #include <QFileDialog> 31 #include <QModelIndex> 32 #include <QPixmapCache> 40 QgsSvgSelectorLoader::QgsSvgSelectorLoader( QObject *parent )
45 QgsSvgSelectorLoader::~QgsSvgSelectorLoader()
50 void QgsSvgSelectorLoader::run()
54 mTraversedPaths.clear();
62 if ( !mQueuedSvgs.isEmpty() )
65 emit foundSvgs( mQueuedSvgs );
70 void QgsSvgSelectorLoader::stop()
73 while ( isRunning() ) {}
76 void QgsSvgSelectorLoader::loadPath(
const QString &path )
86 Q_FOREACH (
const QString &svgPath, svgPaths )
91 if ( !svgPath.isEmpty() )
102 QString canonicalPath = dir.canonicalPath();
103 if ( mTraversedPaths.contains( canonicalPath ) )
106 mTraversedPaths.insert( canonicalPath );
110 Q_FOREACH (
const QString &item, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
115 QString newPath = dir.path() +
'/' + item;
122 void QgsSvgSelectorLoader::loadImages(
const QString &path )
125 Q_FOREACH (
const QString &item, dir.entryList( QStringList(
"*.svg" ), QDir::Files ) )
131 QString svgPath = dir.path() +
'/' + item;
135 mQueuedSvgs << svgPath;
139 if ( mTimer.elapsed() > mTimerThreshold && !mQueuedSvgs.isEmpty() )
141 emit foundSvgs( mQueuedSvgs );
147 if ( mTimerThreshold < 1000 )
148 mTimerThreshold *= 2;
159 QgsSvgGroupLoader::QgsSvgGroupLoader( QObject *parent )
165 QgsSvgGroupLoader::~QgsSvgGroupLoader()
170 void QgsSvgGroupLoader::run()
173 mTraversedPaths.clear();
175 while ( !mCanceled && !mParentPaths.isEmpty() )
177 QString parentPath = mParentPaths.takeFirst();
178 loadGroup( parentPath );
182 void QgsSvgGroupLoader::stop()
185 while ( isRunning() ) {}
188 void QgsSvgGroupLoader::loadGroup(
const QString &parentPath )
190 QDir parentDir( parentPath );
193 QString canonicalPath = parentDir.canonicalPath();
194 if ( mTraversedPaths.contains( canonicalPath ) )
197 mTraversedPaths.insert( canonicalPath );
199 Q_FOREACH (
const QString &item, parentDir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
204 emit foundPath( parentPath, item );
205 mParentPaths.append( parentDir.path() +
'/' + item );
216 : QAbstractListModel( parent )
217 , mSvgLoader( new QgsSvgSelectorLoader( this ) )
218 , mIconSize( iconSize )
220 mSvgLoader->setPath( QString() );
221 connect( mSvgLoader, &QgsSvgSelectorLoader::foundSvgs,
this, &QgsSvgSelectorListModel::addSvgs );
226 : QAbstractListModel( parent )
227 , mSvgLoader( new QgsSvgSelectorLoader( this ) )
228 , mIconSize( iconSize )
230 mSvgLoader->setPath( path );
231 connect( mSvgLoader, &QgsSvgSelectorLoader::foundSvgs,
this, &QgsSvgSelectorListModel::addSvgs );
241 QPixmap QgsSvgSelectorListModel::createPreview(
const QString &entry )
const 245 double strokeWidth, fillOpacity, strokeOpacity;
246 bool fillParam, fillOpacityParam, strokeParam, strokeWidthParam, strokeOpacityParam;
247 bool hasDefaultFillColor =
false, hasDefaultFillOpacity =
false, hasDefaultStrokeColor =
false,
248 hasDefaultStrokeWidth =
false, hasDefaultStrokeOpacity =
false;
250 fillOpacityParam, hasDefaultFillOpacity, fillOpacity,
251 strokeParam, hasDefaultStrokeColor, stroke,
252 strokeWidthParam, hasDefaultStrokeWidth, strokeWidth,
253 strokeOpacityParam, hasDefaultStrokeOpacity, strokeOpacity );
256 if ( !hasDefaultFillColor )
257 fill = QColor( 200, 200, 200 );
258 fill.setAlphaF( hasDefaultFillOpacity ? fillOpacity : 1.0 );
259 if ( !hasDefaultStrokeColor )
261 stroke.setAlphaF( hasDefaultStrokeOpacity ? strokeOpacity : 1.0 );
262 if ( !hasDefaultStrokeWidth )
267 return QPixmap::fromImage( img );
272 QString entry =
mSvgFiles.at( index.row() );
274 if ( role == Qt::DecorationRole )
277 if ( !QPixmapCache::find( entry, pixmap ) )
279 pixmap = createPreview( entry );
280 QPixmapCache::insert( entry, pixmap );
285 else if ( role == Qt::UserRole || role == Qt::ToolTipRole )
293 void QgsSvgSelectorListModel::addSvgs(
const QStringList &svgs )
295 beginInsertRows( QModelIndex(),
mSvgFiles.count(),
mSvgFiles.count() + svgs.size() - 1 );
307 : QStandardItemModel( parent )
308 , mLoader( new QgsSvgGroupLoader( this ) )
311 QStandardItem *parentItem = invisibleRootItem();
312 QStringList parentPaths;
313 parentPaths.reserve( svgPaths.size() );
315 for (
int i = 0; i < svgPaths.size(); i++ )
317 QDir dir( svgPaths.at( i ) );
318 QStandardItem *baseGroup =
nullptr;
322 baseGroup =
new QStandardItem( tr(
"App Symbols" ) );
326 baseGroup =
new QStandardItem( tr(
"User Symbols" ) );
330 baseGroup =
new QStandardItem( dir.dirName() );
332 baseGroup->setData( QVariant( svgPaths.at( i ) ) );
333 baseGroup->setEditable(
false );
334 baseGroup->setCheckable(
false );
336 baseGroup->setToolTip( dir.path() );
337 parentItem->appendRow( baseGroup );
338 parentPaths << svgPaths.at( i );
339 mPathItemHash.insert( svgPaths.at( i ), baseGroup );
340 QgsDebugMsg( QStringLiteral(
"SVG base path %1: %2" ).arg( i ).arg( baseGroup->data().toString() ) );
342 mLoader->setParentPaths( parentPaths );
343 connect( mLoader, &QgsSvgGroupLoader::foundPath,
this, &QgsSvgSelectorGroupsModel::addPath );
352 void QgsSvgSelectorGroupsModel::addPath(
const QString &parentPath,
const QString &item )
354 QStandardItem *parentGroup = mPathItemHash.value( parentPath );
358 QString fullPath = parentPath +
'/' + item;
359 QStandardItem *group =
new QStandardItem( item );
360 group->setData( QVariant( fullPath ) );
361 group->setEditable(
false );
362 group->setCheckable(
false );
363 group->setToolTip( fullPath );
365 parentGroup->appendRow( group );
366 mPathItemHash.insert( fullPath, group );
380 mIconSize = std::max( 30, static_cast< int >( std::round(
Qgis::UI_SCALE_FACTOR * fontMetrics().width( QStringLiteral(
"XXXX" ) ) ) ) );
381 mImagesListView->setGridSize( QSize( mIconSize * 1.2, mIconSize * 1.2 ) );
383 mGroupsTreeView->setHeaderHidden(
true );
386 connect( mImagesListView->selectionModel(), &QItemSelectionModel::currentChanged,
387 this, &QgsSvgSelectorWidget::svgSelectionChanged );
388 connect( mGroupsTreeView->selectionModel(), &QItemSelectionModel::currentChanged,
389 this, &QgsSvgSelectorWidget::populateIcons );
394 mCurrentSvgPath = svgPath;
398 mImagesListView->selectionModel()->blockSignals(
true );
399 QAbstractItemModel *m = mImagesListView->model();
400 QItemSelectionModel *selModel = mImagesListView->selectionModel();
401 for (
int i = 0; i < m->rowCount(); i++ )
403 QModelIndex idx( m->index( i, 0 ) );
404 if ( m->data( idx ).toString() == svgPath )
406 selModel->select( idx, QItemSelectionModel::SelectCurrent );
407 selModel->setCurrentIndex( idx, QItemSelectionModel::SelectCurrent );
408 mImagesListView->scrollTo( idx );
412 mImagesListView->selectionModel()->blockSignals(
false );
417 return mCurrentSvgPath;
420 void QgsSvgSelectorWidget::updateCurrentSvgPath(
const QString &svgPath )
422 mCurrentSvgPath = svgPath;
426 void QgsSvgSelectorWidget::svgSelectionChanged(
const QModelIndex &idx )
428 QString filePath = idx.data( Qt::UserRole ).toString();
430 updateCurrentSvgPath( filePath );
433 void QgsSvgSelectorWidget::populateIcons(
const QModelIndex &idx )
435 QString path = idx.data( Qt::UserRole + 1 ).toString();
437 QAbstractItemModel *oldModel = mImagesListView->model();
439 mImagesListView->setModel( m );
442 connect( mImagesListView->selectionModel(), &QItemSelectionModel::currentChanged,
443 this, &QgsSvgSelectorWidget::svgSelectionChanged );
446 void QgsSvgSelectorWidget::svgSourceChanged(
const QString &text )
449 bool validSVG = !resolvedPath.isNull();
451 updateCurrentSvgPath( validSVG ? resolvedPath : text );
457 mGroupsTreeView->setModel( g );
459 int rows = g->rowCount( g->indexFromItem( g->invisibleRootItem() ) );
460 for (
int i = 0; i < rows; i++ )
462 mGroupsTreeView->setExpanded( g->indexFromItem( g->item( i ) ),
true );
466 QAbstractItemModel *oldModel = mImagesListView->model();
468 mImagesListView->setModel( m );
475 QDialogButtonBox::StandardButtons buttons,
476 Qt::Orientation orientation )
477 : QDialog( parent, fl )
480 Q_UNUSED( orientation );
483 mButtonBox =
new QDialogButtonBox( buttons, orientation,
this );
484 connect(
mButtonBox, &QDialogButtonBox::accepted,
this, &QDialog::accept );
485 connect(
mButtonBox, &QDialogButtonBox::rejected,
this, &QDialog::reject );
487 setMinimumSize( 480, 320 );
498 restoreGeometry( settings.
value( QStringLiteral(
"Windows/SvgSelectorDialog/geometry" ) ).toByteArray() );
QgsSvgSelectorWidget * mSvgSelector
static QgsSvgCache * svgCache()
Returns the application's SVG cache, used for caching SVG images and handling parameter replacement w...
static QString qgisSettingsDirPath()
Returns the path to the settings directory in user's home dir.
A model for displaying SVG files with a preview icon.
static const double UI_SCALE_FACTOR
UI scaling factor.
This class is a composition of two QSettings instances:
QImage svgAsImage(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, bool &fitsInCache, double fixedAspectRatio=0)
Gets SVG as QImage.
QgsSvgSelectorGroupsModel(QObject *parent)
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void saveGeometry(QWidget *widget, const QString &keyName)
Save the wigget geometry into settings.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
bool restoreGeometry(QWidget *widget, const QString &keyName)
Restore the wigget geometry from settings.
~QgsSvgSelectorDialog() override
QDialogButtonBox * mButtonBox
static QString pkgDataPath()
Returns the common root path of all application data directories.
void sourceChanged(const QString &source)
Emitted whenever the SVG source is changed in the widget.
~QgsSvgSelectorGroupsModel() override
A model for displaying SVG search paths.
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasStrokeParam, QColor &defaultStrokeColor, bool &hasStrokeWidthParam, double &defaultStrokeWidth) const
Tests if an svg file contains parameters for fill, stroke color, stroke width.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
QgsSvgSelectorListModel(QObject *parent, int iconSize=30)
Constructor for QgsSvgSelectorListModel.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsSvgSelectorDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags, QDialogButtonBox::StandardButtons buttons=QDialogButtonBox::Close|QDialogButtonBox::Ok, Qt::Orientation orientation=Qt::Horizontal)
Constructor for QgsSvgSelectorDialog.
static QStringList svgPaths()
Returns the paths to svg directories.
static QString svgSymbolNameToPath(const QString &name, const QgsPathResolver &pathResolver)
Determines an SVG symbol's path from its name.