18 #include <QMessageBox> 
   19 #include <QStandardItemModel> 
   20 #include <QStandardItem> 
   64 QgsGraduatedSymbolRendererModel::QgsGraduatedSymbolRendererModel( QObject *parent ) : QAbstractItemModel( parent )
 
   65   , mMimeFormat( QStringLiteral( 
"application/x-qgsgraduatedsymbolrendererv2model" ) )
 
   73     if ( !mRenderer->ranges().isEmpty() )
 
   75       beginRemoveRows( QModelIndex(), 0, mRenderer->ranges().size() - 1 );
 
   86     if ( !renderer->
ranges().isEmpty() )
 
   88       beginInsertRows( QModelIndex(), 0, renderer->
ranges().size() - 1 );
 
   99 void QgsGraduatedSymbolRendererModel::addClass( 
QgsSymbol *symbol )
 
  101   if ( !mRenderer ) 
return;
 
  102   int idx = mRenderer->
ranges().size();
 
  103   beginInsertRows( QModelIndex(), idx, idx );
 
  104   mRenderer->addClass( symbol );
 
  108 void QgsGraduatedSymbolRendererModel::addClass( 
const QgsRendererRange &range )
 
  114   int idx = mRenderer->ranges().size();
 
  115   beginInsertRows( QModelIndex(), idx, idx );
 
  116   mRenderer->addClass( range );
 
  120 QgsRendererRange QgsGraduatedSymbolRendererModel::rendererRange( 
const QModelIndex &index )
 
  122   if ( !index.isValid() || !mRenderer || mRenderer->ranges().size() <= index.row() )
 
  127   return mRenderer->ranges().value( index.row() );
 
  130 Qt::ItemFlags QgsGraduatedSymbolRendererModel::flags( 
const QModelIndex &index )
 const 
  132   if ( !index.isValid() )
 
  134     return Qt::ItemIsDropEnabled;
 
  137   Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable;
 
  139   if ( index.column() == 2 )
 
  141     flags |= Qt::ItemIsEditable;
 
  147 Qt::DropActions QgsGraduatedSymbolRendererModel::supportedDropActions()
 const 
  149   return Qt::MoveAction;
 
  152 QVariant QgsGraduatedSymbolRendererModel::data( 
const QModelIndex &index, 
int role )
 const 
  154   if ( !index.isValid() || !mRenderer ) 
return QVariant();
 
  158   if ( role == Qt::CheckStateRole && index.column() == 0 )
 
  160     return range.
renderState() ? Qt::Checked : Qt::Unchecked;
 
  162   else if ( role == Qt::DisplayRole || role == Qt::ToolTipRole )
 
  164     switch ( index.column() )
 
  168         int decimalPlaces = mRenderer->classificationMethod()->labelPrecision() + 2;
 
  169         if ( decimalPlaces < 0 ) decimalPlaces = 0;
 
  170         return QString( QLocale().toString( range.
lowerValue(), 
'f', decimalPlaces ) + 
" - " + QLocale().toString( range.
upperValue(), 
'f', decimalPlaces ) );
 
  173         return range.
label();
 
  178   else if ( role == Qt::DecorationRole && index.column() == 0 && range.
symbol() )
 
  183   else if ( role == Qt::TextAlignmentRole )
 
  185     return ( index.column() == 0 ) ? 
static_cast<Qt::Alignment::Int
>( Qt::AlignHCenter ) : 
static_cast<Qt::Alignment::Int
>( Qt::AlignLeft );
 
  187   else if ( role == Qt::EditRole )
 
  189     switch ( index.column() )
 
  193         return range.
label();
 
  202 bool QgsGraduatedSymbolRendererModel::setData( 
const QModelIndex &index, 
const QVariant &value, 
int role )
 
  204   if ( !index.isValid() )
 
  207   if ( index.column() == 0 && role == Qt::CheckStateRole )
 
  209     mRenderer->updateRangeRenderState( index.row(), value == Qt::Checked );
 
  210     emit dataChanged( index, index );
 
  214   if ( role != Qt::EditRole )
 
  217   switch ( index.column() )
 
  222       mRenderer->updateRangeLabel( index.row(), value.toString() );
 
  228   emit dataChanged( index, index );
 
  232 QVariant QgsGraduatedSymbolRendererModel::headerData( 
int section, Qt::Orientation orientation, 
int role )
 const 
  234   if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 3 )
 
  237     lst << tr( 
"Symbol" ) << tr( 
"Values" ) << tr( 
"Legend" );
 
  238     return lst.value( section );
 
  243 int QgsGraduatedSymbolRendererModel::rowCount( 
const QModelIndex &parent )
 const 
  245   if ( parent.isValid() || !mRenderer )
 
  249   return mRenderer->ranges().size();
 
  252 int QgsGraduatedSymbolRendererModel::columnCount( 
const QModelIndex &index )
 const 
  258 QModelIndex QgsGraduatedSymbolRendererModel::index( 
int row, 
int column, 
const QModelIndex &parent )
 const 
  260   if ( hasIndex( row, column, parent ) )
 
  262     return createIndex( row, column );
 
  264   return QModelIndex();
 
  267 QModelIndex QgsGraduatedSymbolRendererModel::parent( 
const QModelIndex &index )
 const 
  270   return QModelIndex();
 
  273 QStringList QgsGraduatedSymbolRendererModel::mimeTypes()
 const 
  276   types << mMimeFormat;
 
  280 QMimeData *QgsGraduatedSymbolRendererModel::mimeData( 
const QModelIndexList &indexes )
 const 
  282   QMimeData *mimeData = 
