35QgsPointCloudClassifiedRendererModel::QgsPointCloudClassifiedRendererModel( QObject *parent )
36 : QAbstractItemModel( parent )
37 , mMimeFormat( QStringLiteral(
"application/x-qgspointcloudclassifiedrenderermodel" ) )
43 if ( !mCategories.empty() )
45 beginRemoveRows( QModelIndex(), 0, std::max< int >( mCategories.size() - 1, 0 ) );
49 if ( categories.size() > 0 )
51 beginInsertRows( QModelIndex(), 0, categories.size() - 1 );
52 mCategories = categories;
59 const int idx = mCategories.size();
60 beginInsertRows( QModelIndex(), idx, idx );
61 mCategories.append( cat );
64 emit categoriesChanged();
69 const int row = index.row();
70 if ( row >= mCategories.size() )
74 return mCategories.at( row );
77Qt::ItemFlags QgsPointCloudClassifiedRendererModel::flags(
const QModelIndex &index )
const
79 if ( !index.isValid() || mCategories.empty() )
81 return Qt::ItemIsDropEnabled;
84 Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable;
85 if ( index.column() == 1 )
87 flags |= Qt::ItemIsEditable;
89 else if ( index.column() == 2 )
91 flags |= Qt::ItemIsEditable;
96Qt::DropActions QgsPointCloudClassifiedRendererModel::supportedDropActions()
const
98 return Qt::MoveAction;
101QVariant QgsPointCloudClassifiedRendererModel::data(
const QModelIndex &index,
int role )
const
103 if ( !index.isValid() || mCategories.empty() )
110 case Qt::CheckStateRole:
112 if ( index.column() == 0 )
114 return category.
renderState() ? Qt::Checked : Qt::Unchecked;
119 case Qt::DisplayRole:
120 case Qt::ToolTipRole:
122 switch ( index.column() )
126 return QString::number( category.
value() );
129 return category.
label();
131 const float value = mPercentages.value( category.
value(), -1 );
135 else if ( value != 0 && std::round( value * 10 ) < 1 )
136 str = QStringLiteral(
"< " ) + QLocale().toString( 0.1,
'f', 1 );
138 str = QLocale().toString( mPercentages.value( category.
value() ),
'f', 1 );
144 case Qt::DecorationRole:
146 if ( index.column() == 0 )
149 QPixmap pix( iconSize, iconSize );
150 pix.fill( category.
color() );
156 case Qt::TextAlignmentRole:
158 if ( index.column() == 0 )
159 return static_cast<Qt::Alignment::Int
>( Qt::AlignHCenter );
160 if ( index.column() == 3 )
161 return static_cast<Qt::Alignment::Int
>( Qt::AlignRight );
162 return static_cast<Qt::Alignment::Int
>( Qt::AlignLeft );
167 switch ( index.column() )
171 return QString::number( category.
value() );
175 return category.
label();
184bool QgsPointCloudClassifiedRendererModel::setData(
const QModelIndex &index,
const QVariant &value,
int role )
186 if ( !index.isValid() )
189 if ( index.column() == 0 && role == Qt::CheckStateRole )
191 mCategories[ index.row() ].setRenderState( value == Qt::Checked );
192 emit dataChanged( index, index );
193 emit categoriesChanged();
197 if ( role != Qt::EditRole )
200 switch ( index.column() )
204 const int val = value.toInt();
205 mCategories[ index.row() ].setValue( val );
210 mCategories[ index.row() ].setLabel( value.toString() );
217 emit dataChanged( index, index );
218 emit categoriesChanged();
222QVariant QgsPointCloudClassifiedRendererModel::headerData(
int section, Qt::Orientation orientation,
int role )
const
224 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 4 )
227 lst << tr(
"Color" ) << tr(
"Value" ) << tr(
"Legend" ) << tr(
"Percentage" );
228 return lst.value( section );
233int QgsPointCloudClassifiedRendererModel::rowCount(
const QModelIndex &parent )
const
235 if ( parent.isValid() )
239 return mCategories.size();
242int QgsPointCloudClassifiedRendererModel::columnCount(
const QModelIndex &index )
const
248QModelIndex QgsPointCloudClassifiedRendererModel::index(
int row,
int column,
const QModelIndex &parent )
const
250 if ( hasIndex( row, column, parent ) )
252 return createIndex( row, column );
254 return QModelIndex();
257QModelIndex QgsPointCloudClassifiedRendererModel::parent(
const QModelIndex &index )
const
260 return QModelIndex();
263QStringList QgsPointCloudClassifiedRendererModel::mimeTypes()
const
266 types << mMimeFormat;
270QMimeData *QgsPointCloudClassifiedRendererModel::mimeData(
const QModelIndexList &indexes )
const
272 QMimeData *mimeData =
new QMimeData();
273 QByteArray encodedData;
275 QDataStream stream( &encodedData, QIODevice::WriteOnly );
278 const auto constIndexes = indexes;
279 for (
const QModelIndex &index : constIndexes )
281 if ( !index.isValid() || index.column() != 0 )
284 stream << index.row();
286 mimeData->setData( mMimeFormat, encodedData );
290bool QgsPointCloudClassifiedRendererModel::dropMimeData(
const QMimeData *data, Qt::DropAction action,
int row,
int column,
const QModelIndex &parent )
294 if ( action != Qt::MoveAction )
297 if ( !data->hasFormat( mMimeFormat ) )
300 QByteArray encodedData = data->data( mMimeFormat );
301 QDataStream stream( &encodedData, QIODevice::ReadOnly );
304 while ( !stream.atEnd() )
311 int to = parent.row();
315 to = mCategories.size();
316 for (
int i = rows.size() - 1; i >= 0; i-- )
322 if ( !( rows[i] < 0 || rows[i] >= mCategories.size() || t < 0 || t >= mCategories.size() ) )
324 mCategories.move( rows[i], t );
328 for (
int j = 0; j < i; j++ )
330 if ( to < rows[j] && rows[i] > rows[j] )
337 emit dataChanged( createIndex( 0, 0 ), createIndex( mCategories.size(), 0 ) );
338 emit categoriesChanged();
342void QgsPointCloudClassifiedRendererModel::deleteRows( QList<int> rows )
344 std::sort( rows.begin(), rows.end() );
345 for (
int i = rows.size() - 1; i >= 0; i-- )
347 beginRemoveRows( QModelIndex(), rows[i], rows[i] );
348 mCategories.removeAt( rows[i] );
351 emit categoriesChanged();
354void QgsPointCloudClassifiedRendererModel::removeAllRows()
356 beginRemoveRows( QModelIndex(), 0, mCategories.size() - 1 );
359 emit categoriesChanged();
362void QgsPointCloudClassifiedRendererModel::setCategoryColor(
int row,
const QColor &color )
364 mCategories[row].setColor( color );
365 emit dataChanged( createIndex( row, 0 ), createIndex( row, 0 ) );
366 emit categoriesChanged();
370QgsPointCloudClassifiedRendererViewStyle::QgsPointCloudClassifiedRendererViewStyle( QWidget *parent )
374void QgsPointCloudClassifiedRendererViewStyle::drawPrimitive( PrimitiveElement element,
const QStyleOption *option, QPainter *painter,
const QWidget *widget )
const
376 if ( element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull() )
378 QStyleOption opt( *option );
379 opt.rect.setLeft( 0 );
381 opt.rect.setHeight( 0 );
383 opt.rect.setRight( widget->width() );
384 QProxyStyle::drawPrimitive( element, &opt, painter, widget );
387 QProxyStyle::drawPrimitive( element, option, painter, widget );
396 mAttributeComboBox->setAllowEmptyAttributeName(
true );
399 mModel =
new QgsPointCloudClassifiedRendererModel(
this );
403 mAttributeComboBox->setLayer( layer );
405 setFromRenderer( layer->
renderer() );
408 viewCategories->setModel( mModel );
409 viewCategories->resizeColumnToContents( 0 );
410 viewCategories->resizeColumnToContents( 1 );
411 viewCategories->resizeColumnToContents( 2 );
413 viewCategories->setStyle(
new QgsPointCloudClassifiedRendererViewStyle( viewCategories ) );
416 this, &QgsPointCloudClassifiedRendererWidget::attributeChanged );
417 connect( mModel, &QgsPointCloudClassifiedRendererModel::categoriesChanged,
this, &QgsPointCloudClassifiedRendererWidget::emitWidgetChanged );
419 connect( viewCategories, &QAbstractItemView::doubleClicked,
this, &QgsPointCloudClassifiedRendererWidget::categoriesDoubleClicked );
420 connect( btnAddCategories, &QAbstractButton::clicked,
this, &QgsPointCloudClassifiedRendererWidget::addCategories );
421 connect( btnDeleteCategories, &QAbstractButton::clicked,
this, &QgsPointCloudClassifiedRendererWidget::deleteCategories );
422 connect( btnDeleteAllCategories, &QAbstractButton::clicked,
this, &QgsPointCloudClassifiedRendererWidget::deleteAllCategories );
423 connect( btnAddCategory, &QAbstractButton::clicked,
this, &QgsPointCloudClassifiedRendererWidget::addCategory );
429 return new QgsPointCloudClassifiedRendererWidget( layer, style );
439 std::unique_ptr< QgsPointCloudClassifiedRenderer > renderer = std::make_unique< QgsPointCloudClassifiedRenderer >();
440 renderer->setAttribute( mAttributeComboBox->currentAttribute() );
441 renderer->setCategories( mModel->categories() );
443 return renderer.release();
448 return mModel->categories();
451QString QgsPointCloudClassifiedRendererWidget::attribute()
453 return mAttributeComboBox->currentAttribute();
456void QgsPointCloudClassifiedRendererWidget::attributeChanged()
458 if ( mBlockChangedSignal )
461 mBlockChangedSignal =
true;
462 mModel->removeAllRows();
463 mBlockChangedSignal =
false;
467void QgsPointCloudClassifiedRendererWidget::emitWidgetChanged()
469 if ( mBlockChangedSignal )
472 updateCategoriesPercentages();
473 emit widgetChanged();
476void QgsPointCloudClassifiedRendererWidget::categoriesDoubleClicked(
const QModelIndex &idx )
478 if ( idx.isValid() && idx.column() == 0 )
479 changeCategorySymbol();
482void QgsPointCloudClassifiedRendererWidget::addCategories()
484 if ( !mLayer || !mLayer->dataProvider() )
488 const QString currentAttribute = mAttributeComboBox->currentAttribute();
490 const QList<int> providerCategories = stats.
classesOf( currentAttribute );
494 const bool isClassificationAttribute = ! currentAttribute.compare( QStringLiteral(
"Classification" ), Qt::CaseInsensitive );
497 mBlockChangedSignal =
true;
498 for (
const int &providerCategory : providerCategories )
504 if (
c.value() == providerCategory )
515 if ( isClassificationAttribute )
519 if (
c.value() == providerCategory )
527 mModel->addCategory( category );
529 mBlockChangedSignal =
false;
533void QgsPointCloudClassifiedRendererWidget::addCategory()
539 mModel->addCategory( cat );
542void QgsPointCloudClassifiedRendererWidget::deleteCategories()
544 const QList<int> categoryIndexes = selectedCategories();
545 mModel->deleteRows( categoryIndexes );
548void QgsPointCloudClassifiedRendererWidget::deleteAllCategories()
550 mModel->removeAllRows();
555 mBlockChangedSignal =
true;
558 mModel->setRendererCategories( classifiedRenderer->categories() );
559 mAttributeComboBox->setAttribute( classifiedRenderer->attribute() );
565 mBlockChangedSignal =
false;
569void QgsPointCloudClassifiedRendererWidget::setFromCategories(
QgsPointCloudCategoryList categories,
const QString &attribute )
571 mBlockChangedSignal =
true;
572 mModel->setRendererCategories( categories );
573 if ( !attribute.isEmpty() )
575 mAttributeComboBox->setAttribute( attribute );
581 mBlockChangedSignal =
false;
585void QgsPointCloudClassifiedRendererWidget::initialize()
587 if ( mAttributeComboBox->findText( QStringLiteral(
"Classification" ) ) > -1 )
589 mAttributeComboBox->setAttribute( QStringLiteral(
"Classification" ) );
593 mAttributeComboBox->setCurrentIndex( mAttributeComboBox->count() > 1 ? 1 : 0 );
595 mModel->removeAllRows();
599void QgsPointCloudClassifiedRendererWidget::changeCategorySymbol()
601 const int row = currentCategoryRow();
617 mModel->setCategoryColor( row, newColor );
624 if ( newColor.isValid() )
626 mModel->setCategoryColor( row, newColor );
631QList<int> QgsPointCloudClassifiedRendererWidget::selectedCategories()
634 const QModelIndexList selectedRows = viewCategories->selectionModel()->selectedRows();
635 for (
const QModelIndex &r : selectedRows )
639 rows.append( r.row() );
645int QgsPointCloudClassifiedRendererWidget::currentCategoryRow()
647 const QModelIndex idx = viewCategories->selectionModel()->currentIndex();
648 if ( !idx.isValid() )
653void QgsPointCloudClassifiedRendererWidget::updateCategoriesPercentages()
655 QMap < int, float > percentages;
666 if ( classes.contains( category.
value() ) || statsExact )
667 percentages.insert( category.
value(), (
double ) classes.value( category.
value() ) / pointCount * 100 );
669 mModel->updateCategoriesPercentages( percentages );
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application's color scheme registry, used for managing color schemes.
static QColor getColor(const QColor &initialColor, QWidget *parent, const QString &title=QString(), bool allowOpacity=false)
Returns a color selection from a color dialog.
QColor fetchRandomStyleColor() const
Returns a random color for use with a new symbol style (e.g.
void attributeChanged(const QString &name)
Emitted when the currently selected attribute changes.
@ Char
Character attributes.
Represents an individual category (class) from a QgsPointCloudClassifiedRenderer.
int value() const
Returns the value corresponding to this category.
bool renderState() const
Returns true if the category is currently enabled and should be rendered.
QColor color() const
Returns the color which will be used to render this category.
QString label() const
Returns the label for this category, which is used to represent the category within legends and the l...
Renders point clouds by a classification attribute.
Represents a map layer supporting display of point clouds.
QgsPointCloudRenderer * renderer()
Returns the 2D renderer for the point cloud.
static QgsPointCloudCategoryList classificationAttributeCategories(const QgsPointCloudLayer *layer)
Returns a list of categories using the available Classification classes of a specified layer,...
Abstract base class for 2d point cloud renderers.
Class used to store statistics of a point cloud dataset.
QMap< int, int > availableClasses(const QString &attribute) const
Returns a map containing the count of each class of the attribute attribute If no matching statistic ...
QList< int > classesOf(const QString &attribute) const
Returns a list of existing classes which are present for the specified attribute.
int sampledPointsCount() const
Returns the number of points used to calculate the statistics.
A QProxyStyle subclass which correctly sets the base style to match the QGIS application style,...
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,...
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QList< QgsPointCloudCategory > QgsPointCloudCategoryList