File indexing completed on 2024-04-28 04:20:53

0001 // SPDX-FileCopyrightText: 2012-2022 The KPhotoAlbum Development Team
0002 //
0003 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 
0005 #include "JobModel.h"
0006 
0007 #include "CompletedJobInfo.h"
0008 #include "JobInfo.h"
0009 #include "JobManager.h"
0010 
0011 #include <KLed>
0012 #include <KLocalizedString>
0013 #include <QApplication>
0014 #include <QBitmap>
0015 #include <QPainter>
0016 #include <QPixmap>
0017 #include <QTime>
0018 #include <QTimer>
0019 
0020 namespace BackgroundTaskManager
0021 {
0022 
0023 JobModel::JobModel(QObject *parent)
0024     : QAbstractTableModel(parent)
0025     , blinkStateOn(true)
0026 {
0027     connect(JobManager::instance(), SIGNAL(jobStarted(JobInterface *)), this, SLOT(jobStarted(JobInterface *)));
0028     connect(JobManager::instance(), SIGNAL(jobEnded(JobInterface *)), this, SLOT(jobEnded(JobInterface *)));
0029 
0030     // Make the current task blink
0031     QTimer *timer = new QTimer(this);
0032     timer->start(500);
0033     connect(timer, &QTimer::timeout, this, &JobModel::heartbeat);
0034 }
0035 
0036 JobModel::~JobModel()
0037 {
0038     qDeleteAll(m_previousJobs);
0039 }
0040 
0041 int JobModel::rowCount(const QModelIndex &index) const
0042 {
0043     if (index.isValid())
0044         return 0;
0045     else
0046         return m_previousJobs.count() + JobManager::instance()->activeJobCount() + JobManager::instance()->futureJobCount();
0047 }
0048 
0049 int JobModel::columnCount(const QModelIndex &) const
0050 {
0051     return 4;
0052 }
0053 
0054 QVariant JobModel::data(const QModelIndex &index, int role) const
0055 {
0056     if (!index.isValid())
0057         return QVariant();
0058 
0059     const int row = index.row();
0060     const int col = index.column();
0061 
0062     JobInfo *current = info(row);
0063     if (!current)
0064         return QVariant();
0065 
0066     if (role == Qt::DisplayRole) {
0067         switch (col) {
0068         case IDCol:
0069             return current->jobIndex();
0070         case TitleCol:
0071             return current->title();
0072         case DetailsCol:
0073             return current->details();
0074         case ElapsedCol:
0075             return current->elapsed();
0076         default:
0077             return QVariant();
0078         }
0079     } else if (role == Qt::DecorationRole && col == TitleCol)
0080         return statusImage(current->state);
0081     else if (role == Qt::TextAlignmentRole)
0082         return index.column() == IDCol ? Qt::AlignRight : Qt::AlignLeft;
0083 
0084     return QVariant();
0085 }
0086 
0087 QVariant JobModel::headerData(int section, Qt::Orientation orientation, int role) const
0088 {
0089     if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
0090         return QVariant();
0091     switch (section) {
0092     case IDCol:
0093         return i18nc("@title:column Background job id", "ID");
0094     case TitleCol:
0095         return i18nc("@title:column Background job title", "Title");
0096     case DetailsCol:
0097         return i18nc("@title:column Additional information on background job", "Details");
0098     case ElapsedCol:
0099         return i18nc("@title:column Elapsed time", "Elapsed");
0100     default:
0101         return QVariant();
0102     }
0103 }
0104 
0105 void JobModel::reset()
0106 {
0107     // FIXME: this is just a stand-in replacement for a call to the deprecated
0108     //        QAbstractTableModel::reset();
0109     // fix this by replacing the calls to reset() using:
0110     //  beginInsertRows()
0111     //  beginRemoveRows()
0112     //  beginMoveRows()
0113     beginResetModel();
0114     endResetModel();
0115 }
0116 
0117 void JobModel::jobEnded(JobInterface *job)
0118 {
0119     m_previousJobs.append(new CompletedJobInfo(job));
0120     reset();
0121 }
0122 
0123 void JobModel::jobStarted(JobInterface *job)
0124 {
0125     connect(job, SIGNAL(changed()), this, SLOT(reset()));
0126     reset();
0127 }
0128 
0129 void JobModel::heartbeat()
0130 {
0131     beginResetModel();
0132     blinkStateOn = !blinkStateOn;
0133     // optional improvement: Q_EMIT dataChanged for running jobs only
0134     endResetModel();
0135 }
0136 
0137 JobInfo *JobModel::info(int row) const
0138 {
0139     if (row < m_previousJobs.count())
0140         return m_previousJobs[row];
0141 
0142     row -= m_previousJobs.count();
0143     if (row < JobManager::instance()->activeJobCount())
0144         return JobManager::instance()->activeJob(row);
0145 
0146     row -= JobManager::instance()->activeJobCount();
0147     Q_ASSERT(row < JobManager::instance()->futureJobCount());
0148     return JobManager::instance()->futureJob(row);
0149 }
0150 
0151 QPixmap JobModel::statusImage(JobInfo::State state) const
0152 {
0153     QColor color;
0154     if (state == JobInfo::Running)
0155         color = blinkStateOn ? Qt::green : qApp->palette().mid().color();
0156     else if (state == JobInfo::Completed)
0157         color = Qt::red;
0158     else
0159         color = QColor(Qt::yellow).darker();
0160 
0161     KLed led;
0162     led.setColor(color);
0163 
0164     QPixmap pixmap = led.grab();
0165     // creating the mask by heuristic is expensive, so do it only once:
0166     static QBitmap s_ledMask = pixmap.createHeuristicMask();
0167     pixmap.setMask(s_ledMask);
0168 
0169     return pixmap;
0170 }
0171 
0172 } // namespace BackgroundTaskManager
0173 // vi:expandtab:tabstop=4 shiftwidth=4:
0174 
0175 #include "moc_JobModel.cpp"