/////////////////////////////////////////////////////////////////////////////// // Simple x264 Launcher // Copyright (C) 2004-2012 LoRd_MuldeR // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // // http://www.gnu.org/licenses/gpl-2.0.txt /////////////////////////////////////////////////////////////////////////////// #include "win_main.h" #include "model_jobList.h" #include "model_options.h" #include "win_addJob.h" #include "win_preferences.h" #include "taskbar7.h" #include "resource.h" #include "avisynth_c.h" #include #include #include #include #include #include #include #include #include #include #include #include const char *home_url = "http://mulder.brhack.net/"; const char *update_url = "http://code.google.com/p/mulder/downloads/list"; const char *tpl_last = ""; #define SET_FONT_BOLD(WIDGET,BOLD) { QFont _font = WIDGET->font(); _font.setBold(BOLD); WIDGET->setFont(_font); } #define SET_TEXT_COLOR(WIDGET,COLOR) { QPalette _palette = WIDGET->palette(); _palette.setColor(QPalette::WindowText, (COLOR)); _palette.setColor(QPalette::Text, (COLOR)); WIDGET->setPalette(_palette); } /////////////////////////////////////////////////////////////////////////////// // Constructor & Destructor /////////////////////////////////////////////////////////////////////////////// /* * Constructor */ MainWindow::MainWindow(const x264_cpu_t *const cpuFeatures) : m_cpuFeatures(cpuFeatures), m_appDir(QApplication::applicationDirPath()), m_options(NULL), m_jobList(NULL), m_droppedFiles(NULL), m_firstShow(true) { //Init the dialog, from the .ui file setupUi(this); setWindowFlags(windowFlags() & (~Qt::WindowMaximizeButtonHint)); //Register meta types qRegisterMetaType("QUuid"); qRegisterMetaType("DWORD"); qRegisterMetaType("EncodeThread::JobStatus"); //Load preferences PreferencesDialog::initPreferences(&m_preferences); PreferencesDialog::loadPreferences(&m_preferences); //Create options object m_options = new OptionsModel(); OptionsModel::loadTemplate(m_options, QString::fromLatin1(tpl_last)); //Create IPC thread object m_ipcThread = new IPCThread(); connect(m_ipcThread, SIGNAL(instanceCreated(DWORD)), this, SLOT(instanceCreated(DWORD)), Qt::QueuedConnection); //Freeze minimum size setMinimumSize(size()); splitter->setSizes(QList() << 16 << 196); //Update title labelBuildDate->setText(tr("Built on %1 at %2").arg(x264_version_date().toString(Qt::ISODate), QString::fromLatin1(x264_version_time()))); labelBuildDate->installEventFilter(this); setWindowTitle(QString("%1 (%2 Mode)").arg(windowTitle(), m_cpuFeatures->x64 ? "64-Bit" : "32-Bit")); if(X264_DEBUG) { setWindowTitle(QString("%1 | !!! DEBUG VERSION !!!").arg(windowTitle())); setStyleSheet("QMenuBar, QMainWindow { background-color: yellow }"); } else if(x264_is_prerelease()) { setWindowTitle(QString("%1 | PRE-RELEASE VERSION").arg(windowTitle())); } //Create model m_jobList = new JobListModel(); connect(m_jobList, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(jobChangedData(QModelIndex, QModelIndex))); jobsView->setModel(m_jobList); //Setup view jobsView->horizontalHeader()->setSectionHidden(3, true); jobsView->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch); jobsView->horizontalHeader()->setResizeMode(1, QHeaderView::Fixed); jobsView->horizontalHeader()->setResizeMode(2, QHeaderView::Fixed); jobsView->horizontalHeader()->resizeSection(1, 150); jobsView->horizontalHeader()->resizeSection(2, 90); jobsView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents); connect(jobsView->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(jobSelected(QModelIndex, QModelIndex))); //Create context menu QAction *actionClipboard = new QAction(QIcon(":/buttons/page_paste.png"), tr("Copy to Clipboard"), logView); actionClipboard->setEnabled(false); logView->addAction(actionClipboard); connect(actionClipboard, SIGNAL(triggered(bool)), this, SLOT(copyLogToClipboard(bool))); jobsView->addActions(menuJob->actions()); //Enable buttons connect(buttonAddJob, SIGNAL(clicked()), this, SLOT(addButtonPressed())); connect(buttonStartJob, SIGNAL(clicked()), this, SLOT(startButtonPressed())); connect(buttonAbortJob, SIGNAL(clicked()), this, SLOT(abortButtonPressed())); connect(buttonPauseJob, SIGNAL(toggled(bool)), this, SLOT(pauseButtonPressed(bool))); connect(actionJob_Delete, SIGNAL(triggered()), this, SLOT(deleteButtonPressed())); connect(actionJob_Restart, SIGNAL(triggered()), this, SLOT(restartButtonPressed())); connect(actionJob_Browse, SIGNAL(triggered()), this, SLOT(browseButtonPressed())); //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(actionWebJEEB, SIGNAL(triggered()), this, SLOT(showWebLink())); connect(actionWebAvisynth32, SIGNAL(triggered()), this, SLOT(showWebLink())); connect(actionWebAvisynth64, SIGNAL(triggered()), this, SLOT(showWebLink())); connect(actionWebWiki, SIGNAL(triggered()), this, SLOT(showWebLink())); connect(actionWebBluRay, SIGNAL(triggered()), this, SLOT(showWebLink())); connect(actionWebAvsWiki, SIGNAL(triggered()), this, SLOT(showWebLink())); connect(actionWebSecret, SIGNAL(triggered()), this, SLOT(showWebLink())); connect(actionWebSupport, SIGNAL(triggered()), this, SLOT(showWebLink())); connect(actionPreferences, SIGNAL(triggered()), this, SLOT(showPreferences())); //Create floating label m_label = new QLabel(jobsView->viewport()); m_label->setText(tr("No job created yet. Please click the 'Add New Job' button!")); m_label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); SET_TEXT_COLOR(m_label, Qt::darkGray); SET_FONT_BOLD(m_label, true); m_label->setVisible(true); m_label->setContextMenuPolicy(Qt::ActionsContextMenu); m_label->addActions(jobsView->actions()); connect(splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(updateLabelPos())); updateLabelPos(); } /* * Destructor */ MainWindow::~MainWindow(void) { OptionsModel::saveTemplate(m_options, QString::fromLatin1(tpl_last)); X264_DELETE(m_jobList); X264_DELETE(m_options); X264_DELETE(m_droppedFiles); X264_DELETE(m_label); while(!m_toolsList.isEmpty()) { QFile *temp = m_toolsList.takeFirst(); X264_DELETE(temp); } if(m_ipcThread->isRunning()) { m_ipcThread->setAbort(); if(!m_ipcThread->wait(5000)) { m_ipcThread->terminate(); m_ipcThread->wait(); } } X264_DELETE(m_ipcThread); } /////////////////////////////////////////////////////////////////////////////// // Slots /////////////////////////////////////////////////////////////////////////////// /* * The "add" button was clicked */ void MainWindow::addButtonPressed(const QString &filePathIn, const QString &filePathOut, OptionsModel *options, int fileNo, int fileTotal, bool *ok) { qDebug("MainWindow::addButtonPressed"); if(ok) *ok = false; AddJobDialog *addDialog = new AddJobDialog(this, options ? options : m_options, m_cpuFeatures->x64); addDialog->setRunImmediately(countRunningJobs() < (m_preferences.autoRunNextJob ? m_preferences.maxRunningJobCount : 1)); if(options) addDialog->setWindowTitle(tr("Restart Job")); if((fileNo >= 0) && (fileTotal > 1)) addDialog->setWindowTitle(addDialog->windowTitle().append(tr(" (File %1 of %2)").arg(QString::number(fileNo+1), QString::number(fileTotal)))); if(!filePathIn.isEmpty()) addDialog->setSourceFile(filePathIn); if(!filePathOut.isEmpty()) addDialog->setOutputFile(filePathOut); int result = addDialog->exec(); if(result == QDialog::Accepted) { EncodeThread *thrd = new EncodeThread ( addDialog->sourceFile(), addDialog->outputFile(), options ? options : m_options, QString("%1/toolset").arg(m_appDir), m_cpuFeatures->x64, m_cpuFeatures->x64 && m_preferences.useAvisyth64Bit ); QModelIndex newIndex = m_jobList->insertJob(thrd); if(newIndex.isValid()) { if(addDialog->runImmediately()) { jobsView->selectRow(newIndex.row()); QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); m_jobList->startJob(newIndex); } if(ok) *ok = true; } m_label->setVisible(m_jobList->rowCount(QModelIndex()) == 0); } X264_DELETE(addDialog); } /* * The "start" button was clicked */ void MainWindow::startButtonPressed(void) { m_jobList->startJob(jobsView->currentIndex()); } /* * The "abort" button was clicked */ void MainWindow::abortButtonPressed(void) { m_jobList->abortJob(jobsView->currentIndex()); } /* * The "delete" button was clicked */ void MainWindow::deleteButtonPressed(void) { m_jobList->deleteJob(jobsView->currentIndex()); m_label->setVisible(m_jobList->rowCount(QModelIndex()) == 0); } /* * The "browse" button was clicked */ void MainWindow::browseButtonPressed(void) { QString outputFile = m_jobList->getJobOutputFile(jobsView->currentIndex()); if((!outputFile.isEmpty()) && QFileInfo(outputFile).exists() && QFileInfo(outputFile).isFile()) { QProcess::startDetached(QString::fromLatin1("explorer.exe"), QStringList() << QString::fromLatin1("/select,") << QDir::toNativeSeparators(outputFile), QFileInfo(outputFile).path()); } else { QMessageBox::warning(this, tr("Not Found"), tr("Sorry, the output file could not be found!")); } } /* * The "pause" button was clicked */ void MainWindow::pauseButtonPressed(bool checked) { if(checked) { m_jobList->pauseJob(jobsView->currentIndex()); } else { m_jobList->resumeJob(jobsView->currentIndex()); } } /* * The "restart" button was clicked */ void MainWindow::restartButtonPressed(void) { const QModelIndex index = jobsView->currentIndex(); const QString &source = m_jobList->getJobSourceFile(index); const QString &output = m_jobList->getJobOutputFile(index); const OptionsModel *options = m_jobList->getJobOptions(index); if((options) && (!source.isEmpty()) && (!output.isEmpty())) { OptionsModel *tempOptions = new OptionsModel(*options); addButtonPressed(source, output, tempOptions); X264_DELETE(tempOptions); } } /* * Job item selected by user */ void MainWindow::jobSelected(const QModelIndex & current, const QModelIndex & previous) { qDebug("Job selected: %d", current.row()); if(logView->model()) { disconnect(logView->model(), SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(jobLogExtended(QModelIndex, int, int))); } if(current.isValid()) { logView->setModel(m_jobList->getLogFile(current)); connect(logView->model(), SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(jobLogExtended(QModelIndex, int, int))); logView->actions().first()->setEnabled(true); QTimer::singleShot(0, logView, SLOT(scrollToBottom())); progressBar->setValue(m_jobList->getJobProgress(current)); editDetails->setText(m_jobList->data(m_jobList->index(current.row(), 3, QModelIndex()), Qt::DisplayRole).toString()); updateButtons(m_jobList->getJobStatus(current)); updateTaskbar(m_jobList->getJobStatus(current), m_jobList->data(m_jobList->index(current.row(), 0, QModelIndex()), Qt::DecorationRole).value()); } else { logView->setModel(NULL); logView->actions().first()->setEnabled(false); progressBar->setValue(0); editDetails->clear(); updateButtons(EncodeThread::JobStatus_Undefined); updateTaskbar(EncodeThread::JobStatus_Undefined, QIcon()); } progressBar->repaint(); } /* * Handle update of job info (status, progress, details, etc) */ void MainWindow::jobChangedData(const QModelIndex &topLeft, const QModelIndex &bottomRight) { int selected = jobsView->currentIndex().row(); if(topLeft.column() <= 1 && bottomRight.column() >= 1) /*STATUS*/ { for(int i = topLeft.row(); i <= bottomRight.row(); i++) { EncodeThread::JobStatus status = m_jobList->getJobStatus(m_jobList->index(i, 0, QModelIndex())); if(i == selected) { qDebug("Current job changed status!"); updateButtons(status); updateTaskbar(status, m_jobList->data(m_jobList->index(i, 0, QModelIndex()), Qt::DecorationRole).value()); } if((status == EncodeThread::JobStatus_Completed) || (status == EncodeThread::JobStatus_Failed)) { if(m_preferences.autoRunNextJob) QTimer::singleShot(0, this, SLOT(launchNextJob())); if(m_preferences.shutdownComputer) QTimer::singleShot(0, this, SLOT(shutdownComputer())); } } } if(topLeft.column() <= 2 && bottomRight.column() >= 2) /*PROGRESS*/ { for(int i = topLeft.row(); i <= bottomRight.row(); i++) { if(i == selected) { progressBar->setValue(m_jobList->getJobProgress(m_jobList->index(i, 0, QModelIndex()))); WinSevenTaskbar::setTaskbarProgress(this, progressBar->value(), progressBar->maximum()); break; } } } if(topLeft.column() <= 3 && bottomRight.column() >= 3) /*DETAILS*/ { for(int i = topLeft.row(); i <= bottomRight.row(); i++) { if(i == selected) { editDetails->setText(m_jobList->data(m_jobList->index(i, 3, QModelIndex()), Qt::DisplayRole).toString()); break; } } } } /* * Handle new log file content */ void MainWindow::jobLogExtended(const QModelIndex & parent, int start, int end) { QTimer::singleShot(0, logView, SLOT(scrollToBottom())); } /* * About screen */ void MainWindow::showAbout(void) { QString text; text += QString().sprintf("Simple x264 Launcher v%u.%02u.%u - use 64-Bit x264 with 32-Bit Avisynth
", x264_version_major(), x264_version_minor(), x264_version_build()); text += QString().sprintf("Copyright (c) 2004-%04d LoRd_MuldeR <mulder2@gmx.de>. Some rights reserved.
", qMax(x264_version_date().year(),QDate::currentDate().year())); text += QString().sprintf("Built on %s at %s with %s for Win-%s.

