From 03216df7f86d469e14b95f719223525a75b459a4 Mon Sep 17 00:00:00 2001 From: wonder Date: Sun, 30 May 2010 10:20:38 +0000 Subject: [PATCH] [FEATURE] manual adding of categories in symbology-ng. Patch contributed by Lynx, thanks! + added missing python bindings and fixed some issues. git-svn-id: http://svn.osgeo.org/qgis/trunk@13601 c8812cc2-4d05-0410-92ff-de0c093fc19c --- python/core/symbology-ng-core.sip | 3 + .../qgscategorizedsymbolrendererv2.cpp | 27 ++++- .../qgscategorizedsymbolrendererv2.h | 5 +- .../qgscategorizedsymbolrendererv2widget.cpp | 114 ++++++++++++++---- .../qgscategorizedsymbolrendererv2widget.h | 9 ++ .../qgscategorizedsymbolrendererv2widget.ui | 11 +- 6 files changed, 141 insertions(+), 28 deletions(-) diff --git a/python/core/symbology-ng-core.sip b/python/core/symbology-ng-core.sip index e757fbb7dbb7..95c68bf4e479 100644 --- a/python/core/symbology-ng-core.sip +++ b/python/core/symbology-ng-core.sip @@ -181,6 +181,7 @@ public: QgsSymbolV2* symbol(); QString label() const; + void setValue( const QVariant &value ); void setSymbol(QgsSymbolV2* s /Transfer/); void setLabel(QString label); @@ -220,9 +221,11 @@ public: //! return index of category with specified value (-1 if not found) int categoryIndexForValue(QVariant val); + bool updateCategoryValue( int catIndex, const QVariant &value ); bool updateCategorySymbol(int catIndex, QgsSymbolV2* symbol /Transfer/); bool updateCategoryLabel(int catIndex, QString label); + void addCategory( const QgsRendererCategoryV2 &category ); bool deleteCategory(int catIndex); void deleteAllCategories(); diff --git a/src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp b/src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp index 806b8e9ad5fe..8c8170abb893 100644 --- a/src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp +++ b/src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp @@ -45,6 +45,11 @@ QString QgsRendererCategoryV2::label() const return mLabel; } +void QgsRendererCategoryV2::setValue( const QVariant &value ) +{ + mValue = value; +} + void QgsRendererCategoryV2::setSymbol( QgsSymbolV2* s ) { if ( mSymbol == s ) @@ -53,7 +58,7 @@ void QgsRendererCategoryV2::setSymbol( QgsSymbolV2* s ) mSymbol = s; } -void QgsRendererCategoryV2::setLabel( QString label ) +void QgsRendererCategoryV2::setLabel( const QString &label ) { mLabel = label; } @@ -143,6 +148,14 @@ int QgsCategorizedSymbolRendererV2::categoryIndexForValue( QVariant val ) return -1; } +bool QgsCategorizedSymbolRendererV2::updateCategoryValue( int catIndex, const QVariant &value ) +{ + if ( catIndex < 0 || catIndex >= mCategories.size() ) + return false; + mCategories[catIndex].setValue( value ); + return true; +} + bool QgsCategorizedSymbolRendererV2::updateCategorySymbol( int catIndex, QgsSymbolV2* symbol ) { if ( catIndex < 0 || catIndex >= mCategories.size() ) @@ -159,6 +172,18 @@ bool QgsCategorizedSymbolRendererV2::updateCategoryLabel( int catIndex, QString return true; } +void QgsCategorizedSymbolRendererV2::addCategory( const QgsRendererCategoryV2 &cat ) +{ + if ( cat.symbol() == NULL ) + { + QgsDebugMsg( "invalid symbol in a category! ignoring..." ); + } + else + { + mCategories.append( cat ); + } +} + bool QgsCategorizedSymbolRendererV2::deleteCategory( int catIndex ) { if ( catIndex < 0 || catIndex >= mCategories.size() ) diff --git a/src/core/symbology-ng/qgscategorizedsymbolrendererv2.h b/src/core/symbology-ng/qgscategorizedsymbolrendererv2.h index f5d54f25d6eb..3ab926c9133a 100644 --- a/src/core/symbology-ng/qgscategorizedsymbolrendererv2.h +++ b/src/core/symbology-ng/qgscategorizedsymbolrendererv2.h @@ -24,8 +24,9 @@ class CORE_EXPORT QgsRendererCategoryV2 QgsSymbolV2* symbol() const; QString label() const; + void setValue( const QVariant &value ); void setSymbol( QgsSymbolV2* s ); - void setLabel( QString label ); + void setLabel( const QString &label ); // debugging QString dump(); @@ -65,9 +66,11 @@ class CORE_EXPORT QgsCategorizedSymbolRendererV2 : public QgsFeatureRendererV2 //! return index of category with specified value (-1 if not found) int categoryIndexForValue( QVariant val ); + bool updateCategoryValue( int catIndex, const QVariant &value ); bool updateCategorySymbol( int catIndex, QgsSymbolV2* symbol ); bool updateCategoryLabel( int catIndex, QString label ); + void addCategory( const QgsRendererCategoryV2 &category ); bool deleteCategory( int catIndex ); void deleteAllCategories(); diff --git a/src/gui/symbology-ng/qgscategorizedsymbolrendererv2widget.cpp b/src/gui/symbology-ng/qgscategorizedsymbolrendererv2widget.cpp index ce8e54b77bfe..0e2105954f20 100644 --- a/src/gui/symbology-ng/qgscategorizedsymbolrendererv2widget.cpp +++ b/src/gui/symbology-ng/qgscategorizedsymbolrendererv2widget.cpp @@ -40,6 +40,9 @@ QgsCategorizedSymbolRendererV2Widget::QgsCategorizedSymbolRendererV2Widget( QgsV mRenderer = static_cast( renderer ); } + QString attrName = mRenderer->classAttribute(); + mOldClassificationAttribute = attrName; + // setup user interface setupUi( this ); @@ -47,7 +50,7 @@ QgsCategorizedSymbolRendererV2Widget::QgsCategorizedSymbolRendererV2Widget( QgsV populateColorRamps(); QStandardItemModel* m = new QStandardItemModel( this ); QStringList labels; - labels << "Value" << "Label"; + labels << tr( "Symbol" ) << tr( "Value" ) << tr( "Label" ); m->setHorizontalHeaderLabels( labels ); viewCategories->setModel( m ); @@ -61,6 +64,7 @@ QgsCategorizedSymbolRendererV2Widget::QgsCategorizedSymbolRendererV2Widget( QgsV connect( btnAddCategories, SIGNAL( clicked() ), this, SLOT( addCategories() ) ); connect( btnDeleteCategory, SIGNAL( clicked() ), this, SLOT( deleteCategory() ) ); connect( btnDeleteAllCategories, SIGNAL( clicked() ), this, SLOT( deleteAllCategories() ) ); + connect( btnAddCategory, SIGNAL( clicked() ), this, SLOT( addCategory() ) ); connect( m, SIGNAL( itemChanged( QStandardItem * ) ), this, SLOT( changeCurrentValue( QStandardItem * ) ) ); // update GUI from renderer @@ -81,6 +85,7 @@ void QgsCategorizedSymbolRendererV2Widget::updateUiFromRenderer() // set column disconnect( cboCategorizedColumn, SIGNAL( currentIndexChanged( int ) ), this, SLOT( categoryColumnChanged() ) ); QString attrName = mRenderer->classAttribute(); + mOldClassificationAttribute = attrName; int idx = cboCategorizedColumn->findText( attrName, Qt::MatchExactly ); cboCategorizedColumn->setCurrentIndex( idx >= 0 ? idx : 0 ); connect( cboCategorizedColumn, SIGNAL( currentIndexChanged( int ) ), this, SLOT( categoryColumnChanged() ) ); @@ -127,36 +132,28 @@ void QgsCategorizedSymbolRendererV2Widget::updateCategorizedSymbolIcon() btnChangeCategorizedSymbol->setIcon( icon ); } - void QgsCategorizedSymbolRendererV2Widget::populateCategories() { QStandardItemModel* m = qobject_cast( viewCategories->model() ); m->clear(); QStringList labels; - labels << "Value" << "Label"; + labels << tr( "Symbol" ) << tr( "Value" ) << tr( "Label" ); m->setHorizontalHeaderLabels( labels ); - QSize iconSize( 16, 16 ); - int i, count = mRenderer->categories().count(); // TODO: sort?? utils.sortVariantList(keys); for ( i = 0; i < count; i++ ) { - const QgsRendererCategoryV2& cat = mRenderer->categories()[i]; - QVariant k = cat.value(); - - QIcon icon = QgsSymbolLayerV2Utils::symbolPreviewIcon( cat.symbol(), iconSize ); - QStandardItem* item = new QStandardItem( icon, k.toString() ); - item->setData( k ); // set attribute value as user role - item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled ); - - QList list; - list << item << new QStandardItem( cat.label() ); - m->appendRow( list ); + const QgsRendererCategoryV2 &cat = mRenderer->categories()[i]; + addCategory( cat ); } + + viewCategories->resizeColumnToContents( 0 ); + viewCategories->resizeColumnToContents( 1 ); + viewCategories->resizeColumnToContents( 2 ); } void QgsCategorizedSymbolRendererV2Widget::populateColumns() @@ -185,6 +182,21 @@ void QgsCategorizedSymbolRendererV2Widget::populateColorRamps() } } +void QgsCategorizedSymbolRendererV2Widget::addCategory( const QgsRendererCategoryV2 &cat ) +{ + QSize iconSize( 16, 16 ); + + QIcon icon = QgsSymbolLayerV2Utils::symbolPreviewIcon( cat.symbol(), iconSize ); + QStandardItem *symbolItem = new QStandardItem( icon, "" ); + symbolItem->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled ); + + QStandardItem *valueItem = new QStandardItem( cat.value().toString() ); + valueItem->setData( cat.value() ); // set attribute value as user role + + QList list; + list << symbolItem << valueItem << new QStandardItem( cat.label() ); + qobject_cast( viewCategories->model() )->appendRow( list ); +} void QgsCategorizedSymbolRendererV2Widget::categoryColumnChanged() { @@ -218,9 +230,6 @@ void QgsCategorizedSymbolRendererV2Widget::changeCategorySymbol() populateCategories(); } - - - static void _createCategories( QgsCategoryList& cats, QList& values, QgsSymbolV2* symbol, QgsVectorColorRampV2* ramp ) { // sort the categories first @@ -270,9 +279,47 @@ void QgsCategorizedSymbolRendererV2Widget::addCategories() QgsCategoryList cats; _createCategories( cats, unique_vals, mCategorizedSymbol, ramp ); + bool deleteExisting = false; + if ( !mOldClassificationAttribute.isEmpty() && + attrName != mOldClassificationAttribute && + mRenderer->categories().count() > 0 ) + { + int res = QMessageBox::question( this, + tr( "Confirm Delete" ), + tr( "The classification field was changed from '%1' to '%2'.\n" + "Should the existing classes be deleted before classification?" ) + .arg( mOldClassificationAttribute ).arg( attrName ), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel ); + if ( res == QMessageBox::Cancel ) + return; + if ( res == QMessageBox::Yes ) + deleteExisting = true; + } + + mOldClassificationAttribute = attrName; + + if ( !deleteExisting ) + { + QgsCategoryList prevCats = mRenderer->categories(); + for ( int i = 0; i < cats.size(); ++i ) + { + bool contains = false; + QVariant value = cats.at( i ).value(); + for ( int j = 0; j < prevCats.size() && !contains; ++j ) + { + if ( prevCats.at( j ).value() == value ) + contains = true; + } + + if ( !contains ) + prevCats.append( cats.at( i ) ); + } + cats = prevCats; + } + // TODO: if not all categories are desired, delete some! /* - if (not dlg.radAllCats.isChecked()) + if (not dlg.readAllCats.isChecked()) { cats2 = {} for item in dlg.listCategories.selectedItems(): @@ -307,7 +354,7 @@ QVariant QgsCategorizedSymbolRendererV2Widget::currentCategory() if ( row == -1 ) return QVariant(); QStandardItemModel* m = qobject_cast( viewCategories->model() ); - return m->item( row )->data(); + return m->item( row, 1 )->data(); } void QgsCategorizedSymbolRendererV2Widget::deleteCategory() @@ -333,10 +380,29 @@ void QgsCategorizedSymbolRendererV2Widget::deleteAllCategories() void QgsCategorizedSymbolRendererV2Widget::changeCurrentValue( QStandardItem * item ) { + int idx = item->row(); + QString newtext = item->text(); if ( item->column() == 1 ) { - QString label = item->text(); - int idx = item->row(); - mRenderer->updateCategoryLabel( idx, label ); + QVariant value = newtext; + // try to preserve variant type for this value + QVariant::Type t = item->data().type(); + if ( t == QVariant::Int ) + value = newtext.toInt(); + else if ( t == QVariant::Double ) + value = newtext.toDouble(); + mRenderer->updateCategoryValue( idx, value ); + } + else if ( item->column() == 2 ) + { + mRenderer->updateCategoryLabel( idx, newtext ); } } + +void QgsCategorizedSymbolRendererV2Widget::addCategory() +{ + QgsSymbolV2 *symbol = QgsSymbolV2::defaultSymbol( mLayer->geometryType() ); + QgsRendererCategoryV2 cat( QString(), symbol, QString() ); + addCategory( cat ); + mRenderer->addCategory( cat ); +} diff --git a/src/gui/symbology-ng/qgscategorizedsymbolrendererv2widget.h b/src/gui/symbology-ng/qgscategorizedsymbolrendererv2widget.h index 648917b92883..c9271b5f9ccc 100644 --- a/src/gui/symbology-ng/qgscategorizedsymbolrendererv2widget.h +++ b/src/gui/symbology-ng/qgscategorizedsymbolrendererv2widget.h @@ -5,6 +5,7 @@ #include class QgsCategorizedSymbolRendererV2; +class QgsRendererCategoryV2; #include "ui_qgscategorizedsymbolrendererv2widget.h" @@ -30,6 +31,9 @@ class GUI_EXPORT QgsCategorizedSymbolRendererV2Widget : public QgsRendererV2Widg void deleteAllCategories(); void changeCurrentValue( QStandardItem * item ); + protected slots: + void addCategory(); + protected: void updateUiFromRenderer(); @@ -44,6 +48,8 @@ class GUI_EXPORT QgsCategorizedSymbolRendererV2Widget : public QgsRendererV2Widg void populateColorRamps(); + void addCategory( const QgsRendererCategoryV2& cat ); + //! return row index for the currently selected category (-1 if on no selection) int currentCategoryRow(); @@ -56,6 +62,9 @@ class GUI_EXPORT QgsCategorizedSymbolRendererV2Widget : public QgsRendererV2Widg QgsCategorizedSymbolRendererV2* mRenderer; QgsSymbolV2* mCategorizedSymbol; + + private: + QString mOldClassificationAttribute; }; diff --git a/src/ui/qgscategorizedsymbolrendererv2widget.ui b/src/ui/qgscategorizedsymbolrendererv2widget.ui index 16a48b8adf04..66581e8e0903 100644 --- a/src/ui/qgscategorizedsymbolrendererv2widget.ui +++ b/src/ui/qgscategorizedsymbolrendererv2widget.ui @@ -6,8 +6,8 @@ 0 0 - 464 - 316 + 599 + 298 @@ -114,6 +114,13 @@ + + + + Add + + +