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 );
85 if ( !mRenderer )
return;
86 const int idx = mRenderer->categories().size();
87 beginInsertRows( QModelIndex(), idx, idx );
88 mRenderer->addCategory( cat );
99 const int row = index.row();
100 if ( row >= catList.size() )
104 return catList.at( row );
108Qt::ItemFlags QgsCategorizedSymbolRendererModel::flags(
const QModelIndex &index )
const
110 if ( !index.isValid() || !mRenderer )
112 return Qt::ItemIsDropEnabled;
115 Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable;
116 if ( index.column() == 1 )
119 if ( category.
value().userType() != QMetaType::Type::QVariantList )
121 flags |= Qt::ItemIsEditable;
124 else if ( index.column() == 2 )
126 flags |= Qt::ItemIsEditable;
131Qt::DropActions QgsCategorizedSymbolRendererModel::supportedDropActions()
const
133 return Qt::MoveAction;
136QVariant QgsCategorizedSymbolRendererModel::data(
const QModelIndex &index,
int role )
const
138 if ( !index.isValid() || !mRenderer )
145 case Qt::CheckStateRole:
147 if ( index.column() == 0 )
149 return category.
renderState() ? Qt::Checked : Qt::Unchecked;
154 case Qt::DisplayRole:
155 case Qt::ToolTipRole:
157 switch ( index.column() )
161 if ( category.
value().userType() == QMetaType::Type::QVariantList )
164 const QVariantList list = category.
value().toList();
165 res.reserve( list.size() );
166 for (
const QVariant &v : list )
169 if ( role == Qt::DisplayRole )
170 return res.join(
';' );
172 return res.join(
'\n' );
176 return tr(
"all other values" );
184 return category.
label();
194 italicFont.setItalic(
true );
200 case Qt::DecorationRole:
202 if ( index.column() == 0 && category.
symbol() )
210 case Qt::ForegroundRole:
212 QBrush brush( qApp->palette().color( QPalette::Text ), Qt::SolidPattern );
213 if ( index.column() == 1 && ( category.
value().userType() == QMetaType::Type::QVariantList
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 )
return true;
405 if ( !data->hasFormat( mMimeFormat ) )
return false;
407 QByteArray encodedData = data->data( mMimeFormat );
408 QDataStream stream( &encodedData, QIODevice::ReadOnly );
411 while ( !stream.atEnd() )
418 int to = parent.row();
421 if ( to == -1 ) to = mRenderer->categories().size();
422 for (
int i = rows.size() - 1; i >= 0; i-- )
424 QgsDebugMsgLevel( QStringLiteral(
"move %1 to %2" ).arg( rows[i] ).arg( to ), 2 );
427 if ( rows[i] < t ) t--;
428 mRenderer->moveCategory( rows[i], t );
430 for (
int j = 0; j < i; j++ )
432 if ( to < rows[j] && rows[i] > rows[j] ) rows[j] += 1;
435 if ( rows[i] < to ) to--;
437 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
442void QgsCategorizedSymbolRendererModel::deleteRows( QList<int> rows )
444 std::sort( rows.begin(), rows.end() );
445 for (
int i = rows.size() - 1; i >= 0; i-- )
447 beginRemoveRows( QModelIndex(), rows[i], rows[i] );
448 mRenderer->deleteCategory( rows[i] );
453void QgsCategorizedSymbolRendererModel::removeAllRows()
455 beginRemoveRows( QModelIndex(), 0, mRenderer->categories().size() - 1 );
456 mRenderer->deleteAllCategories();
460void QgsCategorizedSymbolRendererModel::sort(
int column, Qt::SortOrder order )
468 mRenderer->sortByValue( order );
470 else if ( column == 2 )
472 mRenderer->sortByLabel( order );
474 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
477void QgsCategorizedSymbolRendererModel::updateSymbology()
479 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
483QgsCategorizedSymbolRendererViewStyle::QgsCategorizedSymbolRendererViewStyle( QWidget *parent )
487void QgsCategorizedSymbolRendererViewStyle::drawPrimitive( PrimitiveElement element,
const QStyleOption *option, QPainter *painter,
const QWidget *widget )
const
489 if ( element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull() )
491 QStyleOption opt( *option );
492 opt.rect.setLeft( 0 );
494 opt.rect.setHeight( 0 );
495 if ( widget ) opt.rect.setRight( widget->width() );
496 QProxyStyle::drawPrimitive( element, &opt, painter, widget );
499 QProxyStyle::drawPrimitive( element, option, painter, widget );
503QgsCategorizedRendererViewItemDelegate::QgsCategorizedRendererViewItemDelegate(
QgsFieldExpressionWidget *expressionWidget, QObject *parent )
504 : QStyledItemDelegate( parent )
505 , mFieldExpressionWidget( expressionWidget )
509QWidget *QgsCategorizedRendererViewItemDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index )
const
518 const QString fieldName { mFieldExpressionWidget->currentField( &isExpression, &isValid ) };
519 if ( ! fieldName.isEmpty() && mFieldExpressionWidget->layer() && mFieldExpressionWidget->layer()->fields().lookupField( fieldName ) != -1 )
521 userType = mFieldExpressionWidget->layer()->fields().field( fieldName ).type();
523 else if ( isExpression && isValid )
527 if ( mFieldExpressionWidget->layer()->getFeatures().nextFeature( feat ) )
532 expressionContext.
appendScope( mFieldExpressionWidget->layer()->createExpressionContextScope() );
535 const QVariant value = exp.evaluate( &expressionContext );
536 if ( !exp.hasEvalError() )
538 userType =
static_cast<QMetaType::Type
>( value.userType() );
547 case QMetaType::Type::Double:
553 if ( value.toDouble( &ok ); ok )
555 const QString strVal { value.toString() };
556 const int dotPosition( strVal.indexOf(
'.' ) );
557 if ( dotPosition >= 0 )
559 decimals = std::max<int>( 2, strVal.length() - dotPosition - 1 );
562 editor->setDecimals( decimals );
564 editor->setMaximum( std::numeric_limits<double>::max() );
565 editor->setMinimum( std::numeric_limits<double>::lowest() );
568 case QMetaType::Type::Int:
571 editor->setDecimals( 0 );
573 editor->setMaximum( std::numeric_limits<int>::max() );
574 editor->setMinimum( std::numeric_limits<int>::min() );
577 case QMetaType::Type::QChar:
580 editor->setDecimals( 0 );
582 editor->setMaximum( std::numeric_limits<char>::max() );
583 editor->setMinimum( std::numeric_limits<char>::min() );
586 case QMetaType::Type::UInt:
589 editor->setDecimals( 0 );
591 editor->setMaximum( std::numeric_limits<unsigned int>::max() );
592 editor->setMinimum( 0 );
595 case QMetaType::Type::LongLong:
598 editor->setDecimals( 0 );
600 editor->setMaximum(
static_cast<double>( std::numeric_limits<qlonglong>::max() ) );
601 editor->setMinimum( std::numeric_limits<qlonglong>::min() );
604 case QMetaType::Type::ULongLong:
607 editor->setDecimals( 0 );
609 editor->setMaximum(
static_cast<double>( std::numeric_limits<unsigned long long>::max() ) );
610 editor->setMinimum( 0 );
616 return editor ? editor : QStyledItemDelegate::createEditor( parent, option, index );
629 , mContextMenu( new QMenu( this ) )
645 const QString attrName =
mRenderer->classAttribute();
646 mOldClassificationAttribute = attrName;
650 layout()->setContentsMargins( 0, 0, 0, 0 );
652 mExpressionWidget->setLayer(
mLayer );
653 btnChangeCategorizedSymbol->setLayer(
mLayer );
654 btnChangeCategorizedSymbol->registerExpressionContextGenerator(
this );
657 btnColorRamp->setShowRandomColorRamp(
true );
660 std::unique_ptr< QgsColorRamp > colorRamp(
QgsProject::instance()->styleSettings()->defaultColorRamp() );
663 btnColorRamp->setColorRamp( colorRamp.get() );
667 btnColorRamp->setRandomColorRamp();
677 mModel =
new QgsCategorizedSymbolRendererModel(
this, screen() );
683 viewCategories->setModel(
mModel );
684 viewCategories->resizeColumnToContents( 0 );
685 viewCategories->resizeColumnToContents( 1 );
686 viewCategories->resizeColumnToContents( 2 );
687 viewCategories->setItemDelegateForColumn( 1,
new QgsCategorizedRendererViewItemDelegate( mExpressionWidget, viewCategories ) );
689 viewCategories->setStyle(
new QgsCategorizedSymbolRendererViewStyle( viewCategories ) );
690 connect( viewCategories->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QgsCategorizedSymbolRendererWidget::selectionChanged );
698 connect( viewCategories, &QTreeView::customContextMenuRequested,
this, &QgsCategorizedSymbolRendererWidget::showContextMenu );
700 connect( btnChangeCategorizedSymbol, &
QgsSymbolButton::changed,
this, &QgsCategorizedSymbolRendererWidget::updateSymbolsFromButton );
710 QMenu *advMenu =
new QMenu;
717 QAction *actionDdsLegend = advMenu->addAction( tr(
"Data-defined Size Legend…" ) );
719 connect( actionDdsLegend, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::dataDefinedSizeLegend );
722 btnAdvanced->setMenu( advMenu );
724 mExpressionWidget->registerExpressionContextGenerator(
this );
726 mMergeCategoriesAction =
new QAction( tr(
"Merge Categories" ),
this );
727 connect( mMergeCategoriesAction, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::mergeSelectedCategories );
728 mUnmergeCategoriesAction =
new QAction( tr(
"Unmerge Categories" ),
this );
729 connect( mUnmergeCategoriesAction, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::unmergeSelectedCategories );
731 connect( mContextMenu, &QMenu::aboutToShow,
this, [ = ]
752 const QString attrName =
mRenderer->classAttribute();
753 mExpressionWidget->setField( attrName );
765 btnColorRamp->setColorRamp(
mRenderer->sourceColorRamp() );
783 delete mActionLevels;
784 mActionLevels =
nullptr;
791 if ( !selectedCats.isEmpty() )
802 const auto constSelectedCats = selectedCats;
803 for (
const int idx : constSelectedCats )
809 mRenderer->updateCategorySymbol( idx, newCatSymbol );
829 if ( !dlg.exec() || !newSymbol )
852 if ( idx.isValid() && idx.column() == 0 )
860 std::unique_ptr< QgsSymbol > symbol;
862 if (
auto *lSymbol = category.
symbol() )
864 symbol.reset( lSymbol->clone() );
884 if ( !dlg.exec() || !symbol )
897 const QString attrName = mExpressionWidget->currentField();
899 QList<QVariant> uniqueValues;
917 if ( uniqueValues.contains( value ) )
919 uniqueValues << value;
928 if ( uniqueValues.size() >= 1000 )
930 const int res = QMessageBox::warning(
nullptr, tr(
"Classify Categories" ),
931 tr(
"High number of classes. Classification would yield %n entries which might not be expected. Continue?",
nullptr, uniqueValues.size() ),
932 QMessageBox::Ok | QMessageBox::Cancel,
933 QMessageBox::Cancel );
934 if ( res == QMessageBox::Cancel )
941 DlgAddCategories dlg(
mStyle, createDefaultSymbol(), unique_vals,
this );
947 bool deleteExisting =
false;
949 if ( !mOldClassificationAttribute.isEmpty() &&
950 attrName != mOldClassificationAttribute &&
953 const int res = QMessageBox::question(
this,
954 tr(
"Delete Classification" ),
955 tr(
"The classification field was changed from '%1' to '%2'.\n"
956 "Should the existing classes be deleted before classification?" )
957 .arg( mOldClassificationAttribute, attrName ),
958 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel );
959 if ( res == QMessageBox::Cancel )
964 deleteExisting = ( res == QMessageBox::Yes );
968 bool keepExistingColors =
false;
969 if ( !deleteExisting )
972 keepExistingColors = !prevCats.isEmpty();
974 if ( keepExistingColors && btnColorRamp->isRandomColorRamp() )
976 for (
int i = 0; i < cats.size(); ++i )
978 bool contains =
false;
979 const QVariant value = cats.at( i ).value();
980 for (
int j = 0; j < prevCats.size() && !contains; ++j )
982 const QVariant prevCatValue = prevCats.at( j ).value();
983 if ( prevCatValue.userType() == QMetaType::Type::QVariantList )
985 const QVariantList list = prevCatValue.toList();
986 for (
const QVariant &v : list )
997 if ( prevCats.at( j ).value() == value )
1008 if ( keepExistingColors && btnColorRamp->isRandomColorRamp() )
1011 cats.at( i ).symbol()->setColor( randomColors.
color( i ) );
1013 prevCats.append( cats.at( i ) );
1019 mOldClassificationAttribute = attrName;
1036 std::unique_ptr< QgsCategorizedSymbolRenderer > r = std::make_unique< QgsCategorizedSymbolRenderer >( attrName, cats );
1038 std::unique_ptr< QgsColorRamp > ramp( btnColorRamp->colorRamp() );
1040 r->setSourceColorRamp( ramp->clone() );
1044 mModel->setRenderer( r.get() );
1047 if ( ! keepExistingColors && ramp )
1054 if ( !btnColorRamp->isNull() )
1056 mRenderer->updateColorRamp( btnColorRamp->colorRamp() );
1058 mModel->updateSymbology();
1063 const QModelIndex idx = viewCategories->selectionModel()->currentIndex();
1064 if ( !idx.isValid() )
1072 const QModelIndexList selectedRows = viewCategories->selectionModel()->selectedRows();
1074 const auto constSelectedRows = selectedRows;
1075 for (
const QModelIndex &r : constSelectedRows )
1079 rows.append( r.row() );
1088 mModel->deleteRows( categoryIndexes );
1103 mModel->addCategory( cat );
1111 QItemSelectionModel *m = viewCategories->selectionModel();
1112 const QModelIndexList selectedIndexes = m->selectedRows( 1 );
1114 if ( !selectedIndexes.isEmpty() )
1117 QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
1118 for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
1120 const int row = ( *indexIt ).row();
1121 QgsSymbol *s = categories[row].symbol();
1135 QItemSelectionModel *m = viewCategories->selectionModel();
1136 const QModelIndexList selectedIndexes = m->selectedRows( 1 );
1138 if ( !selectedIndexes.isEmpty() )
1140 QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
1141 for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
1143 cl.append(
mModel->category( *indexIt ) );
1162 viewCategories->selectionModel()->clear();
1170 QMessageBox::information(
this, tr(
"Matched Symbols" ),
1171 tr(
"Matched %n categories to symbols.",
nullptr, matched ) );
1175 QMessageBox::warning(
this, tr(
"Matched Symbols" ),
1176 tr(
"No categories could be matched to symbols in library." ) );
1189 QVariantList unmatchedCategories;
1190 QStringList unmatchedSymbols;
1191 const int matched =
mRenderer->matchToSymbols( style, type, unmatchedCategories, unmatchedSymbols );
1193 mModel->updateSymbology();
1200 const QString openFileDir = settings.
value( QStringLiteral(
"UI/lastMatchToSymbolsDir" ), QDir::homePath() ).toString();
1202 const QString fileName = QFileDialog::getOpenFileName(
this, tr(
"Match to Symbols from File" ), openFileDir,
1203 tr(
"XML files (*.xml *.XML)" ) );
1204 if ( fileName.isEmpty() )
1209 const QFileInfo openFileInfo( fileName );
1210 settings.
setValue( QStringLiteral(
"UI/lastMatchToSymbolsDir" ), openFileInfo.absolutePath() );
1213 if ( !importedStyle.
importXml( fileName ) )
1215 QMessageBox::warning(
this, tr(
"Match to Symbols from File" ),
1216 tr(
"An error occurred while reading file:\n%1" ).arg( importedStyle.
errorString() ) );
1223 QMessageBox::information(
this, tr(
"Match to Symbols from File" ),
1224 tr(
"Matched %n categories to symbols from file.",
nullptr, matched ) );
1228 QMessageBox::warning(
this, tr(
"Match to Symbols from File" ),
1229 tr(
"No categories could be matched to symbols in file." ) );
1240 mRenderer->setLegendSymbolItem( legendSymbol.ruleKey(), sym->
clone() );
1243 mRenderer->setUsingSymbolLevels( enabled );
1244 mModel->updateSymbology();
1255 if ( !selectedCats.isEmpty() )
1257 for (
const int idx : selectedCats )
1259 if (
mRenderer->categories().at( idx ).symbol()->type() != tempSymbol->type() )
1262 std::unique_ptr< QgsSymbol > newCatSymbol( tempSymbol->clone() );
1263 if ( selectedCats.count() > 1 )
1266 newCatSymbol->setColor(
mRenderer->categories().at( idx ).symbol()->color() );
1268 mRenderer->updateCategorySymbol( idx, newCatSymbol.release() );
1281void QgsCategorizedSymbolRendererWidget::updateSymbolsFromButton()
1291 QItemSelectionModel *m = viewCategories->selectionModel();
1292 const QModelIndexList i = m->selectedRows();
1298 if ( !selectedCats.isEmpty() )
1300 const auto constSelectedCats = selectedCats;
1301 for (
const int idx : constSelectedCats )
1304 if ( selectedCats.count() > 1 )
1309 mRenderer->updateCategorySymbol( idx, newCatSymbol );
1318 mModel->updateSymbology();
1329 if ( event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier )
1331 mCopyBuffer.clear();
1334 else if ( event->key() == Qt::Key_V && event->modifiers() == Qt::ControlModifier )
1336 QgsCategoryList::const_iterator rIt = mCopyBuffer.constBegin();
1337 for ( ; rIt != mCopyBuffer.constEnd(); ++rIt )
1339 mModel->addCategory( *rIt );
1349 expContext = lMapCanvas->createExpressionContext();
1372void QgsCategorizedSymbolRendererWidget::dataDefinedSizeLegend()
1387void QgsCategorizedSymbolRendererWidget::mergeSelectedCategories()
1392 QList< int > categoryIndexes;
1395 for (
const int i : selectedCategoryIndexes )
1397 const QVariant v = categories.at( i ).value();
1399 if ( !v.isValid() || v ==
"" )
1404 categoryIndexes.append( i );
1407 if ( categoryIndexes.count() < 2 )
1411 QVariantList values;
1412 values.reserve( categoryIndexes.count() );
1413 labels.reserve( categoryIndexes.count() );
1414 for (
const int i : categoryIndexes )
1416 const QVariant v = categories.at( i ).value();
1418 if ( v.userType() == QMetaType::Type::QVariantList )
1420 values.append( v.toList() );
1425 labels << categories.at( i ).label();
1429 mRenderer->updateCategoryLabel( categoryIndexes.at( 0 ), labels.join(
',' ) );
1430 mRenderer->updateCategoryValue( categoryIndexes.at( 0 ), values );
1432 categoryIndexes.pop_front();
1433 mModel->deleteRows( categoryIndexes );
1438void QgsCategorizedSymbolRendererWidget::unmergeSelectedCategories()
1441 if ( categoryIndexes.isEmpty() )
1445 for (
const int i : categoryIndexes )
1447 const QVariant v = categories.at( i ).value();
1448 if ( v.userType() != QMetaType::Type::QVariantList )
1451 const QVariantList list = v.toList();
1452 for (
int j = 1; j < list.count(); ++j )
1454 mModel->addCategory(
QgsRendererCategory( list.at( j ), categories.at( i ).symbol()->clone(), list.at( j ).toString(), categories.at( i ).renderState() ) );
1456 mRenderer->updateCategoryValue( i, list.at( 0 ) );
1457 mRenderer->updateCategoryLabel( i, list.at( 0 ).toString() );
1463void QgsCategorizedSymbolRendererWidget::showContextMenu( QPoint )
1465 mContextMenu->clear();
1466 const QList< QAction * > actions =
contextMenu->actions();
1467 for ( QAction *act : actions )
1469 mContextMenu->addAction( act );
1472 mContextMenu->addSeparator();
1474 if ( viewCategories->selectionModel()->selectedRows().count() > 1 )
1476 mContextMenu->addAction( mMergeCategoriesAction );
1478 if ( viewCategories->selectionModel()->selectedRows().count() == 1 )
1482 const QVariant v = categories.at( categoryIndexes.at( 0 ) ).value();
1483 if ( v.userType() == QMetaType::Type::QVariantList )
1484 mContextMenu->addAction( mUnmergeCategoriesAction );
1486 else if ( viewCategories->selectionModel()->selectedRows().count() > 1 )
1488 mContextMenu->addAction( mUnmergeCategoriesAction );
1491 mContextMenu->exec( QCursor::pos() );
1494void QgsCategorizedSymbolRendererWidget::selectionChanged(
const QItemSelection &,
const QItemSelection & )
1497 if ( !selectedCats.isEmpty() )
1499 whileBlocking( btnChangeCategorizedSymbol )->setSymbol(
mRenderer->categories().at( selectedCats.at( 0 ) ).symbol()->clone() );
1505 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)