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
112 if ( !index.isValid() || !mRenderer )
114 return Qt::ItemIsDropEnabled;
117 Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable;
118 if ( index.column() == 1 )
121 if ( category.
value().userType() != QMetaType::Type::QVariantList )
123 flags |= Qt::ItemIsEditable;
126 else if ( index.column() == 2 )
128 flags |= Qt::ItemIsEditable;
133Qt::DropActions QgsCategorizedSymbolRendererModel::supportedDropActions()
const
135 return Qt::MoveAction;
138QVariant QgsCategorizedSymbolRendererModel::data(
const QModelIndex &index,
int role )
const
140 if ( !index.isValid() || !mRenderer )
147 case Qt::CheckStateRole:
149 if ( index.column() == 0 )
151 return category.
renderState() ? Qt::Checked : Qt::Unchecked;
156 case Qt::DisplayRole:
157 case Qt::ToolTipRole:
159 switch ( index.column() )
163 if ( category.
value().userType() == QMetaType::Type::QVariantList )
166 const QVariantList list = category.
value().toList();
167 res.reserve( list.size() );
168 for (
const QVariant &v : list )
171 if ( role == Qt::DisplayRole )
172 return res.join(
';' );
174 return res.join(
'\n' );
178 return tr(
"all other values" );
186 return category.
label();
196 italicFont.setItalic(
true );
202 case Qt::DecorationRole:
204 if ( index.column() == 0 && category.
symbol() )
212 case Qt::ForegroundRole:
214 QBrush brush( qApp->palette().color( QPalette::Text ), Qt::SolidPattern );
217 QColor fadedTextColor = brush.color();
218 fadedTextColor.setAlpha( 128 );
219 brush.setColor( fadedTextColor );
224 case Qt::TextAlignmentRole:
226 return ( index.column() == 0 ) ?
static_cast<Qt::Alignment::Int
>( Qt::AlignHCenter ) : static_cast<Qt::Alignment::Int>( Qt::AlignLeft );
231 switch ( index.column() )
235 if ( category.
value().userType() == QMetaType::Type::QVariantList )
238 const QVariantList list = category.
value().toList();
239 res.reserve( list.size() );
240 for (
const QVariant &v : list )
243 return res.join(
';' );
247 return category.
value();
252 return category.
label();
258 if ( index.column() == 1 )
259 return category.
value();
267bool QgsCategorizedSymbolRendererModel::setData(
const QModelIndex &index,
const QVariant &value,
int role )
269 if ( !index.isValid() )
272 if ( index.column() == 0 && role == Qt::CheckStateRole )
274 mRenderer->updateCategoryRenderState( index.row(), value == Qt::Checked );
275 emit dataChanged( index, index );
279 if ( role != Qt::EditRole )
282 switch ( index.column() )
287 QVariant val = value;
288 const QVariant previousValue = mRenderer->categories().value( index.row() ).value();
289 if ( previousValue.userType() != QMetaType::Type::QString && !previousValue.toString().isEmpty() )
291 switch ( previousValue.userType() )
293 case QMetaType::Type::Int:
296 case QMetaType::Type::Double:
297 val = value.toDouble();
299 case QMetaType::Type::QVariantList:
301 const QStringList parts = value.toString().split(
';' );
303 list.reserve( parts.count() );
304 for (
const QString &p : parts )
307 if ( list.count() == 1 )
314 val = value.toString();
318 mRenderer->updateCategoryValue( index.row(), val );
322 mRenderer->updateCategoryLabel( index.row(), value.toString() );
328 emit dataChanged( index, index );
332QVariant QgsCategorizedSymbolRendererModel::headerData(
int section, Qt::Orientation orientation,
int role )
const
334 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 3 )
337 lst << tr(
"Symbol" ) << tr(
"Value" ) << tr(
"Legend" );
338 return lst.value( section );
343int QgsCategorizedSymbolRendererModel::rowCount(
const QModelIndex &parent )
const
345 if ( parent.isValid() || !mRenderer )
349 return mRenderer->categories().size();
352int QgsCategorizedSymbolRendererModel::columnCount(
const QModelIndex &index )
const
358QModelIndex QgsCategorizedSymbolRendererModel::index(
int row,
int column,
const QModelIndex &parent )
const
360 if ( hasIndex( row, column, parent ) )
362 return createIndex( row, column );
364 return QModelIndex();
367QModelIndex QgsCategorizedSymbolRendererModel::parent(
const QModelIndex &index )
const
370 return QModelIndex();
373QStringList QgsCategorizedSymbolRendererModel::mimeTypes()
const
376 types << mMimeFormat;
380QMimeData *QgsCategorizedSymbolRendererModel::mimeData(
const QModelIndexList &indexes )
const
382 QMimeData *mimeData =
new QMimeData();
383 QByteArray encodedData;
385 QDataStream stream( &encodedData, QIODevice::WriteOnly );
388 const auto constIndexes = indexes;
389 for (
const QModelIndex &index : constIndexes )
391 if ( !index.isValid() || index.column() != 0 )
394 stream << index.row();
396 mimeData->setData( mMimeFormat, encodedData );
400bool QgsCategorizedSymbolRendererModel::dropMimeData(
const QMimeData *data, Qt::DropAction action,
int row,
int column,
const QModelIndex &parent )
404 if ( action != Qt::MoveAction )
407 if ( !data->hasFormat( mMimeFormat ) )
410 QByteArray encodedData = data->data( mMimeFormat );
411 QDataStream stream( &encodedData, QIODevice::ReadOnly );
414 while ( !stream.atEnd() )
422 std::sort( rows.begin(), rows.end() );
429 to = mRenderer->categories().size();
430 for (
int i = rows.size() - 1; i >= 0; i-- )
432 QgsDebugMsgLevel( QStringLiteral(
"move %1 to %2" ).arg( rows[i] ).arg( to ), 2 );
437 mRenderer->moveCategory( rows[i], t );
439 for (
int j = 0; j < i; j++ )
441 if ( to < rows[j] && rows[i] > rows[j] )
448 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
453void QgsCategorizedSymbolRendererModel::deleteRows( QList<int> rows )
455 std::sort( rows.begin(), rows.end() );
456 for (
int i = rows.size() - 1; i >= 0; i-- )
458 beginRemoveRows( QModelIndex(), rows[i], rows[i] );
459 mRenderer->deleteCategory( rows[i] );
464void QgsCategorizedSymbolRendererModel::removeAllRows()
466 beginRemoveRows( QModelIndex(), 0, mRenderer->categories().size() - 1 );
467 mRenderer->deleteAllCategories();
471void QgsCategorizedSymbolRendererModel::sort(
int column, Qt::SortOrder order )
479 mRenderer->sortByValue( order );
481 else if ( column == 2 )
483 mRenderer->sortByLabel( order );
485 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
488void QgsCategorizedSymbolRendererModel::updateSymbology()
490 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
494QgsCategorizedSymbolRendererViewStyle::QgsCategorizedSymbolRendererViewStyle( QWidget *parent )
498void QgsCategorizedSymbolRendererViewStyle::drawPrimitive( PrimitiveElement element,
const QStyleOption *option, QPainter *painter,
const QWidget *widget )
const
500 if ( element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull() )
502 QStyleOption opt( *option );
503 opt.rect.setLeft( 0 );
505 opt.rect.setHeight( 0 );
507 opt.rect.setRight( widget->width() );
508 QProxyStyle::drawPrimitive( element, &opt, painter, widget );
511 QProxyStyle::drawPrimitive( element, option, painter, widget );
515QgsCategorizedRendererViewItemDelegate::QgsCategorizedRendererViewItemDelegate(
QgsFieldExpressionWidget *expressionWidget, QObject *parent )
516 : QStyledItemDelegate( parent )
517 , mFieldExpressionWidget( expressionWidget )
521QWidget *QgsCategorizedRendererViewItemDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index )
const
530 const QString fieldName { mFieldExpressionWidget->currentField( &isExpression, &isValid ) };
531 if ( !fieldName.isEmpty() && mFieldExpressionWidget->layer() && mFieldExpressionWidget->layer()->fields().lookupField( fieldName ) != -1 )
533 userType = mFieldExpressionWidget->layer()->fields().field( fieldName ).type();
535 else if ( isExpression && isValid )
539 if ( mFieldExpressionWidget->layer()->getFeatures().nextFeature( feat ) )
544 expressionContext.
appendScope( mFieldExpressionWidget->layer()->createExpressionContextScope() );
547 const QVariant value = exp.evaluate( &expressionContext );
548 if ( !exp.hasEvalError() )
550 userType =
static_cast<QMetaType::Type
>( value.userType() );
559 case QMetaType::Type::Double:
565 if ( value.toDouble( &ok ); ok )
567 const QString strVal { value.toString() };
568 const int dotPosition( strVal.indexOf(
'.' ) );
569 if ( dotPosition >= 0 )
571 decimals = std::max<int>( 2, strVal.length() - dotPosition - 1 );
574 editor->setDecimals( decimals );
576 editor->setMaximum( std::numeric_limits<double>::max() );
577 editor->setMinimum( std::numeric_limits<double>::lowest() );
580 case QMetaType::Type::Int:
583 editor->setDecimals( 0 );
585 editor->setMaximum( std::numeric_limits<int>::max() );
586 editor->setMinimum( std::numeric_limits<int>::min() );
589 case QMetaType::Type::QChar:
592 editor->setDecimals( 0 );
594 editor->setMaximum( std::numeric_limits<char>::max() );
595 editor->setMinimum( std::numeric_limits<char>::min() );
598 case QMetaType::Type::UInt:
601 editor->setDecimals( 0 );
603 editor->setMaximum( std::numeric_limits<unsigned int>::max() );
604 editor->setMinimum( 0 );
607 case QMetaType::Type::LongLong:
610 editor->setDecimals( 0 );
612 editor->setMaximum(
static_cast<double>( std::numeric_limits<qlonglong>::max() ) );
613 editor->setMinimum( std::numeric_limits<qlonglong>::min() );
616 case QMetaType::Type::ULongLong:
619 editor->setDecimals( 0 );
621 editor->setMaximum(
static_cast<double>( std::numeric_limits<unsigned long long>::max() ) );
622 editor->setMinimum( 0 );
628 return editor ? editor : QStyledItemDelegate::createEditor( parent, option, index );
641 , mContextMenu( new QMenu( this ) )
656 const QString attrName =
mRenderer->classAttribute();
657 mOldClassificationAttribute = attrName;
661 layout()->setContentsMargins( 0, 0, 0, 0 );
663 mExpressionWidget->setLayer(
mLayer );
664 btnChangeCategorizedSymbol->setLayer(
mLayer );
665 btnChangeCategorizedSymbol->registerExpressionContextGenerator(
this );
668 btnColorRamp->setShowRandomColorRamp(
true );
671 std::unique_ptr<QgsColorRamp> colorRamp(
QgsProject::instance()->styleSettings()->defaultColorRamp() );
674 btnColorRamp->setColorRamp( colorRamp.get() );
678 btnColorRamp->setRandomColorRamp();
688 mModel =
new QgsCategorizedSymbolRendererModel(
this, screen() );
694 viewCategories->setModel(
mModel );
695 viewCategories->resizeColumnToContents( 0 );
696 viewCategories->resizeColumnToContents( 1 );
697 viewCategories->resizeColumnToContents( 2 );
698 viewCategories->setItemDelegateForColumn( 1,
new QgsCategorizedRendererViewItemDelegate( mExpressionWidget, viewCategories ) );
700 viewCategories->setStyle(
new QgsCategorizedSymbolRendererViewStyle( viewCategories ) );
701 connect( viewCategories->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QgsCategorizedSymbolRendererWidget::selectionChanged );
709 connect( viewCategories, &QTreeView::customContextMenuRequested,
this, &QgsCategorizedSymbolRendererWidget::showContextMenu );
711 connect( btnChangeCategorizedSymbol, &
QgsSymbolButton::changed,
this, &QgsCategorizedSymbolRendererWidget::updateSymbolsFromButton );
722 QMenu *advMenu =
new QMenu;
729 QAction *actionDdsLegend = advMenu->addAction( tr(
"Data-defined Size Legend…" ) );
731 connect( actionDdsLegend, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::dataDefinedSizeLegend );
734 btnAdvanced->setMenu( advMenu );
736 mExpressionWidget->registerExpressionContextGenerator(
this );
738 mMergeCategoriesAction =
new QAction( tr(
"Merge Categories" ),
this );
739 connect( mMergeCategoriesAction, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::mergeSelectedCategories );
740 mUnmergeCategoriesAction =
new QAction( tr(
"Unmerge Categories" ),
this );
741 connect( mUnmergeCategoriesAction, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::unmergeSelectedCategories );
743 connect( mContextMenu, &QMenu::aboutToShow,
this, [=] {
763 const QString attrName =
mRenderer->classAttribute();
764 mExpressionWidget->setField( attrName );
776 btnColorRamp->setColorRamp(
mRenderer->sourceColorRamp() );
794 delete mActionLevels;
795 mActionLevels =
nullptr;
802 if ( !selectedCats.isEmpty() )
813 const auto constSelectedCats = selectedCats;
814 for (
const int idx : constSelectedCats )
820 mRenderer->updateCategorySymbol( idx, newCatSymbol );
840 if ( !dlg.exec() || !newSymbol )
863 if ( idx.isValid() && idx.column() == 0 )
871 std::unique_ptr<QgsSymbol> symbol;
873 if (
auto *lSymbol = category.
symbol() )
875 symbol.reset( lSymbol->clone() );
895 if ( !dlg.exec() || !symbol )
908 const QString attrName = mExpressionWidget->currentField();
912 if ( uniqueValues.size() >= 1000 )
914 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 );
915 if ( res == QMessageBox::Cancel )
922 DlgAddCategories dlg(
mStyle, createDefaultSymbol(), unique_vals,
this );
928 bool deleteExisting =
false;
930 if ( !mOldClassificationAttribute.isEmpty() && attrName != mOldClassificationAttribute && !
mRenderer->categories().isEmpty() )
932 const int res = QMessageBox::question(
this, tr(
"Delete Classification" ), tr(
"The classification field was changed from '%1' to '%2'.\n"
933 "Should the existing classes be deleted before classification?" )
934 .arg( mOldClassificationAttribute, attrName ),
935 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel );
936 if ( res == QMessageBox::Cancel )
941 deleteExisting = ( res == QMessageBox::Yes );
945 bool keepExistingColors =
false;
946 if ( !deleteExisting )
949 keepExistingColors = !prevCats.isEmpty();
951 if ( keepExistingColors && btnColorRamp->isRandomColorRamp() )
953 for (
int i = 0; i < cats.size(); ++i )
955 bool contains =
false;
956 const QVariant value = cats.at( i ).value();
957 for (
int j = 0; j < prevCats.size() && !contains; ++j )
959 const QVariant prevCatValue = prevCats.at( j ).value();
960 if ( prevCatValue.userType() == QMetaType::Type::QVariantList )
962 const QVariantList list = prevCatValue.toList();
963 for (
const QVariant &v : list )
974 if ( prevCats.at( j ).value() == value )
985 if ( keepExistingColors && btnColorRamp->isRandomColorRamp() )
988 cats.at( i ).symbol()->setColor( randomColors.
color( i ) );
990 prevCats.append( cats.at( i ) );
996 mOldClassificationAttribute = attrName;
1013 auto r = std::make_unique<QgsCategorizedSymbolRenderer>( attrName, cats );
1015 std::unique_ptr<QgsColorRamp> ramp( btnColorRamp->colorRamp() );
1017 r->setSourceColorRamp( ramp->clone() );
1021 mModel->setRenderer( r.get() );
1024 if ( !keepExistingColors && ramp )
1031 if ( !btnColorRamp->isNull() )
1033 mRenderer->updateColorRamp( btnColorRamp->colorRamp() );
1035 mModel->updateSymbology();
1040 const QModelIndex idx = viewCategories->selectionModel()->currentIndex();
1041 if ( !idx.isValid() )
1049 const QModelIndexList selectedRows = viewCategories->selectionModel()->selectedRows();
1051 const auto constSelectedRows = selectedRows;
1052 for (
const QModelIndex &r : constSelectedRows )
1056 rows.append( r.row() );
1065 mModel->deleteRows( categoryIndexes );
1079 const QString attrName = mExpressionWidget->currentField();
1084 QList<int> unusedIndexes;
1086 for (
int i = 0; i < catList.size(); ++i )
1089 if ( !uniqueValues.contains( cat.
value() ) )
1091 unusedIndexes.append( i );
1094 mModel->deleteRows( unusedIndexes );
1101 QList<QVariant> uniqueValues;
1117 context.setFeature( feature );
1119 if ( uniqueValues.contains( value ) )
1121 uniqueValues << value;
1128 return uniqueValues;
1137 mModel->addCategory( cat );
1145 QItemSelectionModel *m = viewCategories->selectionModel();
1146 const QModelIndexList selectedIndexes = m->selectedRows( 1 );
1148 if ( !selectedIndexes.isEmpty() )
1151 QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
1152 for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
1154 const int row = ( *indexIt ).row();
1155 QgsSymbol *s = categories[row].symbol();
1169 QItemSelectionModel *m = viewCategories->selectionModel();
1170 const QModelIndexList selectedIndexes = m->selectedRows( 1 );
1172 if ( !selectedIndexes.isEmpty() )
1174 QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
1175 for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
1177 cl.append(
mModel->category( *indexIt ) );
1196 viewCategories->selectionModel()->clear();
1204 QMessageBox::information(
this, tr(
"Matched Symbols" ), tr(
"Matched %n categories to symbols.",
nullptr, matched ) );
1208 QMessageBox::warning(
this, tr(
"Matched Symbols" ), tr(
"No categories could be matched to symbols in library." ) );
1221 QVariantList unmatchedCategories;
1222 QStringList unmatchedSymbols;
1223 const int matched =
mRenderer->matchToSymbols( style, type, unmatchedCategories, unmatchedSymbols );
1225 mModel->updateSymbology();
1232 const QString openFileDir = settings.
value( QStringLiteral(
"UI/lastMatchToSymbolsDir" ), QDir::homePath() ).toString();
1234 const QString fileName = QFileDialog::getOpenFileName(
this, tr(
"Match to Symbols from File" ), openFileDir, tr(
"XML files (*.xml *.XML)" ) );
1235 if ( fileName.isEmpty() )
1240 const QFileInfo openFileInfo( fileName );
1241 settings.
setValue( QStringLiteral(
"UI/lastMatchToSymbolsDir" ), openFileInfo.absolutePath() );
1244 if ( !importedStyle.
importXml( fileName ) )
1246 QMessageBox::warning(
this, tr(
"Match to Symbols from File" ), tr(
"An error occurred while reading file:\n%1" ).arg( importedStyle.
errorString() ) );
1253 QMessageBox::information(
this, tr(
"Match to Symbols from File" ), tr(
"Matched %n categories to symbols from file.",
nullptr, matched ) );
1257 QMessageBox::warning(
this, tr(
"Match to Symbols from File" ), tr(
"No categories could be matched to symbols in file." ) );
1268 mRenderer->setLegendSymbolItem( legendSymbol.ruleKey(), sym->
clone() );
1271 mRenderer->setUsingSymbolLevels( enabled );
1272 mModel->updateSymbology();
1283 if ( !selectedCats.isEmpty() )
1285 for (
const int idx : selectedCats )
1287 if (
mRenderer->categories().at( idx ).symbol()->type() != tempSymbol->type() )
1290 std::unique_ptr<QgsSymbol> newCatSymbol( tempSymbol->clone() );
1291 if ( selectedCats.count() > 1 )
1294 newCatSymbol->setColor(
mRenderer->categories().at( idx ).symbol()->color() );
1296 mRenderer->updateCategorySymbol( idx, newCatSymbol.release() );
1309void QgsCategorizedSymbolRendererWidget::updateSymbolsFromButton()
1319 QItemSelectionModel *m = viewCategories->selectionModel();
1320 const QModelIndexList i = m->selectedRows();
1326 if ( !selectedCats.isEmpty() )
1328 const auto constSelectedCats = selectedCats;
1329 for (
const int idx : constSelectedCats )
1332 if ( selectedCats.count() > 1 )
1337 mRenderer->updateCategorySymbol( idx, newCatSymbol );
1346 mModel->updateSymbology();
1357 if ( event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier )
1359 mCopyBuffer.clear();
1362 else if ( event->key() == Qt::Key_V && event->modifiers() == Qt::ControlModifier )
1364 QgsCategoryList::const_iterator rIt = mCopyBuffer.constBegin();
1365 for ( ; rIt != mCopyBuffer.constEnd(); ++rIt )
1367 mModel->addCategory( *rIt );
1377 expContext = lMapCanvas->createExpressionContext();
1400void QgsCategorizedSymbolRendererWidget::dataDefinedSizeLegend()
1414void QgsCategorizedSymbolRendererWidget::mergeSelectedCategories()
1419 QList<int> categoryIndexes;
1422 for (
const int i : selectedCategoryIndexes )
1424 const QVariant v = categories.at( i ).value();
1426 if ( !v.isValid() || v ==
"" )
1431 categoryIndexes.append( i );
1434 if ( categoryIndexes.count() < 2 )
1438 QVariantList values;
1439 values.reserve( categoryIndexes.count() );
1440 labels.reserve( categoryIndexes.count() );
1441 for (
const int i : categoryIndexes )
1443 const QVariant v = categories.at( i ).value();
1445 if ( v.userType() == QMetaType::Type::QVariantList )
1447 values.append( v.toList() );
1452 labels << categories.at( i ).label();
1456 mRenderer->updateCategoryLabel( categoryIndexes.at( 0 ), labels.join(
',' ) );
1457 mRenderer->updateCategoryValue( categoryIndexes.at( 0 ), values );
1459 categoryIndexes.pop_front();
1460 mModel->deleteRows( categoryIndexes );
1465void QgsCategorizedSymbolRendererWidget::unmergeSelectedCategories()
1468 if ( categoryIndexes.isEmpty() )
1472 for (
const int i : categoryIndexes )
1474 const QVariant v = categories.at( i ).value();
1475 if ( v.userType() != QMetaType::Type::QVariantList )
1478 const QVariantList list = v.toList();
1479 for (
int j = 1; j < list.count(); ++j )
1481 mModel->addCategory(
QgsRendererCategory( list.at( j ), categories.at( i ).symbol()->clone(), list.at( j ).toString(), categories.at( i ).renderState() ) );
1483 mRenderer->updateCategoryValue( i, list.at( 0 ) );
1484 mRenderer->updateCategoryLabel( i, list.at( 0 ).toString() );
1490void QgsCategorizedSymbolRendererWidget::showContextMenu( QPoint )
1492 mContextMenu->clear();
1493 const QList<QAction *> actions =
contextMenu->actions();
1494 for ( QAction *act : actions )
1496 mContextMenu->addAction( act );
1499 mContextMenu->addSeparator();
1501 if ( viewCategories->selectionModel()->selectedRows().count() > 1 )
1503 mContextMenu->addAction( mMergeCategoriesAction );
1505 if ( viewCategories->selectionModel()->selectedRows().count() == 1 )
1509 const QVariant v = categories.at( categoryIndexes.at( 0 ) ).value();
1510 if ( v.userType() == QMetaType::Type::QVariantList )
1511 mContextMenu->addAction( mUnmergeCategoriesAction );
1513 else if ( viewCategories->selectionModel()->selectedRows().count() > 1 )
1515 mContextMenu->addAction( mUnmergeCategoriesAction );
1518 mContextMenu->exec( QCursor::pos() );
1521void QgsCategorizedSymbolRendererWidget::selectionChanged(
const QItemSelection &,
const QItemSelection & )
1524 if ( !selectedCats.isEmpty() )
1526 whileBlocking( btnChangeCategorizedSymbol )->setSymbol(
mRenderer->categories().at( selectedCats.at( 0 ) ).symbol()->clone() );
1532 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)