Categorized vector GUI DnD and sorting, fixes #2816

This commit is contained in:
Radim Blazek 2012-11-11 19:51:38 +01:00
parent ae55e6515e
commit c4b74c9266
9 changed files with 499 additions and 163 deletions

View File

@ -16,10 +16,10 @@ class QgsCategorizedSymbolRendererV2Widget : QgsRendererV2Widget
void changeCategorizedSymbol();
void categoryColumnChanged();
void categoriesDoubleClicked( const QModelIndex & idx );
void addCategory();
void addCategories();
void deleteCategory();
void deleteCategories();
void deleteAllCategories();
void changeCurrentValue( QStandardItem * item );
void rotationFieldChanged( QString fldName );
void sizeScaleFieldChanged( QString fldName );
@ -39,19 +39,11 @@ class QgsCategorizedSymbolRendererV2Widget : QgsRendererV2Widget
//! populate column combo
void populateColumns();
void addCategory( const QgsRendererCategoryV2& cat );
//! return row index for the currently selected category (-1 if on no selection)
int currentCategoryRow();
//! return key for the currently selected category
QVariant currentCategory();
void changeCategorySymbol();
QList<QgsSymbolV2*> selectedSymbols();
void refreshSymbolView();
protected slots:
void addCategory();
};

View File

@ -20,6 +20,9 @@
#include "qgsversion.h"
#endif
#include <QCoreApplication>
#include <QDate>
#include <QTime>
#include <QDateTime>
#include "qgsconfig.h"
#include "qgslogger.h"
@ -140,3 +143,36 @@ void QgsFree( void *ptr )
{
free( ptr );
}
bool qgsVariantLessThan( const QVariant& lhs, const QVariant& rhs )
{
switch ( lhs.type() )
{
case QVariant::Int:
return lhs.toInt() < rhs.toInt();
case QVariant::UInt:
return lhs.toUInt() < rhs.toUInt();
case QVariant::LongLong:
return lhs.toLongLong() < rhs.toLongLong();
case QVariant::ULongLong:
return lhs.toULongLong() < rhs.toULongLong();
case QVariant::Double:
return lhs.toDouble() < rhs.toDouble();
case QVariant::Char:
return lhs.toChar() < rhs.toChar();
case QVariant::Date:
return lhs.toDate() < rhs.toDate();
case QVariant::Time:
return lhs.toTime() < rhs.toTime();
case QVariant::DateTime:
return lhs.toDateTime() < rhs.toDateTime();
default:
return QString::localeAwareCompare( lhs.toString(), rhs.toString() ) < 0;
}
}
bool qgsVariantGreaterThan( const QVariant& lhs, const QVariant& rhs )
{
return ! qgsVariantLessThan( lhs, rhs );
}

View File

