Replace QgsNumericSortTreeWidgetItem with upgraded QgsTreeWidgetItem

QgsNumericSortTreeWidgetItem had a giant TODO saying "make it work".
This makes it work, and adds some other useful features like
being able to specify custom sort value and force items to always
sort on top.
This commit is contained in:
Nyall Dawson 2016-07-12 11:51:18 +10:00
parent 631b5e87c3
commit 39b3e721bb
20 changed files with 634 additions and 233 deletions

View File

@ -179,6 +179,21 @@ plugins calling this method will need to be updated.</li>
plugins calling this method will need to be updated.</li>
</ul>
\subsection qgis_api_break_3_0_QgsNumericSortTreeWidgetItem QgsNumericSortTreeWidgetItem
<ul>
<li>QgsNumericSortTreeWidgetItem has been removed and replaced with QgsTreeWidgetItem, which
has improved sort capabilities including the ability to set custom sort values for items
and for forcing certain items to always sort on top.</li>
</ul>
\subsection qgis_api_break_3_0_QgsTreeWidgetItem QgsTreeWidgetItem
<ul>
<li>QgsTreeWidgetItem is no longer a QObject and does not emit the itemEdited signal. Instead,
use QgsTreeWidgetItemObject which is an upgraded version of the original QgsTreeWidgetItem</li>
</ul>
\subsection qgis_api_break_3_0_QgsVectorLayer QgsVectorLayer
<ul>

View File

@ -131,7 +131,6 @@
%Include qgsnewnamedialog.sip
%Include qgsnewvectorlayerdialog.sip
%Include qgsnewgeopackagelayerdialog.sip
%Include qgsnumericsortlistviewitem.sip
%Include qgsoptionsdialogbase.sip
%Include qgsorderbydialog.sip
%Include qgsowssourceselect.sip
@ -162,6 +161,7 @@
%Include qgstablewidgetitem.sip
%Include qgstextannotationitem.sip
%Include qgstrackedvectorlayertools.sip
%Include qgstreewidgetitem.sip
%Include qgsunitselectionwidget.sip
%Include qgsuserinputdockwidget.sip
%Include qgsvariableeditorwidget.sip

View File

@ -1,18 +0,0 @@
class QgsNumericSortTreeWidgetItem : QTreeWidgetItem
{
%TypeHeaderCode
#include <qgsnumericsortlistviewitem.h>
%End
public:
/**
* Constructor.
*/
QgsNumericSortTreeWidgetItem( QTreeWidget * parent );
QgsNumericSortTreeWidgetItem( QTreeWidgetItem * parent );
//! Destructor
virtual ~QgsNumericSortTreeWidgetItem();
virtual bool operator<( const QTreeWidgetItem &other ) const;
};

View File

