diff options
author | Tobias Markmann <tm@ayena.de> | 2018-05-04 11:00:18 (GMT) |
---|---|---|
committer | Tobias Markmann <tm@ayena.de> | 2018-05-04 11:00:18 (GMT) |
commit | 19eefe66821d26a00d24fbe44aa870309d80ad4b (patch) | |
tree | 8ccac3836a98f45bd5e176d58a3a3c38b035653a /Swift/QtUI | |
parent | 202c114d6b1daa1ea1d4693c434bd8daabd41ad1 (diff) | |
download | swift-19eefe66821d26a00d24fbe44aa870309d80ad4b.zip swift-19eefe66821d26a00d24fbe44aa870309d80ad4b.tar.bz2 |
Use dedicated QtExpandedListView in new roster UI
QtExpandedListView is always high enough to show all entries
in the model. It also correctly hands off scrolling events
to the parent widget for smooth scrolling.
Test-Information:
Tested on macOS 10.13.4 with a well sized roster, that sizing
and scrolling works as expected. Tested with Qt 5.5.1.
Change-Id: I6d93db3045e1c2f343b89c0d45874d8f85a20c0a
Diffstat (limited to 'Swift/QtUI')
-rw-r--r-- | Swift/QtUI/QtChatOverviewBundle.cpp | 22 | ||||
-rw-r--r-- | Swift/QtUI/QtChatOverviewBundle.h | 5 | ||||
-rw-r--r-- | Swift/QtUI/QtExpandedListView.cpp | 109 | ||||
-rw-r--r-- | Swift/QtUI/QtExpandedListView.h | 34 | ||||
-rw-r--r-- | Swift/QtUI/SConscript | 1 |
5 files changed, 149 insertions, 22 deletions
diff --git a/Swift/QtUI/QtChatOverviewBundle.cpp b/Swift/QtUI/QtChatOverviewBundle.cpp index bf99b0c..8505541 100644 --- a/Swift/QtUI/QtChatOverviewBundle.cpp +++ b/Swift/QtUI/QtChatOverviewBundle.cpp @@ -9,7 +9,6 @@ #include <QDebug> #include <QHBoxLayout> #include <QLabel> -#include <QListView> #include <QPalette> #include <QSortFilterProxyModel> #include <QVBoxLayout> @@ -19,6 +18,7 @@ #include <Swift/QtUI/ChattablesModel.h> #include <Swift/QtUI/QtChatOverviewDelegate.h> #include <Swift/QtUI/QtClickableLabel.h> +#include <Swift/QtUI/QtExpandedListView.h> #include <Swift/QtUI/QtSwiftUtil.h> namespace Swift { @@ -100,34 +100,16 @@ QtChatOverviewBundle::QtChatOverviewBundle(ChattablesModel* rootModel, QString n headerLayout->addWidget(filterLabel_); connect(filterLabel_, SIGNAL(clicked()), this, SLOT(handleFilterClicked())); } - listView_ = new QListView(this); + listView_ = new QtExpandedListView(this); listView_->setModel(proxyModel_); listView_->setFrameStyle(QFrame::NoFrame); listView_->setItemDelegate(new QtChatOverviewDelegate(this)); connect(listView_, SIGNAL(clicked(const QModelIndex&)), this, SLOT(handleItemClicked(const QModelIndex&))); - recalculateSize(); mainLayout->addWidget(listView_); - connect(proxyModel_, SIGNAL(rowsInserted(const QModelIndex&, int, int)), this, SLOT(recalculateSize())); - connect(proxyModel_, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), this, SLOT(recalculateSize())); - connect(proxyModel_, SIGNAL(modelReset()), this, SLOT(recalculateSize())); } QtChatOverviewBundle::~QtChatOverviewBundle() {} -void QtChatOverviewBundle::recalculateSize() { - int totalHeight = 0; - for (int i = 0; i < proxyModel_->rowCount(); i++) { - totalHeight += listView_->sizeHintForRow(i); - } - listView_->setFixedHeight(totalHeight); - if (hideWhenEmpty_ && totalHeight == 0) { - hide(); - } - else { - show(); - } -} - void QtChatOverviewBundle::handleFilterClicked() { if (proxyModel_->hasFilter(BundleFilter::Filter::Online)) { proxyModel_->removeFilter(BundleFilter::Filter::Online); diff --git a/Swift/QtUI/QtChatOverviewBundle.h b/Swift/QtUI/QtChatOverviewBundle.h index f469fea..6e232ca 100644 --- a/Swift/QtUI/QtChatOverviewBundle.h +++ b/Swift/QtUI/QtChatOverviewBundle.h @@ -19,6 +19,7 @@ class QListView; namespace Swift { class ChattablesModel; class QtClickableLabel; + class QtExpandedListView; class BundleFilter : public QSortFilterProxyModel { Q_OBJECT @@ -44,12 +45,12 @@ namespace Swift { void clicked(JID jid); private slots: - void recalculateSize(); void handleFilterClicked(); void handleItemClicked(const QModelIndex&); + private: ChattablesModel* rootModel_; - QListView* listView_; + QtExpandedListView* listView_; BundleFilter* proxyModel_; bool hideWhenEmpty_; QtClickableLabel* filterLabel_ = nullptr; diff --git a/Swift/QtUI/QtExpandedListView.cpp b/Swift/QtUI/QtExpandedListView.cpp new file mode 100644 index 0000000..8cbfab6 --- /dev/null +++ b/Swift/QtUI/QtExpandedListView.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <Swift/QtUI/QtExpandedListView.h> + +#include <QWheelEvent> +#include <QScrollArea> + +namespace Swift { + +QtExpandedListView::QtExpandedListView(QWidget* parent) : QListView(parent) { + // Disable macOS focus rectangle due to bad performance. + setAttribute(Qt::WA_MacShowFocusRect, 0); + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); +} + +void QtExpandedListView::setModel(QAbstractItemModel* newModel) { + if (model()) { + disconnectFromModel(model()); + } + if (newModel) { + connectToModel(newModel); + } + QListView::setModel(newModel); + adjustHeightToModelChange(); +} + +QtExpandedListView::~QtExpandedListView() { + if (model()) { + disconnectFromModel(model()); + } +} + +bool QtExpandedListView::viewportEvent(QEvent* event) { + // Ignore wheel events for faster mouse scrolling. + if (event && event->type() == QEvent::Wheel) { + return false; + } + + return QListView::viewportEvent(event); +} + +template <typename T> +T getParentOfType(QWidget* start) { + auto parentW = start->parentWidget(); + if (parentW == nullptr) { + return nullptr; + } + T result = dynamic_cast<T>(parentW); + if (result) { + return result; + } + return getParentOfType<T>(parentW); +} + +void QtExpandedListView::currentChanged(const QModelIndex ¤t, const QModelIndex &) { + // Make sure that the current selected index is visible in the parent QScrollArea. + auto scrollArea = getParentOfType<QScrollArea*>(parentWidget()); + if (scrollArea) { + QList<QPoint> points; + auto visRect = visualRect(current); + points << pos() + visRect.topLeft(); + points << pos() + visRect.topRight(); + points << pos() + visRect.bottomLeft(); + points << pos() + visRect.bottomRight(); + + for (auto&& point : points) { + scrollArea->ensureVisible(point.x(), point.y(), 0, 0); + } + } +} + +void QtExpandedListView::adjustHeightToModelChange() { + updateGeometry(); +} + +QSize QtExpandedListView::minimumSizeHint() const { + auto sh = sizeHint(); + return QSize(0, sh.height()); +} + +QSize QtExpandedListView::sizeHint() const { + auto listViewSH = QListView::sizeHint(); + if (model()) { + auto lastRect = rectForIndex(model()->index(model()->rowCount()-1, 0, rootIndex())); + auto idealHeight = lastRect.y() + lastRect.height() + frameWidth() * 2; + listViewSH.setHeight(idealHeight); + } + return listViewSH; +} + +void QtExpandedListView::connectToModel(QAbstractItemModel* model) { + connect(model, &QAbstractItemModel::dataChanged, this, &QtExpandedListView::adjustHeightToModelChange); + connect(model, &QAbstractItemModel::modelReset, this, &QtExpandedListView::adjustHeightToModelChange); + connect(model, &QAbstractItemModel::rowsInserted, this, &QtExpandedListView::adjustHeightToModelChange); + connect(model, &QAbstractItemModel::rowsRemoved, this, &QtExpandedListView::adjustHeightToModelChange); +} + +void QtExpandedListView::disconnectFromModel(QAbstractItemModel* model) { + disconnect(model, &QAbstractItemModel::dataChanged, this, &QtExpandedListView::adjustHeightToModelChange); + disconnect(model, &QAbstractItemModel::modelReset, this, &QtExpandedListView::adjustHeightToModelChange); + disconnect(model, &QAbstractItemModel::rowsInserted, this, &QtExpandedListView::adjustHeightToModelChange); + disconnect(model, &QAbstractItemModel::rowsRemoved, this, &QtExpandedListView::adjustHeightToModelChange); +} + +} diff --git a/Swift/QtUI/QtExpandedListView.h b/Swift/QtUI/QtExpandedListView.h new file mode 100644 index 0000000..df78376 --- /dev/null +++ b/Swift/QtUI/QtExpandedListView.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <QListView> + +namespace Swift { + +class QtExpandedListView : public QListView { +public: + QtExpandedListView(QWidget* parent); + ~QtExpandedListView() override; + + void setModel(QAbstractItemModel* model) override; + bool viewportEvent(QEvent* event) override; + QSize minimumSizeHint() const override; + QSize sizeHint() const override; + +protected slots: + void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override; + +private slots: + void adjustHeightToModelChange(); + +private: + void connectToModel(QAbstractItemModel* model); + void disconnectFromModel(QAbstractItemModel* model); +}; + +} diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index e61bdcf..b8ec3ba 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -169,6 +169,7 @@ sources = [ "QtEmojisScroll.cpp", "QtEmojisSelector.cpp", "QtEmoticonsGrid.cpp", + "QtExpandedListView.cpp", "QtFileTransferListItemModel.cpp", "QtFileTransferListWidget.cpp", "QtFormResultItemModel.cpp", |