", x264_version_date().toString(Qt::ISODate).toLatin1().constData(), x264_version_time(), x264_version_compiler(), x264_version_arch()); 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 !!!
", home_url, home_url); QMessageBox aboutBox(this); aboutBox.setIconPixmap(QIcon(":/images/movie.png").pixmap(64,64)); aboutBox.setWindowTitle(tr("About...")); aboutBox.setText(text.replace("-", "−")); aboutBox.addButton(tr("About x264"), QMessageBox::NoRole); aboutBox.addButton(tr("About AVS"), QMessageBox::NoRole); aboutBox.addButton(tr("About Qt"), QMessageBox::NoRole); aboutBox.setEscapeButton(aboutBox.addButton(tr("Close"), QMessageBox::NoRole)); forever { MessageBeep(MB_ICONINFORMATION); switch(aboutBox.exec()) { case 0: { QString text2; text2 += tr("x264 - the best H.264/AVC encoder. Copyright (c) 2003-2012 x264 project.
"); text2 += tr("Free software library for encoding video streams into the H.264/MPEG-4 AVC format.
"); text2 += tr("Released under the terms of the GNU General Public License.

"); text2 += tr("Please visit %1 for obtaining a commercial x264 license.
").arg("http://x264licensing.com/"); text2 += tr("Read the user's manual to get started and use the support forum for help!
").arg("http://mewiki.project357.com/wiki/X264_Settings", "http://forum.doom9.org/forumdisplay.php?f=77"); QMessageBox x264Box(this); x264Box.setIconPixmap(QIcon(":/images/x264.png").pixmap(48,48)); x264Box.setWindowTitle(tr("About x264")); x264Box.setText(text2.replace("-", "−")); x264Box.setEscapeButton(x264Box.addButton(tr("Close"), QMessageBox::NoRole)); MessageBeep(MB_ICONINFORMATION); x264Box.exec(); } break; case 1: { QString text2; text2 += tr("Avisynth - powerful video processing scripting language.
"); text2 += tr("Copyright (c) 2000 Ben Rudiak-Gould and all subsequent developers.
"); text2 += tr("Released under the terms of the GNU General Public License.

