QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsstylemodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsstylemodel.cpp
3  ---------------
4  begin : September 2018
5  copyright : (C) 2018 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsstylemodel.h"
17 #include "qgsstyle.h"
18 #include "qgssymbollayerutils.h"
19 #include "qgsapplication.h"
20 #include "qgssvgcache.h"
21 #include "qgsimagecache.h"
22 #include "qgsproject.h"
24 #include <QIcon>
25 
26 const double ICON_PADDING_FACTOR = 0.16;
27 
29 
30 QgsStyleModel::QgsStyleModel( QgsStyle *style, QObject *parent )
31  : QAbstractItemModel( parent )
32  , mStyle( style )
33 {
34  Q_ASSERT( mStyle );
35 
36  for ( QgsStyle::StyleEntity entity : ENTITIES )
37  {
38  mEntityNames.insert( entity, mStyle->allNames( entity ) );
39  }
40 
41  connect( mStyle, &QgsStyle::entityAdded, this, &QgsStyleModel::onEntityAdded );
42  connect( mStyle, &QgsStyle::entityRemoved, this, &QgsStyleModel::onEntityRemoved );
43  connect( mStyle, &QgsStyle::entityRenamed, this, &QgsStyleModel::onEntityRename );
44  connect( mStyle, &QgsStyle::entityChanged, this, &QgsStyleModel::onEntityChanged );
45  connect( mStyle, &QgsStyle::entityTagsChanged, this, &QgsStyleModel::onTagsChanged );
46 
47  // when a remote svg or image has been fetched, update the model's decorations.
48  // this is required if a symbol utilizes remote svgs, and the current icons
49  // have been generated using the temporary "downloading" svg. In this case
50  // we require the preview to be regenerated to use the correct fetched
51  // svg
52  connect( QgsApplication::svgCache(), &QgsSvgCache::remoteSvgFetched, this, &QgsStyleModel::rebuildSymbolIcons );
53  connect( QgsApplication::imageCache(), &QgsImageCache::remoteImageFetched, this, &QgsStyleModel::rebuildSymbolIcons );
54 
55  // if project color scheme changes, we need to redraw symbols - they may use project colors and accordingly
56  // need updating to reflect the new colors
57  connect( QgsProject::instance(), &QgsProject::projectColorsChanged, this, &QgsStyleModel::rebuildSymbolIcons );
58 }
59 
60 QVariant QgsStyleModel::data( const QModelIndex &index, int role ) const
61 {
62  if ( index.row() < 0 || index.row() >= rowCount( QModelIndex() ) )
63  return QVariant();
64 
65 
66  QgsStyle::StyleEntity entityType = entityTypeFromRow( index.row() );
67 
68  QString name;
69  switch ( entityType )
70  {
73  break;
74 
75  default:
76  name = mEntityNames[ entityType ].value( index.row() - offsetForEntity( entityType ) );
77  break;
78  }
79 
80  switch ( role )
81  {
82  case Qt::DisplayRole:
83  case Qt::ToolTipRole:
84  case Qt::EditRole:
85  {
86  switch ( index.column() )
87  {
88  case Name:
89  {
90  const QStringList tags = mStyle->tagsOfSymbol( entityType, name );
91 
92  if ( role == Qt::ToolTipRole )
93  {
94  QString tooltip = QStringLiteral( "<h3>%1</h3><p><i>%2</i>" ).arg( name,
95  tags.count() > 0 ? tags.join( QStringLiteral( ", " ) ) : tr( "Not tagged" ) );
96 
97  switch ( entityType )
98  {
100  {
101  // create very large preview image
102  std::unique_ptr< QgsSymbol > symbol( mStyle->symbol( name ) );
103  if ( symbol )
104  {
105 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
106  int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * QFontMetrics( data( index, Qt::FontRole ).value< QFont >() ).width( 'X' ) * 23 );
107 #else
108  int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * QFontMetrics( data( index, Qt::FontRole ).value< QFont >() ).horizontalAdvance( 'X' ) * 23 );
109 #endif
110  int height = static_cast< int >( width / 1.61803398875 ); // golden ratio
111  QPixmap pm = QgsSymbolLayerUtils::symbolPreviewPixmap( symbol.get(), QSize( width, height ), height / 20, nullptr, false, mExpressionContext.get() );
112  QByteArray data;
113  QBuffer buffer( &data );
114  pm.save( &buffer, "PNG", 100 );
115  tooltip += QStringLiteral( "<p><img src='data:image/png;base64, %3'>" ).arg( QString( data.toBase64() ) );
116  }
117  break;
118  }
119 
121  {
122 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
123  int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * QFontMetrics( data( index, Qt::FontRole ).value< QFont >() ).width( 'X' ) * 23 );
124 #else
125  int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * QFontMetrics( data( index, Qt::FontRole ).value< QFont >() ).horizontalAdvance( 'X' ) * 23 );
126 #endif
127  int height = static_cast< int >( width / 1.61803398875 ); // golden ratio
128  const QgsTextFormat format = mStyle->textFormat( name );
129  QPixmap pm = QgsTextFormat::textFormatPreviewPixmap( format, QSize( width, height ), QString(), height / 20 );
130  QByteArray data;
131  QBuffer buffer( &data );
132  pm.save( &buffer, "PNG", 100 );
133  tooltip += QStringLiteral( "<p><img src='data:image/png;base64, %3'>" ).arg( QString( data.toBase64() ) );
134  break;
135  }
136 
138  {
139 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
140  int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * QFontMetrics( data( index, Qt::FontRole ).value< QFont >() ).width( 'X' ) * 23 );
141 #else
142  int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * QFontMetrics( data( index, Qt::FontRole ).value< QFont >() ).horizontalAdvance( 'X' ) * 23 );
143 #endif
144  int height = static_cast< int >( width / 1.61803398875 ); // golden ratio
145  const QgsPalLayerSettings settings = mStyle->labelSettings( name );
146  QPixmap pm = QgsPalLayerSettings::labelSettingsPreviewPixmap( settings, QSize( width, height ), QString(), height / 20 );
147  QByteArray data;
148  QBuffer buffer( &data );
149  pm.save( &buffer, "PNG", 100 );
150  tooltip += QStringLiteral( "<p><img src='data:image/png;base64, %3'>" ).arg( QString( data.toBase64() ) );
151  break;
152  }
153 
155  {
156 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
157  int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * QFontMetrics( data( index, Qt::FontRole ).value< QFont >() ).width( 'X' ) * 23 );
158 #else
159  int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * QFontMetrics( data( index, Qt::FontRole ).value< QFont >() ).horizontalAdvance( 'X' ) * 23 );
160 #endif
161  int height = static_cast< int >( width / 1.61803398875 ); // golden ratio
162 
163  const QgsLegendPatchShape shape = mStyle->legendPatchShape( name );
164  if ( const QgsSymbol *symbol = mStyle->previewSymbolForPatchShape( shape ) )
165  {
166  QPixmap pm = QgsSymbolLayerUtils::symbolPreviewPixmap( symbol, QSize( width, height ), height / 20, nullptr, false, nullptr, &shape );
167  QByteArray data;
168  QBuffer buffer( &data );
169  pm.save( &buffer, "PNG", 100 );
170  tooltip += QStringLiteral( "<p><img src='data:image/png;base64, %3'>" ).arg( QString( data.toBase64() ) );
171  }
172  break;
173  }
174 
176  case QgsStyle::TagEntity:
178  break;
179  }
180  return tooltip;
181  }
182  else
183  {
184  return name;
185  }
186  }
187  case Tags:
188  return mStyle->tagsOfSymbol( entityType, name ).join( QStringLiteral( ", " ) );
189  }
190  return QVariant();
191  }
192 
193  case Qt::DecorationRole:
194  {
195  // Generate icons at all additional sizes specified for the model.
196  // This allows the model to have size responsive icons.
197 
198  if ( !mExpressionContext )
199  {
200  // build the expression context once, and keep it around. Usually this is a no-no, but in this
201  // case we want to avoid creating potentially thousands of contexts one-by-one (usually one context
202  // is created for a batch of multiple evalutions like this), and we only use a very minimal context
203  // anyway...
204  mExpressionContext = qgis::make_unique< QgsExpressionContext >();
205  mExpressionContext->appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
206  }
207 
208  switch ( index.column() )
209  {
210  case Name:
211  switch ( entityType )
212  {
214  {
215  // use cached icon if possible
216  QIcon icon = mIconCache[ entityType ].value( name );
217  if ( !icon.isNull() )
218  return icon;
219 
220  std::unique_ptr< QgsSymbol > symbol( mStyle->symbol( name ) );
221  if ( symbol )
222  {
223  if ( mAdditionalSizes.isEmpty() )
224  icon.addPixmap( QgsSymbolLayerUtils::symbolPreviewPixmap( symbol.get(), QSize( 24, 24 ), 1, nullptr, false, mExpressionContext.get() ) );
225 
226  for ( const QSize &s : mAdditionalSizes )
227  {
228  icon.addPixmap( QgsSymbolLayerUtils::symbolPreviewPixmap( symbol.get(), s, static_cast< int >( s.width() * ICON_PADDING_FACTOR ), nullptr, false, mExpressionContext.get() ) );
229  }
230 
231  }
232  mIconCache[ entityType ].insert( name, icon );
233  return icon;
234  }
236  {
237  // use cached icon if possible
238  QIcon icon = mIconCache[ entityType ].value( name );
239  if ( !icon.isNull() )
240  return icon;
241 
242  std::unique_ptr< QgsColorRamp > ramp( mStyle->colorRamp( name ) );
243  if ( ramp )
244  {
245  if ( mAdditionalSizes.isEmpty() )
246  icon.addPixmap( QgsSymbolLayerUtils::colorRampPreviewPixmap( ramp.get(), QSize( 24, 24 ), 1 ) );
247  for ( const QSize &s : mAdditionalSizes )
248  {
249  icon.addPixmap( QgsSymbolLayerUtils::colorRampPreviewPixmap( ramp.get(), s, static_cast< int >( s.width() * ICON_PADDING_FACTOR ) ) );
250  }
251 
252  }
253  mIconCache[ entityType ].insert( name, icon );
254  return icon;
255  }
256 
258  {
259  // use cached icon if possible
260  QIcon icon = mIconCache[ entityType ].value( name );
261  if ( !icon.isNull() )
262  return icon;
263 
264  const QgsTextFormat format( mStyle->textFormat( name ) );
265  if ( mAdditionalSizes.isEmpty() )
266  icon.addPixmap( QgsTextFormat::textFormatPreviewPixmap( format, QSize( 24, 24 ), QString(), 1 ) );
267  for ( const QSize &s : mAdditionalSizes )
268  {
269  icon.addPixmap( QgsTextFormat::textFormatPreviewPixmap( format, s, QString(), static_cast< int >( s.width() * ICON_PADDING_FACTOR ) ) );
270  }
271  mIconCache[ entityType ].insert( name, icon );
272  return icon;
273  }
274 
276  {
277  // use cached icon if possible
278  QIcon icon = mIconCache[ entityType ].value( name );
279  if ( !icon.isNull() )
280  return icon;
281 
282  const QgsPalLayerSettings settings( mStyle->labelSettings( name ) );
283  if ( mAdditionalSizes.isEmpty() )
284  icon.addPixmap( QgsPalLayerSettings::labelSettingsPreviewPixmap( settings, QSize( 24, 24 ), QString(), 1 ) );
285  for ( const QSize &s : mAdditionalSizes )
286  {
287  icon.addPixmap( QgsPalLayerSettings::labelSettingsPreviewPixmap( settings, s, QString(), static_cast< int >( s.width() * ICON_PADDING_FACTOR ) ) );
288  }
289  mIconCache[ entityType ].insert( name, icon );
290  return icon;
291  }
292 
294  {
295  // use cached icon if possible
296  QIcon icon = mIconCache[ entityType ].value( name );
297  if ( !icon.isNull() )
298  return icon;
299 
300  const QgsLegendPatchShape shape = mStyle->legendPatchShape( name );
301  if ( !shape.isNull() )
302  {
303  if ( const QgsSymbol *symbol = mStyle->previewSymbolForPatchShape( shape ) )
304  {
305  if ( mAdditionalSizes.isEmpty() )
306  icon.addPixmap( QgsSymbolLayerUtils::symbolPreviewPixmap( symbol, QSize( 24, 24 ), 1, nullptr, false, mExpressionContext.get(), &shape ) );
307 
308  for ( const QSize &s : mAdditionalSizes )
309  {
310  icon.addPixmap( QgsSymbolLayerUtils::symbolPreviewPixmap( symbol, s, static_cast< int >( s.width() * ICON_PADDING_FACTOR ), nullptr, false, mExpressionContext.get(), &shape ) );
311  }
312  }
313  }
314  mIconCache[ entityType ].insert( name, icon );
315  return icon;
316  }
317 
318  case QgsStyle::TagEntity:
320  return QVariant();
321  }
322  break;
323 
324  case Tags:
325  return QVariant();
326  }
327  return QVariant();
328  }
329 
330  case TypeRole:
331  return entityType;
332 
333  case TagRole:
334  return mStyle->tagsOfSymbol( entityType, name );
335 
336  case IsFavoriteRole:
337  return mStyle->isFavorite( entityType, name );
338 
339  case SymbolTypeRole:
340  {
341  switch ( entityType )
342  {
344  {
345  const QgsSymbol *symbol = mStyle->symbolRef( name );
346  return symbol ? symbol->type() : QVariant();
347  }
348 
350  return mStyle->legendPatchShapeSymbolType( name );
351 
352  case QgsStyle::TagEntity:
357  return QVariant();
358  }
359  return QVariant();
360  }
361 
362  case LayerTypeRole:
363  {
364  if ( entityType != QgsStyle::LabelSettingsEntity )
365  return QVariant();
366 
367  return mStyle->labelSettingsLayerType( name );
368  }
369 
370  default:
371  return QVariant();
372  }
373 #ifndef _MSC_VER // avoid warning
374  return QVariant(); // avoid warning
375 #endif
376 }
377 
378 bool QgsStyleModel::setData( const QModelIndex &index, const QVariant &value, int role )
379 {
380  if ( index.row() < 0 || index.row() >= rowCount( QModelIndex() ) || role != Qt::EditRole )
381  return false;
382 
383  switch ( index.column() )
384  {
385  case Name:
386  {
387  QgsStyle::StyleEntity entityType = entityTypeFromRow( index.row() );
388  QString name;
389  switch ( entityType )
390  {
391  case QgsStyle::TagEntity:
393  return false;
394 
395  default:
396  name = mEntityNames[ entityType ].value( index.row() - offsetForEntity( entityType ) );
397  break;
398  }
399 
400  const QString newName = value.toString();
401  return mStyle->renameEntity( entityType, name, newName );
402  }
403 
404  case Tags:
405  return false;
406  }
407 
408  return false;
409 }
410 
411 Qt::ItemFlags QgsStyleModel::flags( const QModelIndex &index ) const
412 {
413  Qt::ItemFlags flags = QAbstractItemModel::flags( index );
414  if ( index.isValid() && index.column() == Name )
415  {
416  return flags | Qt::ItemIsEditable;
417  }
418  else
419  {
420  return flags;
421  }
422 }
423 
424 QVariant QgsStyleModel::headerData( int section, Qt::Orientation orientation, int role ) const
425 {
426  if ( role == Qt::DisplayRole )
427  {
428  if ( orientation == Qt::Vertical ) //row
429  {
430  return QVariant( section );
431  }
432  else
433  {
434  switch ( section )
435  {
436  case Name:
437  return QVariant( tr( "Name" ) );
438 
439  case Tags:
440  return QVariant( tr( "Tags" ) );
441 
442  default:
443  return QVariant();
444  }
445  }
446  }
447  else
448  {
449  return QVariant();
450  }
451 }
452 
453 QModelIndex QgsStyleModel::index( int row, int column, const QModelIndex &parent ) const
454 {
455  if ( !hasIndex( row, column, parent ) )
456  return QModelIndex();
457 
458  if ( !parent.isValid() )
459  {
460  return createIndex( row, column );
461  }
462 
463  return QModelIndex();
464 }
465 
466 QModelIndex QgsStyleModel::parent( const QModelIndex & ) const
467 {
468  //all items are top level for now
469  return QModelIndex();
470 }
471 
472 int QgsStyleModel::rowCount( const QModelIndex &parent ) const
473 {
474  if ( !parent.isValid() )
475  {
476  int count = 0;
477  for ( QgsStyle::StyleEntity type : ENTITIES )
478  count += mEntityNames[ type ].size();
479  return count;
480  }
481  return 0;
482 }
483 
484 int QgsStyleModel::columnCount( const QModelIndex & ) const
485 {
486  return 2;
487 }
488 
490 {
491  if ( mAdditionalSizes.contains( size ) )
492  return;
493 
494  mAdditionalSizes << size;
495  mIconCache.clear();
496 }
497 
498 void QgsStyleModel::onEntityAdded( QgsStyle::StyleEntity type, const QString &name )
499 {
500  mIconCache[ type ].remove( name );
501  const QStringList oldSymbolNames = mEntityNames[ type ];
502  const QStringList newSymbolNames = mStyle->allNames( type );
503 
504  // find index of newly added symbol
505  const int newNameIndex = newSymbolNames.indexOf( name );
506  if ( newNameIndex < 0 )
507  return; // shouldn't happen
508 
509  const int offset = offsetForEntity( type );
510  beginInsertRows( QModelIndex(), newNameIndex + offset, newNameIndex + offset );
511  mEntityNames[ type ] = newSymbolNames;
512  endInsertRows();
513 }
514 
515 void QgsStyleModel::onEntityRemoved( QgsStyle::StyleEntity type, const QString &name )
516 {
517  mIconCache[ type ].remove( name );
518  const QStringList oldSymbolNames = mEntityNames[ type ];
519  const QStringList newSymbolNames = mStyle->allNames( type );
520 
521  // find index of removed symbol
522  const int oldNameIndex = oldSymbolNames.indexOf( name );
523  if ( oldNameIndex < 0 )
524  return; // shouldn't happen
525 
526  const int offset = offsetForEntity( type );
527  beginRemoveRows( QModelIndex(), oldNameIndex + offset, oldNameIndex + offset );
528  mEntityNames[ type ] = newSymbolNames;
529  endRemoveRows();
530 }
531 
532 void QgsStyleModel::onEntityChanged( QgsStyle::StyleEntity type, const QString &name )
533 {
534  mIconCache[ type ].remove( name );
535 
536  const int offset = offsetForEntity( type );
537  QModelIndex i = index( offset + mEntityNames[ type ].indexOf( name ), Tags );
538  emit dataChanged( i, i, QVector< int >() << Qt::DecorationRole );
539 }
540 
541 void QgsStyleModel::onEntityRename( QgsStyle::StyleEntity type, const QString &oldName, const QString &newName )
542 {
543  mIconCache[ type ].remove( oldName );
544  const QStringList oldSymbolNames = mEntityNames[ type ];
545  const QStringList newSymbolNames = mStyle->allNames( type );
546 
547  // find index of removed symbol
548  const int oldNameIndex = oldSymbolNames.indexOf( oldName );
549  if ( oldNameIndex < 0 )
550  return; // shouldn't happen
551 
552  // find index of added symbol
553  const int newNameIndex = newSymbolNames.indexOf( newName );
554  if ( newNameIndex < 0 )
555  return; // shouldn't happen
556 
557  if ( newNameIndex == oldNameIndex )
558  {
559  mEntityNames[ type ] = newSymbolNames;
560  return;
561  }
562 
563  const int offset = offsetForEntity( type );
564  beginMoveRows( QModelIndex(), oldNameIndex + offset, oldNameIndex + offset, QModelIndex(), ( newNameIndex > oldNameIndex ? newNameIndex + 1 : newNameIndex ) + offset );
565  mEntityNames[ type ] = newSymbolNames;
566  endMoveRows();
567 }
568 
569 void QgsStyleModel::onTagsChanged( int entity, const QString &name, const QStringList & )
570 {
571  QgsStyle::StyleEntity type = static_cast< QgsStyle::StyleEntity >( entity );
572  QModelIndex i;
573  int row = mEntityNames[type].indexOf( name ) + offsetForEntity( type );
574  switch ( static_cast< QgsStyle::StyleEntity >( entity ) )
575  {
576  case QgsStyle::TagEntity:
578  return;
579 
580  default:
581  i = index( row, Tags );
582  }
583  emit dataChanged( i, i );
584 }
585 
586 void QgsStyleModel::rebuildSymbolIcons()
587 {
588  mIconCache[ QgsStyle::SymbolEntity ].clear();
589  mExpressionContext.reset();
590  emit dataChanged( index( 0, 0 ), index( mEntityNames[ QgsStyle::SymbolEntity ].count() - 1, 0 ), QVector<int>() << Qt::DecorationRole );
591 }
592 
593 QgsStyle::StyleEntity QgsStyleModel::entityTypeFromRow( int row ) const
594 {
595  int maxRowForEntity = 0;
596  for ( QgsStyle::StyleEntity type : ENTITIES )
597  {
598  maxRowForEntity += mEntityNames[ type ].size();
599  if ( row < maxRowForEntity )
600  return type;
601  }
602 
603  // should never happen
604  Q_ASSERT( false );
605  return QgsStyle::SymbolEntity;
606 }
607 
608 int QgsStyleModel::offsetForEntity( QgsStyle::StyleEntity entity ) const
609 {
610  int offset = 0;
611  for ( QgsStyle::StyleEntity type : ENTITIES )
612  {
613  if ( type == entity )
614  return offset;
615 
616  offset += mEntityNames[ type ].size();
617  }
618  return 0;
619 }
620 
621 //
622 // QgsStyleProxyModel
623 //
624 
626  : QSortFilterProxyModel( parent )
627  , mStyle( style )
628 {
629  mModel = new QgsStyleModel( mStyle, this );
630  initialize();
631 }
632 
633 void QgsStyleProxyModel::initialize()
634 {
635  setSortCaseSensitivity( Qt::CaseInsensitive );
636 // setSortLocaleAware( true );
637  setSourceModel( mModel );
638  setDynamicSortFilter( true );
639  sort( 0 );
640 
641  connect( mStyle, &QgsStyle::entityTagsChanged, this, [ = ]
642  {
643  // update tagged symbols if filtering by tag
644  if ( mTagId >= 0 )
645  setTagId( mTagId );
646  if ( mSmartGroupId >= 0 )
647  setSmartGroupId( mSmartGroupId );
648  } );
649 
650  connect( mStyle, &QgsStyle::favoritedChanged, this, [ = ]
651  {
652  // update favorited symbols if filtering by favorite
653  if ( mFavoritesOnly )
654  setFavoritesOnly( mFavoritesOnly );
655  } );
656 
657  connect( mStyle, &QgsStyle::entityRenamed, this, [ = ]( QgsStyle::StyleEntity entity, const QString &, const QString & )
658  {
659  switch ( entity )
660  {
662  case QgsStyle::TagEntity:
663  return;
664 
665  default:
666  break;
667  }
668 
669  if ( mSmartGroupId >= 0 )
670  setSmartGroupId( mSmartGroupId );
671  } );
672 }
673 
675  : QSortFilterProxyModel( parent )
676  , mModel( model )
677  , mStyle( model->style() )
678 {
679  initialize();
680 }
681 
682 bool QgsStyleProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
683 {
684  if ( mFilterString.isEmpty() && !mEntityFilterEnabled && !mSymbolTypeFilterEnabled && mTagId < 0 && mSmartGroupId < 0 && !mFavoritesOnly )
685  return true;
686 
687  QModelIndex index = sourceModel()->index( source_row, 0, source_parent );
688  const QString name = sourceModel()->data( index ).toString();
689  const QStringList tags = sourceModel()->data( index, QgsStyleModel::TagRole ).toStringList();
690 
691  QgsStyle::StyleEntity styleEntityType = static_cast< QgsStyle::StyleEntity >( sourceModel()->data( index, QgsStyleModel::TypeRole ).toInt() );
692  if ( mEntityFilterEnabled && ( mEntityFilters.empty() || !mEntityFilters.contains( styleEntityType ) ) )
693  return false;
694 
695  QgsSymbol::SymbolType symbolType = static_cast< QgsSymbol::SymbolType >( sourceModel()->data( index, QgsStyleModel::SymbolTypeRole ).toInt() );
696  if ( mSymbolTypeFilterEnabled && symbolType != mSymbolType )
697  return false;
698 
699  if ( styleEntityType == QgsStyle::LabelSettingsEntity && mLayerType != QgsWkbTypes::UnknownGeometry &&
700  mLayerType != static_cast< QgsWkbTypes::GeometryType >( sourceModel()->data( index, QgsStyleModel::LayerTypeRole ).toInt() ) )
701  return false;
702 
703  if ( mTagId >= 0 && !mTaggedSymbolNames.contains( name ) )
704  return false;
705 
706  if ( mSmartGroupId >= 0 && !mSmartGroupSymbolNames.contains( name ) )
707  return false;
708 
709  if ( mFavoritesOnly && !sourceModel()->data( index, QgsStyleModel::IsFavoriteRole ).toBool() )
710  return false;
711 
712  if ( !mFilterString.isEmpty() )
713  {
714  // filter by word, in both filter string and style entity name/tags
715  // this allows matching of a filter string "hash line" to the symbol "hashed red lines"
716  const QStringList partsToMatch = mFilterString.trimmed().split( ' ' );
717 
718  QStringList partsToSearch = name.split( ' ' );
719  for ( const QString &tag : tags )
720  {
721  partsToSearch.append( tag.split( ' ' ) );
722  }
723 
724  for ( const QString &part : partsToMatch )
725  {
726  bool found = false;
727  for ( const QString &partToSearch : qgis::as_const( partsToSearch ) )
728  {
729  if ( partToSearch.contains( part, Qt::CaseInsensitive ) )
730  {
731  found = true;
732  break;
733  }
734  }
735  if ( !found )
736  return false; // couldn't find a match for this word, so hide entity
737  }
738  }
739 
740  return true;
741 }
742 
743 void QgsStyleProxyModel::setFilterString( const QString &filter )
744 {
745  mFilterString = filter;
746  invalidateFilter();
747 }
748 
749 
751 {
752  return mFavoritesOnly;
753 }
754 
755 void QgsStyleProxyModel::setFavoritesOnly( bool favoritesOnly )
756 {
757  mFavoritesOnly = favoritesOnly;
758  invalidateFilter();
759 }
760 
762 {
763  mModel->addDesiredIconSize( size );
764 }
765 
767 {
768  return mSymbolTypeFilterEnabled;
769 }
770 
771 void QgsStyleProxyModel::setSymbolTypeFilterEnabled( bool symbolTypeFilterEnabled )
772 {
773  mSymbolTypeFilterEnabled = symbolTypeFilterEnabled;
774  invalidateFilter();
775 }
776 
778 {
779  return mLayerType;
780 }
781 
783 {
784  mLayerType = type;
785  invalidateFilter();
786 }
787 
789 {
790  mTagId = id;
791 
792  mTaggedSymbolNames.clear();
793  if ( mTagId >= 0 )
794  {
795  for ( QgsStyle::StyleEntity entity : ENTITIES )
796  mTaggedSymbolNames.append( mStyle->symbolsWithTag( entity, mTagId ) );
797  }
798 
799  invalidateFilter();
800 }
801 
803 {
804  return mTagId;
805 }
806 
808 {
809  mSmartGroupId = id;
810 
811  mSmartGroupSymbolNames.clear();
812  if ( mSmartGroupId >= 0 )
813  {
814  for ( QgsStyle::StyleEntity entity : ENTITIES )
815  mSmartGroupSymbolNames.append( mStyle->symbolsOfSmartgroup( entity, mSmartGroupId ) );
816  }
817  invalidateFilter();
818 }
819 
821 {
822  return mSmartGroupId;
823 }
824 
826 {
827  return mSymbolType;
828 }
829 
831 {
832  mSymbolType = symbolType;
833  invalidateFilter();
834 }
835 
837 {
838  return mEntityFilterEnabled;
839 }
840 
841 void QgsStyleProxyModel::setEntityFilterEnabled( bool entityFilterEnabled )
842 {
843  mEntityFilterEnabled = entityFilterEnabled;
844  invalidateFilter();
845 }
846 
848 {
849  return mEntityFilters.empty() ? QgsStyle::SymbolEntity : mEntityFilters.at( 0 );
850 }
851 
853 {
854  mEntityFilters = QList< QgsStyle::StyleEntity >() << entityFilter;
855  invalidateFilter();
856 }
857 
858 void QgsStyleProxyModel::setEntityFilters( const QList<QgsStyle::StyleEntity> &filters )
859 {
860  mEntityFilters = filters;
861  invalidateFilter();
862 }
qgsexpressioncontextutils.h
QgsStyle::favoritedChanged
void favoritedChanged(QgsStyle::StyleEntity entity, const QString &name, bool isFavorite)
Emitted whenever an entity is either favorited or un-favorited.
qgssvgcache.h
QgsStyleProxyModel::setEntityFilters
void setEntityFilters(const QList< QgsStyle::StyleEntity > &filters)
Sets the style entity type filters.
Definition: qgsstylemodel.cpp:858
QgsStyle::ColorrampEntity
@ ColorrampEntity
Color ramps.
Definition: qgsstyle.h:182
QgsStyle::entityAdded
void entityAdded(QgsStyle::StyleEntity entity, const QString &name)
Emitted every time a new entity has been added to the database.
QgsStyleModel
Definition: qgsstylemodel.h:45
QgsStyle::labelSettingsLayerType
QgsWkbTypes::GeometryType labelSettingsLayerType(const QString &name) const
Returns the layer geometry type corresponding to the label settings with the specified name,...
Definition: qgsstyle.cpp:1938
QgsStyle::textFormat
QgsTextFormat textFormat(const QString &name) const
Returns the text format with the specified name.
Definition: qgsstyle.cpp:1895
QgsPalLayerSettings
Definition: qgspallabeling.h:205
QgsStyleModel::IsFavoriteRole
@ IsFavoriteRole
Whether entity is flagged as a favorite.
Definition: qgsstylemodel.h:64
qgssymbollayerutils.h
QgsStyleProxyModel::setEntityFilterEnabled
void setEntityFilterEnabled(bool enabled)
Sets whether filtering by entity type is enabled.
Definition: qgsstylemodel.cpp:841
QgsStyleModel::index
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Definition: qgsstylemodel.cpp:453
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:458
QgsStyleProxyModel::setFilterString
void setFilterString(const QString &filter)
Sets a filter string, such that only symbol entities with names matching the specified string will be...
Definition: qgsstylemodel.cpp:743
QgsExpressionContextUtils::globalProjectLayerScopes
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Definition: qgsexpressioncontextutils.cpp:306
QgsSymbol
Definition: qgssymbol.h:63
QgsStyle::LegendPatchShapeEntity
@ LegendPatchShapeEntity
Legend patch shape (since QGIS 3.14)
Definition: qgsstyle.h:186
QgsStyle::renameEntity
bool renameEntity(StyleEntity type, const QString &oldName, const QString &newName)
Renames an entity of the specified type from oldName to newName.
Definition: qgsstyle.cpp:222
QgsStyle::entityRemoved
void entityRemoved(QgsStyle::StyleEntity entity, const QString &name)
Emitted whenever an entity of the specified type is removed from the style and the database has been ...
QgsStyleModel::setData
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Definition: qgsstylemodel.cpp:378
QgsStyle::symbol
QgsSymbol * symbol(const QString &name)
Returns a NEW copy of symbol.
Definition: qgsstyle.cpp:248
QgsStyleProxyModel::setSmartGroupId
void setSmartGroupId(int id)
Sets a smart group id to filter style entities by.
Definition: qgsstylemodel.cpp:807
QgsLegendPatchShape
Definition: qgslegendpatchshape.h:30
QgsStyle::SymbolEntity
@ SymbolEntity
Symbols.
Definition: qgsstyle.h:180
QgsSymbolLayerUtils::colorRampPreviewPixmap
static QPixmap colorRampPreviewPixmap(QgsColorRamp *ramp, QSize size, int padding=0)
Returns a pixmap preview for a color ramp.
Definition: qgssymbollayerutils.cpp:875
QgsStyle::TagEntity
@ TagEntity
Tags.
Definition: qgsstyle.h:181
QgsStyle::LabelSettingsEntity
@ LabelSettingsEntity
Label settings.
Definition: qgsstyle.h:185
qgsapplication.h
QgsStyleModel::flags
Qt::ItemFlags flags(const QModelIndex &index) const override
Definition: qgsstylemodel.cpp:411
QgsStyleModel::TypeRole
@ TypeRole
Style entity type, see QgsStyle::StyleEntity.
Definition: qgsstylemodel.h:61
QgsStyleModel::headerData
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Definition: qgsstylemodel.cpp:424
QgsPalLayerSettings::labelSettingsPreviewPixmap
static QPixmap labelSettingsPreviewPixmap(const QgsPalLayerSettings &settings, QSize size, const QString &previewText=QString(), int padding=0)
Returns a pixmap preview for label settings.
Definition: qgspallabeling.cpp:1258
QgsStyle::symbolsOfSmartgroup
QStringList symbolsOfSmartgroup(StyleEntity type, int id)
Returns the symbols for the smartgroup.
Definition: qgsstyle.cpp:2124
QgsTextFormat
Definition: qgstextformat.h:38
QgsStyleProxyModel::symbolType
QgsSymbol::SymbolType symbolType() const
Returns the symbol type filter.
Definition: qgsstylemodel.cpp:825
QgsStyleModel::Tags
@ Tags
Tags column.
Definition: qgsstylemodel.h:55
QgsSymbolLayerUtils::symbolPreviewPixmap
static QPixmap symbolPreviewPixmap(const QgsSymbol *symbol, QSize size, int padding=0, QgsRenderContext *customContext=nullptr, bool selected=false, const QgsExpressionContext *expressionContext=nullptr, const QgsLegendPatchShape *shape=nullptr)
Returns a pixmap preview for a color ramp.
Definition: qgssymbollayerutils.cpp:767
QgsStyleModel::TagRole
@ TagRole
String list of tags.
Definition: qgsstylemodel.h:62
QgsStyleProxyModel::layerType
QgsWkbTypes::GeometryType layerType() const
Returns the layer type filter, or QgsWkbTypes::UnknownGeometry if no layer type filter is present.
Definition: qgsstylemodel.cpp:777
QgsStyle::entityTagsChanged
void entityTagsChanged(QgsStyle::StyleEntity entity, const QString &name, const QStringList &newTags)
Emitted whenever an entity's tags are changed.
QgsProject::projectColorsChanged
void projectColorsChanged()
Emitted whenever the project's color scheme has been changed.
QgsStyleProxyModel::favoritesOnly
bool favoritesOnly() const
Returns true if the model is showing only favorited entities.
Definition: qgsstylemodel.cpp:750
QgsStyle::previewSymbolForPatchShape
const QgsSymbol * previewSymbolForPatchShape(const QgsLegendPatchShape &shape) const
Returns a symbol to use for rendering preview icons for a patch shape.
Definition: qgsstyle.cpp:1966
QgsApplication::imageCache
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
Definition: qgsapplication.cpp:2134
QgsStyle::SmartgroupEntity
@ SmartgroupEntity
Smart groups.
Definition: qgsstyle.h:183
Qgis::UI_SCALE_FACTOR
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:195
QgsStyleModel::columnCount
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Definition: qgsstylemodel.cpp:484
qgsstylemodel.h
QgsTextFormat::textFormatPreviewPixmap
static QPixmap textFormatPreviewPixmap(const QgsTextFormat &format, QSize size, const QString &previewText=QString(), int padding=0)
Returns a pixmap preview for a text format.
Definition: qgstextformat.cpp:776
QgsStyle::entityChanged
void entityChanged(QgsStyle::StyleEntity entity, const QString &name)
Emitted whenever an entity's definition is changed.
QgsApplication::svgCache
static QgsSvgCache * svgCache()
Returns the application's SVG cache, used for caching SVG images and handling parameter replacement w...
Definition: qgsapplication.cpp:2129
QgsStyleProxyModel::setLayerType
void setLayerType(QgsWkbTypes::GeometryType type)
Sets the layer type filter.
Definition: qgsstylemodel.cpp:782
qgsstyle.h
QgsStyleProxyModel::setEntityFilter
void setEntityFilter(QgsStyle::StyleEntity filter)
Sets the style entity type filter.
Definition: qgsstylemodel.cpp:852
QgsStyleModel::SymbolTypeRole
@ SymbolTypeRole
Symbol type (for symbol or legend patch shape entities)
Definition: qgsstylemodel.h:63
QgsStyle::allNames
QStringList allNames(StyleEntity type) const
Returns a list of the names of all existing entities of the specified type.
Definition: qgsstyle.cpp:1995
QgsStyleProxyModel::setSymbolType
void setSymbolType(QgsSymbol::SymbolType type)
Sets the symbol type filter.
Definition: qgsstylemodel.cpp:830
QgsStyle::legendPatchShape
QgsLegendPatchShape legendPatchShape(const QString &name) const
Returns the legend patch shape with the specified name.
Definition: qgsstyle.cpp:1920
QgsWkbTypes::GeometryType
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:139
QgsStyleProxyModel::symbolTypeFilterEnabled
bool symbolTypeFilterEnabled() const
Returns true if filtering by symbol type is enabled.
Definition: qgsstylemodel.cpp:766
QgsStyleModel::LayerTypeRole
@ LayerTypeRole
Layer type (for label settings entities)
Definition: qgsstylemodel.h:65
QgsStyleProxyModel::filterAcceptsRow
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
Definition: qgsstylemodel.cpp:682
QgsStyle
Definition: qgsstyle.h:159
QgsStyle::TextFormatEntity
@ TextFormatEntity
Text formats.
Definition: qgsstyle.h:184
qgsimagecache.h
QgsStyleProxyModel::entityFilterEnabled
bool entityFilterEnabled() const
Returns true if filtering by entity type is enabled.
Definition: qgsstylemodel.cpp:836
QgsStyleProxyModel::addDesiredIconSize
void addDesiredIconSize(QSize size)
Adds an additional icon size to generate for Qt::DecorationRole data.
Definition: qgsstylemodel.cpp:761
QgsStyleProxyModel::setSymbolTypeFilterEnabled
void setSymbolTypeFilterEnabled(bool enabled)
Sets whether filtering by symbol type is enabled.
Definition: qgsstylemodel.cpp:771
QgsStyleProxyModel::setFavoritesOnly
void setFavoritesOnly(bool favoritesOnly)
Sets whether the model should show only favorited entities.
Definition: qgsstylemodel.cpp:755
QgsStyleProxyModel::smartGroupId
int smartGroupId() const
Returns the smart group id used to filter style entities by.
Definition: qgsstylemodel.cpp:820
QgsStyleProxyModel::tagId
int tagId() const
Returns the tag id used to filter style entities by.
Definition: qgsstylemodel.cpp:802
QgsWkbTypes::UnknownGeometry
@ UnknownGeometry
Definition: qgswkbtypes.h:144
QgsStyleProxyModel::QgsStyleProxyModel
QgsStyleProxyModel(QgsStyle *style, QObject *parent=nullptr)
Constructor for QgsStyleProxyModel, for the specified style and parent object.
Definition: qgsstylemodel.cpp:625
QgsStyleModel::data
QVariant data(const QModelIndex &index, int role) const override
Definition: qgsstylemodel.cpp:60
QgsSymbol::type
SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:122
QgsStyleModel::addDesiredIconSize
void addDesiredIconSize(QSize size)
Adds an additional icon size to generate for Qt::DecorationRole data.
Definition: qgsstylemodel.cpp:489
QgsStyleProxyModel::setTagId
void setTagId(int id)
Sets a tag id to filter style entities by.
Definition: qgsstylemodel.cpp:788
QgsStyle::entityRenamed
void entityRenamed(QgsStyle::StyleEntity entity, const QString &oldName, const QString &newName)
Emitted whenever a entity of the specified type has been renamed from oldName to newName.
ICON_PADDING_FACTOR
const double ICON_PADDING_FACTOR
Definition: qgsstylemodel.cpp:26
QgsStyle::legendPatchShapeSymbolType
QgsSymbol::SymbolType legendPatchShapeSymbolType(const QString &name) const
Returns the symbol type corresponding to the legend patch shape with the specified name,...
Definition: qgsstyle.cpp:1930
QgsSymbol::SymbolType
SymbolType
Type of the symbol.
Definition: qgssymbol.h:85
QgsImageCache::remoteImageFetched
void remoteImageFetched(const QString &url)
Emitted when the cache has finished retrieving an image file from a remote url.
QgsStyle::tagsOfSymbol
QStringList tagsOfSymbol(StyleEntity type, const QString &symbol)
Returns the tags associated with the symbol.
Definition: qgsstyle.cpp:1686
QgsStyleModel::parent
QModelIndex parent(const QModelIndex &index) const override
Definition: qgsstylemodel.cpp:466
QgsStyle::isFavorite
bool isFavorite(StyleEntity type, const QString &name)
Returns true if the symbol with matching type and name is marked as a favorite.
Definition: qgsstyle.cpp:1737
QgsStyle::symbolsWithTag
QStringList symbolsWithTag(StyleEntity type, int tagid) const
Returns the symbol names with which have the given tag.
Definition: qgsstyle.cpp:1119
QgsStyle::labelSettings
QgsPalLayerSettings labelSettings(const QString &name) const
Returns the label settings with the specified name.
Definition: qgsstyle.cpp:1915
QgsStyle::symbolRef
const QgsSymbol * symbolRef(const QString &name) const
Returns a const pointer to a symbol (doesn't create new instance)
Definition: qgsstyle.cpp:254
QgsStyleProxyModel::entityFilter
QgsStyle::StyleEntity entityFilter() const
Returns the style entity type filter.
Definition: qgsstylemodel.cpp:847
ENTITIES
const auto ENTITIES
Definition: qgsstylemodel.cpp:28
qgsproject.h
QgsStyle::colorRamp
QgsColorRamp * colorRamp(const QString &name) const
Returns a new copy of the specified color ramp.
Definition: qgsstyle.cpp:396
QgsStyleModel::rowCount
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Definition: qgsstylemodel.cpp:472
QgsStyleModel::Name
@ Name
Name column.
Definition: qgsstylemodel.h:54
QgsStyle::StyleEntity
StyleEntity
Enum for Entities involved in a style.
Definition: qgsstyle.h:178
QgsStyleModel::QgsStyleModel
QgsStyleModel(QgsStyle *style, QObject *parent=nullptr)
Constructor for QgsStyleModel, for the specified style and parent object.
Definition: qgsstylemodel.cpp:30
QgsSvgCache::remoteSvgFetched
void remoteSvgFetched(const QString &url)
Emitted when the cache has finished retrieving an SVG file from a remote url.
QgsLegendPatchShape::isNull
bool isNull() const
Returns true if the patch shape is a null QgsLegendPatchShape, which indicates that the default legen...
Definition: qgslegendpatchshape.cpp:32