new QMimeData();
 
  283   QByteArray encodedData;
 
  285   QDataStream stream( &encodedData, QIODevice::WriteOnly );
 
  288   const auto constIndexes = indexes;
 
  289   for ( 
const QModelIndex &index : constIndexes )
 
  291     if ( !index.isValid() || index.column() != 0 )
 
  294     stream << index.row();
 
  296   mimeData->setData( mMimeFormat, encodedData );
 
  300 bool QgsGraduatedSymbolRendererModel::dropMimeData( 
const QMimeData *data, Qt::DropAction action, 
int row, 
int column, 
const QModelIndex &parent )
 
  304   if ( action != Qt::MoveAction ) 
return true;
 
  306   if ( !data->hasFormat( mMimeFormat ) ) 
return false;
 
  308   QByteArray encodedData = data->data( mMimeFormat );
 
  309   QDataStream stream( &encodedData, QIODevice::ReadOnly );
 
  312   while ( !stream.atEnd() )
 
  319   int to = parent.row();
 
  322   if ( to == -1 ) to = mRenderer->ranges().size(); 
 
  323   for ( 
int i = rows.size() - 1; i >= 0; i-- )
 
  325     QgsDebugMsg( QStringLiteral( 
"move %1 to %2" ).arg( rows[i] ).arg( to ) );
 
  328     if ( rows[i] < t ) t--;
 
  329     mRenderer->moveClass( rows[i], t );
 
  331     for ( 
int j = 0; j < i; j++ )
 
  333       if ( to < rows[j] && rows[i] > rows[j] ) rows[j] += 1;
 
  336     if ( rows[i] < to ) to--;
 
  338   emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->ranges().size(), 0 ) );
 
  343 void QgsGraduatedSymbolRendererModel::deleteRows( QList<int> rows )
 
  345   for ( 
int i = rows.size() - 1; i >= 0; i-- )
 
  347     beginRemoveRows( QModelIndex(), rows[i], rows[i] );
 
  348     mRenderer->deleteClass( rows[i] );
 
  353 void QgsGraduatedSymbolRendererModel::removeAllRows()
 
  355   beginRemoveRows( QModelIndex(), 0, mRenderer->ranges().size() - 1 );
 
  356   mRenderer->deleteAllClasses();
 
  360 void QgsGraduatedSymbolRendererModel::sort( 
int column, Qt::SortOrder order )
 
  368     mRenderer->sortByValue( order );
 
  370   else if ( column == 2 )
 
  372     mRenderer->sortByLabel( order );
 
  375   emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->ranges().size(), 0 ) );
 
  378 void QgsGraduatedSymbolRendererModel::updateSymbology()
 
  380   emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->ranges().size(), 0 ) );
 
  383 void QgsGraduatedSymbolRendererModel::updateLabels()
 
  385   emit dataChanged( createIndex( 0, 2 ), createIndex( mRenderer->ranges().size(), 2 ) );
 
  389 QgsGraduatedSymbolRendererViewStyle::QgsGraduatedSymbolRendererViewStyle( QWidget *parent )
 
  393 void QgsGraduatedSymbolRendererViewStyle::drawPrimitive( PrimitiveElement element, 
const QStyleOption *option, QPainter *painter, 
const QWidget *widget )
 const 
  395   if ( element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull() )
 
  397     QStyleOption opt( *option );
 
  398     opt.rect.setLeft( 0 );
 
  400     opt.rect.setHeight( 0 );
 
  401     if ( widget ) opt.rect.setRight( widget->width() );
 
  402     QProxyStyle::drawPrimitive( element, &opt, painter, widget );
 
  405   QProxyStyle::drawPrimitive( element, option, painter, widget );
 
  414   return new QgsGraduatedSymbolRendererWidget( layer, style, renderer );
 
  424   if ( 
auto *lMapCanvas = mContext.mapCanvas() )
 
  430       expContext << generator->createExpressionContextScope();
 
  438   if ( 
auto *lVectorLayer = vectorLayer() )
 
  442   const auto constAdditionalExpressionContextScopes = mContext.additionalExpressionContextScopes();
 
  462     mRenderer = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), 
