diff --git a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp index 3792f0ed6..685c54169 100644 --- a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp +++ b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp @@ -42,10 +42,10 @@ Q_GUI_EXPORT int qt_defaultDpi(); #define ROLE_ID Qt::UserRole #define ROLE_NAME Qt::UserRole + 1 #define ROLE_DESCRIPTION Qt::UserRole + 2 -#define ROLE_POPULARITY Qt::UserRole + 3 -#define ROLE_SUBSCRIBE_FLAGS Qt::UserRole + 4 -#define ROLE_COLOR Qt::UserRole + 5 -#define ROLE_REQUEST_ID Qt::UserRole + 6 +#define ROLE_SUBSCRIBE_FLAGS Qt::UserRole + 3 +#define ROLE_COLOR Qt::UserRole + 4 +#define ROLE_REQUEST_ID Qt::UserRole + 5 +#define ROLE_SORT Qt::UserRole + 6 #define FILTER_NAME_INDEX 0 #define FILTER_DESC_INDEX 1 @@ -72,6 +72,14 @@ GroupTreeWidget::GroupTreeWidget(QWidget *parent) : itemDelegate->setSpacing(QSize(0, 2)); ui->treeWidget->setItemDelegate(itemDelegate); + /* Set compare role for each column */ + compareRole = new RSTreeWidgetItemCompareRole(QMap>({ {GTW_COLUMN_UNREAD, {ROLE_SORT}} + , {GTW_COLUMN_POSTS, {ROLE_SORT}} + , {GTW_COLUMN_POPULARITY, {ROLE_SORT}} + , {GTW_COLUMN_LAST_POST, {ROLE_SORT}} + , {GTW_COLUMN_SEARCH_SCORE,{ROLE_SORT}} + })); + /* Initialize tree widget */ ui->treeWidget->setColumnCount(GTW_COLUMN_COUNT); ui->treeWidget->setSortingEnabled(true); @@ -236,10 +244,10 @@ void GroupTreeWidget::itemActivated(QTreeWidgetItem *item, int column) emit treeItemActivated(id); } -QTreeWidgetItem *GroupTreeWidget::addCategoryItem(const QString &name, const QIcon &icon, bool expand) +QTreeWidgetItem *GroupTreeWidget::addCategoryItem(const QString &name, const QIcon &icon, bool expand, int sortOrder /*= -1*/) { QFont font; - QTreeWidgetItem *item = new QTreeWidgetItem(); + RSTreeWidgetItem *item = new RSTreeWidgetItem(); ui->treeWidget->addTopLevelItem(item); // To get StyleSheet for Items ui->treeWidget->style()->unpolish(ui->treeWidget); @@ -260,6 +268,12 @@ QTreeWidgetItem *GroupTreeWidget::addCategoryItem(const QString &name, const QIc item->setExpanded(expand); + item->setNoOrder(true, ROLE_SORT); + if (sortOrder>=0) + item->setData(0, ROLE_SORT, sortOrder); + else + item->setData(0, ROLE_SORT, ui->treeWidget->topLevelItemCount()); + return item; } @@ -369,8 +383,9 @@ void GroupTreeWidget::fillGroupItems(QTreeWidgetItem *categoryItem, const QList< } if (item == NULL) { - item = new RSTreeWidgetItem(); + item = new RSTreeWidgetItem(compareRole); item->setData(GTW_COLUMN_DATA, ROLE_ID, itemInfo.id); + //static_cast(item)->setNoDataAsLast(true); //Uncomment this to sort data with QVariant() always at end. categoryItem->addChild(item); } @@ -392,13 +407,20 @@ void GroupTreeWidget::fillGroupItems(QTreeWidgetItem *categoryItem, const QList< /* Set last post */ if(itemInfo.lastpost == QDateTime::fromTime_t(0)) + { item->setText(GTW_COLUMN_LAST_POST, tr("Never")); + item->setData(GTW_COLUMN_LAST_POST, ROLE_SORT, QVariant());// To allow them not be sorted with ->setNoDataAsLast(true) + } else + { item->setText(GTW_COLUMN_LAST_POST, itemInfo.lastpost.toString(Qt::ISODate).replace("T"," ")); + item->setData(GTW_COLUMN_LAST_POST, ROLE_SORT, itemInfo.lastpost.toTime_t()); + } /* Set visible posts */ item->setText(GTW_COLUMN_POSTS, QString::number(itemInfo.max_visible_posts)); + item->setData(GTW_COLUMN_POSTS, ROLE_SORT, itemInfo.max_visible_posts); /* Set icon */ item->setIcon(GTW_COLUMN_NAME, itemInfo.icon); @@ -407,7 +429,7 @@ void GroupTreeWidget::fillGroupItems(QTreeWidgetItem *categoryItem, const QList< QString tooltip = PopularityDefs::tooltip(itemInfo.popularity); item->setIcon(GTW_COLUMN_POPULARITY, PopularityDefs::icon(itemInfo.popularity)); - item->setData(GTW_COLUMN_DATA, ROLE_POPULARITY, -itemInfo.popularity); // negative for correct sorting + item->setData(GTW_COLUMN_POPULARITY, ROLE_SORT, itemInfo.popularity); /* Set tooltip */ if (itemInfo.adminKey) @@ -493,6 +515,7 @@ void GroupTreeWidget::setUnreadCount(QTreeWidgetItem *item, int unreadCount) item->setText(GTW_COLUMN_UNREAD, ""); font.setBold(false); } + item->setData(GTW_COLUMN_UNREAD, ROLE_SORT, unreadCount); item->setFont(GTW_COLUMN_NAME, font); } @@ -601,6 +624,7 @@ void GroupTreeWidget::calculateScore(QTreeWidgetItem *item, const QString &filte } item->setText(GTW_COLUMN_SEARCH_SCORE, QString::number(score)); + item->setData(GTW_COLUMN_SEARCH_SCORE, ROLE_SORT, score); return; } diff --git a/retroshare-gui/src/gui/common/GroupTreeWidget.h b/retroshare-gui/src/gui/common/GroupTreeWidget.h index be5249ed1..6125dac28 100644 --- a/retroshare-gui/src/gui/common/GroupTreeWidget.h +++ b/retroshare-gui/src/gui/common/GroupTreeWidget.h @@ -90,8 +90,16 @@ public: // Load and save settings (group must be started from the caller) void processSettings(bool load); - // Add a new category item - QTreeWidgetItem *addCategoryItem(const QString &name, const QIcon &icon, bool expand); + /// + /// \brief addCategoryItem: Add a new category item + /// \param name: Name shown on item + /// \param icon: Icon used for item + /// \param expand: If it is expanded by default + /// \param sortOrder: To asc sort them in tree + /// \return + /// + QTreeWidgetItem *addCategoryItem(const QString &name, const QIcon &icon, bool expand, int sortOrder = -1); + // Add a new search item void setDistSearchVisible(bool) ; // shows/hides distant search UI parts. QTreeWidgetItem *addSearchItem(const QString& search_string, uint32_t id, const QIcon &icon) ; @@ -153,6 +161,9 @@ private: /* Color definitions (for standard see qss.default) */ QColor mTextColor[GROUPTREEWIDGET_COLOR_COUNT]; + // Compare role used for each column + RSTreeWidgetItemCompareRole *compareRole; + Ui::GroupTreeWidget *ui; }; diff --git a/retroshare-gui/src/gui/common/RSTreeWidgetItem.cpp b/retroshare-gui/src/gui/common/RSTreeWidgetItem.cpp index 64fb1c861..936f89764 100644 --- a/retroshare-gui/src/gui/common/RSTreeWidgetItem.cpp +++ b/retroshare-gui/src/gui/common/RSTreeWidgetItem.cpp @@ -20,18 +20,26 @@ #include "RSTreeWidgetItem.h" +#include + RSTreeWidgetItemCompareRole::RSTreeWidgetItemCompareRole() { } -void RSTreeWidgetItemCompareRole::setRole(int column, int role) +RSTreeWidgetItemCompareRole::RSTreeWidgetItemCompareRole(QMap> map) + : QMap>(map) +{ +} + + +void RSTreeWidgetItemCompareRole::setRole(const int column, const int role) { QList roles; roles.push_back(role); insert(column, roles); } -void RSTreeWidgetItemCompareRole::addRole(int column, int role) +void RSTreeWidgetItemCompareRole::addRole(const int column, const int role) { RSTreeWidgetItemCompareRole::iterator it = find(column); if (it == end()) { @@ -54,49 +62,51 @@ void RSTreeWidgetItemCompareRole::findRoles(const int column, QList &roles) roles = it.value(); } -RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, int type) : QTreeWidgetItem(type) + + +RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, int type) + : QTreeWidgetItem(type), m_compareRole(compareRole), m_noOrder(false), m_useRoleWhenNoOrder(Qt::UserRole), m_noDataAsLast(false) { - m_compareRole = compareRole; } -RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, const QStringList &strings, int type) : QTreeWidgetItem(strings, type) +RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, const QStringList &strings, int type) + : QTreeWidgetItem(strings, type), m_compareRole(compareRole), m_noOrder(false), m_useRoleWhenNoOrder(Qt::UserRole), m_noDataAsLast(false) { - m_compareRole = compareRole; } -RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidget *view, int type) : QTreeWidgetItem(view, type) +RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidget *view, int type) + : QTreeWidgetItem(view, type), m_compareRole(compareRole), m_noOrder(false), m_useRoleWhenNoOrder(Qt::UserRole), m_noDataAsLast(false) { - m_compareRole = compareRole; } -RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidget *view, const QStringList &strings, int type) : QTreeWidgetItem(view, strings, type) +RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidget *view, const QStringList &strings, int type) + : QTreeWidgetItem(view, strings, type), m_compareRole(compareRole), m_noOrder(false), m_useRoleWhenNoOrder(Qt::UserRole), m_noDataAsLast(false) { - m_compareRole = compareRole; } -RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidget *view, QTreeWidgetItem *after, int type) : QTreeWidgetItem(view, after, type) +RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidget *view, QTreeWidgetItem *after, int type) + : QTreeWidgetItem(view, after, type), m_compareRole(compareRole), m_noOrder(false), m_useRoleWhenNoOrder(Qt::UserRole), m_noDataAsLast(false) { - m_compareRole = compareRole; } -RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidgetItem *parent, int type) : QTreeWidgetItem(parent, type) +RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidgetItem *parent, int type) + : QTreeWidgetItem(parent, type), m_compareRole(compareRole), m_noOrder(false), m_useRoleWhenNoOrder(Qt::UserRole), m_noDataAsLast(false) { - m_compareRole = compareRole; } -RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidgetItem *parent, const QStringList &strings, int type) : QTreeWidgetItem(parent, strings, type) +RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidgetItem *parent, const QStringList &strings, int type) + : QTreeWidgetItem(parent, strings, type), m_compareRole(compareRole), m_noOrder(false), m_useRoleWhenNoOrder(Qt::UserRole), m_noDataAsLast(false) { - m_compareRole = compareRole; } -RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidgetItem *parent, QTreeWidgetItem *after, int type) : QTreeWidgetItem(parent, after, type) +RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidgetItem *parent, QTreeWidgetItem *after, int type) + : QTreeWidgetItem(parent, after, type), m_compareRole(compareRole), m_noOrder(false), m_useRoleWhenNoOrder(Qt::UserRole), m_noDataAsLast(false) { - m_compareRole = compareRole; } -RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, const QTreeWidgetItem &other) : QTreeWidgetItem(other) +RSTreeWidgetItem::RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, const QTreeWidgetItem &other) + : QTreeWidgetItem(other), m_compareRole(compareRole), m_noOrder(false), m_useRoleWhenNoOrder(Qt::UserRole), m_noDataAsLast(false) { - m_compareRole = compareRole; } static uint typeOfVariant(const QVariant &value) @@ -125,56 +135,57 @@ static uint typeOfVariant(const QVariant &value) bool RSTreeWidgetItem::operator<(const QTreeWidgetItem &other) const { - int column = treeWidget()->sortColumn(); - QList roles; + Qt::SortOrder sortOrder = treeWidget() ? treeWidget()->header()->sortIndicatorOrder() : Qt::AscendingOrder; + if (m_noOrder) + { + const QVariant v1 = data(0, m_useRoleWhenNoOrder); + const QVariant v2 = other.data(0, m_useRoleWhenNoOrder); + if (sortOrder == Qt::AscendingOrder) + return v1.toLongLong() < v2.toLongLong(); + else + return v1.toLongLong() >= v2.toLongLong(); + } - /* Own role for sort defined ? */ - if (m_compareRole) { - m_compareRole->findRoles(column, roles); - } + int column = treeWidget() ? treeWidget()->header()->sortIndicatorSection() : 0; - QList::iterator role; - for (role = roles.begin(); role != roles.end(); ++role) { - // taken from "bool QTreeWidgetItem::operator<(const QTreeWidgetItem &other) const" - const QVariant v1 = data(column, *role); - const QVariant v2 = other.data(column, *role); + QList roles; + /* Own role for sort defined ? */ + if (m_compareRole) { + m_compareRole->findRoles(column, roles); + } - // taken from "bool QAbstractItemModelPrivate::variantLessThan(const QVariant &v1, const QVariant &v2)" - switch(qMax(typeOfVariant(v1), typeOfVariant(v2))) - { - case 0: //integer type - { - qlonglong value1 = v1.toLongLong(); - qlonglong value2 = v2.toLongLong(); + for (auto& role : roles) + { + // taken from "bool QTreeWidgetItem::operator<(const QTreeWidgetItem &other) const" + const QVariant v1 = data(column, role); + const QVariant v2 = other.data(column, role); + if (m_noDataAsLast && !v1.isValid() && v2.isValid()) + return sortOrder != Qt::AscendingOrder; + if (m_noDataAsLast && v1.isValid() && !v2.isValid()) + return sortOrder == Qt::AscendingOrder; - if (value1 != value2) { - return value1 < value2; - } - } - break; - case 1: //floating point - { - double value1 = v1.toDouble(); - double value2 = v2.toDouble(); + // taken from "bool QAbstractItemModelPrivate::variantLessThan(const QVariant &v1, const QVariant &v2)" + // but using multi roles to sort + switch(qMax(typeOfVariant(v1), typeOfVariant(v2))) + { + case 0: //integer type + if (v1.toLongLong() != v2.toLongLong()) + return v1.toLongLong() < v2.toLongLong(); + //Fall through + case 1: //floating point + if (v1.toReal() != v2.toReal()) + return v1.toReal() < v2.toReal(); + //Fall through + default: + if (v1.toString().localeAwareCompare(v2.toString()) != 0)//Need Qt::CaseInsensitive ? + return v1.toString().localeAwareCompare(v2.toString()) < 0; + } + } + // If all roles are equals for this column, compare as string - if (value1 != value2) { - return value1 < value2; - } - } - break; - default: - { - int compare = v1.toString().compare (v2.toString(), Qt::CaseInsensitive); - if (compare) { - return (compare < 0); - } - } - } - } + /* Compare DisplayRole */ + const QVariant v1 = data(column, Qt::DisplayRole); + const QVariant v2 = other.data(column, Qt::DisplayRole); - /* Compare DisplayRole */ - const QVariant v1 = data(column, Qt::DisplayRole); - const QVariant v2 = other.data(column, Qt::DisplayRole); - - return (v1.toString().compare (v2.toString(), Qt::CaseInsensitive) < 0); + return (v1.toString().compare (v2.toString(), Qt::CaseInsensitive) < 0); } diff --git a/retroshare-gui/src/gui/common/RSTreeWidgetItem.h b/retroshare-gui/src/gui/common/RSTreeWidgetItem.h index 37119890a..14a22b97c 100644 --- a/retroshare-gui/src/gui/common/RSTreeWidgetItem.h +++ b/retroshare-gui/src/gui/common/RSTreeWidgetItem.h @@ -29,30 +29,49 @@ class RSTreeWidgetItemCompareRole : QMap > { public: - RSTreeWidgetItemCompareRole(); + RSTreeWidgetItemCompareRole(); + explicit RSTreeWidgetItemCompareRole(QMap> map); - void setRole(int column, int role); - void addRole(int column, int role); - void findRoles(const int column, QList &roles) const; + void setRole(const int column, const int role); + void addRole(const int column, const int role); + void findRoles(const int column, QList &roles) const; }; class RSTreeWidgetItem : public QTreeWidgetItem { public: - RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole = NULL, int type = Type); - RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, const QStringList &strings, int type = Type); - RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidget *view, int type = Type); - RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidget *view, const QStringList &strings, int type = Type); - RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidget *view, QTreeWidgetItem *after, int type = Type); - RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidgetItem *parent, int type = Type); - RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidgetItem *parent, const QStringList &strings, int type = Type); - RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidgetItem *parent, QTreeWidgetItem *after, int type = Type); - RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, const QTreeWidgetItem &other); + RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole = NULL, int type = Type); + RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, const QStringList &strings, int type = Type); + RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidget *view, int type = Type); + RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidget *view, const QStringList &strings, int type = Type); + RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidget *view, QTreeWidgetItem *after, int type = Type); + RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidgetItem *parent, int type = Type); + RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidgetItem *parent, const QStringList &strings, int type = Type); + RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, QTreeWidgetItem *parent, QTreeWidgetItem *after, int type = Type); + RSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, const QTreeWidgetItem &other); - bool operator<(const QTreeWidgetItem &other) const; + bool operator<(const QTreeWidgetItem &other) const; + + bool noOrder() const {return m_noOrder;} + /// + /// \brief setNoOrder: Disabled normal sort for this item. It use column 0 and role defined to sort in ascending in qlonglong format. + /// \param value: True disable normal sort but use defined role. + /// \param useRole: The role to use to ascending sort in first(0) column. + /// + void setNoOrder(const bool value, const int useRole = Qt::UserRole) {m_noOrder = value; m_useRoleWhenNoOrder = useRole;} + + bool noDataAsLast() const {return m_noDataAsLast;} + /// + /// \brief setNoDataAsLast: Item without data will be sort as last. Need a RSTreeWidgetItemCompareRole to get it activated. + /// \param value: True to enable this role. + /// + void setNoDataAsLast(const bool value) {m_noDataAsLast = value;} private: - const RSTreeWidgetItemCompareRole *m_compareRole; + const RSTreeWidgetItemCompareRole *m_compareRole; + bool m_noOrder; + int m_useRoleWhenNoOrder; + bool m_noDataAsLast; }; #endif