"); text2 += tr("Please visit the web-site %1 for more information.
").arg("http://avisynth.org/"); text2 += tr("Read the guide to get started and use the support forum for help!
").arg("http://avisynth.org/mediawiki/First_script", "http://forum.doom9.org/forumdisplay.php?f=33"); QMessageBox x264Box(this); x264Box.setIconPixmap(QIcon(":/images/avisynth.png").pixmap(48,67)); x264Box.setWindowTitle(tr("About Avisynth")); x264Box.setText(text2.replace("-", "−")); x264Box.setEscapeButton(x264Box.addButton(tr("Close"), QMessageBox::NoRole)); MessageBeep(MB_ICONINFORMATION); x264Box.exec(); } break; case 2: QMessageBox::aboutQt(this); break; default: return; } } } /* * Open web-link */ 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() == actionWebJEEB) QDesktopServices::openUrl(QUrl("http://x264.fushizen.eu/")); if(QObject::sender() == actionWebAvisynth32) QDesktopServices::openUrl(QUrl("http://sourceforge.net/projects/avisynth2/files/AviSynth%202.5/")); if(QObject::sender() == actionWebAvisynth64) QDesktopServices::openUrl(QUrl("http://code.google.com/p/avisynth64/downloads/list")); if(QObject::sender() == actionWebWiki) QDesktopServices::openUrl(QUrl("http://mewiki.project357.com/wiki/X264_Settings")); if(QObject::sender() == actionWebBluRay) QDesktopServices::openUrl(QUrl("http://www.x264bluray.com/")); if(QObject::sender() == actionWebAvsWiki) QDesktopServices::openUrl(QUrl("http://avisynth.org/mediawiki/Main_Page#Usage")); if(QObject::sender() == actionWebSupport) QDesktopServices::openUrl(QUrl("http://forum.doom9.org/showthread.php?t=144140")); if(QObject::sender() == actionWebSecret) QDesktopServices::openUrl(QUrl("http://www.youtube.com/watch_popup?v=AXIeHY-OYNI")); } /* * Pereferences dialog */ void MainWindow::showPreferences(void) { PreferencesDialog *preferences = new PreferencesDialog(this, &m_preferences, m_cpuFeatures->x64); preferences->exec(); X264_DELETE(preferences); } /* * Launch next job, after running job has finished */ void MainWindow::launchNextJob(void) { qDebug("launchNextJob(void)"); const int rows = m_jobList->rowCount(QModelIndex()); if(countRunningJobs() >= m_preferences.maxRunningJobCount) { qDebug("Still have too many jobs running, won't launch next one yet!"); return; } int startIdx= jobsView->currentIndex().isValid() ? qBound(0, jobsView->currentIndex().row(), rows-1) : 0; for(int i = 0; i < rows; i++) { int currentIdx = (i + startIdx) % rows; EncodeThread::JobStatus status = m_jobList->getJobStatus(m_jobList->index(currentIdx, 0, QModelIndex())); if(status == EncodeThread::JobStatus_Enqueued) { if(m_jobList->startJob(m_jobList->index(currentIdx, 0, QModelIndex()))) { jobsView->selectRow(currentIdx); return; } } } qWarning("No enqueued jobs left!"); } /* * Shut down the computer (with countdown) */ void MainWindow::shutdownComputer(void) { qDebug("shutdownComputer(void)"); if(countPendingJobs() > 0) { qDebug("Still have pending jobs, won't shutdown yet!"); return; } const int iTimeout = 30; const Qt::WindowFlags flags = Qt::WindowStaysOnTopHint | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowSystemMenuHint; const QString text = QString("%1%2%1").arg(QString().fill(' ', 18), tr("Warning: Computer will shutdown in %1 seconds...")); qWarning("Initiating shutdown sequence!"); QProgressDialog progressDialog(text.arg(iTimeout), tr("Cancel Shutdown"), 0, iTimeout + 1, this, flags); QPushButton *cancelButton = new QPushButton(tr("Cancel Shutdown"), &progressDialog); cancelButton->setIcon(QIcon(":/buttons/power_on.png")); progressDialog.setModal(true); progressDialog.setAutoClose(false); progressDialog.setAutoReset(false); progressDialog.setWindowIcon(QIcon(":/buttons/power_off.png")); progressDialog.setWindowTitle(windowTitle()); progressDialog.setCancelButton(cancelButton); progressDialog.show(); QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); QApplication::setOverrideCursor(Qt::WaitCursor); PlaySound(MAKEINTRESOURCE(IDR_WAVE1), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC); QApplication::restoreOverrideCursor(); QTimer timer; timer.setInterval(1000); timer.start(); QEventLoop eventLoop(this); connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); connect(&progressDialog, SIGNAL(canceled()), &eventLoop, SLOT(quit())); for(int i = 1; i <= iTimeout; i++) { eventLoop.exec(); if(progressDialog.wasCanceled()) { progressDialog.close(); return; } progressDialog.setValue(i+1); progressDialog.setLabelText(text.arg(iTimeout-i)); if(iTimeout-i == 3) progressDialog.setCancelButton(NULL); QApplication::processEvents(); PlaySound(MAKEINTRESOURCE((i < iTimeout) ? IDR_WAVE2 : IDR_WAVE3), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC); } qWarning("Shutting down !!!"); if(x264_shutdown_computer("Simple x264 Launcher: All jobs completed, shutting down!", 10, true)) { qApp->closeAllWindows(); } } /* * Main initialization function (called only once!) */ void MainWindow::init(void) { static const char *binFiles = "x264.exe:x264_x64.exe:avs2yuv.exe:avs2yuv_x64.exe"; QStringList binaries = QString::fromLatin1(binFiles).split(":", QString::SkipEmptyParts); updateLabelPos(); //Check for a running instance bool firstInstance = false; if(m_ipcThread->initialize(&firstInstance)) { m_ipcThread->start(); if(!firstInstance) { if(!m_ipcThread->wait(5000)) { QMessageBox::warning(this, tr("Not Responding"), tr("Another instance of this application is already running, but did not respond in time.
If the problem persists, please kill the running instance from the task manager!
"), tr("Quit")); m_ipcThread->terminate(); m_ipcThread->wait(); } close(); qApp->exit(-1); return; } } //Check all binaries while(!binaries.isEmpty()) { qApp->processEvents(QEventLoop::ExcludeUserInputEvents); QString current = binaries.takeFirst(); QFile *file = new QFile(QString("%1/toolset/%2").arg(m_appDir, current)); if(file->open(QIODevice::ReadOnly)) { bool binaryTypeOkay = false; DWORD binaryType; if(GetBinaryType(QWCHAR(file->fileName()), &binaryType)) { binaryTypeOkay = (binaryType == SCS_32BIT_BINARY || binaryType == SCS_64BIT_BINARY); } if(!binaryTypeOkay) { QMessageBox::critical(this, tr("Invalid File!"), tr("At least on required tool is not a valid Win32 or Win64 binary:
%1