QgsRangeList() );
 
  471   cboSymmetryPoint->setEditable( 
true );
 
  472   cboSymmetryPoint->setValidator( mSymmetryPointValidator );
 
  475   for ( QMap<QString, QString>::const_iterator it = methods.constBegin(); it != methods.constEnd(); ++it )
 
  478     cboGraduatedMode->addItem( icon, it.key(), it.value() );
 
  481   connect( methodComboBox, 
static_cast<void ( QComboBox::* )( 
int )
>( &QComboBox::currentIndexChanged ), 
this, &QgsGraduatedSymbolRendererWidget::methodComboBox_currentIndexChanged );
 
  482   this->layout()->setContentsMargins( 0, 0, 0, 0 );
 
  484   mModel = 
new QgsGraduatedSymbolRendererModel( 
this );
 
  487   mExpressionWidget->setLayer( 
mLayer );
 
  489   btnChangeGraduatedSymbol->setLayer( 
mLayer );
 
  490   btnChangeGraduatedSymbol->registerExpressionContextGenerator( 
this );
 
  497   spinPrecision->setClearValue( 4 );
 
  499   spinGraduatedClasses->setShowClearButton( 
false );
 
  501   btnColorRamp->setShowRandomColorRamp( 
true );
 
  504   std::unique_ptr< QgsColorRamp > colorRamp( 
QgsProject::instance()->styleSettings()->defaultColorRamp() );
 
  507     btnColorRamp->setColorRamp( colorRamp.get() );
 
  512     btnColorRamp->setColorRamp( ramp );
 
  517   viewGraduated->setStyle( 
new QgsGraduatedSymbolRendererViewStyle( viewGraduated ) );
 
  520   if ( mGraduatedSymbol )
 
  522     btnChangeGraduatedSymbol->setSymbolType( mGraduatedSymbol->type() );
 
  523     btnChangeGraduatedSymbol->setSymbol( mGraduatedSymbol->clone() );
 
  525     methodComboBox->blockSignals( 
true );
 
  526     methodComboBox->addItem( tr( 
"Color" ), ColorMode );
 
  527     switch ( mGraduatedSymbol->type() )
 
  531         methodComboBox->addItem( tr( 
"Size" ), SizeMode );
 
  532         minSizeSpinBox->setValue( 1 );
 
  533         maxSizeSpinBox->setValue( 8 );
 
  538         methodComboBox->addItem( tr( 
"Size" ), SizeMode );
 
  539         minSizeSpinBox->setValue( .1 );
 
  540         maxSizeSpinBox->setValue( 2 );
 
  546         methodComboBox->hide();
 
  553     methodComboBox->blockSignals( 
false );
 
  562   connect( btnChangeGraduatedSymbol, &
QgsSymbolButton::changed, 
this, &QgsGraduatedSymbolRendererWidget::changeGraduatedSymbol );
 
  569   connect( cboGraduatedMode, qOverload<int>( &QComboBox::currentIndexChanged ), 
this, &QgsGraduatedSymbolRendererWidget::updateMethodParameters );
 
  577   mGroupBoxSymmetric->setCollapsed( 
true ); 
 
  580   QMenu *advMenu = 
new QMenu( 
this );
 
  585     QAction *actionDdsLegend = advMenu->addAction( tr( 
"Data-defined Size Legend…" ) );
 
  587     connect( actionDdsLegend, &QAction::triggered, 
this, &QgsGraduatedSymbolRendererWidget::dataDefinedSizeLegend );
 
  590   btnAdvanced->setMenu( advMenu );
 
  592   mHistogramWidget->setLayer( 
mLayer );
 
  593   mHistogramWidget->setRenderer( mRenderer.get() );
 
  597   mExpressionWidget->registerExpressionContextGenerator( 
this );
 
  600 void QgsGraduatedSymbolRendererWidget::mSizeUnitWidget_changed()
 
  602   if ( !mGraduatedSymbol )
 
  604   mGraduatedSymbol->setOutputUnit( mSizeUnitWidget->unit() );
 
  605   mGraduatedSymbol->setMapUnitScale( mSizeUnitWidget->getMapUnitScale() );
 
  606   mRenderer->updateSymbols( mGraduatedSymbol.get() );
 
  613   mParameterWidgetWrappers.clear();
 
  618   return mRenderer.get();
 
  624   btnChangeGraduatedSymbol->setMapCanvas( context.
mapCanvas() );
 
  625   btnChangeGraduatedSymbol->setMessageBar( context.
messageBar() );
 
  630   delete mActionLevels;
 
  631   mActionLevels = 
