added filtering

This commit is contained in:
csoler 2025-02-23 14:50:48 +01:00
parent 37c0f16a27
commit a826a8651c
3 changed files with 157 additions and 31 deletions

View file

@ -146,6 +146,59 @@ class TreeWidgetItem : public QTreeWidgetItem
}; };
#endif #endif
std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere
class IdListSortFilterProxyModel: public QSortFilterProxyModel
{
public:
explicit IdListSortFilterProxyModel(const QHeaderView *header,QObject *parent = NULL)
: QSortFilterProxyModel(parent)
, m_header(header)
, m_sortingEnabled(false), m_sortByState(false)
{
setDynamicSortFilter(false); // causes crashes when true.
}
bool lessThan(const QModelIndex& left, const QModelIndex& right) const override
{
// bool online1 = (left .data(RsFriendListModel::OnlineRole).toInt() != RS_STATUS_OFFLINE);
// bool online2 = (right.data(RsFriendListModel::OnlineRole).toInt() != RS_STATUS_OFFLINE);
//
// if((online1 != online2) && m_sortByState)
// return (m_header->sortIndicatorOrder()==Qt::AscendingOrder)?online1:online2 ; // always put online nodes first
#ifdef DEBUG_NEW_FRIEND_LIST
std::cerr << "Comparing index " << left << " with index " << right << std::endl;
#endif
return QSortFilterProxyModel::lessThan(left,right);
}
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override
{
// do not show empty groups
QModelIndex index = sourceModel()->index(source_row,0,source_parent);
return index.data(RsIdentityListModel::FilterRole).toString() == RsIdentityListModel::FilterString ;
}
void sort( int column, Qt::SortOrder order = Qt::AscendingOrder ) override
{
if(m_sortingEnabled)
return QSortFilterProxyModel::sort(column,order) ;
}
void setSortingEnabled(bool b) { m_sortingEnabled = b ; }
void setSortByState(bool b) { m_sortByState = b ; }
bool sortByState() const { return m_sortByState ; }
private:
const QHeaderView *m_header ;
bool m_sortingEnabled;
bool m_sortByState;
};
/** Constructor */ /** Constructor */
IdDialog::IdDialog(QWidget *parent) IdDialog::IdDialog(QWidget *parent)
: MainPage(parent) : MainPage(parent)
@ -169,7 +222,15 @@ IdDialog::IdDialog(QWidget *parent)
mIdListModel = new RsIdentityListModel(this); mIdListModel = new RsIdentityListModel(this);
ui->idTreeWidget->setModel(mIdListModel); mProxyModel = new IdListSortFilterProxyModel(ui->idTreeWidget->header(),this);
mProxyModel->setSourceModel(mIdListModel);
mProxyModel->setSortRole(RsIdentityListModel::SortRole);
mProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
mProxyModel->setFilterRole(RsIdentityListModel::FilterRole);
mProxyModel->setFilterRegExp(QRegExp(RsIdentityListModel::FilterString));
ui->idTreeWidget->setModel(mProxyModel);
ui->treeWidget_membership->clear(); ui->treeWidget_membership->clear();
ui->treeWidget_membership->setItemDelegateForColumn(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,new GxsIdTreeItemDelegate()); ui->treeWidget_membership->setItemDelegateForColumn(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,new GxsIdTreeItemDelegate());
@ -1206,9 +1267,18 @@ IdDialog::~IdDialog()
// save settings // save settings
processSettings(false); processSettings(false);
delete mIdListModel;
delete mProxyModel;
delete(ui); delete(ui);
} }
void IdDialog::idListItemExpanded(const QModelIndex& index)
{
mIdListModel->expandItem(mProxyModel->mapToSource(index));
}
void IdDialog::idListItemCollapsed(const QModelIndex& index)
{
mIdListModel->collapseItem(mProxyModel->mapToSource(index));
}
static QString getHumanReadableDuration(uint32_t seconds) static QString getHumanReadableDuration(uint32_t seconds)
{ {
if(seconds < 60) if(seconds < 60)
@ -1299,14 +1369,7 @@ void IdDialog::updateIdList()
std::cerr << "Updating identity list in widget: stack is:" << std::endl; std::cerr << "Updating identity list in widget: stack is:" << std::endl;
//print_stacktrace(); //print_stacktrace();
std::set<QString> expanded_indices; applyWhileKeepingTree( [this]() { mIdListModel->updateIdentityList(); });
std::set<std::pair<RsIdentityListModel::EntryType,QString> > selected_indices;
saveExpandedPathsAndSelection_idTreeView(expanded_indices, selected_indices);
mIdListModel->updateIdentityList();
restoreExpandedPathsAndSelection_idTreeView(expanded_indices, selected_indices);
} }
#ifdef TO_REMOVE #ifdef TO_REMOVE
bool IdDialog::fillIdListItem(const RsGxsIdGroup& data, QTreeWidgetItem *&item, const RsPgpId &ownPgpId, int accept) bool IdDialog::fillIdListItem(const RsGxsIdGroup& data, QTreeWidgetItem *&item, const RsPgpId &ownPgpId, int accept)
@ -1595,12 +1658,8 @@ void IdDialog::updateIdentity()
std::set<QString> expanded_indexes; std::set<QString> expanded_indexes;
std::set<std::pair<RsIdentityListModel::EntryType,QString> > selected_indices; std::set<std::pair<RsIdentityListModel::EntryType,QString> > selected_indices;
//saveExpandedPathsAndSelection_idTreeView(expanded_indexes, selected_indices);
loadIdentity(group); loadIdentity(group);
//restoreExpandedPathsAndSelection_idTreeView(expanded_indexes, selected_indices);
}, this ); }, this );
}); });
} }
@ -2016,7 +2075,7 @@ std::list<RsGxsId> IdDialog::getSelectedIdentities() const
RsGxsId id; RsGxsId id;
if(indx.column() == RsIdentityListModel::COLUMN_THREAD_NAME) // this removes duplicates if(indx.column() == RsIdentityListModel::COLUMN_THREAD_NAME) // this removes duplicates
if( !(id = mIdListModel->getIdentity(indx)).isNull() ) if( !(id = mIdListModel->getIdentity(mProxyModel->mapToSource(indx))).isNull() )
res.push_back(id); res.push_back(id);
} }
@ -2553,23 +2612,24 @@ void IdDialog::saveExpandedPathsAndSelection_idTreeView(std::set<QString>& expan
QString s ; QString s ;
if(t==RsIdentityListModel::ENTRY_TYPE_CATEGORY) if(t==RsIdentityListModel::ENTRY_TYPE_CATEGORY)
s = QString::number(mIdListModel->getCategory(m)); s = QString::number(mIdListModel->getCategory(mProxyModel->mapToSource(m)));
else else
s = QString::fromStdString(mIdListModel->getIdentity(m).toStdString()); s = QString::fromStdString(mIdListModel->getIdentity(mProxyModel->mapToSource(m)).toStdString());
selected_indices.insert(std::make_pair(t,s)); selected_indices.insert(std::make_pair(t,s));
std::cerr << "added " << s.toStdString() << " to selection save" << std::endl; std::cerr << "added " << s.toStdString() << " to selection save" << std::endl;
} }
for(int row = 0; row < mIdListModel->rowCount(); ++row) for(int row = 0; row < mProxyModel->rowCount(); ++row)
{ {
auto m = mIdListModel->index(row,0,QModelIndex()); auto m = mProxyModel->index(row,0);
if(ui->idTreeWidget->isExpanded( m )) if(ui->idTreeWidget->isExpanded( m ))
{ {
expanded_indexes.insert( QString::number(mIdListModel->getCategory(m))); auto str = QString::number(mIdListModel->getCategory(mProxyModel->mapToSource(m)));
std::cerr << "added " << QString::number(mIdListModel->getCategory(m)).toStdString() << " to expanded save" << std::endl; expanded_indexes.insert( str );
std::cerr << "added " << m << " cat " << str.toStdString() << " to expanded save" << std::endl;
} }
} }
@ -2585,19 +2645,17 @@ void IdDialog::restoreExpandedPathsAndSelection_idTreeView(const std::set<QStrin
ui->idTreeWidget->blockSignals(true) ; ui->idTreeWidget->blockSignals(true) ;
ui->idTreeWidget->selectionModel()->blockSignals(true); ui->idTreeWidget->selectionModel()->blockSignals(true);
ui->idTreeWidget->selectionModel()->clear();
for(auto it:selected_indices) for(auto it:selected_indices)
{ {
if(it.first==RsIdentityListModel::ENTRY_TYPE_CATEGORY) if(it.first==RsIdentityListModel::ENTRY_TYPE_CATEGORY)
ui->idTreeWidget->selectionModel()->select(mIdListModel->index(it.first,0,QModelIndex()),QItemSelectionModel::Select | QItemSelectionModel::Rows); ui->idTreeWidget->selectionModel()->select(mProxyModel->mapFromSource(mIdListModel->index(it.first,0,QModelIndex())),QItemSelectionModel::Select | QItemSelectionModel::Rows);
else if(it.first==RsIdentityListModel::ENTRY_TYPE_IDENTITY) else if(it.first==RsIdentityListModel::ENTRY_TYPE_IDENTITY)
{ {
auto indx = mIdListModel->getIndexOfIdentity(RsGxsId(it.second.toStdString())); auto indx = mProxyModel->mapFromSource(mIdListModel->getIndexOfIdentity(RsGxsId(it.second.toStdString())));
if(indx.isValid()) if(indx.isValid())
{ {
std::cerr << "trying to resotre selection of id " << it.second.toStdString() << std::endl; std::cerr << "trying to restore selection of id " << it.second.toStdString() << std::endl;
ui->idTreeWidget->selectionModel()->select(indx,QItemSelectionModel::Select | QItemSelectionModel::Rows); ui->idTreeWidget->selectionModel()->select(indx,QItemSelectionModel::Select | QItemSelectionModel::Rows);
} }
else else
@ -2606,23 +2664,84 @@ void IdDialog::restoreExpandedPathsAndSelection_idTreeView(const std::set<QStrin
} }
//ui->idTreeWidget->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows); //ui->idTreeWidget->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
ui->idTreeWidget->blockSignals(false) ;
ui->idTreeWidget->selectionModel()->blockSignals(false);
#ifdef DEBUG_NEW_FRIEND_LIST #ifdef DEBUG_NEW_FRIEND_LIST
std::cerr << " index to select: \"" << index_to_select.toStdString() << "\"" << std::endl; std::cerr << " index to select: \"" << index_to_select.toStdString() << "\"" << std::endl;
#endif #endif
for(int row = 0; row < mIdListModel->rowCount(); ++row) for(int row = 0; row < mIdListModel->rowCount(); ++row)
{ {
auto m = mIdListModel->index(row,0,QModelIndex()); auto m = ui->idTreeWidget->model()->index(row,0);
std::cerr << " index category = " << mIdListModel->getCategory(m) << std::endl;
if(expanded_indexes.find(QString::number(mIdListModel->getCategory(m))) != expanded_indexes.end()) if(expanded_indexes.find(QString::number(mIdListModel->getCategory(m))) != expanded_indexes.end())
{ {
std::cerr << "Restoring expanded index " << QString::number(mIdListModel->getCategory(m)).toStdString() << std::endl; std::cerr << "Restoring expanded index " << QString::number(mIdListModel->getCategory(m)).toStdString() << std::endl;
std::cerr << "Calling setExpanded " << m << std::endl;
ui->idTreeWidget->setExpanded(m,true); ui->idTreeWidget->setExpanded(m,true);
} }
else else
ui->idTreeWidget->setExpanded(m,false); ui->idTreeWidget->setExpanded(m,false);
} }
ui->idTreeWidget->blockSignals(false) ;
ui->idTreeWidget->selectionModel()->blockSignals(false);
} }
void IdDialog::applyWhileKeepingTree(std::function<void()> predicate)
{
std::set<QString> expanded_indexes;
std::set<std::pair<RsIdentityListModel::EntryType,QString> > selected;
saveExpandedPathsAndSelection_idTreeView(expanded_indexes, selected);
#ifdef DEBUG_NEW_FRIEND_LIST
std::cerr << "After collecting selection, selected paths is: \"" << selected.toStdString() << "\", " ;
std::cerr << "expanded paths are: " << std::endl;
for(auto path:expanded_indexes)
std::cerr << " \"" << path.toStdString() << "\"" << std::endl;
std::cerr << "Current sort column is: " << mLastSortColumn << " and order is " << mLastSortOrder << std::endl;
#endif
whileBlocking(ui->idTreeWidget)->clearSelection();
// This is a hack to avoid crashes on windows while calling endInsertRows(). I'm not sure wether these crashes are
// due to a Qt bug, or a misuse of the proxy model on my side. Anyway, this solves them for good.
// As a side effect we need to save/restore hidden columns because setSourceModel() resets this setting.
// save hidden columns and sizes
std::vector<bool> col_visible(RsIdentityListModel::COLUMN_THREAD_NB_COLUMNS);
std::vector<int> col_sizes(RsIdentityListModel::COLUMN_THREAD_NB_COLUMNS);
for(int i=0;i<RsIdentityListModel::COLUMN_THREAD_NB_COLUMNS;++i)
{
col_visible[i] = !ui->idTreeWidget->isColumnHidden(i);
col_sizes[i] = ui->idTreeWidget->columnWidth(i);
}
#ifdef DEBUG_NEW_FRIEND_LIST
std::cerr << "Applying predicate..." << std::endl;
#endif
mProxyModel->setSourceModel(nullptr);
predicate();
mProxyModel->setSourceModel(mIdListModel);
restoreExpandedPathsAndSelection_idTreeView(expanded_indexes,selected);
// restore hidden columns
for(uint32_t i=0;i<RsIdentityListModel::COLUMN_THREAD_NB_COLUMNS;++i)
{
ui->idTreeWidget->setColumnHidden(i,!col_visible[i]);
ui->idTreeWidget->setColumnWidth(i,col_sizes[i]);
}
// restore sorting
// sortColumn(mLastSortColumn,mLastSortOrder);
#ifdef DEBUG_NEW_FRIEND_LIST
std::cerr << "Sorting again with sort column: " << mLastSortColumn << " and order " << mLastSortOrder << std::endl;
#endif
mProxyModel->setSortingEnabled(true);
// mProxyModel->sort(mLastSortColumn,mLastSortOrder);
mProxyModel->setSortingEnabled(false);
// if(selected_index.isValid())
// ui->idTreeWidget->scrollTo(selected_index);
}

View file

@ -37,6 +37,7 @@ class IdDialog;
class UIStateHelper; class UIStateHelper;
class QTreeWidgetItem; class QTreeWidgetItem;
class RsIdentityListModel; class RsIdentityListModel;
class IdListSortFilterProxyModel;
class IdDialog : public MainPage class IdDialog : public MainPage
{ {
@ -150,14 +151,20 @@ private:
void saveExpandedCircleItems(std::vector<bool> &expanded_root_items, std::set<RsGxsCircleId>& expanded_circle_items) const; void saveExpandedCircleItems(std::vector<bool> &expanded_root_items, std::set<RsGxsCircleId>& expanded_circle_items) const;
void restoreExpandedCircleItems(const std::vector<bool>& expanded_root_items,const std::set<RsGxsCircleId>& expanded_circle_items); void restoreExpandedCircleItems(const std::vector<bool>& expanded_root_items,const std::set<RsGxsCircleId>& expanded_circle_items);
void applyWhileKeepingTree(std::function<void()> predicate);
RsGxsId getSelectedIdentity() const; RsGxsId getSelectedIdentity() const;
std::list<RsGxsId> getSelectedIdentities() const; std::list<RsGxsId> getSelectedIdentities() const;
void idListItemExpanded(const QModelIndex& index);
void idListItemCollapsed(const QModelIndex& index);
RsGxsGroupId mId; RsGxsGroupId mId;
RsGxsGroupId mIdToNavigate; RsGxsGroupId mIdToNavigate;
int filter; int filter;
RsIdentityListModel *mIdListModel; RsIdentityListModel *mIdListModel;
IdListSortFilterProxyModel *mProxyModel;
void handleEvent_main_thread(std::shared_ptr<const RsEvent> event); void handleEvent_main_thread(std::shared_ptr<const RsEvent> event);
RsEventsHandlerId_t mEventHandlerId_identity; RsEventsHandlerId_t mEventHandlerId_identity;

View file

@ -96,7 +96,7 @@ bool RsIdentityListModel::convertIndexToInternalId(const EntryIndex& e,quintptr&
return false; return false;
} }
id = (((uint32_t)e.category_index) << 30) + ((uint32_t)e.identity_index << 2) + ((uint32_t)e.type); id = ((0x3 & (uint32_t)e.category_index) << 30) + ((uint32_t)e.identity_index << 2) + (0x3 & (uint32_t)e.type);
return true; return true;
} }