Please re-install the program in order to fix the problem!
").arg(QDir::toNativeSeparators(QString("%1/toolset/%2").arg(m_appDir, current))).replace("-", "−")); qFatal(QString("Binary is invalid: %1/toolset/%2").arg(m_appDir, current).toLatin1().constData()); close(); qApp->exit(-1); return; } m_toolsList << file; } else { X264_DELETE(file); QMessageBox::critical(this, tr("File Not Found!"), tr("At least on required tool could not be found:
%1

Please re-install the program in order to fix the problem!
").arg(QDir::toNativeSeparators(QString("%1/toolset/%2").arg(m_appDir, current))).replace("-", "−")); qFatal(QString("Binary not found: %1/toolset/%2").arg(m_appDir, current).toLatin1().constData()); close(); qApp->exit(-1); return; } } //Check for portable mode if(x264_portable()) { bool ok = false; static const char *data = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; QFile writeTest(QString("%1/%2").arg(x264_data_path(), QUuid::createUuid().toString())); if(writeTest.open(QIODevice::WriteOnly)) { ok = (writeTest.write(data) == strlen(data)); writeTest.remove(); } if(!ok) { int val = QMessageBox::warning(this, tr("Write Test Failed"), tr("The application was launched in portable mode, but the program path is not writable!"), tr("Quit"), tr("Ignore")); if(val != 1) { close(); qApp->exit(-1); return; } } } //Pre-release popup if(x264_is_prerelease()) { qsrand(time(NULL)); int rnd = qrand() % 3; int val = QMessageBox::information(this, tr("Pre-Release Version"), tr("Note: This is a pre-release version. Please do NOT use for production!
Click the button #%1 in order to continue...

