1 /*
2  * SPDX-FileCopyrightText: 2013 Daniel Vrátil <dvratil@redhat.com>
3  *
4  * SPDX-License-Identifier: GPL-2.0-or-later
5  *
6  */
7 
8 #include "monitorsmodel.h"
9 #include "akonadiconsole_debug.h"
10 #include <Akonadi/Monitor>
11 #include <Akonadi/Session>
12 
13 #include <QTimer>
14 
15 #ifndef COMPILE_WITH_UNITY_CMAKE_SUPPORT
Q_DECLARE_METATYPE(Akonadi::NotificationSubscriber)16 Q_DECLARE_METATYPE(Akonadi::NotificationSubscriber)
17 #endif
18 
19 MonitorsModel::MonitorsModel(QObject *parent)
20     : QAbstractItemModel(parent)
21 {
22     QTimer::singleShot(0, this, &MonitorsModel::init);
23 }
24 
~MonitorsModel()25 MonitorsModel::~MonitorsModel()
26 {
27 }
28 
init()29 void MonitorsModel::init()
30 {
31     mMonitor = new Akonadi::Monitor(this);
32     mMonitor->setTypeMonitored(Akonadi::Monitor::Subscribers, true);
33     connect(mMonitor, &Akonadi::Monitor::notificationSubscriberAdded, this, &MonitorsModel::slotSubscriberAdded);
34     connect(mMonitor, &Akonadi::Monitor::notificationSubscriberChanged, this, &MonitorsModel::slotSubscriberChanged);
35     connect(mMonitor, &Akonadi::Monitor::notificationSubscriberRemoved, this, &MonitorsModel::slotSubscriberRemoved);
36 }
37 
indexForSession(const QByteArray & session)38 QModelIndex MonitorsModel::indexForSession(const QByteArray &session)
39 {
40     int pos = mSessions.indexOf(session);
41     if (pos == -1) {
42         pos = mSessions.count();
43         beginInsertRows({}, pos, pos);
44         mSessions.push_back(session);
45         mData.insert(session, {});
46         endInsertRows();
47     }
48 
49     return index(pos, 0);
50 }
51 
slotSubscriberAdded(const Akonadi::NotificationSubscriber & subscriber)52 void MonitorsModel::slotSubscriberAdded(const Akonadi::NotificationSubscriber &subscriber)
53 {
54     auto sessionIdx = indexForSession(subscriber.sessionId());
55     auto &sessions = mData[subscriber.sessionId()];
56     beginInsertRows(sessionIdx, sessions.count(), sessions.count());
57     sessions.push_back(subscriber);
58     endInsertRows();
59 }
60 
slotSubscriberRemoved(const Akonadi::NotificationSubscriber & subscriber)61 void MonitorsModel::slotSubscriberRemoved(const Akonadi::NotificationSubscriber &subscriber)
62 {
63     int idx = -1;
64     auto sessionIdx = indexForSession(subscriber.sessionId());
65     auto &sessions = mData[subscriber.sessionId()];
66     for (auto it = sessions.begin(), end = sessions.end(); it != end; ++it) {
67         ++idx;
68         if (it->subscriber() == subscriber.subscriber()) {
69             beginRemoveRows(sessionIdx, idx, idx);
70             sessions.erase(it);
71             endRemoveRows();
72             return;
73         }
74     }
75 }
76 
slotSubscriberChanged(const Akonadi::NotificationSubscriber & subscriber)77 void MonitorsModel::slotSubscriberChanged(const Akonadi::NotificationSubscriber &subscriber)
78 {
79     int row = -1;
80     auto sessionIdx = indexForSession(subscriber.sessionId());
81     auto sessions = mData[subscriber.sessionId()];
82     for (auto it = sessions.begin(), end = sessions.end(); it != end; ++it) {
83         ++row;
84         if (it->subscriber() == subscriber.subscriber()) {
85             *it = subscriber;
86             const auto idx = index(row, 0, sessionIdx);
87             Q_EMIT dataChanged(idx, idx);
88             return;
89         }
90     }
91 }
92 
headerData(int section,Qt::Orientation orientation,int role) const93 QVariant MonitorsModel::headerData(int section, Qt::Orientation orientation, int role) const
94 {
95     if (role == Qt::DisplayRole) {
96         if (orientation == Qt::Horizontal) {
97             if (section == 0) {
98                 return QStringLiteral("Session/Subscriber");
99             }
100         }
101     }
102 
103     return QVariant();
104 }
105 
data(const QModelIndex & index,int role) const106 QVariant MonitorsModel::data(const QModelIndex &index, int role) const
107 {
108     if (!index.isValid() || index.column() != 0) {
109         return QVariant();
110     }
111     if ((int)index.internalId() == -1) {
112         if (index.row() >= mSessions.count()) {
113             return {};
114         }
115 
116         if (role == Qt::DisplayRole) {
117             return mSessions.at(index.row());
118         }
119     } else {
120         const auto session = mSessions.at(index.parent().row());
121         const auto subscribers = mData.value(session);
122         if (index.row() >= subscribers.count()) {
123             return {};
124         }
125         const auto subscriber = subscribers.at(index.row());
126         if (role == Qt::DisplayRole || role == Qt::ToolTipRole) {
127             return subscriber.subscriber();
128         } else if (role == SubscriberRole) {
129             return QVariant::fromValue(subscriber);
130         }
131     }
132 
133     return QVariant();
134 }
135 
columnCount(const QModelIndex & parent) const136 int MonitorsModel::columnCount(const QModelIndex &parent) const
137 {
138     Q_UNUSED(parent)
139     return 1;
140 }
141 
rowCount(const QModelIndex & parent) const142 int MonitorsModel::rowCount(const QModelIndex &parent) const
143 {
144     if (!parent.isValid()) {
145         return mSessions.count();
146     }
147 
148     if ((int)parent.internalId() == -1) {
149         const auto session = mSessions.at(parent.row());
150         return mData.value(session).count();
151     }
152 
153     return 0;
154 }
155 
parent(const QModelIndex & child) const156 QModelIndex MonitorsModel::parent(const QModelIndex &child) const
157 {
158     if ((int)child.internalId() == -1) {
159         return {};
160     } else {
161         return index(child.internalId(), 0, {});
162     }
163 
164     return QModelIndex();
165 }
166 
index(int row,int column,const QModelIndex & parent) const167 QModelIndex MonitorsModel::index(int row, int column, const QModelIndex &parent) const
168 {
169     if (!parent.isValid()) {
170         return createIndex(row, column, -1);
171     }
172 
173     return createIndex(row, column, parent.row());
174 }
175