45#include <QStandardItemModel>
46#include <QStandardItem>
56QgsCategorizedSymbolRendererModel::QgsCategorizedSymbolRendererModel( QObject *parent, QScreen *screen )
57 : QAbstractItemModel( parent )
58 , mMimeFormat( QStringLiteral(
"application/x-qgscategorizedsymbolrendererv2model" ) )
67 beginRemoveRows( QModelIndex(), 0, std::max< int >( mRenderer->categories().size() - 1, 0 ) );
76 beginInsertRows( QModelIndex(), 0, renderer->
categories().size() - 1 );
84 if ( !mRenderer )
return;
85 const int idx = mRenderer->categories().size();
86 beginInsertRows( QModelIndex(), idx, idx );
87 mRenderer->addCategory( cat );
98 const int row = index.row();
99 if ( row >= catList.size() )
103 return catList.at( row );
107Qt::ItemFlags QgsCategorizedSymbolRendererModel::flags(
const QModelIndex &index )
const
109 if ( !index.isValid() || !mRenderer )
111 return Qt::ItemIsDropEnabled;
114 Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable;
115 if ( index.column() == 1 )
118 if ( category.
value().userType() != QMetaType::Type::QVariantList )
120 flags |= Qt::ItemIsEditable;
123 else if ( index.column() == 2 )
125 flags |= Qt::ItemIsEditable;
130Qt::DropActions QgsCategorizedSymbolRendererModel::supportedDropActions()
const
132 return Qt::MoveAction;
135QVariant QgsCategorizedSymbolRendererModel::data(
const QModelIndex &index,
int role )
const
137 if ( !index.isValid() || !mRenderer )
144 case Qt::CheckStateRole:
146 if ( index.column() == 0 )
148 return category.
renderState() ? Qt::Checked : Qt::Unchecked;
153 case Qt::DisplayRole:
154 case Qt::ToolTipRole:
156 switch ( index.column() )
160 if ( category.
value().userType() == QMetaType::Type::QVariantList )
163 const QVariantList list = category.
value().toList();
164 res.reserve( list.size() );
165 for (
const QVariant &v : list )
168 if ( role == Qt::DisplayRole )
169 return res.join(
';' );
171 return res.join(
'\n' );
175 return tr(
"all other values" );
183 return category.
label();
193 italicFont.setItalic(
true );
199 case Qt::DecorationRole:
201 if ( index.column() == 0 && category.
symbol() )
209 case Qt::ForegroundRole:
211 QBrush brush( qApp->palette().color( QPalette::Text ), Qt::SolidPattern );
212 if ( index.column() == 1 && ( category.
value().userType() == QMetaType::Type::QVariantList
215 QColor fadedTextColor = brush.color();
216 fadedTextColor.setAlpha( 128 );
217 brush.setColor( fadedTextColor );
222 case Qt::TextAlignmentRole:
224 return ( index.column() == 0 ) ?
static_cast<Qt::Alignment::Int
>( Qt::AlignHCenter ) : static_cast<Qt::Alignment::Int>( Qt::AlignLeft );
229 switch ( index.column() )
233 if ( category.
value().userType() == QMetaType::Type::QVariantList )
236 const QVariantList list = category.
value().toList();
237 res.reserve( list.size() );
238 for (
const QVariant &v : list )
241 return res.join(
';' );
245 return category.
value();
250 return category.
label();
256 if ( index.column() == 1 )
257 return category.
value();
265bool QgsCategorizedSymbolRendererModel::setData(
const QModelIndex &index,
const QVariant &value,
int role )
267 if ( !index.isValid() )
270 if ( index.column() == 0 && role == Qt::CheckStateRole )
272 mRenderer->updateCategoryRenderState( index.row(), value == Qt::Checked );
273 emit dataChanged( index, index );
277 if ( role != Qt::EditRole )
280 switch ( index.column() )
285 QVariant val = value;
286 const QVariant previousValue = mRenderer->categories().value( index.row() ).value();
287 if ( previousValue.userType() != QMetaType::Type::QString && ! previousValue.toString().isEmpty() )
289 switch ( previousValue.userType() )
291 case QMetaType::Type::Int:
294 case QMetaType::Type::Double:
295 val = value.toDouble();
297 case QMetaType::Type::QVariantList:
299 const QStringList parts = value.toString().split(
';' );
301 list.reserve( parts.count() );
302 for (
const QString &p : parts )
305 if ( list.count() == 1 )
312 val = value.toString();
316 mRenderer->updateCategoryValue( index.row(), val );
320 mRenderer->updateCategoryLabel( index.row(), value.toString() );
326 emit dataChanged( index, index );
330QVariant QgsCategorizedSymbolRendererModel::headerData(
int section, Qt::Orientation orientation,
int role )
const
332 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 3 )
335 lst << tr(
"Symbol" ) << tr(
"Value" ) << tr(
"Legend" );
336 return lst.value( section );
341int QgsCategorizedSymbolRendererModel::rowCount(
const QModelIndex &parent )
const
343 if ( parent.isValid() || !mRenderer )
347 return mRenderer->categories().size();
350int QgsCategorizedSymbolRendererModel::columnCount(
const QModelIndex &index )
const
356QModelIndex QgsCategorizedSymbolRendererModel::index(
int row,
int column,
const QModelIndex &parent )
const
358 if ( hasIndex( row, column, parent ) )
360 return createIndex( row, column );
362 return QModelIndex();
365QModelIndex QgsCategorizedSymbolRendererModel::parent(
const QModelIndex &index )
const
368 return QModelIndex();
371QStringList QgsCategorizedSymbolRendererModel::mimeTypes()
const
374 types << mMimeFormat;
378QMimeData *QgsCategorizedSymbolRendererModel::mimeData(
const QModelIndexList &indexes )
const
380 QMimeData *mimeData =
new QMimeData();
381 QByteArray encodedData;
383 QDataStream stream( &encodedData, QIODevice::WriteOnly );
386 const auto constIndexes = indexes;
387 for (
const QModelIndex &index : constIndexes )
389 if ( !index.isValid() || index.column() != 0 )
392 stream << index.row();
394 mimeData->setData( mMimeFormat, encodedData );
398bool QgsCategorizedSymbolRendererModel::dropMimeData(
const QMimeData *data, Qt::DropAction action,
int row,
int column,
const QModelIndex &parent )
402 if ( action != Qt::MoveAction )
return true;
404 if ( !data->hasFormat( mMimeFormat ) )
return false;
406 QByteArray encodedData = data->data( mMimeFormat );
407 QDataStream stream( &encodedData, QIODevice::ReadOnly );
410 while ( !stream.atEnd() )
417 int to = parent.row();
420 if ( to == -1 ) to = mRenderer->categories().size();
421 for (
int i = rows.size() - 1; i >= 0; i-- )
423 QgsDebugMsgLevel( QStringLiteral(
"move %1 to %2" ).arg( rows[i] ).arg( to ), 2 );
426 if ( rows[i] < t ) t--;
427 mRenderer->moveCategory( rows[i], t );
429 for (
int j = 0; j < i; j++ )
431 if ( to < rows[j] && rows[i] > rows[j] ) rows[j] += 1;
434 if ( rows[i] < to ) to--;
436 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
441void QgsCategorizedSymbolRendererModel::deleteRows( QList<int> rows )
443 std::sort( rows.begin(), rows.end() );
444 for (
int i = rows.size() - 1; i >= 0; i-- )
446 beginRemoveRows( QModelIndex(), rows[i], rows[i] );
447 mRenderer->deleteCategory( rows[i] );
452void QgsCategorizedSymbolRendererModel::removeAllRows()
454 beginRemoveRows( QModelIndex(), 0, mRenderer->categories().size() - 1 );
455 mRenderer->deleteAllCategories();
459void QgsCategorizedSymbolRendererModel::sort(
int column, Qt::SortOrder order )
467 mRenderer->sortByValue( order );
469 else if ( column == 2 )
471 mRenderer->sortByLabel( order );
473 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
476void QgsCategorizedSymbolRendererModel::updateSymbology()
478 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
482QgsCategorizedSymbolRendererViewStyle::QgsCategorizedSymbolRendererViewStyle( QWidget *parent )
486void QgsCategorizedSymbolRendererViewStyle::drawPrimitive( PrimitiveElement element,
const QStyleOption *option, QPainter *painter,
const QWidget *widget )
const
488 if ( element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull() )
490 QStyleOption opt( *option );
491 opt.rect.setLeft( 0 );
493 opt.rect.setHeight( 0 );
494 if ( widget ) opt.rect.setRight( widget->width() );
495 QProxyStyle::drawPrimitive( element, &opt, painter, widget );
498 QProxyStyle::drawPrimitive( element, option, painter, widget );
502QgsCategorizedRendererViewItemDelegate::QgsCategorizedRendererViewItemDelegate(
QgsFieldExpressionWidget *expressionWidget, QObject *parent )
503 : QStyledItemDelegate( parent )
504 , mFieldExpressionWidget( expressionWidget )
508QWidget *QgsCategorizedRendererViewItemDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index )
const
517 const QString fieldName { mFieldExpressionWidget->currentField( &isExpression, &isValid ) };
518 if ( ! fieldName.isEmpty() && mFieldExpressionWidget->layer() && mFieldExpressionWidget->layer()->fields().lookupField( fieldName ) != -1 )
520 userType = mFieldExpressionWidget->layer()->fields().field( fieldName ).type();
522 else if ( isExpression && isValid )
526 if ( mFieldExpressionWidget->layer()->getFeatures().nextFeature( feat ) )
531 expressionContext.
appendScope( mFieldExpressionWidget->layer()->createExpressionContextScope() );
534 const QVariant value = exp.evaluate( &expressionContext );
535 if ( !exp.hasEvalError() )
537 userType =
static_cast<QMetaType::Type
>( value.userType() );
546 case QMetaType::Type::Double:
552 if ( value.toDouble( &ok ); ok )
554 const QString strVal { value.toString() };
555 const int dotPosition( strVal.indexOf(
'.' ) );
556 if ( dotPosition >= 0 )
558 decimals = std::max<int>( 2, strVal.length() - dotPosition - 1 );
561 editor->setDecimals( decimals );
563 editor->setMaximum( std::numeric_limits<double>::max() );
564 editor->setMinimum( std::numeric_limits<double>::lowest() );
567 case QMetaType::Type::Int:
570 editor->setDecimals( 0 );
572 editor->setMaximum( std::numeric_limits<int>::max() );
573 editor->setMinimum( std::numeric_limits<int>::min() );
576 case QMetaType::Type::QChar:
579 editor->setDecimals( 0 );
581 editor->setMaximum( std::numeric_limits<char>::max() );
582 editor->setMinimum( std::numeric_limits<char>::min() );
585 case QMetaType::Type::UInt:
588 editor->setDecimals( 0 );
590 editor->setMaximum( std::numeric_limits<unsigned int>::max() );
591 editor->setMinimum( 0 );
594 case QMetaType::Type::LongLong:
597 editor->setDecimals( 0 );
599 editor->setMaximum(
static_cast<double>( std::numeric_limits<qlonglong>::max() ) );
600 editor->setMinimum( std::numeric_limits<qlonglong>::min() );
603 case QMetaType::Type::ULongLong:
606 editor->setDecimals( 0 );
608 editor->setMaximum(
static_cast<double>( std::numeric_limits<unsigned long long>::max() ) );
609 editor->setMinimum( 0 );
615 return editor ? editor : QStyledItemDelegate::createEditor( parent, option, index );
628 , mContextMenu( new QMenu( this ) )
644 const QString attrName =
mRenderer->classAttribute();
645 mOldClassificationAttribute = attrName;
649 layout()->setContentsMargins( 0, 0, 0, 0 );
651 mExpressionWidget->setLayer(
mLayer );
652 btnChangeCategorizedSymbol->setLayer(
mLayer );
653 btnChangeCategorizedSymbol->registerExpressionContextGenerator(
this );
656 btnColorRamp->setShowRandomColorRamp(
true );
659 std::unique_ptr< QgsColorRamp > colorRamp(
QgsProject::instance()->styleSettings()->defaultColorRamp() );
662 btnColorRamp->setColorRamp( colorRamp.get() );
666 btnColorRamp->setRandomColorRamp();
676 mModel =
new QgsCategorizedSymbolRendererModel(
this, screen() );
682 viewCategories->setModel(
mModel );
683 viewCategories->resizeColumnToContents( 0 );
684 viewCategories->resizeColumnToContents( 1 );
685 viewCategories->resizeColumnToContents( 2 );
686 viewCategories->setItemDelegateForColumn( 1,
new QgsCategorizedRendererViewItemDelegate( mExpressionWidget, viewCategories ) );
688 viewCategories->setStyle(
new QgsCategorizedSymbolRendererViewStyle( viewCategories ) );
689 connect( viewCategories->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QgsCategorizedSymbolRendererWidget::selectionChanged );
697 connect( viewCategories, &QTreeView::customContextMenuRequested,
this, &QgsCategorizedSymbolRendererWidget::showContextMenu );
699 connect( btnChangeCategorizedSymbol, &
QgsSymbolButton::changed,
this, &QgsCategorizedSymbolRendererWidget::updateSymbolsFromButton );
709 QMenu *advMenu =
new QMenu;
716 QAction *actionDdsLegend = advMenu->addAction( tr(
"Data-defined Size Legend…" ) );
718 connect( actionDdsLegend, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::dataDefinedSizeLegend );
721 btnAdvanced->setMenu( advMenu );
723 mExpressionWidget->registerExpressionContextGenerator(
this );
725 mMergeCategoriesAction =
new QAction( tr(
"Merge Categories" ),
this );
726 connect( mMergeCategoriesAction, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::mergeSelectedCategories );
727 mUnmergeCategoriesAction =
new QAction( tr(
"Unmerge Categories" ),
this );
728 connect( mUnmergeCategoriesAction, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::unmergeSelectedCategories );
730 connect( mContextMenu, &QMenu::aboutToShow,
this, [ = ]
751 const QString attrName =
mRenderer->classAttribute();
752 mExpressionWidget->setField( attrName );
764 btnColorRamp->setColorRamp(
mRenderer->sourceColorRamp() );
782 delete mActionLevels;
783 mActionLevels =
nullptr;
790 if ( !selectedCats.isEmpty() )
801 const auto constSelectedCats = selectedCats;
802 for (
const int idx : constSelectedCats )
808 mRenderer->updateCategorySymbol( idx, newCatSymbol );
828 if ( !dlg.exec() || !newSymbol )
851 if ( idx.isValid() && idx.column() == 0 )
859 std::unique_ptr< QgsSymbol > symbol;
861 if (
auto *lSymbol = category.
symbol() )
863 symbol.reset( lSymbol->clone() );
883 if ( !dlg.exec() || !symbol )
896 const QString attrName = mExpressionWidget->currentField();
898 QList<QVariant> uniqueValues;
916 if ( uniqueValues.contains( value ) )
918 uniqueValues << value;
927 if ( uniqueValues.size() >= 1000 )
929 const int res = QMessageBox::warning(
nullptr, tr(
"Classify Categories" ),
930 tr(
"High number of classes. Classification would yield %n entries which might not be expected. Continue?",
nullptr, uniqueValues.size() ),
931 QMessageBox::Ok | QMessageBox::Cancel,
932 QMessageBox::Cancel );
933 if ( res == QMessageBox::Cancel )
940 DlgAddCategories dlg(
mStyle, createDefaultSymbol(), unique_vals,
this );
946 bool deleteExisting =
false;
948 if ( !mOldClassificationAttribute.isEmpty() &&
949 attrName != mOldClassificationAttribute &&
952 const int res = QMessageBox::question(
this,
953 tr(
"Delete Classification" ),
954 tr(
"The classification field was changed from '%1' to '%2'.\n"
955 "Should the existing classes be deleted before classification?" )
956 .arg( mOldClassificationAttribute, attrName ),
957 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel );
958 if ( res == QMessageBox::Cancel )
963 deleteExisting = ( res == QMessageBox::Yes );
967 bool keepExistingColors =
false;
968 if ( !deleteExisting )
971 keepExistingColors = !prevCats.isEmpty();
973 if ( keepExistingColors && btnColorRamp->isRandomColorRamp() )
975 for (
int i = 0; i < cats.size(); ++i )
977 bool contains =
false;
978 const QVariant value = cats.at( i ).value();
979 for (
int j = 0; j < prevCats.size() && !contains; ++j )
981 const QVariant prevCatValue = prevCats.at( j ).value();
982 if ( prevCatValue.userType() == QMetaType::Type::QVariantList )
984 const QVariantList list = prevCatValue.toList();
985 for (
const QVariant &v : list )
996 if ( prevCats.at( j ).value() == value )
1007 if ( keepExistingColors && btnColorRamp->isRandomColorRamp() )
1010 cats.at( i ).symbol()->setColor( randomColors.
color( i ) );
1012 prevCats.append( cats.at( i ) );
1018 mOldClassificationAttribute = attrName;
1035 std::unique_ptr< QgsCategorizedSymbolRenderer > r = std::make_unique< QgsCategorizedSymbolRenderer >( attrName, cats );
1037 std::unique_ptr< QgsColorRamp > ramp( btnColorRamp->colorRamp() );
1039 r->setSourceColorRamp( ramp->clone() );
1043 mModel->setRenderer( r.get() );
1046 if ( ! keepExistingColors && ramp )
1053 if ( !btnColorRamp->isNull() )
1055 mRenderer->updateColorRamp( btnColorRamp->colorRamp() );
1057 mModel->updateSymbology();
1062 const QModelIndex idx = viewCategories->selectionModel()->currentIndex();
1063 if ( !idx.isValid() )
1071 const QModelIndexList selectedRows = viewCategories->selectionModel()->selectedRows();
1073 const auto constSelectedRows = selectedRows;
1074 for (
const QModelIndex &r : constSelectedRows )
1078 rows.append( r.row() );
1087 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" ),
1170 tr(
"Matched %n categories to symbols.",
nullptr, matched ) );
1174 QMessageBox::warning(
this, tr(
"Matched Symbols" ),
1175 tr(
"No categories could be matched to symbols in library." ) );
1188 QVariantList unmatchedCategories;
1189 QStringList unmatchedSymbols;
1190 const int matched =
mRenderer->matchToSymbols( style, type, unmatchedCategories, unmatchedSymbols );
1192 mModel->updateSymbology();
1199 const QString openFileDir = settings.
value( QStringLiteral(
"UI/lastMatchToSymbolsDir" ), QDir::homePath() ).toString();
1201 const QString fileName = QFileDialog::getOpenFileName(
this, tr(
"Match to Symbols from File" ), openFileDir,
1202 tr(
"XML files (*.xml *.XML)" ) );
1203 if ( fileName.isEmpty() )
1208 const QFileInfo openFileInfo( fileName );
1209 settings.
setValue( QStringLiteral(
"UI/lastMatchToSymbolsDir" ), openFileInfo.absolutePath() );
1212 if ( !importedStyle.
importXml( fileName ) )
1214 QMessageBox::warning(
this, tr(
"Match to Symbols from File" ),
1215 tr(
"An error occurred while reading file:\n%1" ).arg( importedStyle.
errorString() ) );
1222 QMessageBox::information(
this, tr(
"Match to Symbols from File" ),
1223 tr(
"Matched %n categories to symbols from file.",
nullptr, matched ) );
1227 QMessageBox::warning(
this, tr(
"Match to Symbols from File" ),
1228 tr(
"No categories could be matched to symbols in file." ) );
1239 mRenderer->setLegendSymbolItem( legendSymbol.ruleKey(), sym->
clone() );
1242 mRenderer->setUsingSymbolLevels( enabled );
1243 mModel->updateSymbology();
1254 if ( !selectedCats.isEmpty() )
1256 for (
const int idx : selectedCats )
1258 if (
mRenderer->categories().at( idx ).symbol()->type() != tempSymbol->type() )
1261 std::unique_ptr< QgsSymbol > newCatSymbol( tempSymbol->clone() );
1262 if ( selectedCats.count() > 1 )
1265 newCatSymbol->setColor(
mRenderer->categories().at( idx ).symbol()->color() );
1267 mRenderer->updateCategorySymbol( idx, newCatSymbol.release() );
1280void QgsCategorizedSymbolRendererWidget::updateSymbolsFromButton()
1290 QItemSelectionModel *m = viewCategories->selectionModel();
1291 const QModelIndexList i = m->selectedRows();
1297 if ( !selectedCats.isEmpty() )
1299 const auto constSelectedCats = selectedCats;
1300 for (
const int idx : constSelectedCats )
1303 if ( selectedCats.count() > 1 )
1308 mRenderer->updateCategorySymbol( idx, newCatSymbol );
1317 mModel->updateSymbology();
1328 if ( event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier )
1330 mCopyBuffer.clear();
1333 else if ( event->key() == Qt::Key_V && event->modifiers() == Qt::ControlModifier )
1335 QgsCategoryList::const_iterator rIt = mCopyBuffer.constBegin();
1336 for ( ; rIt != mCopyBuffer.constEnd(); ++rIt )
1338 mModel->addCategory( *rIt );
1356 expContext << generator->createExpressionContextScope();
1377void QgsCategorizedSymbolRendererWidget::dataDefinedSizeLegend()
1392void QgsCategorizedSymbolRendererWidget::mergeSelectedCategories()
1397 QList< int > categoryIndexes;
1400 for (
const int i : selectedCategoryIndexes )
1402 const QVariant v = categories.at( i ).value();
1404 if ( !v.isValid() || v ==
"" )
1409 categoryIndexes.append( i );
1412 if ( categoryIndexes.count() < 2 )
1416 QVariantList values;
1417 values.reserve( categoryIndexes.count() );
1418 labels.reserve( categoryIndexes.count() );
1419 for (
const int i : categoryIndexes )
1421 const QVariant v = categories.at( i ).value();
1423 if ( v.userType() == QMetaType::Type::QVariantList )
1425 values.append( v.toList() );
1430 labels << categories.at( i ).label();
1434 mRenderer->updateCategoryLabel( categoryIndexes.at( 0 ), labels.join(
',' ) );
1435 mRenderer->updateCategoryValue( categoryIndexes.at( 0 ), values );
1437 categoryIndexes.pop_front();
1438 mModel->deleteRows( categoryIndexes );
1443void QgsCategorizedSymbolRendererWidget::unmergeSelectedCategories()
1446 if ( categoryIndexes.isEmpty() )
1450 for (
const int i : categoryIndexes )
1452 const QVariant v = categories.at( i ).value();
1453 if ( v.userType() != QMetaType::Type::QVariantList )
1456 const QVariantList list = v.toList();
1457 for (
int j = 1; j < list.count(); ++j )
1459 mModel->addCategory(
QgsRendererCategory( list.at( j ), categories.at( i ).symbol()->clone(), list.at( j ).toString(), categories.at( i ).renderState() ) );
1461 mRenderer->updateCategoryValue( i, list.at( 0 ) );
1462 mRenderer->updateCategoryLabel( i, list.at( 0 ).toString() );
1468void QgsCategorizedSymbolRendererWidget::showContextMenu( QPoint )
1470 mContextMenu->clear();
1471 const QList< QAction * > actions =
contextMenu->actions();
1472 for ( QAction *act : actions )
1474 mContextMenu->addAction( act );
1477 mContextMenu->addSeparator();
1479 if ( viewCategories->selectionModel()->selectedRows().count() > 1 )
1481 mContextMenu->addAction( mMergeCategoriesAction );
1483 if ( viewCategories->selectionModel()->selectedRows().count() == 1 )
1487 const QVariant v = categories.at( categoryIndexes.at( 0 ) ).value();
1488 if ( v.userType() == QMetaType::Type::QVariantList )
1489 mContextMenu->addAction( mUnmergeCategoriesAction );
1491 else if ( viewCategories->selectionModel()->selectedRows().count() > 1 )
1493 mContextMenu->addAction( mUnmergeCategoriesAction );
1496 mContextMenu->exec( QCursor::pos() );
1499void QgsCategorizedSymbolRendererWidget::selectionChanged(
const QItemSelection &,
const QItemSelection & )
1502 if ( !selectedCats.isEmpty() )
1504 whileBlocking( btnChangeCategorizedSymbol )->setSymbol(
mRenderer->categories().at( selectedCats.at( 0 ) ).symbol()->clone() );
1510 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...
Abstract interface for generating an expression context scope.
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.
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.
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)