49#include <QStandardItemModel>
50#include <QStandardItem>
58QgsCategorizedSymbolRendererModel::QgsCategorizedSymbolRendererModel( QObject *parent ) : QAbstractItemModel( parent )
59 , 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().type() != QVariant::List )
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().type() == QVariant::List )
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().type() == QVariant::List
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().type() == QVariant::List )
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();
254 case QgsCategorizedSymbolRendererWidget::CustomRoles::ValueRole:
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.type() != QVariant::String && ! previousValue.toString().isEmpty() )
289 switch ( previousValue.type() )
294 case QVariant::Double:
295 val = value.toDouble();
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 QgsDebugMsg( QStringLiteral(
"move %1 to %2" ).arg( rows[i] ).arg( to ) );
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
510 QVariant::Type userType { index.data( QgsCategorizedSymbolRendererWidget::CustomRoles::ValueRole ).type() };
513 if ( userType == QVariant::String &&
QgsVariantUtils::isNull( index.data( QgsCategorizedSymbolRendererWidget::CustomRoles::ValueRole ) ) )
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 = value.type();
546 case QVariant::Type::Double:
550 const QVariant value = index.data( QgsCategorizedSymbolRendererWidget::CustomRoles::ValueRole );
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 QVariant::Type::Int:
570 editor->setDecimals( 0 );
572 editor->setMaximum( std::numeric_limits<int>::max() );
573 editor->setMinimum( std::numeric_limits<int>::min() );
576 case QVariant::Type::Char:
579 editor->setDecimals( 0 );
581 editor->setMaximum( std::numeric_limits<char>::max() );
582 editor->setMinimum( std::numeric_limits<char>::min() );
585 case QVariant::Type::UInt:
588 editor->setDecimals( 0 );
590 editor->setMaximum( std::numeric_limits<unsigned int>::max() );
591 editor->setMinimum( 0 );
594 case QVariant::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 QVariant::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 );
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 );
831 if ( !dlg.exec() || !newSymbol )
854 if ( idx.isValid() && idx.column() == 0 )
862 std::unique_ptr< QgsSymbol > symbol;
864 if (
auto *lSymbol = category.
symbol() )
866 symbol.reset( lSymbol->clone() );
887 if ( !dlg.exec() || !symbol )
900 const QString attrName = mExpressionWidget->currentField();
902 QList<QVariant> uniqueValues;
920 if ( uniqueValues.contains( value ) )
922 uniqueValues << value;
931 if ( uniqueValues.size() >= 1000 )
933 const int res = QMessageBox::warning(
nullptr, tr(
"Classify Categories" ),
934 tr(
"High number of classes. Classification would yield %n entries which might not be expected. Continue?",
nullptr, uniqueValues.size() ),
935 QMessageBox::Ok | QMessageBox::Cancel,
936 QMessageBox::Cancel );
937 if ( res == QMessageBox::Cancel )
944 DlgAddCategories dlg(
mStyle, createDefaultSymbol(), unique_vals,
this );
950 bool deleteExisting =
false;
952 if ( !mOldClassificationAttribute.isEmpty() &&
953 attrName != mOldClassificationAttribute &&
956 const int res = QMessageBox::question(
this,
957 tr(
"Delete Classification" ),
958 tr(
"The classification field was changed from '%1' to '%2'.\n"
959 "Should the existing classes be deleted before classification?" )
960 .arg( mOldClassificationAttribute, attrName ),
961 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel );
962 if ( res == QMessageBox::Cancel )
967 deleteExisting = ( res == QMessageBox::Yes );
971 bool keepExistingColors =
false;
972 if ( !deleteExisting )
975 keepExistingColors = !prevCats.isEmpty();
977 if ( keepExistingColors && btnColorRamp->isRandomColorRamp() )
979 for (
int i = 0; i < cats.size(); ++i )
981 bool contains =
false;
982 const QVariant value = cats.at( i ).value();
983 for (
int j = 0; j < prevCats.size() && !contains; ++j )
985 const QVariant prevCatValue = prevCats.at( j ).value();
986 if ( prevCatValue.type() == QVariant::List )
988 const QVariantList list = prevCatValue.toList();
989 for (
const QVariant &v : list )
1000 if ( prevCats.at( j ).value() == value )
1011 if ( keepExistingColors && btnColorRamp->isRandomColorRamp() )
1014 cats.at( i ).symbol()->setColor( randomColors.
color( i ) );
1016 prevCats.append( cats.at( i ) );
1022 mOldClassificationAttribute = attrName;
1039 std::unique_ptr< QgsCategorizedSymbolRenderer > r = std::make_unique< QgsCategorizedSymbolRenderer >( attrName, cats );
1041 std::unique_ptr< QgsColorRamp > ramp( btnColorRamp->colorRamp() );
1043 r->setSourceColorRamp( ramp->clone() );
1047 mModel->setRenderer( r.get() );
1050 if ( ! keepExistingColors && ramp )
1057 if ( !btnColorRamp->isNull() )
1059 mRenderer->updateColorRamp( btnColorRamp->colorRamp() );
1061 mModel->updateSymbology();
1066 const QModelIndex idx = viewCategories->selectionModel()->currentIndex();
1067 if ( !idx.isValid() )
1075 const QModelIndexList selectedRows = viewCategories->selectionModel()->selectedRows();
1077 const auto constSelectedRows = selectedRows;
1078 for (
const QModelIndex &r : constSelectedRows )
1082 rows.append( r.row() );
1091 mModel->deleteRows( categoryIndexes );
1106 mModel->addCategory( cat );
1114 QItemSelectionModel *m = viewCategories->selectionModel();
1115 const QModelIndexList selectedIndexes = m->selectedRows( 1 );
1117 if ( !selectedIndexes.isEmpty() )
1120 QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
1121 for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
1123 const int row = ( *indexIt ).row();
1124 QgsSymbol *s = categories[row].symbol();
1138 QItemSelectionModel *m = viewCategories->selectionModel();
1139 const QModelIndexList selectedIndexes = m->selectedRows( 1 );
1141 if ( !selectedIndexes.isEmpty() )
1143 QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
1144 for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
1146 cl.append(
mModel->category( *indexIt ) );
1165 viewCategories->selectionModel()->clear();
1173 QMessageBox::information(
this, tr(
"Matched Symbols" ),
1174 tr(
"Matched %n categories to symbols.",
nullptr, matched ) );
1178 QMessageBox::warning(
this, tr(
"Matched Symbols" ),
1179 tr(
"No categories could be matched to symbols in library." ) );
1192 QVariantList unmatchedCategories;
1193 QStringList unmatchedSymbols;
1194 const int matched =
mRenderer->matchToSymbols( style, type, unmatchedCategories, unmatchedSymbols );
1196 mModel->updateSymbology();
1203 const QString openFileDir = settings.
value( QStringLiteral(
"UI/lastMatchToSymbolsDir" ), QDir::homePath() ).toString();
1205 const QString fileName = QFileDialog::getOpenFileName(
this, tr(
"Match to Symbols from File" ), openFileDir,
1206 tr(
"XML files (*.xml *.XML)" ) );
1207 if ( fileName.isEmpty() )
1212 const QFileInfo openFileInfo( fileName );
1213 settings.
setValue( QStringLiteral(
"UI/lastMatchToSymbolsDir" ), openFileInfo.absolutePath() );
1216 if ( !importedStyle.
importXml( fileName ) )
1218 QMessageBox::warning(
this, tr(
"Match to Symbols from File" ),
1219 tr(
"An error occurred while reading file:\n%1" ).arg( importedStyle.
errorString() ) );
1226 QMessageBox::information(
this, tr(
"Match to Symbols from File" ),
1227 tr(
"Matched %n categories to symbols from file.",
nullptr, matched ) );
1231 QMessageBox::warning(
this, tr(
"Match to Symbols from File" ),
1232 tr(
"No categories could be matched to symbols in file." ) );
1243 mRenderer->setLegendSymbolItem( legendSymbol.ruleKey(), sym->
clone() );
1246 mRenderer->setUsingSymbolLevels( enabled );
1247 mModel->updateSymbology();
1258 if ( !selectedCats.isEmpty() )
1260 for (
const int idx : selectedCats )
1262 if (
mRenderer->categories().at( idx ).symbol()->type() != tempSymbol->type() )
1265 std::unique_ptr< QgsSymbol > newCatSymbol( tempSymbol->clone() );
1266 if ( selectedCats.count() > 1 )
1269 newCatSymbol->setColor(
mRenderer->categories().at( idx ).symbol()->color() );
1271 mRenderer->updateCategorySymbol( idx, newCatSymbol.release() );
1277void QgsCategorizedSymbolRendererWidget::cleanUpSymbolSelector(
QgsPanelWidget *container )
1286void QgsCategorizedSymbolRendererWidget::updateSymbolsFromWidget()
1294void QgsCategorizedSymbolRendererWidget::updateSymbolsFromButton()
1304 QItemSelectionModel *m = viewCategories->selectionModel();
1305 const QModelIndexList i = m->selectedRows();
1311 if ( !selectedCats.isEmpty() )
1313 const auto constSelectedCats = selectedCats;
1314 for (
const int idx : constSelectedCats )
1317 if ( selectedCats.count() > 1 )
1322 mRenderer->updateCategorySymbol( idx, newCatSymbol );
1331 mModel->updateSymbology();
1342 if ( event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier )
1344 mCopyBuffer.clear();
1347 else if ( event->key() == Qt::Key_V && event->modifiers() == Qt::ControlModifier )
1349 QgsCategoryList::const_iterator rIt = mCopyBuffer.constBegin();
1350 for ( ; rIt != mCopyBuffer.constEnd(); ++rIt )
1352 mModel->addCategory( *rIt );
1370 expContext << generator->createExpressionContextScope();
1391void QgsCategorizedSymbolRendererWidget::dataDefinedSizeLegend()
1406void QgsCategorizedSymbolRendererWidget::mergeSelectedCategories()
1411 QList< int > categoryIndexes;
1414 for (
const int i : selectedCategoryIndexes )
1416 const QVariant v = categories.at( i ).value();
1418 if ( !v.isValid() || v ==
"" )
1423 categoryIndexes.append( i );
1426 if ( categoryIndexes.count() < 2 )
1430 QVariantList values;
1431 values.reserve( categoryIndexes.count() );
1432 labels.reserve( categoryIndexes.count() );
1433 for (
const int i : categoryIndexes )
1435 const QVariant v = categories.at( i ).value();
1437 if ( v.type() == QVariant::List )
1439 values.append( v.toList() );
1444 labels << categories.at( i ).label();
1448 mRenderer->updateCategoryLabel( categoryIndexes.at( 0 ), labels.join(
',' ) );
1449 mRenderer->updateCategoryValue( categoryIndexes.at( 0 ), values );
1451 categoryIndexes.pop_front();
1452 mModel->deleteRows( categoryIndexes );
1457void QgsCategorizedSymbolRendererWidget::unmergeSelectedCategories()
1460 if ( categoryIndexes.isEmpty() )
1464 for (
const int i : categoryIndexes )
1466 const QVariant v = categories.at( i ).value();
1467 if ( v.type() != QVariant::List )
1470 const QVariantList list = v.toList();
1471 for (
int j = 1; j < list.count(); ++j )
1473 mModel->addCategory(
QgsRendererCategory( list.at( j ), categories.at( i ).symbol()->clone(), list.at( j ).toString(), categories.at( i ).renderState() ) );
1475 mRenderer->updateCategoryValue( i, list.at( 0 ) );
1476 mRenderer->updateCategoryLabel( i, list.at( 0 ).toString() );
1482void QgsCategorizedSymbolRendererWidget::showContextMenu( QPoint )
1484 mContextMenu->clear();
1485 const QList< QAction * > actions =
contextMenu->actions();
1486 for ( QAction *act : actions )
1488 mContextMenu->addAction( act );
1491 mContextMenu->addSeparator();
1493 if ( viewCategories->selectionModel()->selectedRows().count() > 1 )
1495 mContextMenu->addAction( mMergeCategoriesAction );
1497 if ( viewCategories->selectionModel()->selectedRows().count() == 1 )
1501 const QVariant v = categories.at( categoryIndexes.at( 0 ) ).value();
1502 if ( v.type() == QVariant::List )
1503 mContextMenu->addAction( mUnmergeCategoriesAction );
1505 else if ( viewCategories->selectionModel()->selectedRows().count() > 1 )
1507 mContextMenu->addAction( mUnmergeCategoriesAction );
1510 mContextMenu->exec( QCursor::pos() );
1513void QgsCategorizedSymbolRendererWidget::selectionChanged(
const QItemSelection &,
const QItemSelection & )
1516 if ( !selectedCats.isEmpty() )
1518 whileBlocking( btnChangeCategorizedSymbol )->setSymbol(
mRenderer->categories().at( selectedCats.at( 0 ) ).symbol()->clone() );
1524 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.
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
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 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.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
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.
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