diff --git a/gui/win_addJob.ui b/gui/win_addJob.ui index 1f9bcec..625fc15 100644 --- a/gui/win_addJob.ui +++ b/gui/win_addJob.ui @@ -7,7 +7,7 @@ 0 0 560 - 498 + 494 @@ -411,7 +411,7 @@ - + 0 @@ -495,7 +495,7 @@ - + 0 @@ -545,7 +545,7 @@ - Advanced Options + Advanced Encoder Options @@ -590,6 +590,51 @@ + + + + + + + 0 + 0 + 255 + + + + + + + + + 0 + 0 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + + + true + + + + PointingHandCursor + Show Help Screen @@ -598,7 +643,11 @@ - + + + true + + @@ -630,6 +679,16 @@ + + + + Start Job Immediately + + + true + + + @@ -692,9 +751,8 @@ spinQuantizer spinBitrate cbxPreset - comboBox_3 - comboBox_2 - lineEdit_3 + cbxTuning + cbxProfile diff --git a/gui/win_main.ui b/gui/win_main.ui index 5af2cb2..f602e81 100644 --- a/gui/win_main.ui +++ b/gui/win_main.ui @@ -223,6 +223,12 @@ ? + + + + + + @@ -243,7 +249,52 @@ :/buttons/information.png:/buttons/information.png - About + About... + + + + + + :/buttons/world_link.png:/buttons/world_link.png + + + MuldeR's Web-Site + + + + + + :/buttons/world_link.png:/buttons/world_link.png + + + Official x264 Web-Site + + + + + + :/buttons/world_link.png:/buttons/world_link.png + + + Komisar's Web-Site + + + + + + :/buttons/world_link.png:/buttons/world_link.png + + + Jarod's Web-Site + + + + + + :/buttons/book_open.png:/buttons/book_open.png + + + MeWiki - x264 Settings diff --git a/res/buttons/book_open.png b/res/buttons/book_open.png new file mode 100644 index 0000000..7d863f9 Binary files /dev/null and b/res/buttons/book_open.png differ diff --git a/res/buttons/world_link.png b/res/buttons/world_link.png new file mode 100644 index 0000000..b8edc12 Binary files /dev/null and b/res/buttons/world_link.png differ diff --git a/res/resources.qrc b/res/resources.qrc index 010ed4a..c832467 100644 --- a/res/resources.qrc +++ b/res/resources.qrc @@ -4,6 +4,7 @@ icons/movie.ico buttons/accept.png buttons/add.png + buttons/book_open.png buttons/cancel.png buttons/clock_pause.png buttons/clock_stop.png @@ -15,5 +16,6 @@ buttons/lightning.png buttons/play.png buttons/play_big.png + buttons/world_link.png diff --git a/src/model_jobList.cpp b/src/model_jobList.cpp index 4b6773d..ff6300b 100644 --- a/src/model_jobList.cpp +++ b/src/model_jobList.cpp @@ -24,6 +24,7 @@ #include "thread_encode.h" #include +#include JobListModel::JobListModel(void) { @@ -101,7 +102,7 @@ QVariant JobListModel::data(const QModelIndex &index, int role) const switch(index.column()) { case 0: - return m_jobs.at(index.row()).toString(); + return m_name.value(m_jobs.at(index.row())); break; case 1: switch(m_status.value(m_jobs.at(index.row()))) @@ -211,6 +212,7 @@ QModelIndex JobListModel::insertJob(EncodeThread *thread) beginInsertRows(QModelIndex(), m_jobs.count(), m_jobs.count()); m_jobs.append(id); + m_name.insert(id, QFileInfo(thread->sourceFileName()).completeBaseName()); m_status.insert(id, EncodeThread::JobStatus_Enqueued); m_progress.insert(id, 0); m_threads.insert(id, thread); diff --git a/src/model_jobList.h b/src/model_jobList.h index 4987908..a78e818 100644 --- a/src/model_jobList.h +++ b/src/model_jobList.h @@ -54,6 +54,7 @@ public: protected: QList m_jobs; + QMap m_name; QMap m_threads; QMap m_status; QMap m_progress; diff --git a/src/thread_encode.cpp b/src/thread_encode.cpp index 40cdef8..eb84e47 100644 --- a/src/thread_encode.cpp +++ b/src/thread_encode.cpp @@ -22,9 +22,11 @@ #include "thread_encode.h" #include "global.h" -EncodeThread::EncodeThread(void) +EncodeThread::EncodeThread(const QString &sourceFileName, const QString &outputFileName) : - m_jobId(QUuid::createUuid()) + m_jobId(QUuid::createUuid()), + m_sourceFileName(sourceFileName), + m_outputFileName(outputFileName) { m_abort = false; } diff --git a/src/thread_encode.h b/src/thread_encode.h index 9072a7b..3205a0f 100644 --- a/src/thread_encode.h +++ b/src/thread_encode.h @@ -43,14 +43,20 @@ public: JobStatus_Aborted = 9 }; - EncodeThread(void); + EncodeThread(const QString &sourceFileName, const QString &outputFileName); ~EncodeThread(void); QUuid getId(void) { return this->m_jobId; }; + const QString &sourceFileName(void) { return this->m_sourceFileName; }; + const QString &outputFileName(void) { return this->m_outputFileName; }; + void abortJob(void) { m_abort = true; } protected: const QUuid m_jobId; + const QString m_sourceFileName; + const QString m_outputFileName; + volatile bool m_abort; virtual void run(void); diff --git a/src/win_addJob.cpp b/src/win_addJob.cpp index aa12ff1..ad289c4 100644 --- a/src/win_addJob.cpp +++ b/src/win_addJob.cpp @@ -27,6 +27,39 @@ #include #include #include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// Validator +/////////////////////////////////////////////////////////////////////////////// + +class StringValidator : public QValidator +{ + virtual State validate(QString &input, int &pos) const + { + bool invalid = input.simplified().compare(input) && input.simplified().append(" ").compare(input) && + input.simplified().prepend(" ").compare(input) && input.simplified().append(" ").prepend(" ").compare(input); + + if(!invalid) + { + invalid = invalid || input.contains("--fps"); + invalid = invalid || input.contains("--frames"); + invalid = invalid || input.contains("--preset"); + invalid = invalid || input.contains("--tune"); + invalid = invalid || input.contains("--profile"); + } + + if(invalid) MessageBeep(MB_ICONWARNING); + return invalid ? QValidator::Invalid : QValidator::Acceptable; + } + + virtual void fixup(QString &input) const + { + input = input.simplified(); + } +}; /////////////////////////////////////////////////////////////////////////////// // Constructor & Destructor @@ -46,20 +79,128 @@ AddJobDialog::AddJobDialog(QWidget *parent) //Activate combobox connect(cbxRateControlMode, SIGNAL(currentIndexChanged(int)), this, SLOT(modeIndexChanged(int))); + + //Activate buttons + connect(buttonBrowseSource, SIGNAL(clicked()), this, SLOT(browseButtonClicked())); + connect(buttonBrowseOutput, SIGNAL(clicked()), this, SLOT(browseButtonClicked())); + + //Setup validator + cbxCustomParams->setValidator(new StringValidator()); + cbxCustomParams->addItem("--bluray-compat --vbv-maxrate 40000 --vbv-bufsize 30000 --level 4.1 --keyint 25 --open-gop --slices 4"); + cbxCustomParams->clearEditText(); } AddJobDialog::~AddJobDialog(void) { } +/////////////////////////////////////////////////////////////////////////////// +// Events +/////////////////////////////////////////////////////////////////////////////// + void AddJobDialog::showEvent(QShowEvent *event) { QDialog::showEvent(event); modeIndexChanged(cbxRateControlMode->currentIndex()); } +/////////////////////////////////////////////////////////////////////////////// +// Slots +/////////////////////////////////////////////////////////////////////////////// + void AddJobDialog::modeIndexChanged(int index) { spinQuantizer->setEnabled(index == 0 || index == 1); spinBitrate->setEnabled(index == 2 || index == 3); } + +void AddJobDialog::accept(void) +{ + if(editSource->text().trimmed().isEmpty()) + { + QMessageBox::warning(this, tr("Not Found!"), tr("Please select a valid source file first!")); + return; + } + + QFileInfo sourceFile = QFileInfo(editSource->text()); + if(!(sourceFile.exists() && sourceFile.isFile())) + { + QMessageBox::warning(this, tr("Not Found!"), tr("The selected source file could not be found!")); + return; + } + + QFileInfo outputDir = QFileInfo(QFileInfo(editOutput->text()).path()); + if(!(outputDir.exists() && outputDir.isDir() && outputDir.isWritable())) + { + QMessageBox::warning(this, tr("Not Writable!"), tr("Output directory does not exist or is not writable!")); + return; + } + + QFileInfo outputFile = QFileInfo(editOutput->text()); + if(outputFile.exists() && outputFile.isFile()) + { + if(QMessageBox::question(this, tr("Already Exists!"), tr("Output file already exists! Overwrite?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) + { + return; + } + } + if(outputFile.exists() && (!outputFile.isFile())) + { + QMessageBox::warning(this, tr("Not a File!"), tr("Selected output files does not appear to be a file!")); + return; + } + + QDialog::accept(); +} + +void AddJobDialog::browseButtonClicked(void) +{ + QString initialDir = QDesktopServices::storageLocation(QDesktopServices::MoviesLocation); + + if(QObject::sender() == buttonBrowseSource) + { + QString filters; + filters += tr("Avisynth Scripts (*.avs)").append(";;"); + filters += tr("Matroska Files (*.mkv)").append(";;"); + filters += tr("MPEG-4 Part 14 Container (*.mp4)").append(";;"); + filters += tr("Audio Video Interleaved (*.avi)").append(";;"); + filters += tr("Flash Video (*.flv)").append(";;"); + + QString filePath = QFileDialog::getOpenFileName(this, tr("Open Source File"), initialDir, filters); + + if(!(filePath.isNull() || filePath.isEmpty())) + { + editSource->setText(filePath); + + QString path = QFileInfo(filePath).path(); + QString name = QFileInfo(filePath).completeBaseName(); + + QString outPath = QString("%1/%2.mkv").arg(path, name); + + if(QFileInfo(outPath).exists()) + { + int i = 2; + while(QFileInfo(outPath).exists()) + { + outPath = QString("%1/%2 (%3).mkv").arg(path, name, QString::number(i++)); + } + } + + editOutput->setText(outPath); + } + } + else if(QObject::sender() == buttonBrowseOutput) + { + QString filters; + filters += tr("Matroska Files (*.mkv)").append(";;"); + filters += tr("MPEG-4 Part 14 Container (*.mp4)").append(";;"); + filters += tr("H.264 Elementary Stream (*.264)").append(";;"); + + QString filePath = QFileDialog::getSaveFileName(this, tr("Choose Output File"), initialDir, filters); + + if(!(filePath.isNull() || filePath.isEmpty())) + { + editOutput->setText(filePath); + } + } +} diff --git a/src/win_addJob.h b/src/win_addJob.h index 5d0f69a..527ebc2 100644 --- a/src/win_addJob.h +++ b/src/win_addJob.h @@ -23,7 +23,7 @@ #include "uic_win_addJob.h" -class AddJobDialog: public QDialog, private Ui::AddJobDialog +class AddJobDialog : public QDialog, private Ui::AddJobDialog { Q_OBJECT @@ -31,9 +31,21 @@ public: AddJobDialog(QWidget *parent); ~AddJobDialog(void); + QString sourceFile(void) { return editSource->text(); } + QString outputFile(void) { return editOutput->text(); } + QString preset(void) { return cbxPreset->itemText(cbxPreset->currentIndex()); } + QString tuning(void) { return cbxTuning->itemText(cbxTuning->currentIndex()); } + QString profile(void) { return cbxProfile->itemText(cbxProfile->currentIndex()); } + QString params(void) { return cbxCustomParams->currentText().simplified(); } + bool runImmediately(void) { return checkBoxRun->isChecked(); } + void setRunImmediately(bool run) { checkBoxRun->setChecked(run); } + protected: virtual void AddJobDialog::showEvent(QShowEvent *event); private slots: void modeIndexChanged(int index); + void browseButtonClicked(void); + + virtual void accept(void); }; diff --git a/src/win_main.cpp b/src/win_main.cpp index 4d28261..bef3f42 100644 --- a/src/win_main.cpp +++ b/src/win_main.cpp @@ -29,6 +29,10 @@ #include #include #include +#include +#include + +const char *home_url = "http://mulder.brhack.net/"; /////////////////////////////////////////////////////////////////////////////// // Constructor & Destructor @@ -75,6 +79,11 @@ MainWindow::MainWindow(bool x64supported) //Enable menu connect(actionAbout, SIGNAL(triggered()), this, SLOT(showAbout())); + connect(actionWebMulder, SIGNAL(triggered()), this, SLOT(showWebLink())); + connect(actionWebX264, SIGNAL(triggered()), this, SLOT(showWebLink())); + connect(actionWebKomisar, SIGNAL(triggered()), this, SLOT(showWebLink())); + connect(actionWebJarod, SIGNAL(triggered()), this, SLOT(showWebLink())); + connect(actionWebWiki, SIGNAL(triggered()), this, SLOT(showWebLink())); } MainWindow::~MainWindow(void) @@ -89,13 +98,25 @@ MainWindow::~MainWindow(void) void MainWindow::addButtonPressed(void) { AddJobDialog *addDialog = new AddJobDialog(this); + addDialog->setRunImmediately(!havePendingJobs()); int result = addDialog->exec(); if(result == QDialog::Accepted) { - EncodeThread *thrd = new EncodeThread(); + EncodeThread *thrd = new EncodeThread + ( + addDialog->sourceFile(), + addDialog->outputFile() + ); + QModelIndex newIndex = m_jobList->insertJob(thrd); - jobsView->selectRow(newIndex.row()); + + if(addDialog->runImmediately()) + { + jobsView->selectRow(newIndex.row()); + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + m_jobList->startJob(newIndex); + } } X264_DELETE(addDialog); @@ -181,7 +202,6 @@ void MainWindow::jobLogExtended(const QModelIndex & parent, int start, int end) void MainWindow::showAbout(void) { QString text; - const char *url = "http://mulder.brhack.net/"; text += QString().sprintf("Simple x264 Launcher v%u.%02u - use 64-Bit x264 with 32-Bit Avisynth
", x264_version_major(), x264_version_minor()); text += QString().sprintf("Copyright (c) 2004-%04d LoRd_MuldeR <mulder2@gmx.de>. Some rights reserved.
", qMax(x264_version_date().year(),QDate::currentDate().year())); @@ -189,11 +209,20 @@ void MainWindow::showAbout(void) text += QString().sprintf("This program is free software: you can redistribute it and/or modify
"); text += QString().sprintf("it under the terms of the GNU General Public License <http://www.gnu.org/>.
"); text += QString().sprintf("Note that this program is distributed with ABSOLUTELY NO WARRANTY.

