Make Gxs categories not sortable, item sort by value and possibility for

null to be always at end.
This commit is contained in:
Phenom 2021-02-15 16:27:18 +01:00
parent 861feb113c
commit d3a0ed7690
4 changed files with 156 additions and 91 deletions

View File

@ -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<int, QList<int>>({ {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<RSTreeWidgetItem*>(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;
}

View File

@ -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;
};

View File

@ -20,18 +20,26 @@
#include "RSTreeWidgetItem.h"
#include <QHeaderView>
RSTreeWidgetItemCompareRole::RSTreeWidgetItemCompareRole()
{
}
void RSTreeWidgetItemCompareRole::setRole(int column, int role)
RSTreeWidgetItemCompareRole::RSTreeWidgetItemCompareRole(QMap<int, QList<int>> map)
: QMap<int, QList<int>>(map)
{
}
void RSTreeWidgetItemCompareRole::setRole(const int column, const int role)
{
QList<int> 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<int> &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<int> 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<int>::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<int> 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);
}

View File

@ -29,30 +29,49 @@
class RSTreeWidgetItemCompareRole : QMap<int, QList<int> >
{
public:
RSTreeWidgetItemCompareRole();
RSTreeWidgetItemCompareRole();
explicit RSTreeWidgetItemCompareRole(QMap<int, QList<int>> map);
void setRole(int column, int role);
void addRole(int column, int role);
void findRoles(const int column, QList<int> &roles) const;
void setRole(const int column, const int role);
void addRole(const int column, const int role);
void findRoles(const int column, QList<int> &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