nullptr;
 
  652   connect( cboSymmetryPoint->lineEdit(), &QLineEdit::editingFinished, 
this, &QgsGraduatedSymbolRendererWidget::symmetryPointEditingFinished );
 
  654   for ( 
const auto &ppww : std::as_const( mParameterWidgetWrappers ) )
 
  678   disconnect( cboSymmetryPoint->lineEdit(), &QLineEdit::editingFinished, 
this, &QgsGraduatedSymbolRendererWidget::symmetryPointEditingFinished );
 
  680   for ( 
const auto &ppww : std::as_const( mParameterWidgetWrappers ) )
 
  688   disconnectUpdateHandlers();
 
  696   int precision = spinPrecision->value() + 2;
 
  697   while ( cboSymmetryPoint->count() )
 
  698     cboSymmetryPoint->removeItem( 0 );
 
  699   for ( 
int i = 0; i < ranges.count() - 1; i++ )
 
  700     cboSymmetryPoint->addItem( QLocale().toString( ranges.at( i ).upperValue(), 
'f', 
precision ), ranges.at( i ).upperValue() );
 
  704     int idx = cboGraduatedMode->findData( method->
id() );
 
  706       cboGraduatedMode->setCurrentIndex( idx );
 
  712       cboSymmetryPoint->setItemText( cboSymmetryPoint->currentIndex(), QLocale().toString( method->
symmetryPoint(), 
'f', method->
labelPrecision() + 2 ) );
 
  719     for ( 
const auto &ppww : std::as_const( mParameterWidgetWrappers ) )
 
  723       ppww->setParameterValue( value, context );
 
  728   int nclasses = ranges.count();
 
  729   if ( nclasses && ( updateCount || ( method && ( method->
flags() & QgsClassificationMethod::MethodProperty::IgnoresClassCount ) ) ) )
 
  731     spinGraduatedClasses->setValue( ranges.count() );
 
  735     spinGraduatedClasses->setEnabled( !( method->
flags() & QgsClassificationMethod::MethodProperty::IgnoresClassCount ) );
 
  739     spinGraduatedClasses->setEnabled( 
true );
 
  743   QString attrName = mRenderer->classAttribute();
 
  744   mExpressionWidget->setField( attrName );
 
  745   mHistogramWidget->setSourceFieldExp( attrName );
 
  748   if ( mRenderer->sourceSymbol() )
 
  750     mGraduatedSymbol.reset( mRenderer->sourceSymbol()->clone() );
 
  751     whileBlocking( btnChangeGraduatedSymbol )->setSymbol( mGraduatedSymbol->clone() );
 
  754   mModel->setRenderer( mRenderer.get() );
 
  755   viewGraduated->setModel( mModel );
 
  757   connect( viewGraduated->selectionModel(), &QItemSelectionModel::selectionChanged, 
this, &QgsGraduatedSymbolRendererWidget::selectionChanged );
 
  759   if ( mGraduatedSymbol )
 
  761     mSizeUnitWidget->blockSignals( 
true );
 
  762     mSizeUnitWidget->setUnit( mGraduatedSymbol->outputUnit() );
 
  763     mSizeUnitWidget->setMapUnitScale( mGraduatedSymbol->mapUnitScale() );
 
  764     mSizeUnitWidget->blockSignals( 
false );
 
  768   methodComboBox->blockSignals( 
true );
 
  769   switch ( mRenderer->graduatedMethod() )
 
  771     case Qgis::GraduatedMethod::Color:
 
  773       methodComboBox->setCurrentIndex( methodComboBox->findData( ColorMode ) );
 
  774       if ( mRenderer->sourceColorRamp() )
 
  776         btnColorRamp->setColorRamp( mRenderer->sourceColorRamp() );
 
  780     case Qgis::GraduatedMethod::Size:
 
  782       methodComboBox->setCurrentIndex( methodComboBox->findData( SizeMode ) );
 
  783       if ( !mRenderer->ranges().isEmpty() ) 
 
  785         minSizeSpinBox->setValue( mRenderer->minSymbolSize() );
 
  786         maxSizeSpinBox->setValue( mRenderer->maxSymbolSize() );
 
  791   toggleMethodWidgets( 
static_cast< MethodMode
>( methodComboBox->currentData().toInt() ) );
 
  792   methodComboBox->blockSignals( 
false );
 
  794   viewGraduated->resizeColumnToContents( 0 );
 
  795   viewGraduated->resizeColumnToContents( 1 );
 
  796   viewGraduated->resizeColumnToContents( 2 );
 
  798   mHistogramWidget->refresh();
 
  800   connectUpdateHandlers();
 
  803   emit widgetChanged();
 
  808   mRenderer->setClassAttribute( 
field );
 
  811 void QgsGraduatedSymbolRendererWidget::methodComboBox_currentIndexChanged( 
int )
 
  813   const MethodMode newMethod = 