"); - text += QString().sprintf("Please check the web-site at %s for updates !!!
", url, url); + text += QString().sprintf("Please check the web-site at %s for updates !!!
", home_url, home_url); QMessageBox::information(this, tr("About..."), text.replace("-", "−")); } +void MainWindow::showWebLink(void) +{ + if(QObject::sender() == actionWebMulder) QDesktopServices::openUrl(QUrl(home_url)); + if(QObject::sender() == actionWebX264) QDesktopServices::openUrl(QUrl("http://www.x264.com/")); + if(QObject::sender() == actionWebKomisar) QDesktopServices::openUrl(QUrl("http://komisar.gin.by/")); + if(QObject::sender() == actionWebJarod) QDesktopServices::openUrl(QUrl("http://www.x264.nl/")); + if(QObject::sender() == actionWebWiki) QDesktopServices::openUrl(QUrl("http://mewiki.project357.com/wiki/X264_Settings")); +} + void MainWindow::launchNextJob(void) { const int rows = m_jobList->rowCount(QModelIndex()); @@ -227,24 +256,36 @@ void MainWindow::launchNextJob(void) void MainWindow::closeEvent(QCloseEvent *e) { - const int rows = m_jobList->rowCount(QModelIndex()); - - for(int i = 0; i < rows; i++) + if(havePendingJobs()) { - EncodeThread::JobStatus status = m_jobList->getJobStatus(m_jobList->index(i, 0, QModelIndex())); - if(status != EncodeThread::JobStatus_Completed && status != EncodeThread::JobStatus_Aborted && status != EncodeThread::JobStatus_Failed) - { - e->ignore(); - MessageBeep(MB_ICONWARNING); - break; - } + e->ignore(); + MessageBeep(MB_ICONWARNING); + return; } + + QMainWindow::closeEvent(e); } /////////////////////////////////////////////////////////////////////////////// // Private functions /////////////////////////////////////////////////////////////////////////////// +bool MainWindow::havePendingJobs(void) +{ + const int rows = m_jobList->rowCount(QModelIndex()); + + for(int i = 0; i < rows; i++) + { + EncodeThread::JobStatus status = m_jobList->getJobStatus(m_jobList->index(i, 0, QModelIndex())); + if(status != EncodeThread::JobStatus_Completed && status != EncodeThread::JobStatus_Aborted && status != EncodeThread::JobStatus_Failed) + { + return true; + } + } + + return false; +} + void MainWindow::updateButtons(EncodeThread::JobStatus status) { qDebug("MainWindow::updateButtons(void)"); diff --git a/src/win_main.h b/src/win_main.h index 1449ccf..adc59cc 100644 --- a/src/win_main.h +++ b/src/win_main.h @@ -42,6 +42,7 @@ private: const bool m_x64supported; void updateButtons(EncodeThread::JobStatus status); + bool havePendingJobs(void); private slots: void addButtonPressed(void); @@ -51,5 +52,6 @@ private slots: void jobChangedData(const QModelIndex &top, const QModelIndex &bottom); void jobLogExtended(const QModelIndex & parent, int start, int end); void showAbout(void); + void showWebLink(void); void launchNextJob(void); };