@ -21,6 +21,7 @@
#include <QEvent>
#include <QString>
#include <QMetaType>
#include <QVariant>
#include <stdlib.h>
#include <cfloat>
#include <cmath>
@ -194,6 +195,10 @@ inline bool doubleNearSig( double a, double b, int significantDigits = 10 )
qRound( ar * pow( 10.0, significantDigits ) ) == qRound( br * pow( 10.0, significantDigits ) ) ;
}
bool qgsVariantLessThan( const QVariant& lhs, const QVariant& rhs );
bool qgsVariantGreaterThan( const QVariant& lhs, const QVariant& rhs );
/** Allocates size bytes and returns a pointer to the allocated memory.
Works like C malloc() but prints debug message by QgsLogger if allocation fails.
@param size size in bytes

View File

@ -12,6 +12,7 @@
* (at your option) any later version. *
* *
***************************************************************************/
#include <algorithm>
#include "qgscategorizedsymbolrendererv2.h"
@ -27,21 +28,40 @@
#include <QDomElement>
#include <QSettings> // for legend
QgsRendererCategoryV2::QgsRendererCategoryV2()
: mValue(), mSymbol( 0 ), mLabel()
{
}
QgsRendererCategoryV2::QgsRendererCategoryV2( QVariant value, QgsSymbolV2* symbol, QString label )
: mValue( value ), mSymbol( symbol ), mLabel( label )
{
}
QgsRendererCategoryV2::QgsRendererCategoryV2( const QgsRendererCategoryV2& cat )
: mValue( cat.mValue ), mLabel( cat.mLabel )
: mValue( cat.mValue ), mSymbol( 0 ), mLabel( cat.mLabel )
{
mSymbol = cat.mSymbol->clone();
if ( cat.mSymbol )
{
mSymbol = cat.mSymbol->clone();
}
}
QgsRendererCategoryV2::~QgsRendererCategoryV2()
{
delete mSymbol;
if ( mSymbol ) delete mSymbol;
}
QgsRendererCategoryV2& QgsRendererCategoryV2::operator=( const QgsRendererCategoryV2 & cat )
{
mValue = cat.mValue;
mLabel = cat.mLabel;
mSymbol = 0;
if ( cat.mSymbol )
{
mSymbol = cat.mSymbol->clone();
}
return *this;
}
QVariant QgsRendererCategoryV2::value() const
@ -293,6 +313,55 @@ void QgsCategorizedSymbolRendererV2::deleteAllCategories()
mCategories.clear();
}
void QgsCategorizedSymbolRendererV2::moveCategory( int from, int to )
{
if ( from < 0 || from >= mCategories.size() || to < 0 || to >= mCategories.size() ) return;
mCategories.move( from, to );
}
bool valueLessThan( const QgsRendererCategoryV2 &c1, const QgsRendererCategoryV2 &c2 )
{
return qgsVariantLessThan( c1.value(), c2.value() );
}
bool valueGreaterThan( const QgsRendererCategoryV2 &c1, const QgsRendererCategoryV2 &c2 )
{
return qgsVariantGreaterThan( c1.value(), c2.value() );
}
void QgsCategorizedSymbolRendererV2::sortByValue( Qt::SortOrder order )
{
if ( order == Qt::AscendingOrder )
{
qSort( mCategories.begin(), mCategories.end(), valueLessThan );
}
else
{
qSort( mCategories.begin(), mCategories.end(), valueGreaterThan );
}
}
bool labelLessThan( const QgsRendererCategoryV2 &c1, const QgsRendererCategoryV2 &c2 )
{
return QString::localeAwareCompare( c1.label(), c2.label() ) < 0;
}
bool labelGreaterThan( const QgsRendererCategoryV2 &c1, const QgsRendererCategoryV2 &c2 )
{
return !labelLessThan( c1, c2 );
}
void QgsCategorizedSymbolRendererV2::sortByLabel( Qt::SortOrder order )
{
if ( order == Qt::AscendingOrder )
{
qSort( mCategories.begin(), mCategories.end(), labelLessThan );
}
else
{
qSort( mCategories.begin(), mCategories.end(), labelGreaterThan );
}
}
void QgsCategorizedSymbolRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
{
// make sure that the hash table is up to date

View File

@ -27,6 +27,7 @@ class QgsVectorLayer;
class CORE_EXPORT QgsRendererCategoryV2
{
public:
QgsRendererCategoryV2( );
//! takes ownership of symbol
QgsRendererCategoryV2( QVariant value, QgsSymbolV2* symbol, QString label );
@ -34,8 +35,11 @@ class CORE_EXPORT QgsRendererCategoryV2
//! copy constructor
QgsRendererCategoryV2( const QgsRendererCategoryV2& cat );
~QgsRendererCategoryV2();
QgsRendererCategoryV2& operator=( const QgsRendererCategoryV2& cat );
QVariant value() const;
QgsSymbolV2* symbol() const;
QString label() const;
@ -100,6 +104,12 @@ class CORE_EXPORT QgsCategorizedSymbolRendererV2 : public QgsFeatureRendererV2
bool deleteCategory( int catIndex );
void deleteAllCategories();
//! Moves the category at index position from to index position to.
void moveCategory( int from, int to );
void sortByValue( Qt::SortOrder order = Qt::AscendingOrder );
void sortByLabel( Qt::SortOrder order = Qt::AscendingOrder );
QString classAttribute() const { return mAttrName; }
void setClassAttribute( QString attr ) { mAttrName = attr; }

View File

@ -2528,6 +2528,7 @@ void QgsSymbolLayerV2Utils::multiplyImageOpacity( QImage* image, qreal alpha )
}
}
#if 0
static bool _QVariantLessThan( const QVariant& lhs, const QVariant& rhs )
{
switch ( lhs.type() )
@ -2559,16 +2560,19 @@ static bool _QVariantGreaterThan( const QVariant& lhs, const QVariant& rhs )
{
return ! _QVariantLessThan( lhs, rhs );
}
#endif
void QgsSymbolLayerV2Utils::sortVariantList( QList<QVariant>& list, Qt::SortOrder order )
{
if ( order == Qt::AscendingOrder )
{
qSort( list.begin(), list.end(), _QVariantLessThan );
//qSort( list.begin(), list.end(), _QVariantLessThan );
qSort( list.begin(), list.end(), qgsVariantLessThan );
}
else // Qt::DescendingOrder
{
qSort( list.begin(), list.end(), _QVariantGreaterThan );
//qSort( list.begin(), list.end(), _QVariantGreaterThan );
qSort( list.begin(), list.end(), qgsVariantGreaterThan );
}
}

View File

@ -12,6 +12,7 @@
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgscategorizedsymbolrendererv2widget.h"
#include "qgscategorizedsymbolrendererv2.h"
@ -32,6 +33,264 @@
#include <QStandardItemModel>
#include <QStandardItem>
QgsCategorizedSymbolRendererV2Model::QgsCategorizedSymbolRendererV2Model( QObject * parent ) : QAbstractItemModel( parent )
, mRenderer( 0 )
, mMimeFormat( "application/x-qgscategorizedsymbolrendererv2model" )
{
}
void QgsCategorizedSymbolRendererV2Model::setRenderer( QgsCategorizedSymbolRendererV2* renderer )
{
if ( mRenderer )
{
beginRemoveRows( QModelIndex(), 0, mRenderer->categories().size() - 1 );
mRenderer = 0;
endRemoveRows();
}
if ( renderer )
{
beginInsertRows( QModelIndex(), 0, renderer->categories().size() - 1 );
mRenderer = renderer;
endInsertRows();
}
}
void QgsCategorizedSymbolRendererV2Model::addCategory( const QgsRendererCategoryV2 &cat )
{
if ( !mRenderer ) return;
int idx = mRenderer->categories().size();
beginInsertRows( QModelIndex(), idx, idx );
mRenderer->addCategory( cat );
endInsertRows();
}
Qt::ItemFlags QgsCategorizedSymbolRendererV2Model::flags( const QModelIndex & index ) const
{
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
if ( index.column() == 1 || index.column() == 2 )
{
flags |= Qt::ItemIsEditable;
}
return flags;
}
Qt::DropActions QgsCategorizedSymbolRendererV2Model::supportedDropActions() const
{
return Qt::MoveAction;
}
QVariant QgsCategorizedSymbolRendererV2Model::data( const QModelIndex &index, int role ) const
{
if ( !index.isValid() || !mRenderer ) return QVariant();
const QgsRendererCategoryV2 category = mRenderer->categories().value( index.row() );
if ( role == Qt::DisplayRole || role == Qt::ToolTipRole )
{
switch ( index.column() )
{
case 1: return category.value().toString();
case 2: return category.label();
default: return QVariant();
}
}
else if ( role == Qt::DecorationRole && index.column() == 0 && category.symbol() )
{
return QgsSymbolLayerV2Utils::symbolPreviewIcon( category.symbol(), QSize( 16, 16 ) );
}
else if ( role == Qt::TextAlignmentRole )
{
return ( index.column() == 0 ) ? Qt::AlignHCenter : Qt::AlignLeft;
}
else if ( role == Qt::EditRole )
{
switch ( index.column() )
{
case 1: return category.value();
case 2: return category.label();
default: return QVariant();
}
}
return QVariant();
}
bool QgsCategorizedSymbolRendererV2Model::setData( const QModelIndex & index, const QVariant & value, int role )
{
if ( !index.isValid() || role != Qt::EditRole )
return false;
switch ( index.column() )
{
case 1: // value
{
// try to preserve variant type for this value
QVariant val;
switch ( mRenderer->categories().value( index.row() ).value().type() )
{
case QVariant::Int:
val = value.toInt();
break;
case QVariant::Double:
val = value.toDouble();
break;
default:
val = value.toString();
break;
}
mRenderer->updateCategoryValue( index.row(), val );
break;
}
case 2: // label
mRenderer->updateCategoryLabel( index.row(), value.toString() );
break;
default:
return false;
}
emit dataChanged( index, index );
return true;
}
QVariant QgsCategorizedSymbolRendererV2Model::headerData( int section, Qt::Orientation orientation, int role ) const
{
if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 3 )
{
QStringList lst; lst << tr( "Symbol" ) << tr( "Value" ) << tr( "Label" );
return lst.value( section );
}
return QVariant();
}
int QgsCategorizedSymbolRendererV2Model::rowCount( const QModelIndex &parent ) const
{
if ( parent.column() > 0 || !mRenderer ) return 0;
return mRenderer->categories().size();
}
int QgsCategorizedSymbolRendererV2Model::columnCount( const QModelIndex & index ) const
{
Q_UNUSED( index );
return 3;
}
QModelIndex QgsCategorizedSymbolRendererV2Model::index( int row, int column, const QModelIndex &parent ) const
{
if ( hasIndex( row, column, parent ) )
{
return createIndex( row, column, 0 );
}
return QModelIndex();
}
QModelIndex QgsCategorizedSymbolRendererV2Model::parent( const QModelIndex &index ) const
{
Q_UNUSED( index );
return QModelIndex();
}
QStringList QgsCategorizedSymbolRendererV2Model::mimeTypes() const
{
QStringList types;
types << mMimeFormat;
return types;
}
QMimeData *QgsCategorizedSymbolRendererV2Model::mimeData( const QModelIndexList &indexes ) const
{
QMimeData *mimeData = new QMimeData();
QByteArray encodedData;
QDataStream stream( &encodedData, QIODevice::WriteOnly );
// Create list of rows
foreach ( const QModelIndex &index, indexes )
{
if ( !index.isValid() || index.column() != 0 )
continue;
stream << index.row();
}
mimeData->setData( mMimeFormat, encodedData );
return mimeData;
}
bool QgsCategorizedSymbolRendererV2Model::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
{
Q_UNUSED( row );
Q_UNUSED( column );
if ( action != Qt::MoveAction ) return true;
if ( !data->hasFormat( mMimeFormat ) ) return false;
QByteArray encodedData = data->data( mMimeFormat );
QDataStream stream( &encodedData, QIODevice::ReadOnly );
QVector<int> rows;
while ( !stream.atEnd() )
{
int r;
stream >> r;
rows.append( r );
}
int to = parent.row();
for ( int i = rows.size() - 1; i >= 0; i-- )
{
QgsDebugMsg( QString( "move %1 to %2" ).arg( rows[i] ).arg( to ) );
int t = to;
// moveCategory first removes and then inserts
if ( rows[i] < to ) t--;
mRenderer->moveCategory( rows[i], t );
// current moved under another, shift its index up
for ( int j = 0; j < i; j++ )
{
if ( to < rows[j] && rows[i] > rows[j] ) rows[j] += 1;
}
// removed under 'to' so the target shifted down
if ( rows[i] < to ) to--;
}
emit dataChanged( createIndex( 0, 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
emit rowsMoved();
return false;
}
void QgsCategorizedSymbolRendererV2Model::removeRows( QList<int> rows )
{
for ( int i = rows.size() - 1; i >= 0; i-- )
{
beginRemoveRows( QModelIndex(), rows[i], rows[i] );
mRenderer->deleteCategory( rows[i] );
endRemoveRows();
}
}
void QgsCategorizedSymbolRendererV2Model::removeAllRows( )
{
beginRemoveRows( QModelIndex(), 0, mRenderer->categories().size() - 1 );
mRenderer->deleteAllCategories();
endRemoveRows();
}
void QgsCategorizedSymbolRendererV2Model::sort( int column, Qt::SortOrder order )
{
QgsDebugMsg( "Entered" );
if ( column == 0 )
{
return;
}
if ( column == 1 )
{
mRenderer->sortByValue( order );
}
else if ( column == 2 )
{
mRenderer->sortByLabel( order );
}
emit dataChanged( createIndex( 0, 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
QgsDebugMsg( "Done" );
}
QgsRendererV2Widget* QgsCategorizedSymbolRendererV2Widget::create( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer )
{
@ -40,6 +299,8 @@ QgsRendererV2Widget* QgsCategorizedSymbolRendererV2Widget::create( QgsVectorLaye
QgsCategorizedSymbolRendererV2Widget::QgsCategorizedSymbolRendererV2Widget( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer )
: QgsRendererV2Widget( layer, style )
, mRenderer( 0 )
, mModel( 0 )
{
// try to recognize the previous renderer
@ -75,14 +336,17 @@ QgsCategorizedSymbolRendererV2Widget::QgsCategorizedSymbolRendererV2Widget( QgsV
cboCategorizedColorRamp->setCurrentIndex( index );
}
QStandardItemModel* m = new QStandardItemModel( this );
QStringList labels;
labels << tr( "Symbol" ) << tr( "Value" ) << tr( "Label" );
m->setHorizontalHeaderLabels( labels );
viewCategories->setModel( m );
mModel = new QgsCategorizedSymbolRendererV2Model( this );
mModel->setRenderer( mRenderer );
viewCategories->setModel( mModel );
viewCategories->resizeColumnToContents( 0 );
viewCategories->resizeColumnToContents( 1 );
viewCategories->resizeColumnToContents( 2 );
mCategorizedSymbol = QgsSymbolV2::defaultSymbol( mLayer->geometryType() );
connect( mModel, SIGNAL( rowsMoved() ), this, SLOT( rowsMoved() ) );
connect( cboCategorizedColumn, SIGNAL( currentIndexChanged( int ) ), this, SLOT( categoryColumnChanged() ) );
connect( viewCategories, SIGNAL( doubleClicked( const QModelIndex & ) ), this, SLOT( categoriesDoubleClicked( const QModelIndex & ) ) );
@ -90,10 +354,9 @@ QgsCategorizedSymbolRendererV2Widget::QgsCategorizedSymbolRendererV2Widget( QgsV
connect( btnChangeCategorizedSymbol, SIGNAL( clicked() ), this, SLOT( changeCategorizedSymbol() ) );
connect( btnAddCategories, SIGNAL( clicked() ), this, SLOT( addCategories() ) );
connect( btnDeleteCategory, SIGNAL( clicked() ), this, SLOT( deleteCategory() ) );
connect( btnDeleteCategories, SIGNAL( clicked() ), this, SLOT( deleteCategories() ) );
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
updateUiFromRenderer();
@ -113,14 +376,15 @@ QgsCategorizedSymbolRendererV2Widget::QgsCategorizedSymbolRendererV2Widget( QgsV
QgsCategorizedSymbolRendererV2Widget::~QgsCategorizedSymbolRendererV2Widget()
{
delete mRenderer;
if ( mRenderer ) delete mRenderer;
if ( mModel ) delete mModel;
}
void QgsCategorizedSymbolRendererV2Widget::updateUiFromRenderer()
{
updateCategorizedSymbolIcon();
populateCategories();
//mModel->setRenderer ( mRenderer ); // necessary?
// set column
disconnect( cboCategorizedColumn, SIGNAL( currentIndexChanged( int ) ), this, SLOT( categoryColumnChanged() ) );
@ -177,8 +441,6 @@ void QgsCategorizedSymbolRendererV2Widget::changeSelectedSymbols()
}
}
}
populateCategories();
}
void QgsCategorizedSymbolRendererV2Widget::changeCategorizedSymbol()
@ -207,7 +469,6 @@ void QgsCategorizedSymbolRendererV2Widget::changeCategorizedSymbol()
updateCategorizedSymbolIcon();
mRenderer->updateSymbols( mCategorizedSymbol );
populateCategories();
}
void QgsCategorizedSymbolRendererV2Widget::updateCategorizedSymbolIcon()
@ -218,26 +479,7 @@ void QgsCategorizedSymbolRendererV2Widget::updateCategorizedSymbolIcon()
void QgsCategorizedSymbolRendererV2Widget::populateCategories()
{
QStandardItemModel* m = qobject_cast<QStandardItemModel*>( viewCategories->model() );
m->clear();
QStringList labels;
labels << tr( "Symbol" ) << tr( "Value" ) << tr( "Label" );
m->setHorizontalHeaderLabels( labels );
int i, count = mRenderer->categories().count();
// TODO: sort?? utils.sortVariantList(keys);
for ( i = 0; i < count; i++ )
{
const QgsRendererCategoryV2 &cat = mRenderer->categories()[i];
addCategory( cat );
}
viewCategories->resizeColumnToContents( 0 );
viewCategories->resizeColumnToContents( 1 );
viewCategories->resizeColumnToContents( 2 );
}
void QgsCategorizedSymbolRendererV2Widget::populateColumns()
@ -251,23 +493,6 @@ void QgsCategorizedSymbolRendererV2Widget::populateColumns()
}
}
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<QStandardItem *> list;
list << symbolItem << valueItem << new QStandardItem( cat.label() );
qobject_cast<QStandardItemModel *>( viewCategories->model() )->appendRow( list );
}
void QgsCategorizedSymbolRendererV2Widget::categoryColumnChanged()
{
mRenderer->setClassAttribute( cboCategorizedColumn->currentText() );
@ -281,29 +506,32 @@ void QgsCategorizedSymbolRendererV2Widget::categoriesDoubleClicked( const QModel
void QgsCategorizedSymbolRendererV2Widget::changeCategorySymbol()
{
QVariant k = currentCategory();
if ( !k.isValid() )
return;
int catIdx = currentCategoryRow();
QgsRendererCategoryV2 category = mRenderer->categories().value( currentCategoryRow() );
int catIdx = mRenderer->categoryIndexForValue( k );
QgsSymbolV2* newSymbol = mRenderer->categories()[catIdx].symbol()->clone();
QgsSymbolV2 *symbol = category.symbol();
if ( symbol )
{
symbol = symbol->clone();
}
else
{
symbol = QgsSymbolV2::defaultSymbol( mLayer->geometryType() );
}
QgsSymbolV2SelectorDialog dlg( newSymbol, mStyle, mLayer, this );
QgsSymbolV2SelectorDialog dlg( symbol, mStyle, mLayer, this );
if ( !dlg.exec() )
{
delete newSymbol;
delete symbol;
return;
}
mRenderer->updateCategorySymbol( catIdx, newSymbol );
populateCategories();
mRenderer->updateCategorySymbol( catIdx, symbol );
}
static void _createCategories( QgsCategoryList& cats, QList<QVariant>& values, QgsSymbolV2* symbol, QgsVectorColorRampV2* ramp )
{
// sort the categories first
//TODO: make the order configurable?
QgsSymbolLayerV2Utils::sortVariantList( values, Qt::AscendingOrder );
int num = values.count();
@ -423,10 +651,13 @@ void QgsCategorizedSymbolRendererV2Widget::addCategories()
r->setScaleMethod( mRenderer->scaleMethod() );
r->setSizeScaleField( mRenderer->sizeScaleField() );
r->setRotationField( mRenderer->rotationField() );
if ( mModel )
{
mModel->setRenderer( r );
}
delete mRenderer;
mRenderer = r;
populateCategories();
}
int QgsCategorizedSymbolRendererV2Widget::currentCategoryRow()
@ -437,87 +668,38 @@ int QgsCategorizedSymbolRendererV2Widget::currentCategoryRow()
return idx.row();
}
QVariant QgsCategorizedSymbolRendererV2Widget::currentCategory()
QList<int> QgsCategorizedSymbolRendererV2Widget::selectedCategories()
{
int row = currentCategoryRow();
if ( row == -1 )
return QVariant();
QStandardItemModel* m = qobject_cast<QStandardItemModel*>( viewCategories->model() );
return m->item( row, 1 )->data();
}
QList<int> rows;
QModelIndexList selectedRows = viewCategories->selectionModel()->selectedRows();
QList<QVariant> QgsCategorizedSymbolRendererV2Widget::selectedCategories()
{
QList<QVariant> categories;
QModelIndexList rows = viewCategories->selectionModel()->selectedRows();
QStandardItemModel* m = qobject_cast<QStandardItemModel*>( viewCategories->model() );
foreach ( QModelIndex r, rows )
foreach ( QModelIndex r, selectedRows )
{
if ( r.isValid() )
{
categories.append( m->item( r.row(), 1 )->data() );
rows.append( r.row() );
}
}
return categories;
return rows;
}
void QgsCategorizedSymbolRendererV2Widget::deleteCategory()
void QgsCategorizedSymbolRendererV2Widget::deleteCategories()
{
QList<QVariant> categories = selectedCategories();
if ( !categories.size() )
return;
foreach ( const QVariant k, categories )
{
if ( k.isValid() )
{
int idx = mRenderer->categoryIndexForValue( k );
if ( idx >= 0 )
{
mRenderer->deleteCategory( idx );
}
}
}
populateCategories();
QList<int> categoryIndexes = selectedCategories();
mModel->removeRows( categoryIndexes );
}
void QgsCategorizedSymbolRendererV2Widget::deleteAllCategories()
{
mRenderer->deleteAllCategories();
populateCategories();
}
void QgsCategorizedSymbolRendererV2Widget::changeCurrentValue( QStandardItem * item )
{
int idx = item->row();
QString newtext = item->text();
if ( item->column() == 1 )
{
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 );
item->setData( value );
}
else if ( item->column() == 2 )
{
mRenderer->updateCategoryLabel( idx, newtext );
}
mModel->removeAllRows();
}
void QgsCategorizedSymbolRendererV2Widget::addCategory()
{
if ( !mModel ) return;
QgsSymbolV2 *symbol = QgsSymbolV2::defaultSymbol( mLayer->geometryType() );
QgsRendererCategoryV2 cat( QString(), symbol, QString() );
addCategory( cat );
mRenderer->addCategory( cat );
mModel->addCategory( cat );
}
void QgsCategorizedSymbolRendererV2Widget::rotationFieldChanged( QString fldName )
@ -548,14 +730,11 @@ QList<QgsSymbolV2*> QgsCategorizedSymbolRendererV2Widget::selectedSymbols()
QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
{
QStandardItem* currentItem = qobject_cast<const QStandardItemModel*>( m->model() )->itemFromIndex( *indexIt );
if ( currentItem )
int row = ( *indexIt ).row();
QgsSymbolV2* s = categories[row].symbol();
if ( s )
{
QgsSymbolV2* s = categories[mRenderer->categoryIndexForValue( currentItem->data() )].symbol();
if ( s )
{
selectedSymbols.append( s );
}
selectedSymbols.append( s );
}
}
}
@ -566,3 +745,8 @@ void QgsCategorizedSymbolRendererV2Widget::showSymbolLevels()
{
showSymbolLevelsDialog( mRenderer );
}
void QgsCategorizedSymbolRendererV2Widget::rowsMoved()
{
viewCategories->selectionModel()->clear();
}

View File

@ -24,6 +24,39 @@ class QgsRendererCategoryV2;
#include "ui_qgscategorizedsymbolrendererv2widget.h"
class GUI_EXPORT QgsCategorizedSymbolRendererV2Model : public QAbstractItemModel
{
Q_OBJECT
public:
QgsCategorizedSymbolRendererV2Model( QObject * parent = 0 );
Qt::ItemFlags flags( const QModelIndex & index ) const;
Qt::DropActions supportedDropActions() const;
QVariant data( const QModelIndex &index, int role ) const;
bool setData( const QModelIndex & index, const QVariant & value, int role );
QVariant headerData( int section, Qt::Orientation orientation, int role ) const;
int rowCount( const QModelIndex &parent = QModelIndex() ) const;
int columnCount( const QModelIndex & = QModelIndex() ) const;
QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const;
QModelIndex parent( const QModelIndex &index ) const;
QStringList mimeTypes() const;
QMimeData *mimeData( const QModelIndexList &indexes ) const;
bool dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent );
void setRenderer( QgsCategorizedSymbolRendererV2* renderer );
void addCategory( const QgsRendererCategoryV2 &cat );
void removeRows( QList<int> rows );
void removeAllRows( );
void sort( int column, Qt::SortOrder order = Qt::AscendingOrder );
signals:
void rowsMoved();
private:
QgsCategorizedSymbolRendererV2* mRenderer;
QString mMimeFormat;
};
class GUI_EXPORT QgsCategorizedSymbolRendererV2Widget : public QgsRendererV2Widget, private Ui::QgsCategorizedSymbolRendererV2Widget
{
Q_OBJECT
@ -39,10 +72,10 @@ class GUI_EXPORT QgsCategorizedSymbolRendererV2Widget : public QgsRendererV2Widg
void changeCategorizedSymbol();
void categoryColumnChanged();
void categoriesDoubleClicked( const QModelIndex & idx );
void addCategory();
void addCategories();
void deleteCategory();
void deleteCategories();
void deleteAllCategories();
void changeCurrentValue( QStandardItem * item );
void rotationFieldChanged( QString fldName );
void sizeScaleFieldChanged( QString fldName );
@ -50,28 +83,25 @@ class GUI_EXPORT QgsCategorizedSymbolRendererV2Widget : public QgsRendererV2Widg
void showSymbolLevels();
void rowsMoved();
protected:
void updateUiFromRenderer();
void updateCategorizedSymbolIcon();
//! populate categories view
// Called by virtual refreshSymbolView()
void populateCategories();
//! populate column combo
void populateColumns();
void addCategory( const QgsRendererCategoryV2& cat );
//! return row index for the currently selected category (-1 if on no selection)
int currentCategoryRow();
//! return key for the currently selected category
QVariant currentCategory();
//! return a list of keys for the categories unders selection
QList<QVariant> selectedCategories();
//! return a list of indexes for the categories unders selection
QList<int> selectedCategories();
//! change the selected symbols alone for the change button, if there is a selection
void changeSelectedSymbols();
@ -81,9 +111,6 @@ class GUI_EXPORT QgsCategorizedSymbolRendererV2Widget : public QgsRendererV2Widg
QList<QgsSymbolV2*> selectedSymbols();
void refreshSymbolView() { populateCategories(); }
protected slots:
void addCategory();
protected:
QgsCategorizedSymbolRendererV2* mRenderer;
@ -91,10 +118,10 @@ class GUI_EXPORT QgsCategorizedSymbolRendererV2Widget : public QgsRendererV2Widg
QgsRendererV2DataDefinedMenus* mDataDefinedMenus;
QgsCategorizedSymbolRendererV2Model* mModel;
private:
QString mOldClassificationAttribute;
};
#endif // QGSCATEGORIZEDSYMBOLRENDERERV2WIDGET_H

View File

@ -94,6 +94,12 @@
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::IgnoreAction</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
@ -106,6 +112,9 @@
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
@ -131,7 +140,7 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDeleteCategory">
<widget class="QPushButton" name="btnDeleteCategories">
<property name="text">
<string>Delete</string>
</property>
@ -191,7 +200,7 @@
<tabstop>cboCategorizedColorRamp</tabstop>
<tabstop>viewCategories</tabstop>
<tabstop>btnAddCategories</tabstop>
<tabstop>btnDeleteCategory</tabstop>
<tabstop>btnDeleteCategories</tabstop>
<tabstop>btnDeleteAllCategories</tabstop>
<tabstop>btnJoinCategories</tabstop>
</tabstops>