static_cast< MethodMode 
>( methodComboBox->currentData().toInt() );
 
  814   toggleMethodWidgets( newMethod );
 
  819       mRenderer->setGraduatedMethod( Qgis::GraduatedMethod::Color );
 
  824         QMessageBox::critical( 
this, tr( 
"Select Method" ), tr( 
"No color ramp defined." ) );
 
  827       mRenderer->setSourceColorRamp( ramp );
 
  834       lblColorRamp->setVisible( 
false );
 
  835       btnColorRamp->setVisible( 
false );
 
  836       lblSize->setVisible( 
true );
 
  837       minSizeSpinBox->setVisible( 
true );
 
  838       lblSize->setVisible( 
true );
 
  839       maxSizeSpinBox->setVisible( 
true );
 
  840       mSizeUnitWidget->setVisible( 
true );
 
  842       mRenderer->setGraduatedMethod( Qgis::GraduatedMethod::Size );
 
  849 void QgsGraduatedSymbolRendererWidget::updateMethodParameters()
 
  851   clearParameterWidgets();
 
  853   const QString methodId = cboGraduatedMode->currentData().toString();
 
  865     QVariant value = method->
parameterValues().value( def->name(), def->defaultValueForGui() );
 
  870     mParameterWidgetWrappers.push_back( std::unique_ptr<QgsAbstractProcessingParameterWidgetWrapper>( ppww ) );
 
  873   spinGraduatedClasses->setEnabled( !( method->
flags() & QgsClassificationMethod::MethodProperty::IgnoresClassCount ) );
 
  876 void QgsGraduatedSymbolRendererWidget::toggleMethodWidgets( MethodMode mode )
 
  882       lblColorRamp->setVisible( 
true );
 
  883       btnColorRamp->setVisible( 
true );
 
  884       lblSize->setVisible( 
false );
 
  885       minSizeSpinBox->setVisible( 
false );
 
  886       lblSizeTo->setVisible( 
false );
 
  887       maxSizeSpinBox->setVisible( 
false );
 
  888       mSizeUnitWidget->setVisible( 
false );
 
  894       lblColorRamp->setVisible( 
false );
 
  895       btnColorRamp->setVisible( 
false );
 
  896       lblSize->setVisible( 
true );
 
  897       minSizeSpinBox->setVisible( 
true );
 
  898       lblSizeTo->setVisible( 
true );
 
  899       maxSizeSpinBox->setVisible( 
true );
 
  900       mSizeUnitWidget->setVisible( 
true );
 
  906 void QgsGraduatedSymbolRendererWidget::clearParameterWidgets()
 
  908   while ( mParametersLayout->rowCount() )
 
  910     QFormLayout::TakeRowResult row = mParametersLayout->takeRow( 0 );
 
  911     for ( QLayoutItem *item : QList<QLayoutItem *>( {row.labelItem, row.fieldItem} ) )
 
  914         if ( item->widget() )
 
  915           item->widget()->deleteLater();
 
  919   mParameterWidgetWrappers.clear();
 
  927   mModel->updateSymbology();
 
  929   disconnectUpdateHandlers();
 
  930   spinGraduatedClasses->setValue( mRenderer->ranges().count() );
 
  931   connectUpdateHandlers();
 
  933   emit widgetChanged();
 
  943       mRenderer->setLegendSymbolItem( legendSymbol.ruleKey(), sym->
clone() );
 
  946   mRenderer->setUsingSymbolLevels( enabled );
 
  947   mModel->updateSymbology();
 
  948   emit widgetChanged();
 
  951 void QgsGraduatedSymbolRendererWidget::cleanUpSymbolSelector( 
QgsPanelWidget *container )
 
  960 void QgsGraduatedSymbolRendererWidget::updateSymbolsFromWidget()
 
  965   applyChangeToSymbol();
 
  970   mSizeUnitWidget->blockSignals( 
true );
 
  971   mSizeUnitWidget->setUnit( mGraduatedSymbol->outputUnit() );
 
  972   mSizeUnitWidget->setMapUnitScale( mGraduatedSymbol->mapUnitScale() );
 
  973   mSizeUnitWidget->blockSignals( 
false );
 
  975   QItemSelectionModel *m = viewGraduated->selectionModel();
 
  976   QModelIndexList selectedIndexes = m->selectedRows( 1 );
 
  977   if ( !selectedIndexes.isEmpty() )
 
  979     const auto constSelectedIndexes = selectedIndexes;
 
  980     for ( 
const QModelIndex &idx : constSelectedIndexes )
 
  984         int rangeIdx = idx.row();
 
  986         if ( selectedIndexes.count() > 1 )
 
  989           newRangeSymbol->
