45#include <QStandardItemModel>
46#include <QStandardItem>
54QgsCategorizedSymbolRendererModel::QgsCategorizedSymbolRendererModel( QObject *parent ) : QAbstractItemModel( parent )
55 , mMimeFormat( QStringLiteral(
"application/x-qgscategorizedsymbolrendererv2model" ) )
63 beginRemoveRows( QModelIndex(), 0, std::max< int >( mRenderer->categories().size() - 1, 0 ) );
72 beginInsertRows( QModelIndex(), 0, renderer->
categories().size() - 1 );
80 if ( !mRenderer )
return;
81 const int idx = mRenderer->categories().size();
82 beginInsertRows( QModelIndex(), idx, idx );
83 mRenderer->addCategory( cat );
94 const int row = index.row();
95 if ( row >= catList.size() )
99 return catList.at( row );
103Qt::ItemFlags QgsCategorizedSymbolRendererModel::flags(
const QModelIndex &index )
const
105 if ( !index.isValid() || !mRenderer )
107 return Qt::ItemIsDropEnabled;
110 Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable;
111 if ( index.column() == 1 )
114 if ( category.
value().type() != QVariant::List )
116 flags |= Qt::ItemIsEditable;
119 else if ( index.column() == 2 )
121 flags |= Qt::ItemIsEditable;
126Qt::DropActions QgsCategorizedSymbolRendererModel::supportedDropActions()
const
128 return Qt::MoveAction;
131QVariant QgsCategorizedSymbolRendererModel::data(
const QModelIndex &index,
int role )
const
133 if ( !index.isValid() || !mRenderer )
140 case Qt::CheckStateRole:
142 if ( index.column() == 0 )
144 return category.
renderState() ? Qt::Checked : Qt::Unchecked;
149 case Qt::DisplayRole:
150 case Qt::ToolTipRole:
152 switch ( index.column() )
156 if ( category.
value().type() == QVariant::List )
159 const QVariantList list = category.
value().toList();
160 res.reserve( list.size() );
161 for (
const QVariant &v : list )
164 if ( role == Qt::DisplayRole )
165 return res.join(
';' );
167 return res.join(
'\n' );
171 return tr(
"all other values" );
179 return category.
label();
189 italicFont.setItalic(
true );
195 case Qt::DecorationRole:
197 if ( index.column() == 0 && category.
symbol() )
205 case Qt::ForegroundRole:
207 QBrush brush( qApp->palette().color( QPalette::Text ), Qt::SolidPattern );
208 if ( index.column() == 1 && ( category.
value().type() == QVariant::List
211 QColor fadedTextColor = brush.color();
212 fadedTextColor.setAlpha( 128 );
213 brush.setColor( fadedTextColor );
218 case Qt::TextAlignmentRole:
220 return ( index.column() == 0 ) ?
static_cast<Qt::Alignment::Int
>( Qt::AlignHCenter ) :
static_cast<Qt::Alignment::Int
>( Qt::AlignLeft );
225 switch ( index.column() )
229 if ( category.
value().type() == QVariant::List )
232 const QVariantList list = category.
value().toList();
233 res.reserve( list.size() );
234 for (
const QVariant &v : list )
237 return res.join(
';' );
241 return category.
value();
246 return category.
label();
250 case QgsCategorizedSymbolRendererWidget::CustomRoles::ValueRole:
252 if ( index.column() == 1 )
253 return category.
value();
261bool QgsCategorizedSymbolRendererModel::setData(
const QModelIndex &index,
const QVariant &value,
int role )
263 if ( !index.isValid() )
266 if ( index.column() == 0 && role == Qt::CheckStateRole )
268 mRenderer->updateCategoryRenderState( index.row(), value == Qt::Checked );
269 emit dataChanged( index, index );
273 if ( role != Qt::EditRole )
276 switch ( index.column() )
281 QVariant val = value;
282 const QVariant previousValue = mRenderer->categories().value( index.row() ).value();
283 if ( previousValue.type() != QVariant::String && ! previousValue.toString().isEmpty() )
285 switch ( previousValue.type() )
290 case QVariant::Double:
291 val = value.toDouble();
295 const QStringList parts = value.toString().split(
';' );
297 list.reserve( parts.count() );
298 for (
const QString &p : parts )
301 if ( list.count() == 1 )
308 val = value.toString();
312 mRenderer->updateCategoryValue( index.row(), val );
316 mRenderer->updateCategoryLabel( index.row(), value.toString() );
322 emit dataChanged( index, index );
326QVariant QgsCategorizedSymbolRendererModel::headerData(
int section, Qt::Orientation orientation,
int role )
const
328 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 3 )
331 lst << tr(
"Symbol" ) << tr(
"Value" ) << tr(
"Legend" );
332 return lst.value( section );
337int QgsCategorizedSymbolRendererModel::rowCount(
const QModelIndex &parent )
const
339 if ( parent.isValid() || !mRenderer )
343 return mRenderer->categories().size();
346int QgsCategorizedSymbolRendererModel::columnCount(
const QModelIndex &index )
const
352QModelIndex QgsCategorizedSymbolRendererModel::index(
int row,
int column,
const QModelIndex &parent )
const
354 if ( hasIndex( row, column, parent ) )
356 return createIndex( row, column );
358 return QModelIndex();
361QModelIndex QgsCategorizedSymbolRendererModel::parent(
const QModelIndex &index )
const
364 return QModelIndex();
367QStringList QgsCategorizedSymbolRendererModel::mimeTypes()
const
370 types << mMimeFormat;
374QMimeData *QgsCategorizedSymbolRendererModel::mimeData(
const QModelIndexList &indexes )
const
376 QMimeData *mimeData =
new QMimeData();
377 QByteArray encodedData;
379 QDataStream stream( &encodedData, QIODevice::WriteOnly );
382 const auto constIndexes = indexes;
383 for (
const QModelIndex &index : constIndexes )
385 if ( !index.isValid() || index.column() != 0 )
388 stream << index.row();
390 mimeData->setData( mMimeFormat, encodedData );
394bool QgsCategorizedSymbolRendererModel::dropMimeData(
const QMimeData *data, Qt::DropAction action,
int row,
int column,
const QModelIndex &parent )
398 if ( action != Qt::MoveAction )
return true;
400 if ( !data->hasFormat( mMimeFormat ) )
return false;
402 QByteArray encodedData = data->data( mMimeFormat );
403 QDataStream stream( &encodedData, QIODevice::ReadOnly );
406 while ( !stream.atEnd() )
413 int to = parent.row();
416 if ( to == -1 ) to = mRenderer->categories().size();
417 for (
int i = rows.size() - 1; i >= 0; i-- )
419 QgsDebugMsg( QStringLiteral(
"move %1 to %2" ).arg( rows[i] ).arg( to ) );
422 if ( rows[i] < t ) t--;
423 mRenderer->moveCategory( rows[i], t );
425 for (
int j = 0; j < i; j++ )
427 if ( to < rows[j] && rows[i] > rows[j] ) rows[j] += 1;
430 if ( rows[i] < to ) to--;
432 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
437void QgsCategorizedSymbolRendererModel::deleteRows( QList<int> rows )
439 std::sort( rows.begin(), rows.end() );
440 for (
int i = rows.size() - 1; i >= 0; i-- )
442 beginRemoveRows( QModelIndex(), rows[i], rows[i] );
443 mRenderer->deleteCategory( rows[i] );
448void QgsCategorizedSymbolRendererModel::removeAllRows()
450 beginRemoveRows( QModelIndex(), 0, mRenderer->categories().size() - 1 );
451 mRenderer->deleteAllCategories();
455void QgsCategorizedSymbolRendererModel::sort(
int column, Qt::SortOrder order )
463 mRenderer->sortByValue( order );
465 else if ( column == 2 )
467 mRenderer->sortByLabel( order );
469 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
472void QgsCategorizedSymbolRendererModel::updateSymbology()
474 emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
478QgsCategorizedSymbolRendererViewStyle::QgsCategorizedSymbolRendererViewStyle( QWidget *parent )
482void QgsCategorizedSymbolRendererViewStyle::drawPrimitive( PrimitiveElement element,
const QStyleOption *option, QPainter *painter,
const QWidget *widget )
const
484 if ( element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull() )
486 QStyleOption opt( *option );
487 opt.rect.setLeft( 0 );
489 opt.rect.setHeight( 0 );
490 if ( widget ) opt.rect.setRight( widget->width() );
491 QProxyStyle::drawPrimitive( element, &opt, painter, widget );
494 QProxyStyle::drawPrimitive( element, option, painter, widget );
498QgsCategorizedRendererViewItemDelegate::QgsCategorizedRendererViewItemDelegate(
QgsFieldExpressionWidget *expressionWidget, QObject *parent )
499 : QStyledItemDelegate( parent )
500 , mFieldExpressionWidget( expressionWidget )
504QWidget *QgsCategorizedRendererViewItemDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index )
const
506 QVariant::Type userType { index.data( QgsCategorizedSymbolRendererWidget::CustomRoles::ValueRole ).type() };
509 if ( userType == QVariant::String &&
QgsVariantUtils::isNull( index.data( QgsCategorizedSymbolRendererWidget::CustomRoles::ValueRole ) ) )
513 const QString fieldName { mFieldExpressionWidget->currentField( &isExpression, &isValid ) };
514 if ( ! fieldName.isEmpty() && mFieldExpressionWidget->layer() && mFieldExpressionWidget->layer()->fields().lookupField( fieldName ) != -1 )
516 userType = mFieldExpressionWidget->layer()->fields().field( fieldName ).type();
518 else if ( isExpression && isValid )
522 if ( mFieldExpressionWidget->layer()->getFeatures().nextFeature( feat ) )
527 expressionContext.
appendScope( mFieldExpressionWidget->layer()->createExpressionContextScope() );
530 const QVariant value = exp.evaluate( &expressionContext );
531 if ( !exp.hasEvalError() )
533 userType = value.type();
542 case QVariant::Type::Double:
546 const QVariant value = index.data( QgsCategorizedSymbolRendererWidget::CustomRoles::ValueRole );
548 if ( value.toDouble( &ok ); ok )
550 const QString strVal { value.toString() };
551 const int dotPosition( strVal.indexOf(
'.' ) );
552 if ( dotPosition >= 0 )
554 decimals = std::max<int>( 2, strVal.length() - dotPosition - 1 );
557 editor->setDecimals( decimals );
559 editor->setMaximum( std::numeric_limits<double>::max() );
560 editor->setMinimum( std::numeric_limits<double>::lowest() );
563 case QVariant::Type::Int:
566 editor->setDecimals( 0 );
568 editor->setMaximum( std::numeric_limits<int>::max() );
569 editor->setMinimum( std::numeric_limits<int>::min() );
572 case QVariant::Type::Char:
575 editor->setDecimals( 0 );
577 editor->setMaximum( std::numeric_limits<char>::max() );
578 editor->setMinimum( std::numeric_limits<char>::min() );
581 case QVariant::Type::UInt:
584 editor->setDecimals( 0 );
586 editor->setMaximum( std::numeric_limits<unsigned int>::max() );
587 editor->setMinimum( 0 );
590 case QVariant::Type::LongLong:
593 editor->setDecimals( 0 );
595 editor->setMaximum(
static_cast<double>( std::numeric_limits<qlonglong>::max() ) );
596 editor->setMinimum( std::numeric_limits<qlonglong>::min() );
599 case QVariant::Type::ULongLong:
602 editor->setDecimals( 0 );
604 editor->setMaximum(
static_cast<double>( std::numeric_limits<unsigned long long>::max() ) );
605 editor->setMinimum( 0 );
611 return editor ? editor : QStyledItemDelegate::createEditor( parent, option, index );
624 , mContextMenu( new QMenu( this ) )
640 const QString attrName =
mRenderer->classAttribute();
641 mOldClassificationAttribute = attrName;
645 layout()->setContentsMargins( 0, 0, 0, 0 );
647 mExpressionWidget->setLayer(
mLayer );
648 btnChangeCategorizedSymbol->setLayer(
mLayer );
649 btnChangeCategorizedSymbol->registerExpressionContextGenerator(
this );
652 btnColorRamp->setShowRandomColorRamp(
true );
655 std::unique_ptr< QgsColorRamp > colorRamp(
QgsProject::instance()->styleSettings()->defaultColorRamp() );
658 btnColorRamp->setColorRamp( colorRamp.get() );
662 btnColorRamp->setRandomColorRamp();
672 mModel =
new QgsCategorizedSymbolRendererModel(
this );
678 viewCategories->setModel(
mModel );
679 viewCategories->resizeColumnToContents( 0 );
680 viewCategories->resizeColumnToContents( 1 );
681 viewCategories->resizeColumnToContents( 2 );
682 viewCategories->setItemDelegateForColumn( 1,
new QgsCategorizedRendererViewItemDelegate( mExpressionWidget, viewCategories ) );
684 viewCategories->setStyle(
new QgsCategorizedSymbolRendererViewStyle( viewCategories ) );
685 connect( viewCategories->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QgsCategorizedSymbolRendererWidget::selectionChanged );
693 connect( viewCategories, &QTreeView::customContextMenuRequested,
this, &QgsCategorizedSymbolRendererWidget::showContextMenu );
695 connect( btnChangeCategorizedSymbol, &
QgsSymbolButton::changed,
this, &QgsCategorizedSymbolRendererWidget::updateSymbolsFromButton );
705 QMenu *advMenu =
new QMenu;
712 QAction *actionDdsLegend = advMenu->addAction( tr(
"Data-defined Size Legend…" ) );
714 connect( actionDdsLegend, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::dataDefinedSizeLegend );
717 btnAdvanced->setMenu( advMenu );
719 mExpressionWidget->registerExpressionContextGenerator(
this );
721 mMergeCategoriesAction =
new QAction( tr(
"Merge Categories" ),
this );
722 connect( mMergeCategoriesAction, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::mergeSelectedCategories );
723 mUnmergeCategoriesAction =
new QAction( tr(
"Unmerge Categories" ),
this );
724 connect( mUnmergeCategoriesAction, &QAction::triggered,
this, &QgsCategorizedSymbolRendererWidget::unmergeSelectedCategories );
726 connect( mContextMenu, &QMenu::aboutToShow,
this, [ = ]
747 const QString attrName =
mRenderer->classAttribute();
748 mExpressionWidget->setField( attrName );
760 btnColorRamp->setColorRamp(
mRenderer->sourceColorRamp() );
778 delete mActionLevels;
779 mActionLevels =
nullptr;
786 if ( !selectedCats.isEmpty() )
797 const auto constSelectedCats = selectedCats;
798 for (
const int idx : constSelectedCats )
804 mRenderer->updateCategorySymbol( idx, newCatSymbol );
827 if ( !dlg.exec() || !newSymbol )
850 if ( idx.isValid() && idx.column() == 0 )
858 std::unique_ptr< QgsSymbol > symbol;
860 if (
auto *lSymbol = category.
symbol() )
862 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.type() == QVariant::List )
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() );
1273void QgsCategorizedSymbolRendererWidget::cleanUpSymbolSelector(
QgsPanelWidget *container )
1282void QgsCategorizedSymbolRendererWidget::updateSymbolsFromWidget()
1290void QgsCategorizedSymbolRendererWidget::updateSymbolsFromButton()
1300 QItemSelectionModel *m = viewCategories->selectionModel();
1301 const QModelIndexList i = m->selectedRows();
1307 if ( !selectedCats.isEmpty() )
1309 const auto constSelectedCats = selectedCats;
1310 for (
const int idx : constSelectedCats )
1313 if ( selectedCats.count() > 1 )
1318 mRenderer->updateCategorySymbol( idx, newCatSymbol );
1327 mModel->updateSymbology();
1338 if ( event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier )
1340 mCopyBuffer.clear();
1343 else if ( event->key() == Qt::Key_V && event->modifiers() == Qt::ControlModifier )
1345 QgsCategoryList::const_iterator rIt = mCopyBuffer.constBegin();
1346 for ( ; rIt != mCopyBuffer.constEnd(); ++rIt )
1348 mModel->addCategory( *rIt );
1366 expContext << generator->createExpressionContextScope();
1387void QgsCategorizedSymbolRendererWidget::dataDefinedSizeLegend()
1402void QgsCategorizedSymbolRendererWidget::mergeSelectedCategories()
1407 QList< int > categoryIndexes;
1410 for (
const int i : selectedCategoryIndexes )
1412 const QVariant v = categories.at( i ).value();
1414 if ( !v.isValid() || v ==
"" )
1419 categoryIndexes.append( i );
1422 if ( categoryIndexes.count() < 2 )
1426 QVariantList values;
1427 values.reserve( categoryIndexes.count() );
1428 labels.reserve( categoryIndexes.count() );
1429 for (
const int i : categoryIndexes )
1431 const QVariant v = categories.at( i ).value();
1433 if ( v.type() == QVariant::List )
1435 values.append( v.toList() );
1440 labels << categories.at( i ).label();
1444 mRenderer->updateCategoryLabel( categoryIndexes.at( 0 ), labels.join(
',' ) );
1445 mRenderer->updateCategoryValue( categoryIndexes.at( 0 ), values );
1447 categoryIndexes.pop_front();
1448 mModel->deleteRows( categoryIndexes );
1453void QgsCategorizedSymbolRendererWidget::unmergeSelectedCategories()
1456 if ( categoryIndexes.isEmpty() )
1460 for (
const int i : categoryIndexes )
1462 const QVariant v = categories.at( i ).value();
1463 if ( v.type() != QVariant::List )
1466 const QVariantList list = v.toList();
1467 for (
int j = 1; j < list.count(); ++j )
1469 mModel->addCategory(
QgsRendererCategory( list.at( j ), categories.at( i ).symbol()->clone(), list.at( j ).toString(), categories.at( i ).renderState() ) );
1471 mRenderer->updateCategoryValue( i, list.at( 0 ) );
1472 mRenderer->updateCategoryLabel( i, list.at( 0 ).toString() );
1478void QgsCategorizedSymbolRendererWidget::showContextMenu( QPoint )
1480 mContextMenu->clear();
1481 const QList< QAction * > actions =
contextMenu->actions();
1482 for ( QAction *act : actions )
1484 mContextMenu->addAction( act );
1487 mContextMenu->addSeparator();
1489 if ( viewCategories->selectionModel()->selectedRows().count() > 1 )
1491 mContextMenu->addAction( mMergeCategoriesAction );
1493 if ( viewCategories->selectionModel()->selectedRows().count() == 1 )
1497 const QVariant v = categories.at( categoryIndexes.at( 0 ) ).value();
1498 if ( v.type() == QVariant::List )
1499 mContextMenu->addAction( mUnmergeCategoriesAction );
1501 else if ( viewCategories->selectionModel()->selectedRows().count() > 1 )
1503 mContextMenu->addAction( mUnmergeCategoriesAction );
1506 mContextMenu->exec( QCursor::pos() );
1509void QgsCategorizedSymbolRendererWidget::selectionChanged(
const QItemSelection &,
const QItemSelection & )
1512 if ( !selectedCats.isEmpty() )
1514 whileBlocking( btnChangeCategorizedSymbol )->setSymbol(
mRenderer->categories().at( selectedCats.at( 0 ) ).symbol()->clone() );
1520 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)
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...
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...
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()
Returns 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)
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)
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.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
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