@ -0,0 +1,129 @@
/** \ingroup gui
* \class QgsTreeWidgetItem
* \note added in QGIS 3.0
* QTreeWidgetItem subclass with custom handling for item sorting.
*
* QgsTreeWidgetItem allows for items to be sorted using a specified user role, and
* also correctly handles sorting numeric or mixed text and numeric values.
*/
class QgsTreeWidgetItem : QTreeWidgetItem
{
%TypeHeaderCode
#include <qgstreewidgetitem.h>
%End
public:
/** Constructor for QgsTreeWidgetItem
* @param view parent QTreeWidget view
* @param type item type
*/
explicit QgsTreeWidgetItem( QTreeWidget * view /TransferThis/, int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param type item type
*/
explicit QgsTreeWidgetItem( int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param strings list of strings containing text for each column in the item
* @param type item type
*/
QgsTreeWidgetItem( const QStringList &strings, int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param view parent QTreeWidget view
* @param strings list of strings containing text for each column in the item
* @param type item type
*/
QgsTreeWidgetItem( QTreeWidget *view /TransferThis/, const QStringList &strings, int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param view parent QTreeWidget view
* @param after QTreeWidgetItem to place insert item after in the view
* @param type item type
*/
QgsTreeWidgetItem( QTreeWidget *view /TransferThis/, QTreeWidgetItem *after, int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param parent QTreeWidgetItem item
* @param type item type
*/
explicit QgsTreeWidgetItem( QTreeWidgetItem *parent /TransferThis/, int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param parent QTreeWidgetItem item
* @param strings list of strings containing text for each column in the item
* @param type item type
*/
QgsTreeWidgetItem( QTreeWidgetItem *parent /TransferThis/, const QStringList &strings, int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param parent QTreeWidgetItem item
* @param after QTreeWidgetItem to place insert item after in the view
* @param type item type
*/
QgsTreeWidgetItem( QTreeWidgetItem *parent /TransferThis/, QTreeWidgetItem *after, int type = Type );
/** Sets the custom sort data for a specified column. If set, this value will be used when
* sorting the item instead of the item's display text. If not set, the item's display
* text will be used when sorting.
* @param column column index
* @param value sort value
* @see sortData()
*/
void setSortData( int column, const QVariant& value );
/** Returns the custom sort data for a specified column. If set, this value will be used when
* sorting the item instead of the item's display text. If not set, the item's display
* text will be used when sorting.
* @see setSortData()
*/
QVariant sortData( int column ) const;
/** Sets a the item to display always on top of other items in the widget, regardless of the
* sort column and sort or display value for the item.
* @param priority priority for sorting always on top items. Items with a lower priority will
* be placed above items with a higher priority.
* @see alwaysOnTopPriority()
*/
void setAlwaysOnTopPriority( int priority );
/** Returns the item's priority when it is set to show always on top. Items with a lower priority will
* be placed above items with a higher priority.
* @returns priority, or -1 if item is not set to show always on top
* @see setAlwaysOnTopPriority()
*/
int alwaysOnTopPriority() const;
virtual bool operator<( const QTreeWidgetItem &other ) const;
};
/** \ingroup gui
* \class QgsTreeWidgetItemObject
* \note added in QGIS 3.0
* Custom QgsTreeWidgetItem with extra signals when item is edited.
*/
class QgsTreeWidgetItemObject: QObject, QgsTreeWidgetItem
{
%TypeHeaderCode
#include <qgstreewidgetitem.h>
%End
public:
/** Constructor for QgsTreeWidgetItemObject
* @param type item type
*/
explicit QgsTreeWidgetItemObject( int type = Type );
/** Constructs a tree widget item of the specified type and appends it to the items in the given parent. */
explicit QgsTreeWidgetItemObject( QTreeWidget * parent /TransferThis/, int type = Type );
/** Sets the value for the item's column and role to the given value. */
virtual void setData( int column, int role, const QVariant & value );
signals:
/** This signal is emitted when the contents of the column in the specified item has been edited by the user. */
void itemEdited( QTreeWidgetItem* item, int column );
};

View File

@ -26,23 +26,3 @@ class QgsSingleBandPseudoColorRendererWidget : QgsRasterRendererWidget
};
/**
* Custom QTreeWidgetItem with extra signal when item is edited and numeric sorting.
*/
class QgsTreeWidgetItem: QObject, QTreeWidgetItem
{
%TypeHeaderCode
#include <qgssinglebandpseudocolorrendererwidget.h>
%End
public:
/** Constructs a tree widget item of the specified type and appends it to the items in the given parent. */
explicit QgsTreeWidgetItem( QTreeWidget * parent, int type = Type );
/** Sets the value for the item's column and role to the given value. */
virtual void setData( int column, int role, const QVariant & value );
virtual bool operator< ( const QTreeWidgetItem & other ) const;
signals:
/** This signal is emitted when the contents of the column in the specified item has been edited by the user. */
void itemEdited( QTreeWidgetItem* item, int column );
};

View File

@ -269,7 +269,6 @@ SET(QGIS_GUI_SRCS
qgsnewnamedialog.cpp
qgsnewvectorlayerdialog.cpp
qgsnewgeopackagelayerdialog.cpp
qgsnumericsortlistviewitem.cpp
qgsoptionsdialogbase.cpp
qgsorderbydialog.cpp
qgsowssourceselect.cpp
@ -301,6 +300,7 @@ SET(QGIS_GUI_SRCS
qgstablewidgetitem.cpp
qgstextannotationitem.cpp
qgstrackedvectorlayertools.cpp
qgstreewidgetitem.cpp
qgsunitselectionwidget.cpp
qgsuserinputdockwidget.cpp
qgsvariableeditorwidget.cpp
@ -447,6 +447,7 @@ SET(QGIS_GUI_MOC_HDRS
qgsslider.h
qgssqlcomposerdialog.h
qgssublayersdialog.h
qgstreewidgetitem.h
qgsunitselectionwidget.h
qgsuserinputdockwidget.h
qgsvariableeditorwidget.h
@ -634,7 +635,6 @@ SET(QGIS_GUI_HDRS
qgsmaplayerconfigwidgetfactory.h
qgsmapmouseevent.h
qgsmaptip.h
qgsnumericsortlistviewitem.h
qgsrubberband.h
qgssqlcomposerdialog.h
qgssvgannotationitem.h

View File

@ -1,49 +0,0 @@
/***************************************************************************
qgsnumericsortlistviewitem.cpp - A QListViewItem that can sort numerically
(as opposed to just lexigraphically)
-------------------
begin : 06 Nov, 2005
copyright : (C) 2005 by Brendan Morley
email : morb at ozemail dot com dot au
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsnumericsortlistviewitem.h"
QgsNumericSortTreeWidgetItem::QgsNumericSortTreeWidgetItem( QTreeWidget * parent )
: QTreeWidgetItem( parent, UserType )
{
// NOOP
}
QgsNumericSortTreeWidgetItem::QgsNumericSortTreeWidgetItem( QTreeWidgetItem * parent )
: QTreeWidgetItem( parent, UserType )
{
// NOOP
}
QgsNumericSortTreeWidgetItem::~QgsNumericSortTreeWidgetItem()
{
// NOOP
}
bool QgsNumericSortTreeWidgetItem::operator<( const QTreeWidgetItem &other ) const
{
int column = treeWidget() ? treeWidget()->sortColumn() : 0;
if ( column == 0 ) // The ID column
{
return text( column ).toUInt() < other.text( column ).toUInt();
}
else
return text( column ) < other.text( column );
}

View File

@ -1,52 +0,0 @@
/***************************************************************************
qgsnumericsortlistviewitem.h - A QListViewItem that can sort numerically
(as opposed to just lexigraphically)
-------------------
begin : 06 Nov, 2005
copyright : (C) 2005 by Brendan Morley
email : morb at ozemail dot com dot au
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSNUMERICSORTLISTVIEWITEM_H
#define QGSNUMERICSORTLISTVIEWITEM_H
#include <QTreeWidgetItem>
/** \ingroup gui
\brief QTreeWidgetItem that can sort numerically (as opposed to just lexigraphically)
This class extends the Qt QTreeWidgetItem concept by
reimplementing QTreeWidgetItem::operator< to allow numeric comparisons
TODO: Make it work
*/
class GUI_EXPORT QgsNumericSortTreeWidgetItem : public QTreeWidgetItem
{
public:
/**
* Constructor.
*/
QgsNumericSortTreeWidgetItem( QTreeWidget * parent );
QgsNumericSortTreeWidgetItem( QTreeWidgetItem * parent );
//! Destructor
virtual ~QgsNumericSortTreeWidgetItem();
virtual bool operator<( const QTreeWidgetItem &other ) const override;
};
#endif

View File

@ -29,7 +29,7 @@
#include "qgsmanageconnectionsdialog.h"
#include "qgsmessageviewer.h"
#include "qgsnewhttpconnection.h"
#include "qgsnumericsortlistviewitem.h"
#include "qgstreewidgetitem.h"
#include "qgsproject.h"
#include "qgsproviderregistry.h"
#include "qgsowsconnection.h"
@ -303,10 +303,10 @@ void QgsOWSSourceSelect::on_mLoadButton_clicked()
emit connectionsChanged();
}
QgsNumericSortTreeWidgetItem *QgsOWSSourceSelect::createItem(
QgsTreeWidgetItem *QgsOWSSourceSelect::createItem(
int id,
const QStringList &names,
QMap<int, QgsNumericSortTreeWidgetItem *> &items,
QMap<int, QgsTreeWidgetItem *> &items,
int &layerAndStyleCount,
const QMap<int, int> &layerParents,
const QMap<int, QStringList> &layerParentNames )
@ -316,15 +316,15 @@ QgsNumericSortTreeWidgetItem *QgsOWSSourceSelect::createItem(
return items[id];
QgsNumericSortTreeWidgetItem *item;
QgsTreeWidgetItem *item;
if ( layerParents.contains( id ) )
{
// it has parent -> create first its parent
int parent = layerParents[ id ];
item = new QgsNumericSortTreeWidgetItem( createItem( parent, layerParentNames[ parent ], items, layerAndStyleCount, layerParents, layerParentNames ) );
item = new QgsTreeWidgetItem( createItem( parent, layerParentNames[ parent ], items, layerAndStyleCount, layerParents, layerParentNames ) );
}
else
item = new QgsNumericSortTreeWidgetItem( mLayersTreeWidget );
item = new QgsTreeWidgetItem( mLayersTreeWidget );
item->setText( 0, QString::number( ++layerAndStyleCount ) );
item->setText( 1, names[0].simplified() );

View File

@ -30,7 +30,7 @@
class QgsDataProvider;
class QButtonGroup;
class QgsNumericSortTreeWidgetItem;
class QgsTreeWidgetItem;
class QDomDocument;
class QDomElement;
@ -180,12 +180,12 @@ class GUI_EXPORT QgsOWSSourceSelect : public QDialog, public Ui::QgsOWSSourceSel
//! create an item including possible parents
//! @note not available in python bindings
QgsNumericSortTreeWidgetItem *createItem( int id,
const QStringList &names,
QMap<int, QgsNumericSortTreeWidgetItem *> &items,
int &layerAndStyleCount,
const QMap<int, int> &layerParents,
const QMap<int, QStringList> &layerParentNames );
QgsTreeWidgetItem *createItem( int id,
const QStringList &names,
QMap<int, QgsTreeWidgetItem *> &items,
int &layerAndStyleCount,
const QMap<int, int> &layerParents,
const QMap<int, QStringList> &layerParentNames );
//! Returns a textual description for the authority id
QString descriptionForAuthId( const QString& authId );

View File

@ -0,0 +1,146 @@
/***************************************************************************
qgstreewidgetitem.cpp
---------------------
begin : 06 Nov, 2005
copyright : (C) 2005 by Brendan Morley
email : morb at ozemail dot com dot au
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgstreewidgetitem.h"
#include "qgis.h"
QgsTreeWidgetItem::QgsTreeWidgetItem( QTreeWidget * parent, int type )
: QTreeWidgetItem( parent, type )
{}
QgsTreeWidgetItem::QgsTreeWidgetItem( int type )
: QTreeWidgetItem( type )
{}
QgsTreeWidgetItem::QgsTreeWidgetItem( const QStringList& strings, int type )
: QTreeWidgetItem( strings, type )
{}
QgsTreeWidgetItem::QgsTreeWidgetItem( QTreeWidget* view, const QStringList& strings, int type )
: QTreeWidgetItem( view, strings, type )
{}
QgsTreeWidgetItem::QgsTreeWidgetItem( QTreeWidget* view, QTreeWidgetItem* after, int type )
: QTreeWidgetItem( view, after, type )
{}
QgsTreeWidgetItem::QgsTreeWidgetItem( QTreeWidgetItem* parent, int type )
: QTreeWidgetItem( parent, type )
{}
QgsTreeWidgetItem::QgsTreeWidgetItem( QTreeWidgetItem* parent, const QStringList& strings, int type )
: QTreeWidgetItem( parent, strings, type )
{}
QgsTreeWidgetItem::QgsTreeWidgetItem( QTreeWidgetItem* parent, QTreeWidgetItem* after, int type )
: QTreeWidgetItem( parent, after, type )
{}
void QgsTreeWidgetItem::setSortData( int column, const QVariant& value )
{
setData( column, CustomSortRole, value );
}
QVariant QgsTreeWidgetItem::sortData( int column ) const
{
return data( column, CustomSortRole );
}
void QgsTreeWidgetItem::setAlwaysOnTopPriority( int priority )
{
setData( 0, AlwaysOnTopPriorityRole, priority );
}
int QgsTreeWidgetItem::alwaysOnTopPriority() const
{
QVariant val = data( 0, AlwaysOnTopPriorityRole );
return val.isValid() ? val.toInt() : -1;
}
bool QgsTreeWidgetItem::operator<( const QTreeWidgetItem &other ) const
{
int column = treeWidget()->sortColumn();
// check always on top priority - note - no way of determining sort order from tree widget, so
// these will sometimes be incorrectly placed at the bottom
QVariant priority1 = data( 0, AlwaysOnTopPriorityRole );
QVariant priority2 = other.data( 0, AlwaysOnTopPriorityRole );
if ( priority1.isValid() && priority2.isValid() )
{
int i1 = priority1.toInt();
int i2 = priority2.toInt();
if ( i1 != i2 )
return priority1.toInt() < priority2.toInt();
}
else if ( priority1.isValid() )
{
return true;
}
else if ( priority2.isValid() )
{
return false;
}
// no always on top priorities, check data
bool ok1, ok2, val;
// prefer the custom sort role, but fall back to display text
QVariant val1 = data( column, CustomSortRole );
if ( !val1.isValid() )
val1 = text( column );
QVariant val2 = other.data( column, CustomSortRole );
if ( !val2.isValid() )
val2 = other.text( column );
if ( !val1.isNull() && !val2.isNull() )
{
val = val1.toDouble( &ok1 ) < val2.toDouble( &ok2 );
if ( ok1 && ok2 )
{
return val;
}
else if ( ok1 || ok2 )
{
// sort numbers before strings
return ok1;
}
}
return qgsVariantLessThan( val1, val2 );
}
//
// QgsTreeWidgetItemObject
//
QgsTreeWidgetItemObject::QgsTreeWidgetItemObject( int type )
: QgsTreeWidgetItem( type )
{}
QgsTreeWidgetItemObject::QgsTreeWidgetItemObject( QTreeWidget* parent, int type )
: QgsTreeWidgetItem( parent, type )
{}
// override setData to emit signal when edited. By default the itemChanged signal fires way too often
void QgsTreeWidgetItemObject::setData( int column, int role, const QVariant& value )
{
QgsTreeWidgetItem::setData( column, role, value );
if ( role == Qt::EditRole )
{
emit itemEdited( this, column );
}
}

158
src/gui/qgstreewidgetitem.h Normal file
View File

@ -0,0 +1,158 @@
/***************************************************************************
qgstreewidgetitem.h
-------------------
begin : 06 Nov, 2005
copyright : (C) 2005 by Brendan Morley
email : morb at ozemail dot com dot au
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSTREEWIDGETITEM_H
#define QGSTREEWIDGETITEM_H
#include <QTreeWidgetItem>
#include <QObject>
/** \ingroup gui
* \class QgsTreeWidgetItem
* QTreeWidgetItem subclass with custom handling for item sorting.
*
* QgsTreeWidgetItem allows for items to be sorted using a specified user role, and
* also correctly handles sorting numeric or mixed text and numeric values.
* \note added in QGIS 3.0
*/
class GUI_EXPORT QgsTreeWidgetItem : public QTreeWidgetItem
{
public:
/** Constructor for QgsTreeWidgetItem
* @param view parent QTreeWidget view
* @param type item type
*/
explicit QgsTreeWidgetItem( QTreeWidget * view, int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param type item type
*/
explicit QgsTreeWidgetItem( int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param strings list of strings containing text for each column in the item
* @param type item type
*/
QgsTreeWidgetItem( const QStringList &strings, int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param view parent QTreeWidget view
* @param strings list of strings containing text for each column in the item
* @param type item type
*/
QgsTreeWidgetItem( QTreeWidget *view, const QStringList &strings, int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param view parent QTreeWidget view
* @param after QTreeWidgetItem to place insert item after in the view
* @param type item type
*/
QgsTreeWidgetItem( QTreeWidget *view, QTreeWidgetItem *after, int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param parent QTreeWidgetItem item
* @param type item type
*/
explicit QgsTreeWidgetItem( QTreeWidgetItem *parent, int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param parent QTreeWidgetItem item
* @param strings list of strings containing text for each column in the item
* @param type item type
*/
QgsTreeWidgetItem( QTreeWidgetItem *parent, const QStringList &strings, int type = Type );
/** Constructor for QgsTreeWidgetItem
* @param parent QTreeWidgetItem item
* @param after QTreeWidgetItem to place insert item after in the view
* @param type item type
*/
QgsTreeWidgetItem( QTreeWidgetItem *parent, QTreeWidgetItem *after, int type = Type );
/** Sets the custom sort data for a specified column. If set, this value will be used when
* sorting the item instead of the item's display text. If not set, the item's display
* text will be used when sorting.
* @param column column index
* @param value sort value
* @see sortData()
*/
void setSortData( int column, const QVariant& value );
/** Returns the custom sort data for a specified column. If set, this value will be used when
* sorting the item instead of the item's display text. If not set, the item's display
* text will be used when sorting.
* @see setSortData()
*/
QVariant sortData( int column ) const;
/** Sets a the item to display always on top of other items in the widget, regardless of the
* sort column and sort or display value for the item.
* @param priority priority for sorting always on top items. Items with a lower priority will
* be placed above items with a higher priority.
* @see alwaysOnTopPriority()
*/
void setAlwaysOnTopPriority( int priority );
/** Returns the item's priority when it is set to show always on top. Items with a lower priority will
* be placed above items with a higher priority.
* @returns priority, or -1 if item is not set to show always on top
* @see setAlwaysOnTopPriority()
*/
int alwaysOnTopPriority() const;
virtual bool operator<( const QTreeWidgetItem &other ) const override;
private:
enum ItemDataRole
{
CustomSortRole = Qt::UserRole + 1001,
AlwaysOnTopPriorityRole = Qt::UserRole + 1002,
};
};
/** \ingroup gui
* \class QgsTreeWidgetItemObject
* Custom QgsTreeWidgetItem with extra signals when item is edited.
* \note added in QGIS 3.0
*/
class GUI_EXPORT QgsTreeWidgetItemObject: public QObject, public QgsTreeWidgetItem
{
Q_OBJECT
public:
/** Constructor for QgsTreeWidgetItemObject
* @param type item type
*/
explicit QgsTreeWidgetItemObject( int type = Type );
/** Constructs a tree widget item of the specified type and appends it to the items in the given parent. */
explicit QgsTreeWidgetItemObject( QTreeWidget * parent, int type = Type );
/** Sets the value for the item's column and role to the given value. */
virtual void setData( int column, int role, const QVariant & value );
signals:
/** This signal is emitted when the contents of the column in the specified item has been edited by the user. */
void itemEdited( QTreeWidgetItem* item, int column );
};
#endif // QGSTREEWIDGETITEM_H

View File

@ -21,7 +21,7 @@
#include "qgsrasterdataprovider.h"
#include "qgsrastershader.h"
#include "qgsrasterminmaxwidget.h"
#include "qgstreewidgetitem.h"
// for color ramps - todo add rasterStyle and refactor raster vs. vector ramps
#include "qgsstylev2.h"
@ -33,41 +33,6 @@
#include <QSettings>
#include <QTextStream>
// override setData to emit signal when edited. By default the itemChanged signal fires way too often
void QgsTreeWidgetItem::setData( int column, int role, const QVariant & value )
{
QTreeWidgetItem::setData( column, role, value );
if ( role == Qt::EditRole )
{
emit itemEdited( this, column );
}
}
// override < operator to allow numeric sorting
/** Returns true if the text in the item is less than the text in the other item, otherwise returns false.
*
* Compares on numeric value of text if possible, otherwise on text.
*/
bool QgsTreeWidgetItem::operator<( const QTreeWidgetItem & other ) const
{
int column = treeWidget()->sortColumn();
bool ok1, ok2, val;
val = text( column ).toDouble( &ok1 ) < other.text( column ).toDouble( &ok2 );
if ( ok1 && ok2 )
{
return val;
}
else if ( ok1 || ok2 )
{
// sort numbers before strings
return ok1;
}
else
{
return text( column ) < other.text( column );
}
}
QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent )
: QgsRasterRendererWidget( layer, extent )
, mMinMaxWidget( nullptr )
@ -319,7 +284,7 @@ void QgsSingleBandPseudoColorRendererWidget::setUnitFromLabels()
void QgsSingleBandPseudoColorRendererWidget::on_mAddEntryButton_clicked()
{
QgsTreeWidgetItem* newItem = new QgsTreeWidgetItem( mColormapTreeWidget );
QgsTreeWidgetItemObject* newItem = new QgsTreeWidgetItemObject( mColormapTreeWidget );
newItem->setText( ValueColumn, "0" );
newItem->setBackground( ColorColumn, QBrush( QColor( Qt::magenta ) ) );
newItem->setText( LabelColumn, QString() );
@ -523,7 +488,7 @@ void QgsSingleBandPseudoColorRendererWidget::on_mClassifyButton_clicked()
for ( ; value_it != entryValues.end(); ++value_it, ++color_it )
{
QgsTreeWidgetItem* newItem = new QgsTreeWidgetItem( mColormapTreeWidget );
QgsTreeWidgetItemObject* newItem = new QgsTreeWidgetItemObject( mColormapTreeWidget );
newItem->setText( ValueColumn, QString::number( *value_it, 'g', nDecimals ) );
newItem->setBackground( ColorColumn, QBrush( *color_it ) );
newItem->setText( LabelColumn, QString() );
@ -567,7 +532,7 @@ void QgsSingleBandPseudoColorRendererWidget::populateColormapTreeWidget( const Q
QList<QgsColorRampShader::ColorRampItem>::const_iterator it = colorRampItems.constBegin();
for ( ; it != colorRampItems.constEnd(); ++it )
{
QgsTreeWidgetItem* newItem = new QgsTreeWidgetItem( mColormapTreeWidget );
QgsTreeWidgetItemObject* newItem = new QgsTreeWidgetItemObject( mColormapTreeWidget );
newItem->setText( ValueColumn, QString::number( it->value, 'g', 15 ) );
newItem->setBackground( ColorColumn, QBrush( it->color ) );
newItem->setText( LabelColumn, it->label );
@ -822,7 +787,7 @@ void QgsSingleBandPseudoColorRendererWidget::setFromRenderer( const QgsRasterRen
QList<QgsColorRampShader::ColorRampItem>::const_iterator it = colorRampItemList.constBegin();
for ( ; it != colorRampItemList.end(); ++it )
{
QgsTreeWidgetItem* newItem = new QgsTreeWidgetItem( mColormapTreeWidget );
QgsTreeWidgetItemObject* newItem = new QgsTreeWidgetItemObject( mColormapTreeWidget );
newItem->setText( ValueColumn, QString::number( it->value, 'g', 15 ) );
newItem->setBackground( ColorColumn, QBrush( it->color ) );
newItem->setText( LabelColumn, it->label );

View File

@ -93,23 +93,5 @@ class GUI_EXPORT QgsSingleBandPseudoColorRendererWidget: public QgsRasterRendere
int mMinMaxOrigin;
};
/** \ingroup gui
* Custom QTreeWidgetItem with extra signal when item is edited and numeric sorting.
*/
class GUI_EXPORT QgsTreeWidgetItem: public QObject, public QTreeWidgetItem
{
Q_OBJECT
public:
/** Constructs a tree widget item of the specified type and appends it to the items in the given parent. */
explicit QgsTreeWidgetItem( QTreeWidget * parent, int type = Type ) : QTreeWidgetItem( parent, type ) {}
/** Sets the value for the item's column and role to the given value. */
virtual void setData( int column, int role, const QVariant & value );
virtual bool operator< ( const QTreeWidgetItem & other ) const;
signals:
/** This signal is emitted when the contents of the column in the specified item has been edited by the user. */
void itemEdited( QTreeWidgetItem* item, int column );
};
#endif // QGSSINGLEBANDCOLORRENDERERWIDGET_H

View File

@ -23,7 +23,7 @@
#include "qgswcsprovider.h"
#include "qgswcssourceselect.h"
#include "qgswcscapabilities.h"
#include "qgsnumericsortlistviewitem.h"
#include "qgstreewidgetitem.h"
#include <QWidget>
@ -67,7 +67,7 @@ void QgsWCSSourceSelect::populateLayerList()
if ( !mCapabilities.supportedCoverages( coverages ) )
return;
QMap<int, QgsNumericSortTreeWidgetItem *> items;
QMap<int, QgsTreeWidgetItem *> items;
QMap<int, int> coverageParents;
QMap<int, QStringList> coverageParentNames;
mCapabilities.coverageParents( coverageParents, coverageParentNames );
@ -82,7 +82,7 @@ void QgsWCSSourceSelect::populateLayerList()
{
QgsDebugMsg( QString( "coverage orderId = %1 identifier = %2" ).arg( coverage->orderId ).arg( coverage->identifier ) );
QgsNumericSortTreeWidgetItem *lItem = createItem( coverage->orderId, QStringList() << coverage->identifier << coverage->title << coverage->abstract, items, coverageAndStyleCount, coverageParents, coverageParentNames );
QgsTreeWidgetItem *lItem = createItem( coverage->orderId, QStringList() << coverage->identifier << coverage->title << coverage->abstract, items, coverageAndStyleCount, coverageParents, coverageParentNames );
lItem->setData( 0, Qt::UserRole + 0, coverage->identifier );
lItem->setData( 0, Qt::UserRole + 1, "" );

View File

@ -34,7 +34,7 @@
class QgisApp;
class QgsDataProvider;
class QButtonGroup;
class QgsNumericSortTreeWidgetItem;
class QgsTreeWidgetItem;
class QDomDocument;
class QDomElement;

View File

@ -28,7 +28,7 @@
#include "qgsmanageconnectionsdialog.h"
#include "qgsmessageviewer.h"
#include "qgsnewhttpconnection.h"
#include "qgsnumericsortlistviewitem.h"
#include "qgstreewidgetitem.h"
#include "qgsproject.h"
#include "qgsproviderregistry.h"
#include "qgswmsconnection.h"
@ -227,10 +227,10 @@ void QgsWMSSourceSelect::on_btnLoad_clicked()
emit connectionsChanged();
}
QgsNumericSortTreeWidgetItem *QgsWMSSourceSelect::createItem(
QgsTreeWidgetItem *QgsWMSSourceSelect::createItem(
int id,
const QStringList &names,
QMap<int, QgsNumericSortTreeWidgetItem *> &items,
QMap<int, QgsTreeWidgetItem *> &items,
int &layerAndStyleCount,
const QMap<int, int> &layerParents,
const QMap<int, QStringList> &layerParentNames )
@ -238,14 +238,14 @@ QgsNumericSortTreeWidgetItem *QgsWMSSourceSelect::createItem(
if ( items.contains( id ) )
return items[id];
QgsNumericSortTreeWidgetItem *item;
QgsTreeWidgetItem *item;
if ( layerParents.contains( id ) )
{
int parent = layerParents[ id ];
item = new QgsNumericSortTreeWidgetItem( createItem( parent, layerParentNames[ parent ], items, layerAndStyleCount, layerParents, layerParentNames ) );
item = new QgsTreeWidgetItem( createItem( parent, layerParentNames[ parent ], items, layerAndStyleCount, layerParents, layerParentNames ) );
}
else
item = new QgsNumericSortTreeWidgetItem( lstLayers );
item = new QgsTreeWidgetItem( lstLayers );
item->setText( 0, QString::number( ++layerAndStyleCount ) );
item->setText( 1, names[0].simplified() );
@ -297,7 +297,7 @@ bool QgsWMSSourceSelect::populateLayerList( const QgsWmsCapabilities& capabiliti
btnGrpImageEncoding->setEnabled( true );
QMap<int, QgsNumericSortTreeWidgetItem *> items;
QMap<int, QgsTreeWidgetItem *> items;
QMap<int, int> layerParents;
QMap<int, QStringList> layerParentNames;
capabilities.layerParents( layerParents, layerParentNames );
@ -310,7 +310,7 @@ bool QgsWMSSourceSelect::populateLayerList( const QgsWmsCapabilities& capabiliti
layer != layers.end();
++layer )
{
QgsNumericSortTreeWidgetItem *lItem = createItem( layer->orderId, QStringList() << layer->name << layer->title << layer->abstract, items, layerAndStyleCount, layerParents, layerParentNames );
QgsTreeWidgetItem *lItem = createItem( layer->orderId, QStringList() << layer->name << layer->title << layer->abstract, items, layerAndStyleCount, layerParents, layerParentNames );
lItem->setData( 0, Qt::UserRole + 0, layer->name );
lItem->setData( 0, Qt::UserRole + 1, "" );
@ -323,7 +323,7 @@ bool QgsWMSSourceSelect::populateLayerList( const QgsWmsCapabilities& capabiliti
{
QgsDebugMsg( QString( "got style name %1 and title '%2'." ).arg( layer->style.at( j ).name, layer->style.at( j ).title ) );
QgsNumericSortTreeWidgetItem *lItem2 = new QgsNumericSortTreeWidgetItem( lItem );
QgsTreeWidgetItem *lItem2 = new QgsTreeWidgetItem( lItem );
lItem2->setText( 0, QString::number( ++layerAndStyleCount ) );
lItem2->setText( 1, layer->style.at( j ).name.simplified() );
lItem2->setText( 2, layer->style.at( j ).title.simplified() );

View File

@ -30,7 +30,7 @@
class QgisApp;
class QgsWmsProvider;
class QButtonGroup;
class QgsNumericSortTreeWidgetItem;
class QgsTreeWidgetItem;
class QDomDocument;
class QDomElement;
class QgsWmsCapabilities;
@ -148,12 +148,12 @@ class QgsWMSSourceSelect : public QDialog, private Ui::QgsWMSSourceSelectBase
bool populateLayerList( const QgsWmsCapabilities& capabilities );
//! create an item including possible parents
QgsNumericSortTreeWidgetItem *createItem( int id,
const QStringList &names,
QMap<int, QgsNumericSortTreeWidgetItem *> &items,
int &layerAndStyleCount,
const QMap<int, int> &layerParents,
const QMap<int, QStringList> &layerParentNames );
QgsTreeWidgetItem *createItem( int id,
const QStringList &names,
QMap<int, QgsTreeWidgetItem *> &items,
int &layerAndStyleCount,
const QMap<int, int> &layerParents,
const QMap<int, QStringList> &layerParentNames );
//! Returns a textual description for the authority id
QString descriptionForAuthId( const QString& authId );

View File

@ -90,6 +90,7 @@ ADD_PYTHON_TEST(PyQgsArrowSymbolLayer test_qgsarrowsymbollayer.py)
ADD_PYTHON_TEST(PyQgsSymbolExpressionVariables test_qgssymbolexpressionvariables.py)
ADD_PYTHON_TEST(PyQgsSyntacticSugar test_syntactic_sugar.py)
ADD_PYTHON_TEST(PyQgsSymbolV2 test_qgssymbolv2.py)
ADD_PYTHON_TEST(PyQgsTreeWidgetItem test_qgstreewidgetitem.py)
ADD_PYTHON_TEST(PyQgsUnitTypes test_qgsunittypes.py)
ADD_PYTHON_TEST(PyQgsVectorColorRamp test_qgsvectorcolorramp.py)
ADD_PYTHON_TEST(PyQgsVectorFileWriter test_qgsvectorfilewriter.py)

View File

@ -0,0 +1,144 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsTreeWidgetItem.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Nyall Dawson'
__date__ = '12/07/2016'
__copyright__ = 'Copyright 2016, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import qgis # switch sip api
from qgis.core import NULL
from qgis.gui import QgsTreeWidgetItem, QgsTreeWidgetItemObject
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import QTreeWidget
from qgis.testing import (
start_app,
unittest
)
try:
from qgis.PyQt.QtTest import QSignalSpy
use_signal_spy = True
except:
use_signal_spy = False
start_app()
class TestQgsTreeWidgetItem(unittest.TestCase):
def testGettersSetters(self):
""" test getters and setters """
i = QgsTreeWidgetItem()
# sort data should be empty by default
self.assertEqual(i.sortData(0), NULL)
i.setSortData(0, '5')
self.assertEqual(i.sortData(0), '5')
self.assertEqual(i.sortData(1), NULL)
i.setSortData(1, 'a')
self.assertEqual(i.sortData(0), '5')
self.assertEqual(i.sortData(1), 'a')
# should not be always on top by default
self.assertEqual(i.alwaysOnTopPriority(), -1)
i.setAlwaysOnTopPriority(1)
self.assertEqual(i.alwaysOnTopPriority(), 1)
def testSort(self):
""" test sort logic """
w = QTreeWidget()
i1 = QgsTreeWidgetItem(w)
i2 = QgsTreeWidgetItem(w)
# should default to search by display text
i1.setText(0, '2')
i1.setText(1, 'b')
i1.setText(2, 'c')
i2.setText(0, '1')
i2.setText(1, 'a')
i2.setText(2, 'd')
w.sortItems(0, Qt.AscendingOrder)
self.assertEqual(i1 < i2, False)
self.assertEqual(i2 < i1, True)
w.sortItems(1, Qt.AscendingOrder)
self.assertEqual(i1 < i2, False)
self.assertEqual(i2 < i1, True)
w.sortItems(2, Qt.AscendingOrder)
self.assertEqual(i1 < i2, True)
self.assertEqual(i2 < i1, False)
# sortData should take precedence over display text
i1.setText(1, '2')
i1.setSortData(1, '200')
i2.setText(1, '3')
w.sortItems(1, Qt.AscendingOrder)
self.assertEqual(i1 < i2, False)
self.assertEqual(i2 < i1, True)
i2.setSortData(1, '300')
self.assertEqual(i1 < i2, True)
self.assertEqual(i2 < i1, False)
# test that nulls are sorted before other values
i1.setSortData(0, '2')
i2.setSortData(0, NULL)
w.sortItems(0, Qt.AscendingOrder)
self.assertEqual(i1 < i2, False)
self.assertEqual(i2 < i1, True)
# test numeric sorting
i1.setSortData(0, '02')
i2.setSortData(0, '005')
w.sortItems(0, Qt.AscendingOrder)
self.assertEqual(i1 < i2, True)
self.assertEqual(i2 < i1, False)
# numbers should come first
i2.setSortData(0, 'a')
self.assertEqual(i1 < i2, True)
self.assertEqual(i2 < i1, False)
i1.setSortData(0, 'a')
i2.setSortData(0, '5')
self.assertEqual(i1 < i2, False)
self.assertEqual(i2 < i1, True)
# always on top items should be first
i1.setSortData(0, 'a')
i2.setSortData(0, 'b')
i2.setAlwaysOnTopPriority(5)
self.assertEqual(i1 < i2, False)
self.assertEqual(i2 < i1, True)
i1.setAlwaysOnTopPriority(3)
self.assertEqual(i1 < i2, True)
self.assertEqual(i2 < i1, False)
# otherwise fall back to sort order
i2.setAlwaysOnTopPriority(3)
i1.setSortData(0, 'c')
self.assertEqual(i1 < i2, False)
self.assertEqual(i2 < i1, True)
class TestQgsTreeWidgetItemObject(unittest.TestCase):
@unittest.skipIf(not use_signal_spy, "No QSignalSpy available")
def testItemEdited(self):
""" test that itemEdited signal is correctly emitted"""
i = QgsTreeWidgetItemObject()
item_edited_spy = QSignalSpy(i.itemEdited)
i.setData(1, Qt.EditRole, 'a')
self.assertEqual(len(item_edited_spy), 1)
i.setData(1, Qt.EditRole, 'b')
self.assertEqual(len(item_edited_spy), 2)
if __name__ == '__main__':
unittest.main()