QGIS API Documentation  3.2.0-Bonn (bc43194)
qgsgraduatedsymbolrendererwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgraduatedsymbolrendererwidget.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
16 #include "qgspanelwidget.h"
17 
20 #include "qgssymbol.h"
21 #include "qgssymbollayerutils.h"
22 #include "qgscolorramp.h"
23 #include "qgscolorrampbutton.h"
24 #include "qgsstyle.h"
25 
26 #include "qgsvectorlayer.h"
27 
30 #include "qgslogger.h"
31 
32 #include "qgsludialog.h"
33 
34 #include "qgsproject.h"
35 #include "qgsmapcanvas.h"
36 
37 #include <QKeyEvent>
38 #include <QMenu>
39 #include <QMessageBox>
40 #include <QStandardItemModel>
41 #include <QStandardItem>
42 #include <QPen>
43 #include <QPainter>
44 
45 // ------------------------------ Model ------------------------------------
46 
48 
49 QgsGraduatedSymbolRendererModel::QgsGraduatedSymbolRendererModel( QObject *parent ) : QAbstractItemModel( parent )
50  , mMimeFormat( QStringLiteral( "application/x-qgsgraduatedsymbolrendererv2model" ) )
51 {
52 }
53 
54 void QgsGraduatedSymbolRendererModel::setRenderer( QgsGraduatedSymbolRenderer *renderer )
55 {
56  if ( mRenderer )
57  {
58  if ( mRenderer->ranges().size() )
59  {
60  beginRemoveRows( QModelIndex(), 0, mRenderer->ranges().size() - 1 );
61  mRenderer = nullptr;
62  endRemoveRows();
63  }
64  else
65  {
66  mRenderer = nullptr;
67  }
68  }
69  if ( renderer )
70  {
71  if ( renderer->ranges().size() )
72  {
73  beginInsertRows( QModelIndex(), 0, renderer->ranges().size() - 1 );
74  mRenderer = renderer;
75  endInsertRows();
76  }
77  else
78  {
79  mRenderer = renderer;
80  }
81  }
82 }
83 
84 void QgsGraduatedSymbolRendererModel::addClass( QgsSymbol *symbol )
85 {
86  if ( !mRenderer ) return;
87  int idx = mRenderer->ranges().size();
88  beginInsertRows( QModelIndex(), idx, idx );
89  mRenderer->addClass( symbol );
90  endInsertRows();
91 }
92 
93 void QgsGraduatedSymbolRendererModel::addClass( const QgsRendererRange &range )
94 {
95  if ( !mRenderer )
96  {
97  return;
98  }
99  int idx = mRenderer->ranges().size();
100  beginInsertRows( QModelIndex(), idx, idx );
101  mRenderer->addClass( range );
102  endInsertRows();
103 }
104 
105 QgsRendererRange QgsGraduatedSymbolRendererModel::rendererRange( const QModelIndex &index )
106 {
107  if ( !index.isValid() || !mRenderer || mRenderer->ranges().size() <= index.row() )
108  {
109  return QgsRendererRange();
110  }
111 
112  return mRenderer->ranges().value( index.row() );
113 }
114 
115 Qt::ItemFlags QgsGraduatedSymbolRendererModel::flags( const QModelIndex &index ) const
116 {
117  if ( !index.isValid() )
118  {
119  return Qt::ItemIsDropEnabled;
120  }
121 
122  Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable;
123 
124  if ( index.column() == 2 )
125  {
126  flags |= Qt::ItemIsEditable;
127  }
128 
129  return flags;
130 }
131 
132 Qt::DropActions QgsGraduatedSymbolRendererModel::supportedDropActions() const
133 {
134  return Qt::MoveAction;
135 }
136 
137 QVariant QgsGraduatedSymbolRendererModel::data( const QModelIndex &index, int role ) const
138 {
139  if ( !index.isValid() || !mRenderer ) return QVariant();
140 
141  const QgsRendererRange range = mRenderer->ranges().value( index.row() );
142 
143  if ( role == Qt::CheckStateRole && index.column() == 0 )
144  {
145  return range.renderState() ? Qt::Checked : Qt::Unchecked;
146  }
147  else if ( role == Qt::DisplayRole || role == Qt::ToolTipRole )
148  {
149  switch ( index.column() )
150  {
151  case 1:
152  {
153  int decimalPlaces = mRenderer->labelFormat().precision() + 2;
154  if ( decimalPlaces < 0 ) decimalPlaces = 0;
155  return QString::number( range.lowerValue(), 'f', decimalPlaces ) + " - " + QString::number( range.upperValue(), 'f', decimalPlaces );
156  }
157  case 2:
158  return range.label();
159  default:
160  return QVariant();
161  }
162  }
163  else if ( role == Qt::DecorationRole && index.column() == 0 && range.symbol() )
164  {
165  return QgsSymbolLayerUtils::symbolPreviewIcon( range.symbol(), QSize( 16, 16 ) );
166  }
167  else if ( role == Qt::TextAlignmentRole )
168  {
169  return ( index.column() == 0 ) ? Qt::AlignHCenter : Qt::AlignLeft;
170  }
171  else if ( role == Qt::EditRole )
172  {
173  switch ( index.column() )
174  {
175  // case 1: return rangeStr;
176  case 2:
177  return range.label();
178  default:
179  return QVariant();
180  }
181  }
182 
183  return QVariant();
184 }
185 
186 bool QgsGraduatedSymbolRendererModel::setData( const QModelIndex &index, const QVariant &value, int role )
187 {
188  if ( !index.isValid() )
189  return false;
190 
191  if ( index.column() == 0 && role == Qt::CheckStateRole )
192  {
193  mRenderer->updateRangeRenderState( index.row(), value == Qt::Checked );
194  emit dataChanged( index, index );
195  return true;
196  }
197 
198  if ( role != Qt::EditRole )
199  return false;
200 
201  switch ( index.column() )
202  {
203  case 1: // range
204  return false; // range is edited in popup dialog
205  case 2: // label
206  mRenderer->updateRangeLabel( index.row(), value.toString() );
207  break;
208  default:
209  return false;
210  }
211 
212  emit dataChanged( index, index );
213  return true;
214 }
215 
216 QVariant QgsGraduatedSymbolRendererModel::headerData( int section, Qt::Orientation orientation, int role ) const
217 {
218  if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 3 )
219  {
220  QStringList lst;
221  lst << tr( "Symbol" ) << tr( "Values" ) << tr( "Legend" );
222  return lst.value( section );
223  }
224  return QVariant();
225 }
226 
227 int QgsGraduatedSymbolRendererModel::rowCount( const QModelIndex &parent ) const
228 {
229  if ( parent.isValid() || !mRenderer )
230  {
231  return 0;
232  }
233  return mRenderer->ranges().size();
234 }
235 
236 int QgsGraduatedSymbolRendererModel::columnCount( const QModelIndex &index ) const
237 {
238  Q_UNUSED( index );
239  return 3;
240 }
241 
242 QModelIndex QgsGraduatedSymbolRendererModel::index( int row, int column, const QModelIndex &parent ) const
243 {
244  if ( hasIndex( row, column, parent ) )
245  {
246  return createIndex( row, column );
247  }
248  return QModelIndex();
249 }
250 
251 QModelIndex QgsGraduatedSymbolRendererModel::parent( const QModelIndex &index ) const
252 {
253  Q_UNUSED( index );
254  return QModelIndex();
255 }
256 
257 QStringList QgsGraduatedSymbolRendererModel::mimeTypes() const
258 {
259  QStringList types;
260  types << mMimeFormat;
261  return types;
262 }
263 
264 QMimeData *QgsGraduatedSymbolRendererModel::mimeData( const QModelIndexList &indexes ) const
265 {
266  QMimeData *mimeData = new QMimeData();
267  QByteArray encodedData;
268 
269  QDataStream stream( &encodedData, QIODevice::WriteOnly );
270 
271  // Create list of rows
272  Q_FOREACH ( const QModelIndex &index, indexes )
273  {
274  if ( !index.isValid() || index.column() != 0 )
275  continue;
276 
277  stream << index.row();
278  }
279  mimeData->setData( mMimeFormat, encodedData );
280  return mimeData;
281 }
282 
283 bool QgsGraduatedSymbolRendererModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
284 {
285  Q_UNUSED( row );
286  Q_UNUSED( column );
287  if ( action != Qt::MoveAction ) return true;
288 
289  if ( !data->hasFormat( mMimeFormat ) ) return false;
290 
291  QByteArray encodedData = data->data( mMimeFormat );
292  QDataStream stream( &encodedData, QIODevice::ReadOnly );
293 
294  QVector<int> rows;
295  while ( !stream.atEnd() )
296  {
297  int r;
298  stream >> r;
299  rows.append( r );
300  }
301 
302  int to = parent.row();
303  // to is -1 if dragged outside items, i.e. below any item,
304  // then move to the last position
305  if ( to == -1 ) to = mRenderer->ranges().size(); // out of rang ok, will be decreased
306  for ( int i = rows.size() - 1; i >= 0; i-- )
307  {
308  QgsDebugMsg( QStringLiteral( "move %1 to %2" ).arg( rows[i] ).arg( to ) );
309  int t = to;
310  // moveCategory first removes and then inserts
311  if ( rows[i] < t ) t--;
312  mRenderer->moveClass( rows[i], t );
313  // current moved under another, shift its index up
314  for ( int j = 0; j < i; j++ )
315  {
316  if ( to < rows[j] && rows[i] > rows[j] ) rows[j] += 1;
317  }
318  // removed under 'to' so the target shifted down
319  if ( rows[i] < to ) to--;
320  }
321  emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->ranges().size(), 0 ) );
322  emit rowsMoved();
323  return false;
324 }
325 
326 void QgsGraduatedSymbolRendererModel::deleteRows( QList<int> rows )
327 {
328  for ( int i = rows.size() - 1; i >= 0; i-- )
329  {
330  beginRemoveRows( QModelIndex(), rows[i], rows[i] );
331  mRenderer->deleteClass( rows[i] );
332  endRemoveRows();
333  }
334 }
335 
336 void QgsGraduatedSymbolRendererModel::removeAllRows()
337 {
338  beginRemoveRows( QModelIndex(), 0, mRenderer->ranges().size() - 1 );
339  mRenderer->deleteAllClasses();
340  endRemoveRows();
341 }
342 
343 void QgsGraduatedSymbolRendererModel::sort( int column, Qt::SortOrder order )
344 {
345  if ( column == 0 )
346  {
347  return;
348  }
349  if ( column == 1 )
350  {
351  mRenderer->sortByValue( order );
352  }
353  else if ( column == 2 )
354  {
355  mRenderer->sortByLabel( order );
356  }
357  emit rowsMoved();
358  emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->ranges().size(), 0 ) );
359 }
360 
361 void QgsGraduatedSymbolRendererModel::updateSymbology( bool resetModel )
362 {
363  if ( resetModel )
364  {
365  reset();
366  }
367  else
368  {
369  emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->ranges().size(), 0 ) );
370  }
371 }
372 
373 void QgsGraduatedSymbolRendererModel::updateLabels()
374 {
375  emit dataChanged( createIndex( 0, 2 ), createIndex( mRenderer->ranges().size(), 2 ) );
376 }
377 
378 // ------------------------------ View style --------------------------------
379 QgsGraduatedSymbolRendererViewStyle::QgsGraduatedSymbolRendererViewStyle( QWidget *parent )
380  : QgsProxyStyle( parent )
381 {}
382 
383 void QgsGraduatedSymbolRendererViewStyle::drawPrimitive( PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget ) const
384 {
385  if ( element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull() )
386  {
387  QStyleOption opt( *option );
388  opt.rect.setLeft( 0 );
389  // draw always as line above, because we move item to that index
390  opt.rect.setHeight( 0 );
391  if ( widget ) opt.rect.setRight( widget->width() );
392  QProxyStyle::drawPrimitive( element, &opt, painter, widget );
393  return;
394  }
395  QProxyStyle::drawPrimitive( element, option, painter, widget );
396 }
397 
399 
400 // ------------------------------ Widget ------------------------------------
401 
403 {
404  return new QgsGraduatedSymbolRendererWidget( layer, style, renderer );
405 }
406 
407 QgsExpressionContext QgsGraduatedSymbolRendererWidget::createExpressionContext() const
408 {
409  QgsExpressionContext expContext;
413 
414  if ( mContext.mapCanvas() )
415  {
416  expContext << QgsExpressionContextUtils::mapSettingsScope( mContext.mapCanvas()->mapSettings() )
417  << new QgsExpressionContextScope( mContext.mapCanvas()->expressionContextScope() );
418  }
419  else
420  {
422  }
423 
424  if ( vectorLayer() )
425  expContext << QgsExpressionContextUtils::layerScope( vectorLayer() );
426 
427  // additional scopes
428  Q_FOREACH ( const QgsExpressionContextScope &scope, mContext.additionalExpressionContextScopes() )
429  {
430  expContext.appendScope( new QgsExpressionContextScope( scope ) );
431  }
432 
433  return expContext;
434 }
435 
437  : QgsRendererWidget( layer, style )
438 
439 {
440 
441 
442  // try to recognize the previous renderer
443  // (null renderer means "no previous renderer")
444  if ( renderer )
445  {
446  mRenderer.reset( QgsGraduatedSymbolRenderer::convertFromRenderer( renderer ) );
447  }
448  if ( !mRenderer )
449  {
450  mRenderer = qgis::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
451  }
452 
453  // setup user interface
454  setupUi( this );
455  connect( methodComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsGraduatedSymbolRendererWidget::methodComboBox_currentIndexChanged );
456  this->layout()->setContentsMargins( 0, 0, 0, 0 );
457 
458  mModel = new QgsGraduatedSymbolRendererModel( this );
459 
460  mExpressionWidget->setFilters( QgsFieldProxyModel::Numeric | QgsFieldProxyModel::Date );
461  mExpressionWidget->setLayer( mLayer );
462 
465 
466  spinPrecision->setMinimum( QgsRendererRangeLabelFormat::MIN_PRECISION );
467  spinPrecision->setMaximum( QgsRendererRangeLabelFormat::MAX_PRECISION );
468 
469  btnColorRamp->setShowRandomColorRamp( true );
470 
471  // set project default color ramp
472  QString defaultColorRamp = QgsProject::instance()->readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/ColorRamp" ), QLatin1String( "" ) );
473  if ( !defaultColorRamp.isEmpty() )
474  {
475  btnColorRamp->setColorRampFromName( defaultColorRamp );
476  }
477  else
478  {
479  QgsColorRamp *ramp = new QgsGradientColorRamp( QColor( 255, 255, 255 ), QColor( 255, 0, 0 ) );
480  btnColorRamp->setColorRamp( ramp );
481  delete ramp;
482  }
483 
484 
485  viewGraduated->setStyle( new QgsGraduatedSymbolRendererViewStyle( viewGraduated ) );
486 
487  mGraduatedSymbol.reset( QgsSymbol::defaultSymbol( mLayer->geometryType() ) );
488 
489  methodComboBox->blockSignals( true );
490  methodComboBox->addItem( QStringLiteral( "Color" ) );
491  if ( mGraduatedSymbol->type() == QgsSymbol::Marker )
492  {
493  methodComboBox->addItem( QStringLiteral( "Size" ) );
494  minSizeSpinBox->setValue( 1 );
495  maxSizeSpinBox->setValue( 8 );
496  }
497  else if ( mGraduatedSymbol->type() == QgsSymbol::Line )
498  {
499  methodComboBox->addItem( QStringLiteral( "Size" ) );
500  minSizeSpinBox->setValue( .1 );
501  maxSizeSpinBox->setValue( 2 );
502  }
503  methodComboBox->blockSignals( false );
504 
505  connect( mExpressionWidget, static_cast < void ( QgsFieldExpressionWidget::* )( const QString & ) >( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsGraduatedSymbolRendererWidget::graduatedColumnChanged );
506  connect( viewGraduated, &QAbstractItemView::doubleClicked, this, &QgsGraduatedSymbolRendererWidget::rangesDoubleClicked );
507  connect( viewGraduated, &QAbstractItemView::clicked, this, &QgsGraduatedSymbolRendererWidget::rangesClicked );
508  connect( viewGraduated, &QTreeView::customContextMenuRequested, this, &QgsGraduatedSymbolRendererWidget::contextMenuViewCategories );
509 
510  connect( btnGraduatedClassify, &QAbstractButton::clicked, this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
511  connect( btnChangeGraduatedSymbol, &QAbstractButton::clicked, this, &QgsGraduatedSymbolRendererWidget::changeGraduatedSymbol );
512  connect( btnGraduatedDelete, &QAbstractButton::clicked, this, &QgsGraduatedSymbolRendererWidget::deleteClasses );
513  connect( btnDeleteAllClasses, &QAbstractButton::clicked, this, &QgsGraduatedSymbolRendererWidget::deleteAllClasses );
514  connect( btnGraduatedAdd, &QAbstractButton::clicked, this, &QgsGraduatedSymbolRendererWidget::addClass );
515  connect( cbxLinkBoundaries, &QAbstractButton::toggled, this, &QgsGraduatedSymbolRendererWidget::toggleBoundariesLink );
516 
517  connect( mSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsGraduatedSymbolRendererWidget::mSizeUnitWidget_changed );
518 
520 
521  // initialize from previously set renderer
523 
524  // menus for data-defined rotation/size
525  QMenu *advMenu = new QMenu( this );
526 
527  advMenu->addAction( tr( "Symbol Levels…" ), this, SLOT( showSymbolLevels() ) );
528  if ( mGraduatedSymbol->type() == QgsSymbol::Marker )
529  {
530  QAction *actionDdsLegend = advMenu->addAction( tr( "Data-defined Size Legend…" ) );
531  // only from Qt 5.6 there is convenience addAction() with new style connection
532  connect( actionDdsLegend, &QAction::triggered, this, &QgsGraduatedSymbolRendererWidget::dataDefinedSizeLegend );
533  }
534 
535  btnAdvanced->setMenu( advMenu );
536 
537  mHistogramWidget->setLayer( mLayer );
538  mHistogramWidget->setRenderer( mRenderer.get() );
540  connect( mExpressionWidget, static_cast < void ( QgsFieldExpressionWidget::* )( const QString & ) >( &QgsFieldExpressionWidget::fieldChanged ), mHistogramWidget, &QgsHistogramWidget::setSourceFieldExp );
541 
542  mExpressionWidget->registerExpressionContextGenerator( this );
543 }
544 
545 void QgsGraduatedSymbolRendererWidget::mSizeUnitWidget_changed()
546 {
547  if ( !mGraduatedSymbol ) return;
548  mGraduatedSymbol->setOutputUnit( mSizeUnitWidget->unit() );
549  mGraduatedSymbol->setMapUnitScale( mSizeUnitWidget->getMapUnitScale() );
551  mRenderer->updateSymbols( mGraduatedSymbol.get() );
553 }
554 
556 {
557  delete mModel;
558 }
559 
561 {
562  return mRenderer.get();
563 }
564 
565 // Connect/disconnect event handlers which trigger updating renderer
566 
568 {
569  connect( spinGraduatedClasses, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
570  connect( cboGraduatedMode, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
572  connect( spinPrecision, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsGraduatedSymbolRendererWidget::labelFormatChanged );
573  connect( cbxTrimTrailingZeroes, &QAbstractButton::toggled, this, &QgsGraduatedSymbolRendererWidget::labelFormatChanged );
574  connect( txtLegendFormat, &QLineEdit::textChanged, this, &QgsGraduatedSymbolRendererWidget::labelFormatChanged );
575  connect( minSizeSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsGraduatedSymbolRendererWidget::reapplySizes );
576  connect( maxSizeSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsGraduatedSymbolRendererWidget::reapplySizes );
577 
578  connect( mModel, &QgsGraduatedSymbolRendererModel::rowsMoved, this, &QgsGraduatedSymbolRendererWidget::rowsMoved );
579  connect( mModel, &QAbstractItemModel::dataChanged, this, &QgsGraduatedSymbolRendererWidget::modelDataChanged );
580 }
581 
582 // Connect/disconnect event handlers which trigger updating renderer
583 
585 {
586  disconnect( spinGraduatedClasses, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
587  disconnect( cboGraduatedMode, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsGraduatedSymbolRendererWidget::classifyGraduated );
589  disconnect( spinPrecision, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsGraduatedSymbolRendererWidget::labelFormatChanged );
590  disconnect( cbxTrimTrailingZeroes, &QAbstractButton::toggled, this, &QgsGraduatedSymbolRendererWidget::labelFormatChanged );
591  disconnect( txtLegendFormat, &QLineEdit::textChanged, this, &QgsGraduatedSymbolRendererWidget::labelFormatChanged );
592  disconnect( minSizeSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsGraduatedSymbolRendererWidget::reapplySizes );
593  disconnect( maxSizeSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsGraduatedSymbolRendererWidget::reapplySizes );
594 
595  disconnect( mModel, &QgsGraduatedSymbolRendererModel::rowsMoved, this, &QgsGraduatedSymbolRendererWidget::rowsMoved );
596  disconnect( mModel, &QAbstractItemModel::dataChanged, this, &QgsGraduatedSymbolRendererWidget::modelDataChanged );
597 }
598 
600 {
602 
604 
605  // update UI from the graduated renderer (update combo boxes, view)
606  if ( mRenderer->mode() < cboGraduatedMode->count() )
607  cboGraduatedMode->setCurrentIndex( mRenderer->mode() );
608 
609  // Only update class count if different - otherwise typing value gets very messy
610  int nclasses = mRenderer->ranges().count();
611  if ( nclasses && updateCount )
612  spinGraduatedClasses->setValue( mRenderer->ranges().count() );
613 
614  // set column
615  QString attrName = mRenderer->classAttribute();
616  mExpressionWidget->setField( attrName );
617  mHistogramWidget->setSourceFieldExp( attrName );
618 
619  // set source symbol
620  if ( mRenderer->sourceSymbol() )
621  {
622  mGraduatedSymbol.reset( mRenderer->sourceSymbol()->clone() );
624  }
625 
626  mModel->setRenderer( mRenderer.get() );
627  viewGraduated->setModel( mModel );
628 
629  if ( mGraduatedSymbol )
630  {
631  mSizeUnitWidget->blockSignals( true );
632  mSizeUnitWidget->setUnit( mGraduatedSymbol->outputUnit() );
633  mSizeUnitWidget->setMapUnitScale( mGraduatedSymbol->mapUnitScale() );
634  mSizeUnitWidget->blockSignals( false );
635  }
636 
637  // set source color ramp
638  methodComboBox->blockSignals( true );
639  if ( mRenderer->graduatedMethod() == QgsGraduatedSymbolRenderer::GraduatedColor )
640  {
641  methodComboBox->setCurrentIndex( 0 );
642  if ( mRenderer->sourceColorRamp() )
643  {
644  btnColorRamp->setColorRamp( mRenderer->sourceColorRamp() );
645  }
646  }
647  else
648  {
649  methodComboBox->setCurrentIndex( 1 );
650  if ( !mRenderer->ranges().isEmpty() ) // avoid overriding default size with zeros
651  {
652  minSizeSpinBox->setValue( mRenderer->minSymbolSize() );
653  maxSizeSpinBox->setValue( mRenderer->maxSymbolSize() );
654  }
655  }
656  toggleMethodWidgets( methodComboBox->currentIndex() );
657  methodComboBox->blockSignals( false );
658 
659  QgsRendererRangeLabelFormat labelFormat = mRenderer->labelFormat();
660  txtLegendFormat->setText( labelFormat.format() );
661  spinPrecision->setValue( labelFormat.precision() );
662  cbxTrimTrailingZeroes->setChecked( labelFormat.trimTrailingZeroes() );
663 
664  viewGraduated->resizeColumnToContents( 0 );
665  viewGraduated->resizeColumnToContents( 1 );
666  viewGraduated->resizeColumnToContents( 2 );
667 
668  mHistogramWidget->refresh();
669 
671  emit widgetChanged();
672 }
673 
675 {
676  mRenderer->setClassAttribute( field );
677 }
678 
679 void QgsGraduatedSymbolRendererWidget::methodComboBox_currentIndexChanged( int idx )
680 {
681  toggleMethodWidgets( idx );
682  if ( idx == 0 )
683  {
684  mRenderer->setGraduatedMethod( QgsGraduatedSymbolRenderer::GraduatedColor );
685  QgsColorRamp *ramp = btnColorRamp->colorRamp();
686 
687  if ( !ramp )
688  {
689  QMessageBox::critical( this, tr( "Select Method" ), tr( "No color ramp defined." ) );
690  return;
691  }
692  mRenderer->setSourceColorRamp( ramp );
694  }
695  else
696  {
697  lblColorRamp->setVisible( false );
698  btnColorRamp->setVisible( false );
699  lblSize->setVisible( true );
700  minSizeSpinBox->setVisible( true );
701  lblSize->setVisible( true );
702  maxSizeSpinBox->setVisible( true );
703  mSizeUnitWidget->setVisible( true );
704 
705  mRenderer->setGraduatedMethod( QgsGraduatedSymbolRenderer::GraduatedSize );
706  reapplySizes();
707  }
708 }
709 
710 void QgsGraduatedSymbolRendererWidget::toggleMethodWidgets( int idx )
711 {
712  if ( idx == 0 )
713  {
714  lblColorRamp->setVisible( true );
715  btnColorRamp->setVisible( true );
716  lblSize->setVisible( false );
717  minSizeSpinBox->setVisible( false );
718  lblSizeTo->setVisible( false );
719  maxSizeSpinBox->setVisible( false );
720  mSizeUnitWidget->setVisible( false );
721  }
722  else
723  {
724  lblColorRamp->setVisible( false );
725  btnColorRamp->setVisible( false );
726  lblSize->setVisible( true );
727  minSizeSpinBox->setVisible( true );
728  lblSizeTo->setVisible( true );
729  maxSizeSpinBox->setVisible( true );
730  mSizeUnitWidget->setVisible( true );
731  }
732 }
733 
735 {
736  if ( !mModel )
737  return;
738 
739  mModel->updateSymbology( reset );
740  emit widgetChanged();
741 }
742 
743 void QgsGraduatedSymbolRendererWidget::cleanUpSymbolSelector( QgsPanelWidget *container )
744 {
745  QgsSymbolSelectorWidget *dlg = qobject_cast<QgsSymbolSelectorWidget *>( container );
746  if ( !dlg )
747  return;
748 
749  delete dlg->symbol();
750 }
751 
752 void QgsGraduatedSymbolRendererWidget::updateSymbolsFromWidget()
753 {
754  QgsSymbolSelectorWidget *dlg = qobject_cast<QgsSymbolSelectorWidget *>( sender() );
755  mGraduatedSymbol.reset( dlg->symbol()->clone() );
756 
758 }
759 
761 {
762  mSizeUnitWidget->blockSignals( true );
763  mSizeUnitWidget->setUnit( mGraduatedSymbol->outputUnit() );
764  mSizeUnitWidget->setMapUnitScale( mGraduatedSymbol->mapUnitScale() );
765  mSizeUnitWidget->blockSignals( false );
766 
767  QItemSelectionModel *m = viewGraduated->selectionModel();
768  QModelIndexList selectedIndexes = m->selectedRows( 1 );
769  if ( m && !selectedIndexes.isEmpty() )
770  {
771  Q_FOREACH ( const QModelIndex &idx, selectedIndexes )
772  {
773  if ( idx.isValid() )
774  {
775  int rangeIdx = idx.row();
776  QgsSymbol *newRangeSymbol = mGraduatedSymbol->clone();
777  if ( selectedIndexes.count() > 1 )
778  {
779  //if updating multiple ranges, retain the existing range colors
780  newRangeSymbol->setColor( mRenderer->ranges().at( rangeIdx ).symbol()->color() );
781  }
782  mRenderer->updateRangeSymbol( rangeIdx, newRangeSymbol );
783  }
784  }
785  }
786  else
787  {
788  mRenderer->updateSymbols( mGraduatedSymbol.get() );
789  }
790 
792  emit widgetChanged();
793 }
794 
795 
797 {
798  QString attrName = mExpressionWidget->currentField();
799 
800  int nclasses = spinGraduatedClasses->value();
801 
802  std::unique_ptr<QgsColorRamp> ramp( btnColorRamp->colorRamp() );
803  if ( !ramp )
804  {
805  QMessageBox::critical( this, tr( "Apply Classification" ), tr( "No color ramp defined." ) );
806  return;
807  }
808 
810  if ( cboGraduatedMode->currentIndex() == 0 )
812  else if ( cboGraduatedMode->currentIndex() == 2 )
814  else if ( cboGraduatedMode->currentIndex() == 3 )
816  else if ( cboGraduatedMode->currentIndex() == 4 )
818  else // default should be quantile for now
820 
821  // Jenks is n^2 complexity, warn for big dataset (more than 50k records)
822  // and give the user the chance to cancel
823  if ( QgsGraduatedSymbolRenderer::Jenks == mode && mLayer->featureCount() > 50000 )
824  {
825  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 ) )
826  return;
827  }
828 
829  // create and set new renderer
830 
831  mRenderer->setClassAttribute( attrName );
832  mRenderer->setMode( mode );
833 
834  if ( methodComboBox->currentIndex() == 0 )
835  {
836  if ( !ramp )
837  {
838  QMessageBox::critical( this, tr( "Apply Classification" ), tr( "No color ramp defined." ) );
839  return;
840  }
841  mRenderer->setSourceColorRamp( ramp.release() );
842  }
843  else
844  {
845  mRenderer->setSourceColorRamp( nullptr );
846  }
847 
848  QApplication::setOverrideCursor( Qt::WaitCursor );
849  mRenderer->updateClasses( mLayer, mode, nclasses );
850 
851  if ( methodComboBox->currentIndex() == 1 )
852  mRenderer->setSymbolSizes( minSizeSpinBox->value(), maxSizeSpinBox->value() );
853 
854  mRenderer->calculateLabelPrecision();
855  QApplication::restoreOverrideCursor();
856  // PrettyBreaks and StdDev calculation don't generate exact
857  // number of classes - leave user interface unchanged for these
858  updateUiFromRenderer( false );
859 }
860 
862 {
863  std::unique_ptr< QgsColorRamp > ramp( btnColorRamp->colorRamp() );
864  if ( !ramp )
865  return;
866 
867  mRenderer->updateColorRamp( ramp.release() );
868  mRenderer->updateSymbols( mGraduatedSymbol.get() );
870 }
871 
873 {
874  mRenderer->setSymbolSizes( minSizeSpinBox->value(), maxSizeSpinBox->value() );
875  mRenderer->updateSymbols( mGraduatedSymbol.get() );
877 }
878 
880 {
882  std::unique_ptr< QgsSymbol > newSymbol( mGraduatedSymbol->clone() );
883  if ( panel && panel->dockMode() )
884  {
885  QgsSymbolSelectorWidget *dlg = new QgsSymbolSelectorWidget( newSymbol.release(), mStyle, mLayer, panel );
886  dlg->setContext( mContext );
887 
888  connect( dlg, &QgsPanelWidget::widgetChanged, this, &QgsGraduatedSymbolRendererWidget::updateSymbolsFromWidget );
889  connect( dlg, &QgsPanelWidget::panelAccepted, this, &QgsGraduatedSymbolRendererWidget::cleanUpSymbolSelector );
891  panel->openPanel( dlg );
892  }
893  else
894  {
895  QgsSymbolSelectorDialog dlg( newSymbol.get(), mStyle, mLayer, panel );
896  if ( !dlg.exec() || !newSymbol )
897  {
898  return;
899  }
900 
901  mGraduatedSymbol = std::move( newSymbol );
904  }
905 }
906 
908 {
909  if ( !mGraduatedSymbol )
910  return;
911 
912  QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( mGraduatedSymbol.get(), btnChangeGraduatedSymbol->iconSize() );
913  btnChangeGraduatedSymbol->setIcon( icon );
914 }
915 
916 #if 0
917 int QgsRendererPropertiesDialog::currentRangeRow()
918 {
919  QModelIndex idx = viewGraduated->selectionModel()->currentIndex();
920  if ( !idx.isValid() )
921  return -1;
922  return idx.row();
923 }
924 #endif
925 
927 {
928  QList<int> rows;
929  QModelIndexList selectedRows = viewGraduated->selectionModel()->selectedRows();
930 
931  Q_FOREACH ( const QModelIndex &r, selectedRows )
932  {
933  if ( r.isValid() )
934  {
935  rows.append( r.row() );
936  }
937  }
938  return rows;
939 }
940 
942 {
944  QModelIndexList selectedRows = viewGraduated->selectionModel()->selectedRows();
945  QModelIndexList::const_iterator sIt = selectedRows.constBegin();
946 
947  for ( ; sIt != selectedRows.constEnd(); ++sIt )
948  {
949  selectedRanges.append( mModel->rendererRange( *sIt ) );
950  }
951  return selectedRanges;
952 }
953 
955 {
956  if ( idx.isValid() && idx.column() == 0 )
957  changeRangeSymbol( idx.row() );
958  if ( idx.isValid() && idx.column() == 1 )
959  changeRange( idx.row() );
960 }
961 
963 {
964  if ( !idx.isValid() )
965  mRowSelected = -1;
966  else
967  mRowSelected = idx.row();
968 }
969 
971 {
972 }
973 
975 {
976  std::unique_ptr< QgsSymbol > newSymbol( mRenderer->ranges()[rangeIdx].symbol()->clone() );
978  if ( panel && panel->dockMode() )
979  {
980  QgsSymbolSelectorWidget *dlg = new QgsSymbolSelectorWidget( newSymbol.get(), mStyle, mLayer, panel );
981  dlg->setContext( mContext );
982  connect( dlg, &QgsPanelWidget::widgetChanged, this, &QgsGraduatedSymbolRendererWidget::updateSymbolsFromWidget );
983  connect( dlg, &QgsPanelWidget::panelAccepted, this, &QgsGraduatedSymbolRendererWidget::cleanUpSymbolSelector );
984  openPanel( dlg );
985  }
986  else
987  {
988  QgsSymbolSelectorDialog dlg( newSymbol.get(), mStyle, mLayer, panel );
989  dlg.setContext( mContext );
990  if ( !dlg.exec() || !newSymbol )
991  {
992  return;
993  }
994 
995  mGraduatedSymbol = std::move( newSymbol );
997  }
998 }
999 
1001 {
1002  QgsLUDialog dialog( this );
1003 
1004  const QgsRendererRange &range = mRenderer->ranges()[rangeIdx];
1005  // Add arbitrary 2 to number of decimal places to retain a bit extra.
1006  // Ensures users can see if legend is not completely honest!
1007  int decimalPlaces = mRenderer->labelFormat().precision() + 2;
1008  if ( decimalPlaces < 0 ) decimalPlaces = 0;
1009  dialog.setLowerValue( QString::number( range.lowerValue(), 'f', decimalPlaces ) );
1010  dialog.setUpperValue( QString::number( range.upperValue(), 'f', decimalPlaces ) );
1011 
1012  if ( dialog.exec() == QDialog::Accepted )
1013  {
1014  double lowerValue = dialog.lowerValue().toDouble();
1015  double upperValue = dialog.upperValue().toDouble();
1016  mRenderer->updateRangeUpperValue( rangeIdx, upperValue );
1017  mRenderer->updateRangeLowerValue( rangeIdx, lowerValue );
1018 
1019  //If the boundaries have to stay linked, we update the ranges above and below, as well as their label if needed
1020  if ( cbxLinkBoundaries->isChecked() )
1021  {
1022  if ( rangeIdx > 0 )
1023  {
1024  mRenderer->updateRangeUpperValue( rangeIdx - 1, lowerValue );
1025  }
1026 
1027  if ( rangeIdx < mRenderer->ranges().size() - 1 )
1028  {
1029  mRenderer->updateRangeLowerValue( rangeIdx + 1, upperValue );
1030  }
1031  }
1032  }
1033  mHistogramWidget->refresh();
1034  emit widgetChanged();
1035 }
1036 
1038 {
1039  mModel->addClass( mGraduatedSymbol.get() );
1040  mHistogramWidget->refresh();
1041 }
1042 
1044 {
1045  QList<int> classIndexes = selectedClasses();
1046  mModel->deleteRows( classIndexes );
1047  mHistogramWidget->refresh();
1048 }
1049 
1051 {
1052  mModel->removeAllRows();
1053  mHistogramWidget->refresh();
1054 }
1055 
1057 {
1058  const QgsRangeList &ranges = mRenderer->ranges();
1059  bool ordered = true;
1060  for ( int i = 1; i < ranges.size(); ++i )
1061  {
1062  if ( ranges[i] < ranges[i - 1] )
1063  {
1064  ordered = false;
1065  break;
1066  }
1067  }
1068  return ordered;
1069 }
1070 
1072 {
1073  //If the checkbox controlling the link between boundaries was unchecked and we check it, we have to link the boundaries
1074  //This is done by updating all lower ranges to the upper value of the range above
1075  if ( linked )
1076  {
1077  if ( ! rowsOrdered() )
1078  {
1079  int result = QMessageBox::warning(
1080  this,
1081  tr( "Link Class Boundaries" ),
1082  tr( "Rows will be reordered before linking boundaries. Continue?" ),
1083  QMessageBox::Ok | QMessageBox::Cancel );
1084  if ( result != QMessageBox::Ok )
1085  {
1086  cbxLinkBoundaries->setChecked( false );
1087  return;
1088  }
1089  mRenderer->sortByValue();
1090  }
1091 
1092  // Ok to proceed
1093  for ( int i = 1; i < mRenderer->ranges().size(); ++i )
1094  {
1095  mRenderer->updateRangeLowerValue( i, mRenderer->ranges()[i - 1].upperValue() );
1096  }
1098  }
1099 }
1100 
1102 {
1103  if ( item->column() == 2 )
1104  {
1105  QString label = item->text();
1106  int idx = item->row();
1107  mRenderer->updateRangeLabel( idx, label );
1108  }
1109 }
1110 
1112 {
1114  txtLegendFormat->text(),
1115  spinPrecision->value(),
1116  cbxTrimTrailingZeroes->isChecked() );
1117  mRenderer->setLabelFormat( labelFormat, true );
1118  mModel->updateLabels();
1119 }
1120 
1121 
1123 {
1124  QList<QgsSymbol *> selectedSymbols;
1125 
1126  QItemSelectionModel *m = viewGraduated->selectionModel();
1127  QModelIndexList selectedIndexes = m->selectedRows( 1 );
1128  if ( m && !selectedIndexes.isEmpty() )
1129  {
1130  const QgsRangeList &ranges = mRenderer->ranges();
1131  QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
1132  for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
1133  {
1134  QStringList list = m->model()->data( *indexIt ).toString().split( ' ' );
1135  if ( list.size() < 3 )
1136  {
1137  continue;
1138  }
1139 
1140  double lowerBound = list.at( 0 ).toDouble();
1141  double upperBound = list.at( 2 ).toDouble();
1142  QgsSymbol *s = findSymbolForRange( lowerBound, upperBound, ranges );
1143  if ( s )
1144  {
1145  selectedSymbols.append( s );
1146  }
1147  }
1148  }
1149  return selectedSymbols;
1150 }
1151 
1152 QgsSymbol *QgsGraduatedSymbolRendererWidget::findSymbolForRange( double lowerBound, double upperBound, const QgsRangeList &ranges ) const
1153 {
1154  int decimalPlaces = mRenderer->labelFormat().precision() + 2;
1155  if ( decimalPlaces < 0 )
1156  decimalPlaces = 0;
1157  double precision = 1.0 / std::pow( 10, decimalPlaces );
1158 
1159  for ( QgsRangeList::const_iterator it = ranges.begin(); it != ranges.end(); ++it )
1160  {
1161  if ( qgsDoubleNear( lowerBound, it->lowerValue(), precision ) && qgsDoubleNear( upperBound, it->upperValue(), precision ) )
1162  {
1163  return it->symbol();
1164  }
1165  }
1166  return nullptr;
1167 }
1168 
1170 {
1171  if ( mModel )
1172  {
1173  mModel->updateSymbology();
1174  }
1175  mHistogramWidget->refresh();
1176  emit widgetChanged();
1177 }
1178 
1180 {
1181  showSymbolLevelsDialog( mRenderer.get() );
1182 }
1183 
1185 {
1186  viewGraduated->selectionModel()->clear();
1187  if ( ! rowsOrdered() )
1188  {
1189  cbxLinkBoundaries->setChecked( false );
1190  }
1191  emit widgetChanged();
1192 }
1193 
1195 {
1196  emit widgetChanged();
1197 }
1198 
1200 {
1201  if ( !event )
1202  {
1203  return;
1204  }
1205 
1206  if ( event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier )
1207  {
1208  mCopyBuffer.clear();
1209  mCopyBuffer = selectedRanges();
1210  }
1211  else if ( event->key() == Qt::Key_V && event->modifiers() == Qt::ControlModifier )
1212  {
1213  QgsRangeList::const_iterator rIt = mCopyBuffer.constBegin();
1214  for ( ; rIt != mCopyBuffer.constEnd(); ++rIt )
1215  {
1216  mModel->addClass( *rIt );
1217  }
1218  emit widgetChanged();
1219  }
1220 }
1221 
1222 void QgsGraduatedSymbolRendererWidget::dataDefinedSizeLegend()
1223 {
1224  QgsMarkerSymbol *s = static_cast<QgsMarkerSymbol *>( mGraduatedSymbol.get() ); // this should be only enabled for marker symbols
1225  QgsDataDefinedSizeLegendWidget *panel = createDataDefinedSizeLegendWidget( s, mRenderer->dataDefinedSizeLegend() );
1226  if ( panel )
1227  {
1228  connect( panel, &QgsPanelWidget::widgetChanged, this, [ = ]
1229  {
1230  mRenderer->setDataDefinedSizeLegend( panel->dataDefinedSizeLegend() );
1231  emit widgetChanged();
1232  } );
1233  openPanel( panel ); // takes ownership of the panel
1234  }
1235 }
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
const QgsRendererRangeLabelFormat & labelFormat() const
Returns the label format used to generate default classification labels.
static QgsGraduatedSymbolRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
creates a QgsGraduatedSymbolRenderer from an existing renderer.
The QgsFieldExpressionWidget class reates a widget to choose fields and edit expressions It contains ...
bool dockMode()
Returns the dock mode state.
QString readEntry(const QString &scope, const QString &key, const QString &def=QString(), bool *ok=nullptr) const
QList< QgsRendererRange > QgsRangeList
QgsSymbol * symbol()
Returns the symbol that is currently active in the widget.
void showSymbolLevelsDialog(QgsFeatureRenderer *r)
show a dialog with renderer&#39;s symbol level settings
void colorRampChanged()
Emitted whenever a new color ramp is set for the button.
Base class for renderer settings widgets.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:251
Abstract base class for color ramps.
Definition: qgscolorramp.h:31
QgsVectorLayer * mLayer
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Base class for any widget that can be shown as a inline panel.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
Line symbol.
Definition: qgssymbol.h:86
A QProxyStyle subclass which correctly sets the base style to match the QGIS application style...
Definition: qgsproxystyle.h:30
void setLowerValue(const QString &val)
Definition: qgsludialog.cpp:37
void rangesModified(bool rangesAdded)
Emitted when the user modifies the graduated ranges using the histogram widget.
void panelAccepted(QgsPanelWidget *panel)
Emitted when the panel is accepted by the user.
QList< QgsUnitTypes::RenderUnit > RenderUnitList
List of render units.
Definition: qgsunittypes.h:173
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
The QgsMapSettings class contains configuration for rendering of the map.
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns new default symbol for specified geometry type.
Definition: qgssymbol.cpp:267
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
static QIcon symbolPreviewIcon(QgsSymbol *symbol, QSize size, int padding=0)
Returns an icon preview for a color ramp.
Date or datetime fields.
QgsGraduatedSymbolRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget...
Widget for configuration of appearance of legend for marker symbols with data-defined size...
long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
void applyChangeToSymbol()
Applies current symbol to selected ranges, or to all ranges if none is selected.
void setSourceFieldExp(const QString &fieldOrExp)
Sets the source field or expression to use for values in the histogram.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
points (e.g., for font sizes)
Definition: qgsunittypes.h:107
QList< int > selectedClasses()
Returns a list of indexes for the classes under selection.
QgsDataDefinedSizeLegendWidget * createDataDefinedSizeLegendWidget(const QgsMarkerSymbol *symbol, const QgsDataDefinedSizeLegend *ddsLegend)
Creates widget to setup data-defined size legend.
Symbol selector widget that can be used to select and build a symbol.
QgsSymbol * symbol() const
QgsFeatureRenderer * renderer() override
Returns pointer to the renderer (no transfer of ownership)
Single scope for storing variables and functions for use within a QgsExpressionContext.
void addClass()
Adds a class manually to the classification.
void widgetChanged()
Emitted when the widget state changes.
void moveClass(int from, int to)
Moves the category at index position from to index position to.
void fieldChanged(const QString &fieldName)
the signal is emitted when the currently selected field changes
Marker symbol.
Definition: qgssymbol.h:85
QList< QgsSymbol * > selectedSymbols() override
Subclasses may provide the capability of changing multiple symbols at once by implementing the follow...
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
static QgsExpressionContextScope * atlasScope(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...
QgsSymbolWidgetContext mContext
Context in which widget is shown.
void sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration as set up in the dialog (may be null). Ownership is passed to the caller...
virtual QgsSymbol * clone() const =0
Gets a deep copy of this symbol.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:391
void toggleBoundariesLink(bool linked)
Toggle the link between classes boundaries.
void contextMenuViewCategories(QPoint p)
void deleteAllClasses()
Removes all classes from the classification.
void setUpperValue(const QString &val)
Definition: qgsludialog.cpp:42
bool updateRangeRenderState(int rangeIndex, bool render)
QString lowerValue() const
Definition: qgsludialog.cpp:27
bool updateRangeLabel(int rangeIndex, const QString &label)
QString upperValue() const
Definition: qgsludialog.cpp:32
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
Definition: qgscolorramp.h:139
Represents a vector layer which manages a vector based data sets.
const QgsRangeList & ranges() const
QgsSymbol * findSymbolForRange(double lowerBound, double upperBound, const QgsRangeList &ranges) const
void deleteClasses()
Removes currently selected classes.
QgsVectorLayer * layer()
Returns the layer currently associated with the widget.
void setColor(const QColor &color)
Definition: qgssymbol.cpp:440