1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2013 LoRd_MuldeR <MuldeR2@GMX.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
23 #include "model_jobList.h"
24 #include "thread_encode.h"
25 #include "model_options.h"
26 #include "model_preferences.h"
34 JobListModel::JobListModel(PreferencesModel *preferences)
36 m_preferences = preferences;
39 JobListModel::~JobListModel(void)
41 while(!m_jobs.isEmpty())
43 QUuid id = m_jobs.takeFirst();
44 EncodeThread *thread = m_threads.value(id, NULL);
45 LogFileModel *logFile = m_logFile.value(id, NULL);
51 ///////////////////////////////////////////////////////////////////////////////
53 ///////////////////////////////////////////////////////////////////////////////
55 int JobListModel::columnCount(const QModelIndex &parent) const
60 int JobListModel::rowCount(const QModelIndex &parent) const
62 return m_jobs.count();
65 QVariant JobListModel::headerData(int section, Qt::Orientation orientation, int role) const
67 if((orientation == Qt::Horizontal) && (role == Qt::DisplayRole))
72 return QVariant::fromValue<QString>(tr("Job"));
75 return QVariant::fromValue<QString>(tr("Status"));
78 return QVariant::fromValue<QString>(tr("Progress"));
81 return QVariant::fromValue<QString>(tr("Details"));
92 QModelIndex JobListModel::index(int row, int column, const QModelIndex &parent) const
94 return createIndex(row, column, NULL);
97 QModelIndex JobListModel::parent(const QModelIndex &index) const
102 QVariant JobListModel::data(const QModelIndex &index, int role) const
104 if(role == Qt::DisplayRole)
106 if(index.row() >= 0 && index.row() < m_jobs.count())
108 switch(index.column())
111 return m_name.value(m_jobs.at(index.row()));
114 switch(m_status.value(m_jobs.at(index.row())))
116 case EncodeThread::JobStatus_Enqueued:
117 return QVariant::fromValue<QString>(tr("Enqueued."));
119 case EncodeThread::JobStatus_Starting:
120 return QVariant::fromValue<QString>(tr("Starting..."));
122 case EncodeThread::JobStatus_Indexing:
123 return QVariant::fromValue<QString>(tr("Indexing..."));
125 case EncodeThread::JobStatus_Running:
126 return QVariant::fromValue<QString>(tr("Running..."));
128 case EncodeThread::JobStatus_Running_Pass1:
129 return QVariant::fromValue<QString>(tr("Running... (Pass 1)"));
131 case EncodeThread::JobStatus_Running_Pass2:
132 return QVariant::fromValue<QString>(tr("Running... (Pass 2)"));
134 case EncodeThread::JobStatus_Completed:
135 return QVariant::fromValue<QString>(tr("Completed."));
137 case EncodeThread::JobStatus_Failed:
138 return QVariant::fromValue<QString>(tr("Failed!"));
140 case EncodeThread::JobStatus_Pausing:
141 return QVariant::fromValue<QString>(tr("Pausing..."));
143 case EncodeThread::JobStatus_Paused:
144 return QVariant::fromValue<QString>(tr("Paused."));
146 case EncodeThread::JobStatus_Resuming:
147 return QVariant::fromValue<QString>(tr("Resuming..."));
149 case EncodeThread::JobStatus_Aborting:
150 return QVariant::fromValue<QString>(tr("Aborting..."));
152 case EncodeThread::JobStatus_Aborted:
153 return QVariant::fromValue<QString>(tr("Aborted!"));
156 return QVariant::fromValue<QString>(tr("(Unknown)"));
161 return QString().sprintf("%d%%", m_progress.value(m_jobs.at(index.row())));
164 return m_details.value(m_jobs.at(index.row()));
172 else if(role == Qt::DecorationRole)
174 if(index.row() >= 0 && index.row() < m_jobs.count() && index.column() == 0)
176 switch(m_status.value(m_jobs.at(index.row())))
178 case EncodeThread::JobStatus_Enqueued:
179 return QIcon(":/buttons/hourglass.png");
181 case EncodeThread::JobStatus_Starting:
182 return QIcon(":/buttons/lightning.png");
184 case EncodeThread::JobStatus_Indexing:
185 return QIcon(":/buttons/find.png");
187 case EncodeThread::JobStatus_Running:
188 case EncodeThread::JobStatus_Running_Pass1:
189 case EncodeThread::JobStatus_Running_Pass2:
190 return QIcon(":/buttons/play.png");
192 case EncodeThread::JobStatus_Completed:
193 return QIcon(":/buttons/accept.png");
195 case EncodeThread::JobStatus_Failed:
196 return QIcon(":/buttons/exclamation.png");
198 case EncodeThread::JobStatus_Pausing:
199 return QIcon(":/buttons/clock_pause.png");
201 case EncodeThread::JobStatus_Paused:
202 return QIcon(":/buttons/suspended.png");
204 case EncodeThread::JobStatus_Resuming:
205 return QIcon(":/buttons/clock_play.png");
207 case EncodeThread::JobStatus_Aborting:
208 return QIcon(":/buttons/clock_stop.png");
210 case EncodeThread::JobStatus_Aborted:
211 return QIcon(":/buttons/error.png");
223 ///////////////////////////////////////////////////////////////////////////////
225 ///////////////////////////////////////////////////////////////////////////////
227 QModelIndex JobListModel::insertJob(EncodeThread *thread)
229 QUuid id = thread->getId();
231 if(m_jobs.contains(id))
233 return QModelIndex();
236 QString config = "N/A";
238 switch(thread->options()->rcMode())
240 case OptionsModel::RCMode_CRF:
241 config = QString("CRF@%1").arg(QString::number(thread->options()->quantizer()));
243 case OptionsModel::RCMode_CQ:
244 config = QString("CQ@%1").arg(QString::number(qRound(thread->options()->quantizer())));
246 case OptionsModel::RCMode_2Pass:
247 config = QString("2Pass@%1").arg(QString::number(thread->options()->bitrate()));
249 case OptionsModel::RCMode_ABR:
250 config = QString("ABR@%1").arg(QString::number(thread->options()->bitrate()));
255 QString jobName = QString("%1 (%2)").arg(QFileInfo(thread->sourceFileName()).completeBaseName().simplified(), config);
260 for(int i = 0; i < m_jobs.count(); i++)
262 if(m_name.value(m_jobs.at(i)).compare(jobName, Qt::CaseInsensitive) == 0)
270 jobName = QString("%1 %2 (%3)").arg(QFileInfo(thread->sourceFileName()).completeBaseName().simplified(), QString::number(n++), config);
276 LogFileModel *logFile = new LogFileModel(thread->sourceFileName(), thread->outputFileName(), config);
278 beginInsertRows(QModelIndex(), m_jobs.count(), m_jobs.count());
280 m_name.insert(id, jobName);
281 m_status.insert(id, EncodeThread::JobStatus_Enqueued);
282 m_progress.insert(id, 0);
283 m_threads.insert(id, thread);
284 m_logFile.insert(id, logFile);
285 m_details.insert(id, tr("Not started yet."));
288 connect(thread, SIGNAL(statusChanged(QUuid, EncodeThread::JobStatus)), this, SLOT(updateStatus(QUuid, EncodeThread::JobStatus)), Qt::QueuedConnection);
289 connect(thread, SIGNAL(progressChanged(QUuid, unsigned int)), this, SLOT(updateProgress(QUuid, unsigned int)), Qt::QueuedConnection);
290 connect(thread, SIGNAL(messageLogged(QUuid, QString)), logFile, SLOT(addLogMessage(QUuid, QString)), Qt::QueuedConnection);
291 connect(thread, SIGNAL(detailsChanged(QUuid, QString)), this, SLOT(updateDetails(QUuid, QString)), Qt::QueuedConnection);
293 return createIndex(m_jobs.count() - 1, 0, NULL);
296 bool JobListModel::startJob(const QModelIndex &index)
298 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
300 QUuid id = m_jobs.at(index.row());
301 if(m_status.value(id) == EncodeThread::JobStatus_Enqueued)
303 updateStatus(id, EncodeThread::JobStatus_Starting);
304 updateDetails(id, tr("Starting up, please wait..."));
305 m_threads.value(id)->start();
313 bool JobListModel::pauseJob(const QModelIndex &index)
315 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
317 QUuid id = m_jobs.at(index.row());
318 EncodeThread::JobStatus status = m_status.value(id);
319 if((status == EncodeThread::JobStatus_Indexing) || (status == EncodeThread::JobStatus_Running) ||
320 (status == EncodeThread::JobStatus_Running_Pass1) || (status == EncodeThread::JobStatus_Running_Pass2))
322 updateStatus(id, EncodeThread::JobStatus_Pausing);
323 m_threads.value(id)->pauseJob();
331 bool JobListModel::resumeJob(const QModelIndex &index)
333 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
335 QUuid id = m_jobs.at(index.row());
336 EncodeThread::JobStatus status = m_status.value(id);
337 if(status == EncodeThread::JobStatus_Paused)
339 updateStatus(id, EncodeThread::JobStatus_Resuming);
340 m_threads.value(id)->resumeJob();
348 bool JobListModel::abortJob(const QModelIndex &index)
350 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
352 QUuid id = m_jobs.at(index.row());
353 if(m_status.value(id) == EncodeThread::JobStatus_Indexing || m_status.value(id) == EncodeThread::JobStatus_Running ||
354 m_status.value(id) == EncodeThread::JobStatus_Running_Pass1 || EncodeThread::JobStatus_Running_Pass2)
356 updateStatus(id, EncodeThread::JobStatus_Aborting);
357 m_threads.value(id)->abortJob();
365 bool JobListModel::deleteJob(const QModelIndex &index)
367 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
369 QUuid id = m_jobs.at(index.row());
370 if(m_status.value(id) == EncodeThread::JobStatus_Completed || m_status.value(id) == EncodeThread::JobStatus_Failed ||
371 m_status.value(id) == EncodeThread::JobStatus_Aborted || m_status.value(id) == EncodeThread::JobStatus_Enqueued)
373 int idx = index.row();
374 QUuid id = m_jobs.at(idx);
375 EncodeThread *thread = m_threads.value(id, NULL);
376 LogFileModel *logFile = m_logFile.value(id, NULL);
377 if((thread == NULL) || (!thread->isRunning()))
380 beginRemoveRows(QModelIndex(), idx, idx);
381 m_jobs.removeAt(index.row());
383 m_threads.remove(id);
385 m_progress.remove(id);
386 m_logFile.remove(id);
387 m_details.remove(id);
390 X264_DELETE(logFile);
399 LogFileModel *JobListModel::getLogFile(const QModelIndex &index)
401 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
403 return m_logFile.value(m_jobs.at(index.row()));
409 const QString &JobListModel::getJobSourceFile(const QModelIndex &index)
411 static QString nullStr;
413 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
415 EncodeThread *thread = m_threads.value(m_jobs.at(index.row()));
416 return (thread != NULL) ? thread->sourceFileName() : nullStr;
422 const QString &JobListModel::getJobOutputFile(const QModelIndex &index)
424 static QString nullStr;
426 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
428 EncodeThread *thread = m_threads.value(m_jobs.at(index.row()));
429 return (thread != NULL) ? thread->outputFileName() : nullStr;
435 EncodeThread::JobStatus JobListModel::getJobStatus(const QModelIndex &index)
437 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
439 return m_status.value(m_jobs.at(index.row()));
442 return static_cast<EncodeThread::JobStatus>(-1);
445 unsigned int JobListModel::getJobProgress(const QModelIndex &index)
447 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
449 return m_progress.value(m_jobs.at(index.row()));
455 const OptionsModel *JobListModel::getJobOptions(const QModelIndex &index)
457 static QString nullStr;
459 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
461 EncodeThread *thread = m_threads.value(m_jobs.at(index.row()));
462 return (thread != NULL) ? thread->options() : NULL;
468 QModelIndex JobListModel::getJobIndexById(const QUuid &id)
470 if(m_jobs.contains(id))
472 return createIndex(m_jobs.indexOf(id), 0);
475 return QModelIndex();
478 ///////////////////////////////////////////////////////////////////////////////
480 ///////////////////////////////////////////////////////////////////////////////
482 void JobListModel::updateStatus(const QUuid &jobId, EncodeThread::JobStatus newStatus)
486 if((index = m_jobs.indexOf(jobId)) >= 0)
488 m_status.insert(jobId, newStatus);
489 emit dataChanged(createIndex(index, 0), createIndex(index, 1));
491 if(m_preferences->enableSounds())
495 case EncodeThread::JobStatus_Completed:
496 PlaySound(MAKEINTRESOURCE(IDR_WAVE4), GetModuleHandle(NULL), SND_RESOURCE | SND_ASYNC);
498 case EncodeThread::JobStatus_Aborted:
499 PlaySound(MAKEINTRESOURCE(IDR_WAVE5), GetModuleHandle(NULL), SND_RESOURCE | SND_ASYNC);
501 case EncodeThread::JobStatus_Failed:
502 PlaySound(MAKEINTRESOURCE(IDR_WAVE6), GetModuleHandle(NULL), SND_RESOURCE | SND_ASYNC);
509 void JobListModel::updateProgress(const QUuid &jobId, unsigned int newProgress)
513 if((index = m_jobs.indexOf(jobId)) >= 0)
515 m_progress.insert(jobId, qBound(0U, newProgress, 100U));
516 emit dataChanged(createIndex(index, 2), createIndex(index, 2));
520 void JobListModel::updateDetails(const QUuid &jobId, const QString &details)
524 if((index = m_jobs.indexOf(jobId)) >= 0)
526 m_details.insert(jobId, details);
527 emit dataChanged(createIndex(index, 3), createIndex(index, 3));