Changeset View
Changeset View
Standalone View
Standalone View
src/folder/accounttabbar.cpp
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | Copyright (c) 2017 Daniel Vrátil <dvratil@kde.org> | ||||
3 | | ||||
4 | This program is free software; you can redistribute it and/or modify it | ||||
5 | under the terms of the GNU General Public License, version 2, as | ||||
6 | published by the Free Software Foundation. | ||||
7 | | ||||
8 | This program is distributed in the hope that it will be useful, but | ||||
9 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
11 | General Public License for more details. | ||||
12 | | ||||
13 | You should have received a copy of the GNU General Public License along | ||||
14 | with this program; if not, write to the Free Software Foundation, Inc., | ||||
15 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
16 | */ | ||||
17 | | ||||
18 | #include "accounttabbar_p.h" | ||||
19 | | ||||
20 | #include <QAbstractItemModel> | ||||
21 | #include <QIcon> | ||||
22 | #include <QLabel> | ||||
23 | #include <QPainter> | ||||
24 | #include <AkonadiCore/EntityTreeModel> | ||||
25 | #include <QResizeEvent> | ||||
26 | | ||||
27 | #include <KColorScheme> | ||||
28 | | ||||
29 | using namespace MailCommon; | ||||
30 | | ||||
31 | AccountTabBar::AccountTabBar(QWidget *parent) | ||||
32 | : QTabBar(parent) | ||||
33 | , mModel(nullptr) | ||||
34 | {} | ||||
35 | | ||||
36 | AccountTabBar::~AccountTabBar() | ||||
37 | { | ||||
38 | } | ||||
39 | | ||||
40 | void AccountTabBar::setModel(QAbstractItemModel *model) | ||||
41 | { | ||||
42 | if (mModel) { | ||||
43 | disconnect(mModel, &QAbstractItemModel::rowsInserted, | ||||
44 | this, &AccountTabBar::onRowsInserted); | ||||
45 | disconnect(mModel, &QAbstractItemModel::rowsRemoved, | ||||
46 | this, &AccountTabBar::onRowsRemoved); | ||||
47 | disconnect(mModel, &QAbstractItemModel::rowsMoved, | ||||
48 | this, &AccountTabBar::onRowsMoved); | ||||
49 | disconnect(mModel, &QAbstractItemModel::modelReset, | ||||
50 | this, &AccountTabBar::onModelReset); | ||||
51 | disconnect(mModel, &QAbstractItemModel::dataChanged, | ||||
52 | this, &AccountTabBar::onDataChanged); | ||||
53 | } | ||||
54 | | ||||
55 | mModel = model; | ||||
56 | if (model) { | ||||
57 | connect(mModel, &QAbstractItemModel::rowsInserted, | ||||
58 | this, &AccountTabBar::onRowsInserted); | ||||
59 | connect(mModel, &QAbstractItemModel::rowsRemoved, | ||||
60 | this, &AccountTabBar::onRowsRemoved); | ||||
61 | connect(mModel, &QAbstractItemModel::rowsMoved, | ||||
62 | this, &AccountTabBar::onRowsMoved); | ||||
63 | connect(mModel, &QAbstractItemModel::modelReset, | ||||
64 | this, &AccountTabBar::onModelReset); | ||||
65 | connect(mModel, &QAbstractItemModel::dataChanged, | ||||
66 | this, &AccountTabBar::onDataChanged); | ||||
67 | | ||||
68 | onModelReset(); | ||||
69 | } else { | ||||
70 | onRowsRemoved(QModelIndex(), 0, count() - 1); | ||||
71 | } | ||||
72 | } | ||||
73 | | ||||
74 | QAbstractItemModel *AccountTabBar::model() const | ||||
75 | { | ||||
76 | return mModel; | ||||
77 | } | ||||
78 | | ||||
79 | int AccountTabBar::tabForIndex(const QModelIndex &index) const | ||||
80 | { | ||||
81 | QModelIndex idx = index; | ||||
82 | while (idx.parent().isValid()) { | ||||
83 | idx = idx.parent(); | ||||
84 | } | ||||
85 | | ||||
86 | for (int i = 0; i < count(); ++i) { | ||||
87 | if (idx == tabData(i).value<QPersistentModelIndex>()) { | ||||
88 | return i; | ||||
89 | } | ||||
90 | } | ||||
91 | | ||||
92 | return -1; | ||||
93 | } | ||||
94 | | ||||
95 | void AccountTabBar::onRowsInserted(const QModelIndex &parent, int first, int last) | ||||
96 | { | ||||
97 | if (!parent.isValid()) { | ||||
98 | for (int i = first; i <= last; ++i) { | ||||
99 | const auto index = mModel->index(i, 0, parent); | ||||
100 | | ||||
101 | const auto title = mModel->data(index, Qt::DisplayRole).toString(); | ||||
102 | const auto icon = mModel->data(index, Qt::DecorationRole).value<QIcon>(); | ||||
103 | | ||||
104 | insertTab(i, icon, title); | ||||
105 | setTabData(i, QVariant::fromValue(QPersistentModelIndex(index))); | ||||
106 | updateUnreadCount(i); | ||||
107 | } | ||||
108 | } else { | ||||
109 | updateUnreadCount(tabForIndex(parent)); | ||||
110 | } | ||||
111 | } | ||||
112 | | ||||
113 | void AccountTabBar::onRowsRemoved(const QModelIndex &parent, int first, int last) | ||||
114 | { | ||||
115 | if (!parent.isValid()) { | ||||
116 | for (int i = last; i >= first; --i) { | ||||
117 | removeTab(i); | ||||
118 | } | ||||
119 | } else { | ||||
120 | updateUnreadCount(tabForIndex(parent)); | ||||
121 | } | ||||
122 | } | ||||
123 | | ||||
124 | void AccountTabBar::onRowsMoved(const QModelIndex &parent, int start, int end, | ||||
125 | const QModelIndex &dest, int row) | ||||
126 | { | ||||
127 | // Rows moved from top-level to inner-level is a remove to us | ||||
128 | if (dest.isValid()) { | ||||
129 | onRowsRemoved(parent, start, end); | ||||
130 | const int srcTab = tabForIndex(parent); | ||||
131 | const int dstTab = tabForIndex(dest); | ||||
132 | if (srcTab != dstTab) { | ||||
133 | updateUnreadCount(srcTab); | ||||
134 | updateUnreadCount(dstTab); | ||||
135 | } | ||||
136 | } else if (parent.isValid()) { | ||||
137 | for (int i = start; i <= end; ++i) { | ||||
138 | onRowsInserted(QModelIndex(), i, 0); | ||||
139 | } | ||||
140 | } else { | ||||
141 | for (int i = start; i <= end; ++i) { | ||||
142 | moveTab(i, row); | ||||
143 | } | ||||
144 | } | ||||
145 | } | ||||
146 | | ||||
147 | void AccountTabBar::onModelReset() | ||||
148 | { | ||||
149 | onRowsRemoved(QModelIndex(), 0, count() - 1); | ||||
150 | onRowsInserted(QModelIndex(), 0, mModel->rowCount() - 1); | ||||
151 | } | ||||
152 | | ||||
153 | void AccountTabBar::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, | ||||
154 | const QVector<int> &roles) | ||||
155 | { | ||||
156 | if (!topLeft.parent().isValid()) { | ||||
157 | const bool empty = roles.isEmpty(); | ||||
158 | const bool nameChanged = empty || roles.contains(Qt::DisplayRole); | ||||
159 | const bool iconChanged = empty || roles.contains(Qt::DecorationRole); | ||||
160 | | ||||
161 | if (!nameChanged && !iconChanged) { | ||||
162 | return; | ||||
163 | } | ||||
164 | | ||||
165 | for (int i = topLeft.row(), end = bottomRight.row(); i <= end; ++i) { | ||||
166 | const QModelIndex idx = topLeft.sibling(i, 0); | ||||
167 | if (nameChanged) { | ||||
168 | setTabText(i, mModel->data(idx, Qt::DisplayRole).toString()); | ||||
169 | } | ||||
170 | if (iconChanged) { | ||||
171 | setTabIcon(i, mModel->data(idx, Qt::DecorationRole).value<QIcon>()); | ||||
172 | } | ||||
173 | } | ||||
174 | } | ||||
175 | | ||||
176 | const int tab = tabForIndex(topLeft); | ||||
177 | updateUnreadCount(tab); | ||||
178 | } | ||||
179 | | ||||
180 | void AccountTabBar::updateUnreadCount(int tabIndex) | ||||
181 | { | ||||
182 | const QModelIndex tabModelIndex = tabData(tabIndex).value<QPersistentModelIndex>(); | ||||
183 | QVector<QModelIndex> stack; | ||||
184 | stack << tabModelIndex; | ||||
185 | quint64 unreadCnt = 0; | ||||
186 | while (!stack.isEmpty()) { | ||||
187 | QModelIndex idx = stack.takeFirst(); | ||||
188 | unreadCnt += mModel->data(idx, Akonadi::EntityTreeModel::UnreadCountRole).toLongLong(); | ||||
189 | | ||||
190 | for (int i = 0, c = mModel->rowCount(idx); i < c; ++i) { | ||||
191 | stack.push_front(mModel->index(i, 0, idx)); | ||||
192 | } | ||||
193 | } | ||||
194 | | ||||
195 | const auto name = mModel->data(tabModelIndex, Qt::DisplayRole).toString(); | ||||
196 | if (unreadCnt > 0) { | ||||
197 | setTabText(tabIndex, QStringLiteral("%1 (%2)").arg(name).arg(unreadCnt)); | ||||
198 | } else { | ||||
199 | setTabText(tabIndex, name); | ||||
200 | } | ||||
201 | } |