setColor( mRenderer->ranges().at( rangeIdx ).symbol()->color() );
 
  991         mRenderer->updateRangeSymbol( rangeIdx, newRangeSymbol );
 
  997     mRenderer->updateSymbols( mGraduatedSymbol.get() );
 
 1000   refreshSymbolView();
 
 1001   emit widgetChanged();
 
 1004 void QgsGraduatedSymbolRendererWidget::symmetryPointEditingFinished( )
 
 1006   const QString text = cboSymmetryPoint->lineEdit()->text();
 
 1007   int index = cboSymmetryPoint->findText( text );
 
 1010     cboSymmetryPoint->setCurrentIndex( index );
 
 1014     cboSymmetryPoint->setItemText( cboSymmetryPoint->currentIndex(), text );
 
 1015     classifyGraduated();
 
 1022   if ( mBlockUpdates )
 
 1026   QString attrName = mExpressionWidget->currentField();
 
 1027   int nclasses = spinGraduatedClasses->value();
 
 1029   const QString methodId = cboGraduatedMode->currentData().toString();
 
 1033   int attrNum = mLayer->fields().lookupField( attrName );
 
 1037   mLayer->minimumAndMaximumValue( attrNum, minVal, maxVal );
 
 1039   double minimum = minVal.toDouble();
 
 1040   double maximum = maxVal.toDouble();
 
 1041   mSymmetryPointValidator->setBottom( minimum );
 
 1042   mSymmetryPointValidator->setTop( maximum );
 
 1043   mSymmetryPointValidator->setMaxDecimals( spinPrecision->value() );
 
 1051     if ( currentValue < ( minimum + ( maximum - minimum ) / 100. ) || currentValue > ( maximum - ( maximum - minimum ) / 100. ) )
 
 1052       cboSymmetryPoint->setItemText( cboSymmetryPoint->currentIndex(), QLocale().toString( minimum + ( maximum - minimum ) / 2., 
'f', method->
labelPrecision() + 2 ) );
 
 1055   if ( mGroupBoxSymmetric->isChecked() )
 
 1058     bool astride = cbxAstride->isChecked();
 
 1062   QVariantMap parameterValues;
 
 1063   for ( 
const auto &ppww : std::as_const( mParameterWidgetWrappers ) )
 
 1068   mRenderer->setClassificationMethod( method );
 
 1071   mRenderer->setClassAttribute( attrName );
 
 1075   if ( method->
codeComplexity() > 1 && mLayer->featureCount() > 50000 )
 
 1077     if ( QMessageBox::Cancel == QMessageBox::question( 
this, tr( 
"Apply Classification" ), tr( 
"Natural break classification (Jenks) is O(n2) complexity, your classification may take a long time.\nPress cancel to abort breaks calculation or OK to continue." ), QMessageBox::Cancel, QMessageBox::Ok ) )
 
 1083   if ( methodComboBox->currentData() == ColorMode )
 
 1085     std::unique_ptr<QgsColorRamp> ramp( btnColorRamp->colorRamp() );
 
 1088       QMessageBox::critical( 
this, tr( 
"Apply Classification" ), tr( 
"No color ramp defined." ) );
 
 1091     mRenderer->setSourceColorRamp( ramp.release() );
 
 1095     mRenderer->setSourceColorRamp( 
nullptr );
 
 1098   mRenderer->updateClasses( mLayer, nclasses );
 
 1100   if ( methodComboBox->currentData() == SizeMode )
 
 1101     mRenderer->setSymbolSizes( minSizeSpinBox->value(), maxSizeSpinBox->value() );
 
 1103   mRenderer->calculateLabelPrecision();
 
 1106   updateUiFromRenderer( 
false );
 
 1111   std::unique_ptr< QgsColorRamp > ramp( btnColorRamp->colorRamp() );
 
 1115   mRenderer->updateColorRamp( ramp.release() );
 
 1116   mRenderer->updateSymbols( mGraduatedSymbol.get() );
 
 1117   refreshSymbolView();
 
 1122   mRenderer->setSymbolSizes( minSizeSpinBox->value(), maxSizeSpinBox->value() );
 
 1123   mRenderer->updateSymbols( mGraduatedSymbol.get() );
 
 1124   refreshSymbolView();
 
 1128 int QgsRendererPropertiesDialog::currentRangeRow()
 
 1130   QModelIndex idx = viewGraduated->selectionModel()->currentIndex();
 
 1131   if ( !idx.isValid() )
 
 1140   QModelIndexList selectedRows = viewGraduated->selectionModel()->selectedRows();
 
 1142   const auto constSelectedRows = selectedRows;
 
 1143   for ( 
const QModelIndex &r : constSelectedRows )
 
 1147       rows.append( r.row() );
 
 1156   QModelIndexList selectedRows = viewGraduated->selectionModel()->selectedRows();
 
 1157   QModelIndexList::const_iterator sIt = selectedRows.constBegin();
 
 1159   for ( ; sIt != selectedRows.constEnd(); ++sIt )
 
 1161     selectedRanges.append( mModel->rendererRange( *sIt ) );
 
 1163   return selectedRanges;
 
 1168   if ( idx.isValid() && idx.column() == 0 )
 
 1169     changeRangeSymbol( idx.row() );
 
 1170   if ( idx.isValid() && idx.column() == 1 )
 
 1171     changeRange( idx.row() );
 
 1176   if ( !idx.isValid() )
 
 1179     mRowSelected = idx.row();
 
 1189   std::unique_ptr< QgsSymbol > newSymbol( range.
symbol()->
clone() );
 
 1206     if ( !dlg.exec() || !newSymbol )
 
 1211     mGraduatedSymbol = std::move( newSymbol );
 
 1212     whileBlocking( btnChangeGraduatedSymbol )->setSymbol( mGraduatedSymbol->clone() );
 
 1213     applyChangeToSymbol();
 
 1224   int decimalPlaces = mRenderer->classificationMethod()->labelPrecision() + 2;
 
 1225   if ( decimalPlaces < 0 ) decimalPlaces = 0;
 
 1229   if ( dialog.exec() == QDialog::Accepted )
 
 1235     if ( cbxLinkBoundaries->isChecked() )
 
 1239         mRenderer->updateRangeUpperValue( rangeIdx - 1, dialog.
lowerValueDouble() );
 
 1242       if ( rangeIdx < mRenderer->ranges().size() - 1 )
 
 1244         mRenderer->updateRangeLowerValue( rangeIdx + 1, dialog.
upperValueDouble() );
 
 1248   mHistogramWidget->refresh();
 
 1249   emit widgetChanged();
 
 1254   mModel->addClass( mGraduatedSymbol.get() );
 
 1255   mHistogramWidget->refresh();
 
 1256   emit widgetChanged();
 
 1262   QList<int> classIndexes = selectedClasses();
 
 1263   mModel->deleteRows( classIndexes );
 
 1264   mHistogramWidget->refresh();
 
 1265   emit widgetChanged();
 
 1270   mModel->removeAllRows();
 
 1271   mHistogramWidget->refresh();
 
 1272   emit widgetChanged();
 
 1278   bool ordered = 