(There will be no such message box in the final version of this application)").arg(QString::number(rnd + 1)), tr("(1)"), tr("(2)"), tr("(3)"), qrand() % 3); if(rnd != val) { close(); qApp->exit(-1); return; } } //Make sure this CPU can run x264 (requires MMX + MMXEXT/iSSE to run x264 with ASM enabled, additionally requires SSE1 for most x264 builds) if(!(m_cpuFeatures->mmx && m_cpuFeatures->mmx2)) { QMessageBox::critical(this, tr("Unsupported CPU"), tr("Sorry, but this machine is not physically capable of running x264 (with assembly).
Please get a CPU that supports at least the MMX and MMXEXT instruction sets!
"), tr("Quit")); qFatal("System does not support MMX and MMXEXT, x264 will not work !!!"); close(); qApp->exit(-1); return; } else if(!(m_cpuFeatures->mmx && m_cpuFeatures->sse)) { qWarning("WARNING: System does not support SSE1, most x264 builds will not work !!!\n"); int val = QMessageBox::warning(this, tr("Unsupported CPU"), tr("It appears that this machine does not support the SSE1 instruction set.
Thus most builds of x264 will not run on this computer at all.

Please get a CPU that supports the MMX and SSE1 instruction sets!
"), tr("Quit"), tr("Ignore")); if(val != 1) { close(); qApp->exit(-1); return; } } //Check for Avisynth support if(!qApp->arguments().contains("--skip-avisynth-check", Qt::CaseInsensitive)) { double avisynthVersion = 0.0; QLibrary *avsLib = new QLibrary("avisynth.dll"); if(avsLib->load()) { avisynthVersion = detectAvisynthVersion(avsLib); if(avisynthVersion < 0.0) { int val = QMessageBox::critical(this, tr("Avisynth Error"), tr("A critical error was encountered while checking your Avisynth version!").replace("-", "−"), tr("Quit"), tr("Ignore")); if(val != 1) { close(); qApp->exit(-1); return; } } } if(avisynthVersion < 2.5) { int val = QMessageBox::warning(this, tr("Avisynth Missing"), tr("It appears that Avisynth is not currently installed on your computer.
Therefore Avisynth (.avs) input will not be working at all!

