2 This file is part of Akonadi.
4 Copyright (c) 2009 KDAB
5 Author: Till Adam <adam@kde.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
23 #include "jobtrackermodel.h"
24 #include "jobtracker.h"
27 #include <QStringList>
28 #include <QModelIndex>
36 class JobTrackerModel::Private
39 Private(const char *name
, JobTrackerModel
*_q
)
40 : q(_q
), tracker(name
)
44 int rowForParentId(int parentid
)
46 const int grandparentid
= tracker
.parentId(parentid
);
48 if (grandparentid
== -1) {
49 const QString session
= tracker
.sessionForId(parentid
);
50 if (!session
.isEmpty()) {
51 row
= tracker
.sessions().indexOf(session
);
54 // offset of the parent in the list of children of the grandparent
55 row
= tracker
.jobNames(grandparentid
).indexOf(tracker
.jobForId(parentid
));
61 JobTrackerModel
*const q
;
66 JobTrackerModel::JobTrackerModel(const char *name
, QObject
*parent
)
67 : QAbstractItemModel(parent
), d(new Private(name
, this))
69 connect(&d
->tracker
, SIGNAL(reset()),
70 this, SIGNAL(modelReset()));
71 connect(&d
->tracker
, &JobTracker::added
,
72 this, &JobTrackerModel::jobsAdded
);
73 connect(&d
->tracker
, &JobTracker::updated
,
74 this, &JobTrackerModel::jobsUpdated
);
77 JobTrackerModel::~JobTrackerModel()
82 QModelIndex
JobTrackerModel::index(int row
, int column
, const QModelIndex
&parent
) const
84 if (!parent
.isValid()) { // session, at top level
85 if (row
< 0 || row
>= d
->tracker
.sessions().size()) {
88 return createIndex(row
, column
, d
->tracker
.idForSession(d
->tracker
.sessions().at(row
)));
91 const QStringList jobs
= d
->tracker
.jobNames(parent
.internalId());
92 if (row
>= jobs
.size()) {
95 return createIndex(row
, column
, d
->tracker
.idForJob(jobs
.at(row
)));
98 QModelIndex
JobTrackerModel::parent(const QModelIndex
&idx
) const
100 if (!idx
.isValid()) {
101 return QModelIndex();
104 const int parentid
= d
->tracker
.parentId(idx
.internalId());
105 if (parentid
== -1) {
106 return QModelIndex(); // top level session
109 const int row
= d
->rowForParentId(parentid
);
111 return createIndex(row
, 0, parentid
);
113 return QModelIndex();
117 int JobTrackerModel::rowCount(const QModelIndex
&parent
) const
119 if (!parent
.isValid()) {
120 return d
->tracker
.sessions().size();
122 return d
->tracker
.jobNames(parent
.internalId()).size();
126 int JobTrackerModel::columnCount(const QModelIndex
&parent
) const
132 static QString
formatTimeWithMsec(const QTime
&time
)
134 return QString(QLocale().toString(time
)
135 + QStringLiteral(".%1").arg(time
.msec(), 3, 10, QLatin1Char('0')));
138 static QString
formatDurationWithMsec(qint64 msecs
)
141 time
= time
.addMSecs(msecs
);
142 return formatTimeWithMsec(time
);
145 QVariant
JobTrackerModel::data(const QModelIndex
&idx
, int role
) const
147 // top level items are sessions
148 if (!idx
.parent().isValid()) {
149 if (role
== Qt::DisplayRole
) {
150 const QStringList sessions
= d
->tracker
.sessions();
151 if (idx
.column() == 0 && idx
.row() <= sessions
.size()) {
152 return sessions
.at(idx
.row());
155 } else { // not top level, so a job or subjob
156 const int id
= idx
.internalId();
157 const JobInfo info
= d
->tracker
.info(id
);
158 if (role
== Qt::DisplayRole
) {
159 switch (idx
.column()) {
163 return formatTimeWithMsec(info
.timestamp
.time());
165 if (info
.startedTimestamp
.isNull() || info
.timestamp
.isNull()) {
168 return formatDurationWithMsec(info
.timestamp
.msecsTo(info
.startedTimestamp
));
170 if (info
.endedTimestamp
.isNull() || info
.startedTimestamp
.isNull()) {
173 return formatDurationWithMsec(info
.startedTimestamp
.msecsTo(info
.endedTimestamp
));
177 return info
.stateAsString();
179 return info
.debugString
;
181 } else if (role
== Qt::ForegroundRole
) {
182 if (info
.state
== JobInfo::Failed
) {
183 return QColor(Qt::red
);
185 } else if (role
== Qt::FontRole
) {
186 if (info
.state
== JobInfo::Running
) {
191 } else if (role
== Qt::ToolTipRole
) {
192 if (info
.state
== JobInfo::Failed
) {
200 QVariant
JobTrackerModel::headerData(int section
, Qt::Orientation orientation
, int role
) const
202 if (role
== Qt::DisplayRole
) {
203 if (orientation
== Qt::Horizontal
) {
206 return QStringLiteral("Job ID");
208 return QStringLiteral("Created");
210 return QStringLiteral("Wait time"); // duration (time started - time created)
212 return QStringLiteral("Job duration"); // duration (time ended - time started)
214 return QStringLiteral("Job Type");
216 return QStringLiteral("State");
218 return QStringLiteral("Info");
225 void JobTrackerModel::resetTracker()
227 d
->tracker
.triggerReset();
230 bool JobTrackerModel::isEnabled() const
232 return d
->tracker
.isEnabled();
235 void JobTrackerModel::setEnabled(bool on
)
237 d
->tracker
.setEnabled(on
);
240 void JobTrackerModel::jobsAdded(const QList
< QPair
< int, int > > &jobs
)
242 // TODO group them by parent? It's likely that multiple jobs for the same
243 // parent will come in in the same batch, isn't it?
244 #define PAIR QPair<int, int> // the parser in foreach barfs otherwise
245 Q_FOREACH (const PAIR
&job
, jobs
) {
246 const int pos
= job
.first
;
247 const int parentId
= job
.second
;
248 QModelIndex parentIdx
;
249 if (parentId
!= -1) {
250 const int row
= d
->rowForParentId(parentId
);
252 parentIdx
= createIndex(row
, 0, parentId
);
255 beginInsertRows(parentIdx
, pos
, pos
);
261 void JobTrackerModel::jobsUpdated(const QList
< QPair
< int, int > > &jobs
)
263 // TODO group them by parent? It's likely that multiple jobs for the same
264 // parent will come in in the same batch, isn't it?
265 #define PAIR QPair<int, int> // the parser in foreach barfs otherwise
266 Q_FOREACH (const PAIR
&job
, jobs
) {
267 const int pos
= job
.first
;
268 const int parentId
= job
.second
;
269 QModelIndex parentIdx
;
270 if (parentId
!= -1) {
271 const int row
= d
->rowForParentId(parentId
);
273 parentIdx
= createIndex(row
, 0, parentId
);
276 dataChanged(index(pos
, 0, parentIdx
), index(pos
, 3, parentIdx
));