summaryrefslogtreecommitdiffstats
blob: 8cbfab6ad37adcc9d41e87bd64175fd5d56cdb9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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 &current, 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);
}

}