mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Categorized vector GUI DnD and sorting, fixes #2816
This commit is contained in:
parent
ae55e6515e
commit
c4b74c9266
@ -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();
|
||||
};
|
||||
|
@ -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 );
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user