17#include "moc_qgscategorizedsymbolrendererwidget.cpp"
46#include <QStandardItemModel>
47#include <QStandardItem>
57QgsCategorizedSymbolRendererModel::QgsCategorizedSymbolRendererModel( QObject *parent, QScreen *screen )
58 : QAbstractItemModel( parent )
59 , mMimeFormat( QStringLiteral(
"application/x-qgscategorizedsymbolrendererv2model" ) )
68 beginRemoveRows( QModelIndex(), 0, std::max<int>( mRenderer->categories().size() - 1, 0 ) );
77 beginInsertRows( QModelIndex(), 0, renderer->
categories().size() - 1 );
87 const int idx = mRenderer->categories().size();
88 beginInsertRows( QModelIndex(), idx, idx );
89 mRenderer->addCategory( cat );
100 const int row = index.row();
101 if ( row >= catList.size() )
105 return catList.at( row );
109Qt::ItemFlags QgsCategorizedSymbolRendererModel::flags(
const QModelIndex &index )
const
111 if ( !index.isValid() || !mRenderer )
113 return Qt::ItemIsDropEnabled;
116 Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable;
117 if ( index.column() == 1 )
120 if ( category.
value().userType() != QMetaType::Type::QVariantList )
122 flags |= Qt::ItemIsEditable;
125 else if ( index.column() == 2 )
127 flags |= Qt::ItemIsEditable;
132Qt::DropActions QgsCategorizedSymbolRendererModel::supportedDropActions()
const
134 return Qt::MoveAction;
137QVariant QgsCategorizedSymbolRendererModel::data(
const QModelIndex &index,
int role )
const
139 if ( !index.isValid() || !mRenderer )
146 case Qt::CheckStateRole:
148 if ( index.column() == 0 )
150 return category.
renderState() ? Qt::Checked : Qt::Unchecked;
155 case Qt::DisplayRole:
156 case Qt::ToolTipRole:
158 switch ( index.column() )
162 if ( category.
value().userType() == QMetaType::Type::QVariantList )
165 const QVariantList list = category.
value().toList();
166 res.reserve( list.size() );
167 for (
const QVariant &v : list )
170 if ( role == Qt::DisplayRole )
171 return res.join(
';' );
173 return res.join(
'\n' );
177 return tr(
"all other values" );
185 return category.
label();
195 italicFont.setItalic(
true );
201 case Qt::DecorationRole:
203 if ( index.column() == 0 && category.
symbol() )
211 case Qt::ForegroundRole:
213 QBrush brush( qApp->palette().color( QPalette::Text ), Qt::SolidPattern );
216 QColor fadedTextColor = brush.color();
217 fadedTextColor.setAlpha( 128 );
218 brush.setColor( fadedTextColor );
223 case Qt::TextAlignmentRole:
225 return ( index.column() == 0 ) ?
static_cast<Qt::Alignment::Int
>( Qt::AlignHCenter ) : static_cast<Qt::Alignment::Int>( Qt::AlignLeft );
230 switch ( index.column() )
234 if ( category.
value().userType() == QMetaType::Type::QVariantList )
237 const QVariantList list = category.
value().toList();
238 res.reserve( list.size() );
239 for (
const QVariant &v : list )
242 return res.join(
';' );
246 return category.
value();
251 return category.
label();
257 if ( index.column() == 1 )
258 return category.
value();
266bool QgsCategorizedSymbolRendererModel::setData(
const QModelIndex &index,
const QVariant &value,
int role )
268 if ( !index.isValid() )
271 if ( index.column() == 0 && role == Qt::CheckStateRole )
273 mRenderer->updateCategoryRenderState( index.row(), value == Qt::Checked );
274 emit dataChanged( index, index );
278 if ( role != Qt::EditRole )
281 switch ( index.column() )
286 QVariant val = value;
287 const QVariant previousValue = mRenderer->categories().value( index.row() ).value();
288 if ( previousValue.userType() != QMetaType::Type::QString && !previousValue.toString().isEmpty() )
290 switch ( previousValue.userType() )
292 case QMetaType::Type::Int:
295 case QMetaType::Type::Double:
296 val = value.toDouble();
298 case QMetaType::Type::QVariantList:
300 const QStringList parts = value.toString().split(
';' );
302 list.reserve( parts.count() );
303 for (
const QString &p : parts )
306 if ( list.count() == 1 )
313 val = value.toString();
317 mRenderer->updateCategoryValue( index.row(), val );
321 mRenderer->updateCategoryLabel( index.row(), value.toString() );
327 emit dataChanged( index, index );
331QVariant QgsCategorizedSymbolRendererModel::headerData(
int section, Qt::Orientation orientation,
int role )
const
333 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 3 )
336 lst << tr(
"Symbol" ) << tr(
"Value" ) << tr(
"Legend" );
337 return lst.value( section );
342int QgsCategorizedSymbolRendererModel::rowCount(
const QModelIndex &parent )
const
344 if ( parent.isValid() || !mRenderer )
348 return mRenderer->categories().size();
351int QgsCategorizedSymbolRendererModel::columnCount(
const QModelIndex &index )
const
357QModelIndex QgsCategorizedSymbolRendererModel::index(
int row,
int column,
const QModelIndex &parent )
const
359 if ( hasIndex( row, column, parent ) )
361 return createIndex( row, column );
363 return QModelIndex();
366QModelIndex QgsCategorizedSymbolRendererModel::parent(
const QModelIndex &index )
const
369 return QModelIndex();
372QStringList QgsCategorizedSymbolRendererModel::mimeTypes()
const
375 types << mMimeFormat;
379QMimeData *QgsCategorizedSymbolRendererModel::mimeData(
const QModelIndexList &indexes )
const
381 QMimeData *mimeData =
new QMimeData();
382 QByteArray encodedData;
384 QDataStream stream( &encodedData, QIODevice::WriteOnly );
387 const auto constIndexes = indexes;
388 for (
const QModelIndex &index : constIndexes )
390 if ( !index.isValid() || index.column() != 0 )
393 stream << index.row();
395 mimeData->setData( mMimeFormat, encodedData );
399bool QgsCategorizedSymbolRendererModel::dropMimeData(
const QMimeData *data, Qt::DropAction action,
int row,
int column,
const QModelIndex &parent )
403 if ( action != Qt::MoveAction )
406 if ( !data->hasFormat( mMimeFormat ) )
409 QByteArray encodedData = data->data( mMimeFormat );
410 QDataStream stream( &encodedData, QIODevice::ReadOnly );
413 while ( !stream.atEnd() )
420 int to = parent.row();
424 to = mRenderer->categories().size();
425 for (
int i = rows.size() - 1; i >= 0; i-- )
427 QgsDebugMsgLevel( QStringLiteral(
"move %1 to %2" ).arg( rows[i] ).arg( to ), 2 );
432 mRenderer->moveCategory( rows[i], t );
434 for (
int j = 0; j < i; j++ )
436 if ( to < rows[j] && rows[i] > rows[j] )
443 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
448void QgsCategorizedSymbolRendererModel::deleteRows( QList<int> rows )
450 std::sort( rows.begin(), rows.end() );
451 for (
int i = rows.size() - 1; i >= 0; i-- )
453 beginRemoveRows( QModelIndex(), rows[i], rows[i] );
454 mRenderer->deleteCategory( rows[i] );
459void QgsCategorizedSymbolRendererModel::removeAllRows()
461 beginRemoveRows( QModelIndex(), 0, mRenderer->categories().size() - 1 );
462 mRenderer->deleteAllCategories();
466void QgsCategorizedSymbolRendererModel::sort(
int column, Qt::SortOrder order )
474 mRenderer->sortByValue( order );
476 else if ( column == 2 )
478 mRenderer->sortByLabel( order );
480 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
483void QgsCategorizedSymbolRendererModel::updateSymbology()
485 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
489QgsCategorizedSymbolRendererViewStyle::QgsCategorizedSymbolRendererViewStyle( QWidget *parent )
493void QgsCategorizedSymbolRendererViewStyle::drawPrimitive( PrimitiveElement element,
const QStyleOption *option, QPainter *painter,
const QWidget *widget )
const
495 if ( element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull() )
497 QStyleOption opt( *option );
498 opt.rect.setLeft( 0 );
500 opt.rect.setHeight( 0 );
502 opt.rect.setRight( widget->width() );
503 QProxyStyle::drawPrimitive( element, &opt, painter, widget );
506 QProxyStyle::drawPrimitive( element, option, painter, widget );
510QgsCategorizedRendererViewItemDelegate::QgsCategorizedRendererViewItemDelegate(
QgsFieldExpressionWidget *expressionWidget, QObject *parent )
511 : QStyledItemDelegate( parent )
512 , mFieldExpressionWidget( expressionWidget )
516QWidget *QgsCategorizedRendererViewItemDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index )
const
525 const QString fieldName { mFieldExpressionWidget->currentField( &isExpression, &isValid ) };
526 if ( !fieldName.isEmpty() && mFieldExpressionWidget->layer() && mFieldExpressionWidget->layer()->fields().lookupField( fieldName ) != -1 )
528 userType = mFieldExpressionWidget->layer()->fields().field( fieldName ).type();
530 else if ( isExpression && isValid )
534 if ( mFieldExpressionWidget->layer()->getFeatures().nextFeature( feat ) )
539 expressionContext.
appendScope( mFieldExpressionWidget->layer()->createExpressionContextScope() );
542 const QVariant value = exp.evaluate( &expressionContext );
543 if ( !exp.hasEvalError() )
545 userType =
static_cast<QMetaType::Type
>( value.userType() );
554 case QMetaType::Type::Double:
560 if ( value.toDouble( &ok ); ok )
562 const QString strVal { value.toString() };
563 const int dotPosition( strVal.indexOf(
'.' ) );
564 if ( dotPosition >= 0 )
566 decimals = std::max<int>( 2, strVal.length() - dotPosition - 1 );
569 editor->setDecimals( decimals );
571 editor->setMaximum( std::numeric_limits<double>::max() );
572 editor->setMinimum( std::numeric_limits<double>::lowest() );
575 case QMetaType::Type::Int:
578 editor->setDecimals( 0 );
580 editor->setMaximum( std::numeric_limits<int>::max() );
581 editor->setMinimum( std::numeric_limits<int>::min() );
584 case QMetaType::Type::QChar:
587 editor->setDecimals( 0 );
589 editor->setMaximum( std::numeric_limits<char>::max() );
590 editor->setMinimum( std::numeric_limits<char>::min() );
593 case QMetaType::Type::UInt:
596 editor->setDecimals( 0 );
598 editor->setMaximum( std::numeric_limits<unsigned int>::max() );
599 editor->setMinimum( 0 );
602 case QMetaType::Type::LongLong:
605 editor->setDecimals( 0 );
607 editor->setMaximum(
static_cast<double>( std::numeric_limits<qlonglong>::max() ) );
608 editor->setMinimum( std::numeric_limits<qlonglong>::min() );
611 case QMetaType::Type::ULongLong:
614 editor->setDecimals( 0 );
616 editor->setMaximum(
static_cast<double>( std::numeric_limits<unsigned long long>::max() ) );
617 editor->setMinimum( 0 );
623 return editor ? editor : QStyledItemDelegate::createEditor( parent, option, index );
636 , mContextMenu( new QMenu( this ) )
651 const QString attrName =
mRenderer->classAttribute();
652 mOldClassificationAttribute = attrName;
656 layout()->setContentsMargins( 0, 0, 0, 0 );
658 mExpressionWidget->setLayer(
mLayer );
659 btnChangeCategorizedSymbol->setLayer(
mLayer );
660 btnChangeCategorizedSymbol->registerExpressionContextGenerator(
this );
663 btnColorRamp->setShowRandomColorRamp(
true );
666 std::unique_ptr<QgsColorRamp> colorRamp(
QgsProject::instance()->styleSettings()->defaultColorRamp() );
669 btnColorRamp->setColorRamp( colorRamp.get() );
673 btnColorRamp->setRandomColorRamp();
683 mModel =
new QgsCategorizedSymbolRendererModel(
this, screen() );
689 viewCategories->setModel(
mModel );
690 viewCategories->resizeColumnToContents( 0 );
691 viewCategories->resizeColumnToContents( 1 );
692 viewCategories->resizeColumnToContents( 2 );
693 viewCategories->setItemDelegateForColumn( 1,
new QgsCategorizedRendererViewItemDelegate( mExpressionWidget, viewCategories ) );
695 viewCategories->setStyle(
new QgsCategorizedSymbolRendererViewStyle( viewCategories ) );
696 connect( viewCategories->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QgsCategorizedSymbolRendererWidget::selectionChanged );
704 connect( viewCategories, &QTreeView::customContextMenuRequested,
this, &QgsCategorizedSymbolRendererWidget::showContextMenu );
706 connect( btnChangeCategorizedSymbol, &
QgsSymbolButton::changed,
this, &QgsCategorizedSymbolRendererWidget::updateSymbolsFromButton );
716 QMenu *advMenu =
new QMenu;
723 QAction *actionDdsLegend = advMenu->addAction( tr(
"Data-defined Size Legend…" ) );
725 connect( actionDdsLegend, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::dataDefinedSizeLegend );
728 btnAdvanced->setMenu( advMenu );
730 mExpressionWidget->registerExpressionContextGenerator(
this );
732 mMergeCategoriesAction =
new QAction( tr(
"Merge Categories" ),
this );
733 connect( mMergeCategoriesAction, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::mergeSelectedCategories );
734 mUnmergeCategoriesAction =
new QAction( tr(
"Unmerge Categories" ),
this );
735 connect( mUnmergeCategoriesAction, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::unmergeSelectedCategories );
737 connect( mContextMenu, &QMenu::aboutToShow,
this, [=] {
757 const QString attrName =
mRenderer->classAttribute();
758 mExpressionWidget->setField( attrName );
770 btnColorRamp->setColorRamp(
mRenderer->sourceColorRamp() );
788 delete mActionLevels;
789 mActionLevels =
nullptr;
796 if ( !selectedCats.isEmpty() )
807 const auto constSelectedCats = selectedCats;
808 for (
const int idx : constSelectedCats )
814 mRenderer->updateCategorySymbol( idx, newCatSymbol );
834 if ( !dlg.exec() || !newSymbol )
857 if ( idx.isValid() && idx.column() == 0 )
865 std::unique_ptr<QgsSymbol> symbol;
867 if (
auto *lSymbol = category.
symbol() )
869 symbol.reset( lSymbol->clone() );
889 if ( !dlg.exec() || !symbol )
902 const QString attrName = mExpressionWidget->currentField();
904 QList<QVariant> uniqueValues;
922 if ( uniqueValues.contains( value ) )
924 uniqueValues << value;
933 if ( uniqueValues.size() >= 1000 )
935 const int res = QMessageBox::warning(
nullptr, tr(
"Classify Categories" ), tr(
"High number of classes. Classification would yield %n entries which might not be expected. Continue?",
nullptr, uniqueValues.size() ), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel );
936 if ( res == QMessageBox::Cancel )
943 DlgAddCategories dlg(
mStyle, createDefaultSymbol(), unique_vals,
this );
949 bool deleteExisting =
false;
951 if ( !mOldClassificationAttribute.isEmpty() && attrName != mOldClassificationAttribute && !
mRenderer->categories().isEmpty() )
953 const int res = QMessageBox::question(
this, tr(
"Delete Classification" ), tr(
"The classification field was changed from '%1' to '%2'.\n"
954 "Should the existing classes be deleted before classification?" )
955 .arg( mOldClassificationAttribute, attrName ),
956 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel );
957 if ( res == QMessageBox::Cancel )
962 deleteExisting = ( res == QMessageBox::Yes );
966 bool keepExistingColors =
false;
967 if ( !deleteExisting )
970 keepExistingColors = !prevCats.isEmpty();
972 if ( keepExistingColors && btnColorRamp->isRandomColorRamp() )
974 for (
int i = 0; i < cats.size(); ++i )
976 bool contains =
false;
977 const QVariant value = cats.at( i ).value();
978 for (
int j = 0; j < prevCats.size() && !contains; ++j )
980 const QVariant prevCatValue = prevCats.at( j ).value();
981 if ( prevCatValue.userType() == QMetaType::Type::QVariantList )
983 const QVariantList list = prevCatValue.toList();
984 for (
const QVariant &v : list )
995 if ( prevCats.at( j ).value() == value )
1006 if ( keepExistingColors && btnColorRamp->isRandomColorRamp() )
1009 cats.at( i ).symbol()->setColor( randomColors.
color( i ) );
1011 prevCats.append( cats.at( i ) );
1017 mOldClassificationAttribute = attrName;
1034 std::unique_ptr<QgsCategorizedSymbolRenderer> r = std::make_unique<QgsCategorizedSymbolRenderer>( attrName, cats );
1036 std::unique_ptr<QgsColorRamp> ramp( btnColorRamp->colorRamp() );
1038 r->setSourceColorRamp( ramp->clone() );
1042 mModel->setRenderer( r.get() );
1045 if ( !keepExistingColors && ramp )
1052 if ( !btnColorRamp->isNull() )
1054 mRenderer->updateColorRamp( btnColorRamp->colorRamp() );
1056 mModel->updateSymbology();
1061 const QModelIndex idx = viewCategories->selectionModel()->currentIndex();
1062 if ( !idx.isValid() )
1070 const QModelIndexList selectedRows = viewCategories->selectionModel()->selectedRows();
1072 const auto constSelectedRows = selectedRows;
1073 for (
const QModelIndex &r : constSelectedRows )
1077 rows.append( r.row() );
1086 mModel->deleteRows( categoryIndexes );
1102 mModel->addCategory( cat );
1110 QItemSelectionModel *m = viewCategories->selectionModel();
1111 const QModelIndexList selectedIndexes = m->selectedRows( 1 );
1113 if ( !selectedIndexes.isEmpty() )
1116 QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
1117 for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
1119 const int row = ( *indexIt ).row();
1120 QgsSymbol *s = categories[row].symbol();
1134 QItemSelectionModel *m = viewCategories->selectionModel();
1135 const QModelIndexList selectedIndexes = m->selectedRows( 1 );
1137 if ( !selectedIndexes.isEmpty() )
1139 QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
1140 for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
1142 cl.append(
mModel->category( *indexIt ) );
1161 viewCategories->selectionModel()->clear();
1169 QMessageBox::information(
this, tr(
"Matched Symbols" ), tr(
"Matched %n categories to symbols.",
nullptr, matched ) );
1173 QMessageBox::warning(
this, tr(
"Matched Symbols" ), tr(
"No categories could be matched to symbols in library." ) );
1186 QVariantList unmatchedCategories;
1187 QStringList unmatchedSymbols;
1188 const int matched =
mRenderer->matchToSymbols( style, type, unmatchedCategories, unmatchedSymbols );
1190 mModel->updateSymbology();
1197 const QString openFileDir = settings.
value( QStringLiteral(
"UI/lastMatchToSymbolsDir" ), QDir::homePath() ).toString();
1199 const QString fileName = QFileDialog::getOpenFileName(
this, tr(
"Match to Symbols from File" ), openFileDir, tr(
"XML files (*.xml *.XML)" ) );
1200 if ( fileName.isEmpty() )
1205 const QFileInfo openFileInfo( fileName );
1206 settings.
setValue( QStringLiteral(
"UI/lastMatchToSymbolsDir" ), openFileInfo.absolutePath() );
1209 if ( !importedStyle.
importXml( fileName ) )
1211 QMessageBox::warning(
this, tr(
"Match to Symbols from File" ), tr(
"An error occurred while reading file:\n%1" ).arg( importedStyle.
errorString() ) );
1218 QMessageBox::information(
this, tr(
"Match to Symbols from File" ), tr(
"Matched %n categories to symbols from file.",
nullptr, matched ) );
1222 QMessageBox::warning(
this, tr(
"Match to Symbols from File" ), tr(
"No categories could be matched to symbols in file." ) );
1233 mRenderer->setLegendSymbolItem( legendSymbol.ruleKey(), sym->
clone() );
1236 mRenderer->setUsingSymbolLevels( enabled );
1237 mModel->updateSymbology();
1248 if ( !selectedCats.isEmpty() )
1250 for (
const int idx : selectedCats )
1252 if (
mRenderer->categories().at( idx ).symbol()->type() != tempSymbol->type() )
1255 std::unique_ptr<QgsSymbol> newCatSymbol( tempSymbol->clone() );
1256 if ( selectedCats.count() > 1 )
1259 newCatSymbol->setColor(
mRenderer->categories().at( idx ).symbol()->color() );
1261 mRenderer->updateCategorySymbol( idx, newCatSymbol.release() );
1274void QgsCategorizedSymbolRendererWidget::updateSymbolsFromButton()
1284 QItemSelectionModel *m = viewCategories->selectionModel();
1285 const QModelIndexList i = m->selectedRows();
1291 if ( !selectedCats.isEmpty() )
1293 const auto constSelectedCats = selectedCats;
1294 for (
const int idx : constSelectedCats )
1297 if ( selectedCats.count() > 1 )
1302 mRenderer->updateCategorySymbol( idx, newCatSymbol );
1311 mModel->updateSymbology();
1322 if ( event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier )
1324 mCopyBuffer.clear();
1327 else if ( event->key() == Qt::Key_V && event->modifiers() == Qt::ControlModifier )
1329 QgsCategoryList::const_iterator rIt = mCopyBuffer.constBegin();
1330 for ( ; rIt != mCopyBuffer.constEnd(); ++rIt )
1332 mModel->addCategory( *rIt );
1342 expContext = lMapCanvas->createExpressionContext();
1365void QgsCategorizedSymbolRendererWidget::dataDefinedSizeLegend()
1379void QgsCategorizedSymbolRendererWidget::mergeSelectedCategories()
1384 QList<int> categoryIndexes;
1387 for (
const int i : selectedCategoryIndexes )
1389 const QVariant v = categories.at( i ).value();
1391 if ( !v.isValid() || v ==
"" )
1396 categoryIndexes.append( i );
1399 if ( categoryIndexes.count() < 2 )
1403 QVariantList values;
1404 values.reserve( categoryIndexes.count() );
1405 labels.reserve( categoryIndexes.count() );
1406 for (
const int i : categoryIndexes )
1408 const QVariant v = categories.at( i ).value();
1410 if ( v.userType() == QMetaType::Type::QVariantList )
1412 values.append( v.toList() );
1417 labels << categories.at( i ).label();
1421 mRenderer->updateCategoryLabel( categoryIndexes.at( 0 ), labels.join(
',' ) );
1422 mRenderer->updateCategoryValue( categoryIndexes.at( 0 ), values );
1424 categoryIndexes.pop_front();
1425 mModel->deleteRows( categoryIndexes );
1430void QgsCategorizedSymbolRendererWidget::unmergeSelectedCategories()
1433 if ( categoryIndexes.isEmpty() )
1437 for (
const int i : categoryIndexes )
1439 const QVariant v = categories.at( i ).value();
1440 if ( v.userType() != QMetaType::Type::QVariantList )
1443 const QVariantList list = v.toList();
1444 for (
int j = 1; j < list.count(); ++j )
1446 mModel->addCategory(
QgsRendererCategory( list.at( j ), categories.at( i ).symbol()->clone(), list.at( j ).toString(), categories.at( i ).renderState() ) );
1448 mRenderer->updateCategoryValue( i, list.at( 0 ) );
1449 mRenderer->updateCategoryLabel( i, list.at( 0 ).toString() );
1455void QgsCategorizedSymbolRendererWidget::showContextMenu( QPoint )
1457 mContextMenu->clear();
1458 const QList<QAction *> actions =
contextMenu->actions();
1459 for ( QAction *act : actions )
1461 mContextMenu->addAction( act );
1464 mContextMenu->addSeparator();
1466 if ( viewCategories->selectionModel()->selectedRows().count() > 1 )
1468 mContextMenu->addAction( mMergeCategoriesAction );
1470 if ( viewCategories->selectionModel()->selectedRows().count() == 1 )
1474 const QVariant v = categories.at( categoryIndexes.at( 0 ) ).value();
1475 if ( v.userType() == QMetaType::Type::QVariantList )
1476 mContextMenu->addAction( mUnmergeCategoriesAction );
1478 else if ( viewCategories->selectionModel()->selectedRows().count() > 1 )
1480 mContextMenu->addAction( mUnmergeCategoriesAction );
1483 mContextMenu->exec( QCursor::pos() );
1486void QgsCategorizedSymbolRendererWidget::selectionChanged(
const QItemSelection &,
const QItemSelection & )
1489 if ( !selectedCats.isEmpty() )
1491 whileBlocking( btnChangeCategorizedSymbol )->setSymbol(
mRenderer->categories().at( selectedCats.at( 0 ) ).symbol()->clone() );
1497 btnChangeCategorizedSymbol->setDialogTitle( selectedCats.size() == 1 ?
mRenderer->categories().at( selectedCats.at( 0 ) ).label() : tr(
"Symbol Settings" ) );
const QgsCategoryList & categories() const
Returns a list of all categories recognized by the renderer.
static QgsCategorizedSymbolRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer, QgsVectorLayer *layer=nullptr)
Creates a new QgsCategorizedSymbolRenderer from an existing renderer.
static QgsCategoryList createCategories(const QVariantList &values, const QgsSymbol *symbol, QgsVectorLayer *layer=nullptr, const QString &fieldName=QString())
Create categories for a list of values.
static QString displayString(const QVariant &value, int precision=-1)
Returns a localized representation of value with the given precision, if precision is -1 then precisi...
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
void setClearValue(double customValue, const QString &clearValueText=QString())
Defines the clear value as a custom value and will automatically set the clear value mode to CustomVa...
Single scope for storing variables and functions for use within a QgsExpressionContext.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * atlasScope(const QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QString expression() const
Returns the original, unmodified expression string.
QVariant evaluate()
Evaluate the feature and return the result.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Abstract base class for all 2D vector feature renderers.
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
The QgsMapSettings class contains configuration for rendering of the map.
A marker symbol type, for rendering Point and MultiPoint geometries.
static QgsProject * instance()
Returns the QgsProject singleton instance.
A QProxyStyle subclass which correctly sets the base style to match the QGIS application style,...
Totally random color ramp.
virtual void setTotalColorCount(int colorCount)
Sets the desired total number of unique colors for the resultant ramp.
QColor color(double value) const override
Returns the color corresponding to a specified value.
Represents an individual category (class) from a QgsCategorizedSymbolRenderer.
QgsSymbol * symbol() const
Returns the symbol which will be used to render this category.
bool renderState() const
Returns true if the category is currently enabled and should be rendered.
QVariant value() const
Returns the value corresponding to this category.
QString label() const
Returns the label for this category, which is used to represent the category within legends and the l...
Stores properties relating to a screen.
This class is a composition of two QSettings instances:
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.
QString errorString() const
Returns the last error from a load() operation.
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
bool importXml(const QString &filename)
Imports the symbols and colorramps into the default style database from the given XML file.
static QgsSymbol * symbolFromMimeData(const QMimeData *data)
Attempts to parse mime data as a symbol.
static QIcon symbolPreviewIcon(const QgsSymbol *symbol, QSize size, int padding=0, QgsLegendPatchShape *shape=nullptr, const QgsScreenProperties &screen=QgsScreenProperties())
Returns an icon preview for a color ramp.
A dialog that can be used to select and build a symbol.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
QList< QgsExpressionContextScope > additionalExpressionContextScopes() const
Returns the list of additional expression context scopes to show as available within the layer.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
Abstract base class for all rendered symbols.
void setColor(const QColor &color) const
Sets the color for the symbol.
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
static QgsSymbol * defaultSymbol(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based data sets.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const FINAL
Calculates a list of unique values contained within an attribute in the layer.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
QList< QgsRendererCategory > QgsCategoryList
QList< QgsLegendSymbolItem > QgsLegendSymbolList
#define QgsDebugMsgLevel(str, level)