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. 
 
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key. 
 
void sourceChanged(const QString &source)
Emitted whenever the file source is changed in the widget. 
 
QgsSvgSelectorGroupsModel(QObject *parent)
 
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 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. 
 
~QgsSvgSelectorGroupsModel() override
 
A model for displaying SVG search paths. 
 
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.