Please download and install Avisynth:
http://sourceforge.net/projects/avisynth2/files/AviSynth 2.5/
").replace("-", "−"), tr("Quit"), tr("Ignore")); avsLib->unload(); X264_DELETE(avsLib); if(val != 1) { close(); qApp->exit(-1); return; } } } //Check for expiration if(x264_version_date().addMonths(6) < QDate::currentDate()) { QMessageBox msgBox(this); msgBox.setIconPixmap(QIcon(":/images/update.png").pixmap(56,56)); msgBox.setWindowTitle(tr("Update Notification")); msgBox.setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint); msgBox.setText(tr("Your version of 'Simple x264 Launcher' is more than 6 months old!

Please download the most recent version from the official web-site at:
%1
").replace("-", "−").arg(update_url)); QPushButton *btn1 = msgBox.addButton(tr("Discard"), QMessageBox::NoRole); QPushButton *btn2 = msgBox.addButton(tr("Discard"), QMessageBox::AcceptRole); btn1->setEnabled(false); btn2->setVisible(false); QTimer::singleShot(5000, btn1, SLOT(hide())); QTimer::singleShot(5000, btn2, SLOT(show())); msgBox.exec(); } //Add files from command-line bool bAddFile = false; QStringList files, args = qApp->arguments(); while(!args.isEmpty()) { QString current = args.takeFirst(); if(!bAddFile) { bAddFile = (current.compare("--add", Qt::CaseInsensitive) == 0); continue; } if((!current.startsWith("--")) && QFileInfo(current).exists() && QFileInfo(current).isFile()) { files << QFileInfo(current).canonicalFilePath(); } } if(int totalFiles = files.count()) { bool ok = true; int n = 0; while((!files.isEmpty()) && ok) { QString currentFile = files.takeFirst(); qDebug("Adding file: %s", currentFile.toUtf8().constData()); addButtonPressed(currentFile, QString(), NULL, n++, totalFiles, &ok); } } } /* * Update the label position */ void MainWindow::updateLabelPos(void) { const QWidget *const viewPort = jobsView->viewport(); m_label->setGeometry(0, 0, viewPort->width(), viewPort->height()); } /* * Copy the complete log to the clipboard */ void MainWindow::copyLogToClipboard(bool checked) { qDebug("copyLogToClipboard"); if(LogFileModel *log = dynamic_cast(logView->model())) { log->copyToClipboard(); MessageBeep(MB_ICONINFORMATION); } } /* * Process the dropped files */ void MainWindow::handleDroppedFiles(void) { qDebug("MainWindow::handleDroppedFiles"); if(m_droppedFiles) { QStringList droppedFiles(*m_droppedFiles); m_droppedFiles->clear(); int totalFiles = droppedFiles.count(); bool ok = true; int n = 0; while((!droppedFiles.isEmpty()) && ok) { QString currentFile = droppedFiles.takeFirst(); qDebug("Adding file: %s", currentFile.toUtf8().constData()); addButtonPressed(currentFile, QString(), NULL, n++, totalFiles, &ok); } } qDebug("Leave from MainWindow::handleDroppedFiles!"); } void MainWindow::instanceCreated(DWORD pid) { qDebug("Notification from other instance (PID=0x%X) received!", pid); FLASHWINFO flashWinInfo; memset(&flashWinInfo, 0, sizeof(FLASHWINFO)); flashWinInfo.cbSize = sizeof(FLASHWINFO); flashWinInfo.hwnd = this->winId(); flashWinInfo.dwFlags = FLASHW_ALL; flashWinInfo.dwTimeout = 125; flashWinInfo.uCount = 5; SwitchToThisWindow(this->winId(), TRUE); SetForegroundWindow(this->winId()); qApp->processEvents(); FlashWindowEx(&flashWinInfo); } /////////////////////////////////////////////////////////////////////////////// // Event functions /////////////////////////////////////////////////////////////////////////////// /* * Window shown event */ void MainWindow::showEvent(QShowEvent *e) { QMainWindow::showEvent(e); if(m_firstShow) { m_firstShow = false; QTimer::singleShot(0, this, SLOT(init())); } } /* * Window close event */ void MainWindow::closeEvent(QCloseEvent *e) { if(countRunningJobs() > 0) { e->ignore(); QMessageBox::warning(this, tr("Jobs Are Running"), tr("Sorry, can not exit while there still are running jobs!")); return; } if(countPendingJobs() > 0) { int ret = QMessageBox::question(this, tr("Jobs Are Pending"), tr("Do you really want to quit and discard the pending jobs?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if(ret != QMessageBox::Yes) { e->ignore(); return; } } while(m_jobList->rowCount(QModelIndex()) > 0) { qApp->processEvents(QEventLoop::ExcludeUserInputEvents); if(!m_jobList->deleteJob(m_jobList->index(0, 0, QModelIndex()))) { e->ignore(); QMessageBox::warning(this, tr("Failed To Exit"), tr("Sorry, at least one job could not be deleted!")); return; } } qApp->processEvents(QEventLoop::ExcludeUserInputEvents); QMainWindow::closeEvent(e); } /* * Window resize event */ void MainWindow::resizeEvent(QResizeEvent *e) { QMainWindow::resizeEvent(e); updateLabelPos(); } /* * Event filter */ bool MainWindow::eventFilter(QObject *o, QEvent *e) { if((o == labelBuildDate) && (e->type() == QEvent::MouseButtonPress)) { QTimer::singleShot(0, this, SLOT(showAbout())); return true; } return false; } /* * Win32 message filter */ bool MainWindow::winEvent(MSG *message, long *result) { return WinSevenTaskbar::handleWinEvent(message, result); } /* * File dragged over window */ void MainWindow::dragEnterEvent(QDragEnterEvent *event) { QStringList formats = event->mimeData()->formats(); if(formats.contains("application/x-qt-windows-mime;value=\"FileNameW\"", Qt::CaseInsensitive) && formats.contains("text/uri-list", Qt::CaseInsensitive)) { event->acceptProposedAction(); } } /* * File dropped onto window */ void MainWindow::dropEvent(QDropEvent *event) { QStringList droppedFiles; QList urls = event->mimeData()->urls(); while(!urls.isEmpty()) { QUrl currentUrl = urls.takeFirst(); QFileInfo file(currentUrl.toLocalFile()); if(file.exists() && file.isFile()) { qDebug("MainWindow::dropEvent: %s", file.canonicalFilePath().toUtf8().constData()); droppedFiles << file.canonicalFilePath(); } } if(droppedFiles.count() > 0) { if(!m_droppedFiles) { m_droppedFiles = new QStringList(); } m_droppedFiles->append(droppedFiles); m_droppedFiles->sort(); QTimer::singleShot(0, this, SLOT(handleDroppedFiles())); } } /////////////////////////////////////////////////////////////////////////////// // Private functions /////////////////////////////////////////////////////////////////////////////// /* * Jobs that are not completed (or failed, or aborted) yet */ unsigned int MainWindow::countPendingJobs(void) { unsigned int count = 0; 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) { count++; } } return count; } /* * Jobs that are still active, i.e. not terminated or enqueued */ unsigned int MainWindow::countRunningJobs(void) { unsigned int count = 0; 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 && status != EncodeThread::JobStatus_Enqueued) { count++; } } return count; } /* * Update all buttons with respect to current job status */ void MainWindow::updateButtons(EncodeThread::JobStatus status) { qDebug("MainWindow::updateButtons(void)"); buttonStartJob->setEnabled(status == EncodeThread::JobStatus_Enqueued); buttonAbortJob->setEnabled(status == EncodeThread::JobStatus_Indexing || status == EncodeThread::JobStatus_Running || status == EncodeThread::JobStatus_Running_Pass1 || status == EncodeThread::JobStatus_Running_Pass2 || status == EncodeThread::JobStatus_Paused); buttonPauseJob->setEnabled(status == EncodeThread::JobStatus_Indexing || status == EncodeThread::JobStatus_Running || status == EncodeThread::JobStatus_Paused || status == EncodeThread::JobStatus_Running_Pass1 || status == EncodeThread::JobStatus_Running_Pass2); buttonPauseJob->setChecked(status == EncodeThread::JobStatus_Paused || status == EncodeThread::JobStatus_Pausing); actionJob_Delete->setEnabled(status == EncodeThread::JobStatus_Completed || status == EncodeThread::JobStatus_Aborted || status == EncodeThread::JobStatus_Failed || status == EncodeThread::JobStatus_Enqueued); actionJob_Restart->setEnabled(status == EncodeThread::JobStatus_Completed || status == EncodeThread::JobStatus_Aborted || status == EncodeThread::JobStatus_Failed || status == EncodeThread::JobStatus_Enqueued); actionJob_Browse->setEnabled(status == EncodeThread::JobStatus_Completed); actionJob_Start->setEnabled(buttonStartJob->isEnabled()); actionJob_Abort->setEnabled(buttonAbortJob->isEnabled()); actionJob_Pause->setEnabled(buttonPauseJob->isEnabled()); actionJob_Pause->setChecked(buttonPauseJob->isChecked()); editDetails->setEnabled(status != EncodeThread::JobStatus_Paused); } /* * Update the taskbar with current job status */ void MainWindow::updateTaskbar(EncodeThread::JobStatus status, const QIcon &icon) { qDebug("MainWindow::updateTaskbar(void)"); switch(status) { case EncodeThread::JobStatus_Undefined: WinSevenTaskbar::setTaskbarState(this, WinSevenTaskbar::WinSevenTaskbarNoState); break; case EncodeThread::JobStatus_Aborting: case EncodeThread::JobStatus_Starting: case EncodeThread::JobStatus_Pausing: case EncodeThread::JobStatus_Resuming: WinSevenTaskbar::setTaskbarState(this, WinSevenTaskbar::WinSevenTaskbarIndeterminateState); break; case EncodeThread::JobStatus_Aborted: case EncodeThread::JobStatus_Failed: WinSevenTaskbar::setTaskbarState(this, WinSevenTaskbar::WinSevenTaskbarErrorState); break; case EncodeThread::JobStatus_Paused: WinSevenTaskbar::setTaskbarState(this, WinSevenTaskbar::WinSevenTaskbarPausedState); break; default: WinSevenTaskbar::setTaskbarState(this, WinSevenTaskbar::WinSevenTaskbarNormalState); break; } switch(status) { case EncodeThread::JobStatus_Aborting: case EncodeThread::JobStatus_Starting: case EncodeThread::JobStatus_Pausing: case EncodeThread::JobStatus_Resuming: break; default: WinSevenTaskbar::setTaskbarProgress(this, progressBar->value(), progressBar->maximum()); break; } WinSevenTaskbar::setOverlayIcon(this, icon.isNull() ? NULL : &icon); } /* * Detect Avisynth version */ double MainWindow::detectAvisynthVersion(QLibrary *avsLib) { double version_number = 0.0; __try { avs_create_script_environment_func avs_create_script_environment_ptr = (avs_create_script_environment_func) avsLib->resolve("avs_create_script_environment"); avs_invoke_func avs_invoke_ptr = (avs_invoke_func) avsLib->resolve("avs_invoke"); avs_function_exists_func avs_function_exists_ptr = (avs_function_exists_func) avsLib->resolve("avs_function_exists"); avs_delete_script_environment_func avs_delete_script_environment_ptr = (avs_delete_script_environment_func) avsLib->resolve("avs_delete_script_environment"); if((avs_create_script_environment_ptr != NULL) && (avs_invoke_ptr != NULL) && (avs_function_exists_ptr != NULL)) { AVS_ScriptEnvironment* avs_env = avs_create_script_environment_ptr(AVS_INTERFACE_25); if(avs_env != NULL) { if(avs_function_exists_ptr(avs_env, "VersionNumber")) { AVS_Value avs_version = avs_invoke_ptr(avs_env, "VersionNumber", avs_new_value_array(NULL, 0), NULL); if(!avs_is_error(avs_version)) { if(avs_is_float(avs_version)) { qDebug("Avisynth version: v%.2f", avs_as_float(avs_version)); version_number = avs_as_float(avs_version); } } } if(avs_delete_script_environment_ptr != NULL) { avs_delete_script_environment_ptr(avs_env); avs_env = NULL; } } } else { qWarning("It seems the Avisynth DLL is missing required API functions!"); } } __except(1) { qWarning("Exception in Avisynth initialization code!"); version_number = -1.0; } return version_number; }