diff --git a/doc/api_break.dox b/doc/api_break.dox
index 260e70affb5..3d621466fbd 100644
--- a/doc/api_break.dox
+++ b/doc/api_break.dox
@@ -179,6 +179,21 @@ plugins calling this method will need to be updated.
plugins calling this method will need to be updated.
+\subsection qgis_api_break_3_0_QgsNumericSortTreeWidgetItem QgsNumericSortTreeWidgetItem
+
+
+- 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.
+
+
+\subsection qgis_api_break_3_0_QgsTreeWidgetItem QgsTreeWidgetItem
+
+
+- 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
+
+
\subsection qgis_api_break_3_0_QgsVectorLayer QgsVectorLayer
diff --git a/python/gui/gui.sip b/python/gui/gui.sip
index a9eac813576..972e33e7ad1 100644
--- a/python/gui/gui.sip
+++ b/python/gui/gui.sip
@@ -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
diff --git a/python/gui/qgsnumericsortlistviewitem.sip b/python/gui/qgsnumericsortlistviewitem.sip
deleted file mode 100644
index 92da1643e7e..00000000000
--- a/python/gui/qgsnumericsortlistviewitem.sip
+++ /dev/null
@@ -1,18 +0,0 @@
-class QgsNumericSortTreeWidgetItem : QTreeWidgetItem
-{
-%TypeHeaderCode
-#include
-%End
- public:
- /**
- * Constructor.
- */
- QgsNumericSortTreeWidgetItem( QTreeWidget * parent );
- QgsNumericSortTreeWidgetItem( QTreeWidgetItem * parent );
-
- //! Destructor
- virtual ~QgsNumericSortTreeWidgetItem();
-
- virtual bool operator<( const QTreeWidgetItem &other ) const;
-
-};
diff --git a/python/gui/qgstreewidgetitem.sip b/python/gui/qgstreewidgetitem.sip
new file mode 100644
index 00000000000..51374457cd9
--- /dev/null
+++ b/python/gui/qgstreewidgetitem.sip
@@ -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
+%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
+%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 );
+};
+
diff --git a/python/gui/raster/qgssinglebandpseudocolorrendererwidget.sip b/python/gui/raster/qgssinglebandpseudocolorrendererwidget.sip
index 968d22b8c70..ce150784719 100644
--- a/python/gui/raster/qgssinglebandpseudocolorrendererwidget.sip
+++ b/python/gui/raster/qgssinglebandpseudocolorrendererwidget.sip
@@ -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
-%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 );
-};
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index fc352e49355..433068504a1 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -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
diff --git a/src/gui/qgsnumericsortlistviewitem.cpp b/src/gui/qgsnumericsortlistviewitem.cpp
deleted file mode 100644
index cb6e320e3a2..00000000000
--- a/src/gui/qgsnumericsortlistviewitem.cpp
+++ /dev/null
@@ -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 );
-}
diff --git a/src/gui/qgsnumericsortlistviewitem.h b/src/gui/qgsnumericsortlistviewitem.h
deleted file mode 100644
index 1159763a902..00000000000
--- a/src/gui/qgsnumericsortlistviewitem.h
+++ /dev/null
@@ -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
-
-/** \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
diff --git a/src/gui/qgsowssourceselect.cpp b/src/gui/qgsowssourceselect.cpp
index e096f24b207..986f9862be7 100644
--- a/src/gui/qgsowssourceselect.cpp
+++ b/src/gui/qgsowssourceselect.cpp
@@ -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 &items,
+ QMap &items,
int &layerAndStyleCount,
const QMap &layerParents,
const QMap &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() );
diff --git a/src/gui/qgsowssourceselect.h b/src/gui/qgsowssourceselect.h
index 8b1e7091942..48cadd3cfd9 100644
--- a/src/gui/qgsowssourceselect.h
+++ b/src/gui/qgsowssourceselect.h
@@ -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 &items,
- int &layerAndStyleCount,
- const QMap &layerParents,
- const QMap &layerParentNames );
+ QgsTreeWidgetItem *createItem( int id,
+ const QStringList &names,
+ QMap &items,
+ int &layerAndStyleCount,
+ const QMap &layerParents,
+ const QMap &layerParentNames );
//! Returns a textual description for the authority id
QString descriptionForAuthId( const QString& authId );
diff --git a/src/gui/qgstreewidgetitem.cpp b/src/gui/qgstreewidgetitem.cpp
new file mode 100644
index 00000000000..6f949276b0f
--- /dev/null
+++ b/src/gui/qgstreewidgetitem.cpp
@@ -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 );
+ }
+}
diff --git a/src/gui/qgstreewidgetitem.h b/src/gui/qgstreewidgetitem.h
new file mode 100644
index 00000000000..9232b7eb930
--- /dev/null
+++ b/src/gui/qgstreewidgetitem.h
@@ -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
+#include
+
+/** \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
diff --git a/src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp b/src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp
index 4f08369cb49..ce2ac685a99 100644
--- a/src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp
+++ b/src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp
@@ -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
#include
-// 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::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::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 );
diff --git a/src/gui/raster/qgssinglebandpseudocolorrendererwidget.h b/src/gui/raster/qgssinglebandpseudocolorrendererwidget.h
index c09c6bbe126..110d0feb1a4 100644
--- a/src/gui/raster/qgssinglebandpseudocolorrendererwidget.h
+++ b/src/gui/raster/qgssinglebandpseudocolorrendererwidget.h
@@ -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
diff --git a/src/providers/wcs/qgswcssourceselect.cpp b/src/providers/wcs/qgswcssourceselect.cpp
index 14000654366..6418be2f610 100644
--- a/src/providers/wcs/qgswcssourceselect.cpp
+++ b/src/providers/wcs/qgswcssourceselect.cpp
@@ -23,7 +23,7 @@
#include "qgswcsprovider.h"
#include "qgswcssourceselect.h"
#include "qgswcscapabilities.h"
-#include "qgsnumericsortlistviewitem.h"
+#include "qgstreewidgetitem.h"
#include
@@ -67,7 +67,7 @@ void QgsWCSSourceSelect::populateLayerList()
if ( !mCapabilities.supportedCoverages( coverages ) )
return;
- QMap items;
+ QMap items;
QMap coverageParents;
QMap 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, "" );
diff --git a/src/providers/wcs/qgswcssourceselect.h b/src/providers/wcs/qgswcssourceselect.h
index 9e49db0fc21..a74fb5316e4 100644
--- a/src/providers/wcs/qgswcssourceselect.h
+++ b/src/providers/wcs/qgswcssourceselect.h
@@ -34,7 +34,7 @@
class QgisApp;
class QgsDataProvider;
class QButtonGroup;
-class QgsNumericSortTreeWidgetItem;
+class QgsTreeWidgetItem;
class QDomDocument;
class QDomElement;
diff --git a/src/providers/wms/qgswmssourceselect.cpp b/src/providers/wms/qgswmssourceselect.cpp
index 456b10156aa..1cee2d88a54 100644
--- a/src/providers/wms/qgswmssourceselect.cpp
+++ b/src/providers/wms/qgswmssourceselect.cpp
@@ -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 &items,
+ QMap &items,
int &layerAndStyleCount,
const QMap &layerParents,
const QMap &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 items;
+ QMap items;
QMap layerParents;
QMap 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() );
diff --git a/src/providers/wms/qgswmssourceselect.h b/src/providers/wms/qgswmssourceselect.h
index b97049f0103..5df2e121faf 100644
--- a/src/providers/wms/qgswmssourceselect.h
+++ b/src/providers/wms/qgswmssourceselect.h
@@ -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 &items,
- int &layerAndStyleCount,
- const QMap &layerParents,
- const QMap &layerParentNames );
+ QgsTreeWidgetItem *createItem( int id,
+ const QStringList &names,
+ QMap &items,
+ int &layerAndStyleCount,
+ const QMap &layerParents,
+ const QMap &layerParentNames );
//! Returns a textual description for the authority id
QString descriptionForAuthId( const QString& authId );
diff --git a/tests/src/python/CMakeLists.txt b/tests/src/python/CMakeLists.txt
index ce514421e8a..c2ccdb961b5 100644
--- a/tests/src/python/CMakeLists.txt
+++ b/tests/src/python/CMakeLists.txt
@@ -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)
diff --git a/tests/src/python/test_qgstreewidgetitem.py b/tests/src/python/test_qgstreewidgetitem.py
new file mode 100644
index 00000000000..33350fac9ba
--- /dev/null
+++ b/tests/src/python/test_qgstreewidgetitem.py
@@ -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()