20 #include "statisticsproxymodel.h"
22 #include "entitytreemodel.h"
23 #include "collectionutils_p.h"
25 #include <akonadi/collectionquotaattribute.h>
26 #include <akonadi/collectionstatistics.h>
27 #include <akonadi/entitydisplayattribute.h>
30 #include <kiconloader.h>
31 #include <klocalizedstring.h>
32 #include <kio/global.h>
34 #include <QApplication>
42 class StatisticsProxyModel::Private
47 , mToolTipEnabled(false)
48 , mExtraColumnsEnabled(true)
52 int sourceColumnCount(
const QModelIndex &parent)
54 return mParent->sourceModel()->columnCount(mParent->mapToSource(parent));
57 void getCountRecursive(
const QModelIndex &index, qint64 &totalSize)
const
62 if (collection.isValid()) {
64 totalSize += qMax(0LL, statistics.
size());
65 if (index.model()->hasChildren(index)) {
66 const int rowCount = index.model()->rowCount(index);
67 for (
int row = 0; row < rowCount; row++) {
68 static const int column = 0;
69 getCountRecursive(index.model()->index(row, column, index), totalSize);
75 QString toolTipForCollection(
const QModelIndex &index,
const Collection &collection)
77 QString bckColor = QApplication::palette().color(QPalette::ToolTipBase).name();
78 QString txtColor = QApplication::palette().color(QPalette::ToolTipText).name();
80 QString tip = QString::fromLatin1(
81 "<table width=\"100%\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\">\n"
83 const QString textDirection = (QApplication::layoutDirection() == Qt::LeftToRight) ? QLatin1String(
"left") : QLatin1String(
"right");
84 tip += QString::fromLatin1(
86 " <td bgcolor=\"%1\" colspan=\"2\" align=\"%4\" valign=\"middle\">\n"
87 " <div style=\"color: %2; font-weight: bold;\">\n"
92 ).arg(txtColor).arg(bckColor).arg(index.data(Qt::DisplayRole).toString()).arg(textDirection);
94 tip += QString::fromLatin1(
96 " <td align=\"%1\" valign=\"top\">\n"
100 tipInfo += QString::fromLatin1(
101 " <strong>%1</strong>: %2<br>\n"
102 " <strong>%3</strong>: %4<br><br>\n"
103 ).arg(i18n(
"Total Messages")).arg(collection.statistics().count())
104 .arg(i18n(
"Unread Messages")).arg(collection.statistics().unreadCount());
111 if (qAbs(percentage) >= 0.01) {
112 QString percentStr = QString::number(percentage,
'f', 2);
113 tipInfo += QString::fromLatin1(
114 " <strong>%1</strong>: %2%<br>\n"
115 ).arg(i18n(
"Quota")).arg(percentStr);
120 qint64 currentFolderSize(collection.statistics().size());
121 tipInfo += QString::fromLatin1(
122 " <strong>%1</strong>: %2<br>\n"
123 ).arg(i18n(
"Storage Size")).arg(KIO::convertSize((KIO::filesize_t)(currentFolderSize)));
125 qint64 totalSize = 0;
126 getCountRecursive(index, totalSize);
127 totalSize -= currentFolderSize;
129 tipInfo += QString::fromLatin1(
130 "<strong>%1</strong>: %2<br>"
131 ).arg(i18n(
"Subfolder Storage Size")).arg(KIO::convertSize((KIO::filesize_t)(totalSize)));
134 QString iconName = CollectionUtils::defaultIconName(collection);
144 int iconSizes[] = { 32, 22 };
145 int icon_size_found = 32;
149 for (
int i = 0; i < 2; i++) {
150 iconPath = KIconLoader::global()->iconPath(iconName, -iconSizes[i],
true);
151 if (!iconPath.isEmpty()) {
152 icon_size_found = iconSizes[i];
157 if (iconPath.isEmpty()) {
158 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"folder"), -32,
false);
161 QString tipIcon = QString::fromLatin1(
162 " <table border=\"0\"><tr><td width=\"32\" height=\"32\" align=\"center\" valign=\"middle\">\n"
163 " <img src=\"%1\" width=\"%2\" height=\"32\">\n"
164 " </td></tr></table>\n"
166 ).arg(iconPath).arg(icon_size_found) ;
168 if (QApplication::layoutDirection() == Qt::LeftToRight) {
169 tip += tipInfo + QString::fromLatin1(
"</td><td align=\"%3\" valign=\"top\">").arg(textDirection) + tipIcon;
171 tip += tipIcon + QString::fromLatin1(
"</td><td align=\"%3\" valign=\"top\">").arg(textDirection) + tipInfo;
174 tip += QString::fromLatin1(
182 void proxyDataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight);
184 void sourceLayoutAboutToBeChanged();
185 void sourceLayoutChanged();
187 QVector<QModelIndex> m_nonPersistent;
188 QVector<QModelIndex> m_nonPersistentFirstColumn;
189 QVector<QPersistentModelIndex> m_persistent;
190 QVector<QPersistentModelIndex> m_persistentFirstColumn;
194 bool mToolTipEnabled;
195 bool mExtraColumnsEnabled;
198 void StatisticsProxyModel::Private::proxyDataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight)
200 if (mExtraColumnsEnabled) {
203 QModelIndex parent = topLeft.parent();
204 int parentColumnCount = mParent->columnCount(parent);
205 QModelIndex extraTopLeft = mParent->index(topLeft.row(), parentColumnCount - 1 - 3 , parent);
206 QModelIndex extraBottomRight = mParent->index(bottomRight.row(), parentColumnCount - 1, parent);
207 mParent->disconnect(mParent, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
208 mParent, SLOT(proxyDataChanged(QModelIndex,QModelIndex)));
209 emit mParent->dataChanged(extraTopLeft, extraBottomRight);
214 while (parent.isValid()) {
215 emit mParent->dataChanged(parent.sibling(parent.row(), parentColumnCount - 1 - 3),
216 parent.sibling(parent.row(), parentColumnCount - 1));
217 parent = parent.parent();
218 parentColumnCount = mParent->columnCount(parent);
220 mParent->connect(mParent, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
221 SLOT(proxyDataChanged(QModelIndex,QModelIndex)));
225 void StatisticsProxyModel::Private::sourceLayoutAboutToBeChanged()
227 QModelIndexList persistent = mParent->persistentIndexList();
228 const int columnCount = mParent->sourceModel()->columnCount();
229 foreach (
const QModelIndex &idx, persistent) {
230 if (idx.column() >= columnCount) {
231 m_nonPersistent.push_back(idx);
232 m_persistent.push_back(idx);
233 const QModelIndex firstColumn = idx.sibling(0, idx.column());
234 m_nonPersistentFirstColumn.push_back(firstColumn);
235 m_persistentFirstColumn.push_back(firstColumn);
240 void StatisticsProxyModel::Private::sourceLayoutChanged()
242 QModelIndexList oldList;
243 QModelIndexList newList;
245 const int columnCount = mParent->sourceModel()->columnCount();
247 for (
int i = 0; i < m_persistent.size(); ++i) {
248 const QModelIndex persistentIdx = m_persistent.at(i);
249 const QModelIndex nonPersistentIdx = m_nonPersistent.at(i);
250 if (m_persistentFirstColumn.at(i) != m_nonPersistentFirstColumn.at(i) && persistentIdx.column() >= columnCount) {
251 oldList.append(nonPersistentIdx);
252 newList.append(persistentIdx);
255 mParent->changePersistentIndexList(oldList, newList);
258 void StatisticsProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
262 disconnect(
this, SIGNAL(layoutChanged()),
this, SLOT(sourceLayoutChanged()));
263 connect(
this, SIGNAL(layoutChanged()), SLOT(sourceLayoutChanged()));
264 QSortFilterProxyModel::setSourceModel(sourceModel);
267 disconnect(
this, SIGNAL(layoutAboutToBeChanged()),
this, SLOT(sourceLayoutAboutToBeChanged()));
268 connect(
this, SIGNAL(layoutAboutToBeChanged()), SLOT(sourceLayoutAboutToBeChanged()));
271 void StatisticsProxyModel::connectNotify(
const char *signal)
273 static bool ignore =
false;
274 if (ignore || QLatin1String(signal) == SIGNAL(layoutAboutToBeChanged())) {
275 return QSortFilterProxyModel::connectNotify(signal);
278 disconnect(
this, SIGNAL(layoutAboutToBeChanged()),
this, SLOT(sourceLayoutAboutToBeChanged()));
279 connect(
this, SIGNAL(layoutAboutToBeChanged()), SLOT(sourceLayoutAboutToBeChanged()));
281 QSortFilterProxyModel::connectNotify(signal);
285 : QSortFilterProxyModel(parent)
286 , d(new Private(this))
288 connect(
this, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
289 SLOT(proxyDataChanged(QModelIndex,QModelIndex)));
299 d->mToolTipEnabled = enable;
304 return d->mToolTipEnabled;
309 d->mExtraColumnsEnabled = enable;
314 return d->mExtraColumnsEnabled;
317 QModelIndex Akonadi::StatisticsProxyModel::index(
int row,
int column,
const QModelIndex &parent)
const
319 if (!hasIndex(row, column, parent)) {
320 return QModelIndex();
323 int sourceColumn = column;
325 if (column >= d->sourceColumnCount(parent)) {
329 QModelIndex i = QSortFilterProxyModel::index(row, sourceColumn, parent);
330 return createIndex(i.row(), column, i.internalPointer());
333 QVariant StatisticsProxyModel::data(
const QModelIndex &index,
int role)
const
335 if (!sourceModel()) {
338 if (role == Qt::DisplayRole && index.column() >= d->sourceColumnCount(index.parent())) {
339 const QModelIndex sourceIndex = mapToSource(index.sibling(index.row(), 0));
342 if (collection.isValid() && collection.statistics().count() >= 0) {
343 if (index.column() == d->sourceColumnCount(QModelIndex()) + 2) {
344 return KIO::convertSize((KIO::filesize_t)(collection.statistics().size()));
345 }
else if (index.column() == d->sourceColumnCount(QModelIndex()) + 1) {
346 return collection.statistics().count();
347 }
else if (index.column() == d->sourceColumnCount(QModelIndex())) {
348 if (collection.statistics().unreadCount() > 0) {
349 return collection.statistics().unreadCount();
354 kWarning() <<
"We shouldn't get there for a column which is not total, unread or size.";
359 }
else if (role == Qt::TextAlignmentRole && index.column() >= d->sourceColumnCount(index.parent())) {
360 return Qt::AlignRight;
362 }
else if (role == Qt::ToolTipRole && d->mToolTipEnabled) {
363 const QModelIndex sourceIndex = mapToSource(index.sibling(index.row(), 0));
366 if (collection.isValid() && collection.statistics().count() > 0) {
367 return d->toolTipForCollection(index, collection);
370 }
else if (role == Qt::DecorationRole && index.column() == 0) {
371 const QModelIndex sourceIndex = mapToSource(index.sibling(index.row(), 0));
374 if (collection.isValid()) {
375 return KIcon(CollectionUtils::displayIconName(collection));
381 return QAbstractProxyModel::data(index, role);
384 QVariant StatisticsProxyModel::headerData(
int section, Qt::Orientation orientation,
int role)
const
386 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
387 if (section == d->sourceColumnCount(QModelIndex()) + 2) {
388 return i18nc(
"collection size",
"Size");
389 }
else if (section == d->sourceColumnCount(QModelIndex()) + 1) {
390 return i18nc(
"number of entities in the collection",
"Total");
391 }
else if (section == d->sourceColumnCount(QModelIndex())) {
392 return i18nc(
"number of unread entities in the collection",
"Unread");
396 return QSortFilterProxyModel::headerData(section, orientation, role);
399 Qt::ItemFlags StatisticsProxyModel::flags(
const QModelIndex &index)
const
401 if (index.column() >= d->sourceColumnCount(index.parent())) {
402 return QSortFilterProxyModel::flags(index.sibling(index.row(), 0))
403 & (Qt::ItemIsSelectable | Qt::ItemIsDragEnabled
404 | Qt::ItemIsDropEnabled | Qt::ItemIsEnabled);
407 return QSortFilterProxyModel::flags(index);
410 int StatisticsProxyModel::columnCount(
const QModelIndex &parent)
const
412 if (sourceModel() == 0) {
415 return d->sourceColumnCount(parent)
416 + (d->mExtraColumnsEnabled ? 3 : 0);
420 QModelIndexList StatisticsProxyModel::match(
const QModelIndex &start,
int role,
const QVariant &value,
421 int hits, Qt::MatchFlags flags)
const
423 if (role < Qt::UserRole) {
424 return QSortFilterProxyModel::match(start, role, value, hits, flags);
427 QModelIndexList list;
428 QModelIndex proxyIndex;
429 foreach (
const QModelIndex &idx, sourceModel()->match(mapToSource(start), role, value, hits, flags)) {
430 proxyIndex = mapFromSource(idx);
431 if (proxyIndex.isValid()) {
439 #include "moc_statisticsproxymodel.cpp"