true;
 
 1279   for ( 
int i = 1; i < ranges.size(); ++i )
 
 1281     if ( ranges[i] < ranges[i - 1] )
 
 1296     if ( ! rowsOrdered() )
 
 1298       int result = QMessageBox::warning(
 
 1300                      tr( 
"Link Class Boundaries" ),
 
 1301                      tr( 
"Rows will be reordered before linking boundaries. Continue?" ),
 
 1302                      QMessageBox::Ok | QMessageBox::Cancel );
 
 1303       if ( result != QMessageBox::Ok )
 
 1305         cbxLinkBoundaries->setChecked( 
false );
 
 1308       mRenderer->sortByValue();
 
 1312     for ( 
int i = 1; i < mRenderer->ranges().size(); ++i )
 
 1314       mRenderer->updateRangeLowerValue( i, mRenderer->ranges()[i - 1].upperValue() );
 
 1316     refreshSymbolView();
 
 1322   if ( item->column() == 2 )
 
 1324     QString label = item->text();
 
 1325     int idx = item->row();
 
 1326     mRenderer->updateRangeLabel( idx, label );
 
 1332   mRenderer->classificationMethod()->setLabelFormat( txtLegendFormat->text() );
 
 1333   mRenderer->classificationMethod()->setLabelPrecision( spinPrecision->value() );
 
 1334   mRenderer->classificationMethod()->setLabelTrimTrailingZeroes( cbxTrimTrailingZeroes->isChecked() );
 
 1335   mRenderer->updateRangeLabels();
 
 1336   mModel->updateLabels();
 
 1342   QList<QgsSymbol *> selectedSymbols;
 
 1344   QItemSelectionModel *m = viewGraduated->selectionModel();
 
 1345   QModelIndexList selectedIndexes = m->selectedRows( 1 );
 
 1346   if ( !selectedIndexes.isEmpty() )
 
 1349     QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
 
 1350     for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
 
 1352       QStringList list = m->model()->data( *indexIt ).toString().split( 
' ' );
 
 1353       if ( list.size() < 3 )
 
 1366       QgsSymbol *s = findSymbolForRange( lowerBound, upperBound, ranges );
 
 1369         selectedSymbols.append( s );
 
 1373   return selectedSymbols;
 
 1378   int decimalPlaces = mRenderer->classificationMethod()->labelPrecision() + 2;
 
 1379   if ( decimalPlaces < 0 )
 
 1381   double precision = 1.0 / std::pow( 10, decimalPlaces );
 
 1383   for ( QgsRangeList::const_iterator it = ranges.begin(); it != ranges.end(); ++it )
 
 1387       return it->symbol();
 
 1397     mModel->updateSymbology();
 
 1399   mHistogramWidget->refresh();
 
 1400   emit widgetChanged();
 
 1405   showSymbolLevelsDialog( mRenderer.get() );
 
 1410   viewGraduated->selectionModel()->clear();
 
 1411   if ( ! rowsOrdered() )
 
 1413     cbxLinkBoundaries->setChecked( 
false );
 
 1415   emit widgetChanged();
 
 1420   emit widgetChanged();
 
 1430   if ( event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier )
 
 1432     mCopyBuffer.clear();
 
 1433     mCopyBuffer = selectedRanges();
 
 1435   else if ( event->key() == Qt::Key_V && event->modifiers() == Qt::ControlModifier )
 
 1437     QgsRangeList::const_iterator rIt = mCopyBuffer.constBegin();
 
 1438     for ( ; rIt != mCopyBuffer.constEnd(); ++rIt )
 
 1440       mModel->addClass( *rIt );
 
 1442     emit widgetChanged();
 
 1446 void QgsGraduatedSymbolRendererWidget::selectionChanged( 
const QItemSelection &, 
const QItemSelection & )
 
 1449   if ( !ranges.isEmpty() )
 
 1451     whileBlocking( btnChangeGraduatedSymbol )->setSymbol( ranges.at( 0 ).symbol()->clone() );
 
 1453   else if ( mRenderer->sourceSymbol() )
 
 1455     whileBlocking( btnChangeGraduatedSymbol )->setSymbol( mRenderer->sourceSymbol()->clone() );
 
 1457   btnChangeGraduatedSymbol->setDialogTitle( ranges.size() == 1 ? ranges.at( 0 ).label() : tr( 
"Symbol Settings" ) );
 
 1460 void QgsGraduatedSymbolRendererWidget::dataDefinedSizeLegend()
 
 1463   QgsDataDefinedSizeLegendWidget *panel = createDataDefinedSizeLegendWidget( s, mRenderer->dataDefinedSizeLegend() );
 
 1468       mRenderer->setDataDefinedSizeLegend( panel->dataDefinedSizeLegend() );
 
 1469       emit widgetChanged();
 
 1475 void QgsGraduatedSymbolRendererWidget::changeGraduatedSymbol()
 
 1477   mGraduatedSymbol.reset( btnChangeGraduatedSymbol->symbol()->clone() );
 
 1478   applyChangeToSymbol();
 
 1487   const QModelIndexList selectedRows = viewGraduated->selectionModel()->selectedRows();
 
 1488   for ( 
const QModelIndex &index : selectedRows )
 
 1490     if ( !index.isValid() )
 
 1493     const int row = index.row();
 
 1494     if ( !mRenderer || mRenderer->ranges().size() <= row )
 
 1497     if ( mRenderer->ranges().at( row ).symbol()->type() != tempSymbol->type() )
 
 1500     std::unique_ptr< QgsSymbol > newCatSymbol( tempSymbol->clone() );
 
 1501     if ( selectedRows.count() > 1 )
 
 1504       newCatSymbol->setColor( mRenderer->ranges().at( row ).symbol()->color() );
 
 1507     mRenderer->updateRangeSymbol( row, newCatSymbol.release() );
 
 1509   emit widgetChanged();