1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2014 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"
32 JobListModel::JobListModel(PreferencesModel *preferences)
34 m_preferences = preferences;
37 JobListModel::~JobListModel(void)
39 while(!m_jobs.isEmpty())
41 QUuid id = m_jobs.takeFirst();
42 EncodeThread *thread = m_threads.value(id, NULL);
43 LogFileModel *logFile = m_logFile.value(id, NULL);
49 ///////////////////////////////////////////////////////////////////////////////
51 ///////////////////////////////////////////////////////////////////////////////
53 int JobListModel::columnCount(const QModelIndex &parent) const
58 int JobListModel::rowCount(const QModelIndex &parent) const
60 return m_jobs.count();
63 QVariant JobListModel::headerData(int section, Qt::Orientation orientation, int role) const
65 if((orientation == Qt::Horizontal) && (role == Qt::DisplayRole))
70 return QVariant::fromValue<QString>(tr("Job"));
73 return QVariant::fromValue<QString>(tr("Status"));
76 return QVariant::fromValue<QString>(tr("Progress"));
79 return QVariant::fromValue<QString>(tr("Details"));
90 QModelIndex JobListModel::index(int row, int column, const QModelIndex &parent) const
92 return createIndex(row, column, NULL);
95 QModelIndex JobListModel::parent(const QModelIndex &index) const
100 QVariant JobListModel::data(const QModelIndex &index, int role) const
102 if(role == Qt::DisplayRole)
104 if(index.row() >= 0 && index.row() < m_jobs.count())
106 switch(index.column())
109 return m_name.value(m_jobs.at(index.row()));
112 switch(m_status.value(m_jobs.at(index.row())))
114 case JobStatus_Enqueued:
115 return QVariant::fromValue<QString>(tr("Enqueued."));
117 case JobStatus_Starting:
118 return QVariant::fromValue<QString>(tr("Starting..."));
120 case JobStatus_Indexing:
121 return QVariant::fromValue<QString>(tr("Indexing..."));
123 case JobStatus_Running:
124 return QVariant::fromValue<QString>(tr("Running..."));
126 case JobStatus_Running_Pass1:
127 return QVariant::fromValue<QString>(tr("Running... (Pass 1)"));
129 case JobStatus_Running_Pass2:
130 return QVariant::fromValue<QString>(tr("Running... (Pass 2)"));
132 case JobStatus_Completed:
133 return QVariant::fromValue<QString>(tr("Completed."));
135 case JobStatus_Failed:
136 return QVariant::fromValue<QString>(tr("Failed!"));
138 case JobStatus_Pausing:
139 return QVariant::fromValue<QString>(tr("Pausing..."));
141 case JobStatus_Paused:
142 return QVariant::fromValue<QString>(tr("Paused."));
144 case JobStatus_Resuming:
145 return QVariant::fromValue<QString>(tr("Resuming..."));
147 case JobStatus_Aborting:
148 return QVariant::fromValue<QString>(tr("Aborting..."));
150 case JobStatus_Aborted:
151 return QVariant::fromValue<QString>(tr("Aborted!"));
154 return QVariant::fromValue<QString>(tr("(Unknown)"));
159 return QString().sprintf("%d%%", m_progress.value(m_jobs.at(index.row())));
162 return m_details.value(m_jobs.at(index.row()));
170 else if(role == Qt::DecorationRole)
172 if(index.row() >= 0 && index.row() < m_jobs.count() && index.column() == 0)
174 switch(m_status.value(m_jobs.at(index.row())))
176 case JobStatus_Enqueued:
177 return QIcon(":/buttons/hourglass.png");
179 case JobStatus_Starting:
180 return QIcon(":/buttons/lightning.png");
182 case JobStatus_Indexing:
183 return QIcon(":/buttons/find.png");
185 case JobStatus_Running:
186 case JobStatus_Running_Pass1:
187 case JobStatus_Running_Pass2:
188 return QIcon(":/buttons/play.png");
190 case JobStatus_Completed:
191 return QIcon(":/buttons/accept.png");
193 case JobStatus_Failed:
194 return QIcon(":/buttons/exclamation.png");
196 case JobStatus_Pausing:
197 return QIcon(":/buttons/clock_pause.png");
199 case JobStatus_Paused:
200 return QIcon(":/buttons/suspended.png");
202 case JobStatus_Resuming:
203 return QIcon(":/buttons/clock_play.png");
205 case JobStatus_Aborting:
206 return QIcon(":/buttons/clock_stop.png");
208 case JobStatus_Aborted:
209 return QIcon(":/buttons/error.png");
221 ///////////////////////////////////////////////////////////////////////////////
223 ///////////////////////////////////////////////////////////////////////////////
225 QModelIndex JobListModel::insertJob(EncodeThread *thread)
227 QUuid id = thread->getId();
229 if(m_jobs.contains(id))
231 return QModelIndex();
234 QString config = "N/A";
236 switch(thread->options()->rcMode())
238 case OptionsModel::RCMode_CRF:
239 config = QString("CRF@%1").arg(QString::number(thread->options()->quantizer()));
241 case OptionsModel::RCMode_CQ:
242 config = QString("CQ@%1").arg(QString::number(qRound(thread->options()->quantizer())));
244 case OptionsModel::RCMode_2Pass:
245 config = QString("2Pass@%1").arg(QString::number(thread->options()->bitrate()));
247 case OptionsModel::RCMode_ABR:
248 config = QString("ABR@%1").arg(QString::number(thread->options()->bitrate()));
253 QString jobName = QString("%1 (%2)").arg(QFileInfo(thread->sourceFileName()).completeBaseName().simplified(), config);
258 for(int i = 0; i < m_jobs.count(); i++)
260 if(m_name.value(m_jobs.at(i)).compare(jobName, Qt::CaseInsensitive) == 0)
268 jobName = QString("%1 %2 (%3)").arg(QFileInfo(thread->sourceFileName()).completeBaseName().simplified(), QString::number(n++), config);
274 LogFileModel *logFile = new LogFileModel(thread->sourceFileName(), thread->outputFileName(), config);
276 beginInsertRows(QModelIndex(), m_jobs.count(), m_jobs.count());
278 m_name.insert(id, jobName);
279 m_status.insert(id, JobStatus_Enqueued);
280 m_progress.insert(id, 0);
281 m_threads.insert(id, thread);
282 m_logFile.insert(id, logFile);
283 m_details.insert(id, tr("Not started yet."));
286 connect(thread, SIGNAL(statusChanged(QUuid, JobStatus)), this, SLOT(updateStatus(QUuid, JobStatus)), Qt::QueuedConnection);
287 connect(thread, SIGNAL(progressChanged(QUuid, unsigned int)), this, SLOT(updateProgress(QUuid, unsigned int)), Qt::QueuedConnection);
288 connect(thread, SIGNAL(messageLogged(QUuid, QString)), logFile, SLOT(addLogMessage(QUuid, QString)), Qt::QueuedConnection);
289 connect(thread, SIGNAL(detailsChanged(QUuid, QString)), this, SLOT(updateDetails(QUuid, QString)), Qt::QueuedConnection);
291 return createIndex(m_jobs.count() - 1, 0, NULL);
294 bool JobListModel::startJob(const QModelIndex &index)
296 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
298 QUuid id = m_jobs.at(index.row());
299 if(m_status.value(id) == JobStatus_Enqueued)
301 updateStatus(id, JobStatus_Starting);
302 updateDetails(id, tr("Starting up, please wait..."));
303 m_threads.value(id)->start();
311 bool JobListModel::pauseJob(const QModelIndex &index)
313 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
315 QUuid id = m_jobs.at(index.row());
316 JobStatus status = m_status.value(id);
317 if((status == JobStatus_Indexing) || (status == JobStatus_Running) ||
318 (status == JobStatus_Running_Pass1) || (status == JobStatus_Running_Pass2))
320 updateStatus(id, JobStatus_Pausing);
321 m_threads.value(id)->pauseJob();
329 bool JobListModel::resumeJob(const QModelIndex &index)
331 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
333 QUuid id = m_jobs.at(index.row());
334 JobStatus status = m_status.value(id);
335 if(status == JobStatus_Paused)
337 updateStatus(id, JobStatus_Resuming);
338 m_threads.value(id)->resumeJob();
346 bool JobListModel::abortJob(const QModelIndex &index)
348 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
350 QUuid id = m_jobs.at(index.row());
351 if(m_status.value(id) == JobStatus_Indexing || m_status.value(id) == JobStatus_Running ||
352 m_status.value(id) == JobStatus_Running_Pass1 || JobStatus_Running_Pass2)
354 updateStatus(id, JobStatus_Aborting);
355 m_threads.value(id)->abortJob();
363 bool JobListModel::deleteJob(const QModelIndex &index)
365 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
367 QUuid id = m_jobs.at(index.row());
368 if(m_status.value(id) == JobStatus_Completed || m_status.value(id) == JobStatus_Failed ||
369 m_status.value(id) == JobStatus_Aborted || m_status.value(id) == JobStatus_Enqueued)
371 int idx = index.row();
372 QUuid id = m_jobs.at(idx);
373 EncodeThread *thread = m_threads.value(id, NULL);
374 LogFileModel *logFile = m_logFile.value(id, NULL);
375 if((thread == NULL) || (!thread->isRunning()))
378 beginRemoveRows(QModelIndex(), idx, idx);
379 m_jobs.removeAt(index.row());
381 m_threads.remove(id);
383 m_progress.remove(id);
384 m_logFile.remove(id);
385 m_details.remove(id);
388 X264_DELETE(logFile);
397 LogFileModel *JobListModel::getLogFile(const QModelIndex &index)
399 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
401 return m_logFile.value(m_jobs.at(index.row()));
407 const QString &JobListModel::getJobSourceFile(const QModelIndex &index)
409 static QString nullStr;
411 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
413 EncodeThread *thread = m_threads.value(m_jobs.at(index.row()));
414 return (thread != NULL) ? thread->sourceFileName() : nullStr;
420 const QString &JobListModel::getJobOutputFile(const QModelIndex &index)
422 static QString nullStr;
424 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
426 EncodeThread *thread = m_threads.value(m_jobs.at(index.row()));
427 return (thread != NULL) ? thread->outputFileName() : nullStr;
433 JobStatus JobListModel::getJobStatus(const QModelIndex &index)
435 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
437 return m_status.value(m_jobs.at(index.row()));
440 return static_cast<JobStatus>(-1);
443 unsigned int JobListModel::getJobProgress(const QModelIndex &index)
445 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
447 return m_progress.value(m_jobs.at(index.row()));
453 const OptionsModel *JobListModel::getJobOptions(const QModelIndex &index)
455 static QString nullStr;
457 if(index.isValid() && index.row() >= 0 && index.row() < m_jobs.count())
459 EncodeThread *thread = m_threads.value(m_jobs.at(index.row()));
460 return (thread != NULL) ? thread->options() : NULL;
466 QModelIndex JobListModel::getJobIndexById(const QUuid &id)
468 if(m_jobs.contains(id))
470 return createIndex(m_jobs.indexOf(id), 0);
473 return QModelIndex();
476 ///////////////////////////////////////////////////////////////////////////////
478 ///////////////////////////////////////////////////////////////////////////////
480 void JobListModel::updateStatus(const QUuid &jobId, JobStatus newStatus)
484 if((index = m_jobs.indexOf(jobId)) >= 0)
486 m_status.insert(jobId, newStatus);
487 emit dataChanged(createIndex(index, 0), createIndex(index, 1));
489 if(m_preferences->getEnableSounds())
493 case JobStatus_Completed:
494 x264_play_sound(IDR_WAVE4, true);
496 case JobStatus_Aborted:
497 x264_play_sound(IDR_WAVE5, true);
499 case JobStatus_Failed:
500 x264_play_sound(IDR_WAVE6, true);
507 void JobListModel::updateProgress(const QUuid &jobId, unsigned int newProgress)
511 if((index = m_jobs.indexOf(jobId)) >= 0)
513 m_progress.insert(jobId, qBound(0U, newProgress, 100U));
514 emit dataChanged(createIndex(index, 2), createIndex(index, 2));
518 void JobListModel::updateDetails(const QUuid &jobId, const QString &details)
522 if((index = m_jobs.indexOf(jobId)) >= 0)
524 m_details.insert(jobId, details);
525 emit dataChanged(createIndex(index, 3), createIndex(index, 3));