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 ///////////////////////////////////////////////////////////////////////////////
22 #include "win_addJob.h"
25 #include "model_options.h"
26 #include "model_recently.h"
28 #include "win_editor.h"
32 #include <QCloseEvent>
33 #include <QMessageBox>
34 #include <QFileDialog>
35 #include <QDesktopServices>
38 #include <QInputDialog>
45 #define ARRAY_SIZE(ARRAY) (sizeof((ARRAY))/sizeof((ARRAY[0])))
46 #define VALID_DIR(PATH) ((!(PATH).isEmpty()) && QFileInfo(PATH).exists() && QFileInfo(PATH).isDir())
48 #define REMOVE_USAFED_ITEM \
50 for(int i = 0; i < cbxTemplate->count(); i++) \
52 OptionsModel* temp = reinterpret_cast<OptionsModel*>(cbxTemplate->itemData(i).value<void*>()); \
55 cbxTemplate->blockSignals(true); \
56 cbxTemplate->removeItem(i); \
57 cbxTemplate->blockSignals(false); \
63 #define ADD_CONTEXTMENU_ACTION(WIDGET, ICON, TEXT, SLOTNAME) \
65 QAction *_action = new QAction((ICON), (TEXT), this); \
66 _action->setData(QVariant::fromValue<void*>(WIDGET)); \
67 WIDGET->addAction(_action); \
68 connect(_action, SIGNAL(triggered(bool)), this, SLOT(SLOTNAME())); \
71 #define ADD_CONTEXTMENU_SEPARATOR(WIDGET) \
73 QAction *_action = new QAction(this); \
74 _action->setSeparator(true); \
75 WIDGET->addAction(_action); \
78 ///////////////////////////////////////////////////////////////////////////////
80 ///////////////////////////////////////////////////////////////////////////////
82 class StringValidator : public QValidator
85 StringValidator(QLabel *notifier, QLabel *icon)
87 m_notifier(notifier), m_icon(icon)
93 virtual State validate(QString &input, int &pos) const = 0;
95 virtual void fixup(QString &input) const
97 input = input.simplified();
101 QLabel *const m_notifier, *const m_icon;
103 bool checkParam(const QString &input, const QString ¶m, const bool doubleMinus) const
105 static const char c[20] = {' ', '*', '?', '<', '>', '/', '\\', '"', '\'', '!', '+', '#', '&', '%', '=', ',', ';', '.', 'ยด', '`'};
106 const QString prefix = doubleMinus ? QLatin1String("--") : QLatin1String("-");
109 if(param.length() > 1)
111 flag = flag || input.endsWith(QString("%1%2").arg(prefix, param), Qt::CaseInsensitive);
112 for(size_t i = 0; i < sizeof(c); i++)
114 flag = flag || input.contains(QString("%1%2%3").arg(prefix, param, QChar::fromLatin1(c[i])), Qt::CaseInsensitive);
119 flag = flag || input.startsWith(QString("-%1").arg(param));
120 for(size_t i = 0; i < sizeof(c); i++)
122 flag = flag || input.contains(QString("%1-%2").arg(QChar::fromLatin1(c[i]), param), Qt::CaseSensitive);
125 if((flag) && (m_notifier))
127 m_notifier->setText(tr("Invalid parameter: %1").arg((param.length() > 1) ? QString("%1%2").arg(prefix, param) : QString("-%1").arg(param)));
132 const bool &setStatus(const bool &flag, const QString &toolName) const
138 if(m_notifier->isHidden()) m_notifier->show();
139 if(m_icon) { if(m_icon->isHidden()) m_icon->show(); }
140 if(QWidget *w = m_notifier->topLevelWidget()->focusWidget())
142 QToolTip::showText(static_cast<QWidget*>(w->parent())->mapToGlobal(w->pos()), QString("<nobr>%1</nobr>").arg(tr("<b>Warning:</b> You entered a parameter that is incomaptible with using %1 from a GUI.<br>Please note that the GUI will automatically set <i>this</i> parameter for you (if required).").arg(toolName)), m_notifier, QRect());
150 if(m_notifier->isVisible()) m_notifier->hide();
151 if(m_icon) { if(m_icon->isVisible()) m_icon->hide(); }
152 QToolTip::hideText();
159 class StringValidatorX264 : public StringValidator
162 StringValidatorX264(QLabel *notifier, QLabel *icon) : StringValidator(notifier, icon) {}
164 virtual State validate(QString &input, int &pos) const
166 static const char* p[] = {"B", "o", "h", "p", "q", /*"fps", "frames",*/ "preset", "tune", "profile",
167 "stdin", "crf", "bitrate", "qp", "pass", "stats", "output", "help","quiet", NULL};
169 bool invalid = false;
171 for(size_t i = 0; p[i] && (!invalid); i++)
173 invalid = invalid || checkParam(input, QString::fromLatin1(p[i]), true);
176 return setStatus(invalid, "x264") ? QValidator::Intermediate : QValidator::Acceptable;
180 class StringValidatorAvs2YUV : public StringValidator
183 StringValidatorAvs2YUV(QLabel *notifier, QLabel *icon) : StringValidator(notifier, icon) {}
185 virtual State validate(QString &input, int &pos) const
187 static const char* p[] = {"o", "frames", "seek", "raw", "hfyu", "slave", NULL};
189 bool invalid = false;
191 for(size_t i = 0; p[i] && (!invalid); i++)
193 invalid = invalid || checkParam(input, QString::fromLatin1(p[i]), false);
196 return setStatus(invalid, "Avs2YUV") ? QValidator::Intermediate : QValidator::Acceptable;
200 ///////////////////////////////////////////////////////////////////////////////
201 // Constructor & Destructor
202 ///////////////////////////////////////////////////////////////////////////////
204 AddJobDialog::AddJobDialog(QWidget *parent, OptionsModel *options, RecentlyUsed *recentlyUsed, bool x64supported, bool use10BitEncoding, bool saveToSourceFolder)
207 m_defaults(new OptionsModel()),
209 m_x64supported(x64supported),
210 m_use10BitEncoding(use10BitEncoding),
211 m_saveToSourceFolder(saveToSourceFolder),
212 m_recentlyUsed(recentlyUsed)
214 //Init the dialog, from the .ui file
216 setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
219 buttonSaveTemplate->setMaximumHeight(20);
220 buttonDeleteTemplate->setMaximumHeight(20);
221 resize(width(), minimumHeight());
222 setMinimumSize(size());
223 setMaximumHeight(height());
225 //Hide optional controls
226 checkBoxApplyToAll->setVisible(false);
228 //Monitor RC mode combobox
229 connect(cbxRateControlMode, SIGNAL(currentIndexChanged(int)), this, SLOT(modeIndexChanged(int)));
232 connect(buttonBrowseSource, SIGNAL(clicked()), this, SLOT(browseButtonClicked()));
233 connect(buttonBrowseOutput, SIGNAL(clicked()), this, SLOT(browseButtonClicked()));
234 connect(buttonSaveTemplate, SIGNAL(clicked()), this, SLOT(saveTemplateButtonClicked()));
235 connect(buttonDeleteTemplate, SIGNAL(clicked()), this, SLOT(deleteTemplateButtonClicked()));
238 editCustomX264Params->installEventFilter(this);
239 editCustomX264Params->setValidator(new StringValidatorX264(labelNotificationX264, iconNotificationX264));
240 editCustomX264Params->clear();
241 editCustomAvs2YUVParams->installEventFilter(this);
242 editCustomAvs2YUVParams->setValidator(new StringValidatorAvs2YUV(labelNotificationAvs2YUV, iconNotificationAvs2YUV));
243 editCustomAvs2YUVParams->clear();
245 //Install event filter
246 labelHelpScreenX264->installEventFilter(this);
247 labelHelpScreenAvs2YUV->installEventFilter(this);
249 //Monitor for options changes
250 connect(cbxRateControlMode, SIGNAL(currentIndexChanged(int)), this, SLOT(configurationChanged()));
251 connect(spinQuantizer, SIGNAL(valueChanged(double)), this, SLOT(configurationChanged()));
252 connect(spinBitrate, SIGNAL(valueChanged(int)), this, SLOT(configurationChanged()));
253 connect(cbxPreset, SIGNAL(currentIndexChanged(int)), this, SLOT(configurationChanged()));
254 connect(cbxTuning, SIGNAL(currentIndexChanged(int)), this, SLOT(configurationChanged()));
255 connect(cbxProfile, SIGNAL(currentIndexChanged(int)), this, SLOT(configurationChanged()));
256 connect(editCustomX264Params, SIGNAL(textChanged(QString)), this, SLOT(configurationChanged()));
257 connect(editCustomAvs2YUVParams, SIGNAL(textChanged(QString)), this, SLOT(configurationChanged()));
259 //Create context menus
260 ADD_CONTEXTMENU_ACTION(editCustomX264Params, QIcon(":/buttons/page_edit.png"), tr("Open the Text-Editor"), editorActionTriggered);
261 ADD_CONTEXTMENU_ACTION(editCustomAvs2YUVParams, QIcon(":/buttons/page_edit.png"), tr("Open the Text-Editor"), editorActionTriggered);
262 ADD_CONTEXTMENU_SEPARATOR(editCustomX264Params);
263 ADD_CONTEXTMENU_SEPARATOR(editCustomAvs2YUVParams);
264 ADD_CONTEXTMENU_ACTION(editCustomX264Params, QIcon(":/buttons/page_copy.png"), tr("Copy to Clipboard"), copyActionTriggered);
265 ADD_CONTEXTMENU_ACTION(editCustomAvs2YUVParams, QIcon(":/buttons/page_copy.png"), tr("Copy to Clipboard"), copyActionTriggered);
266 ADD_CONTEXTMENU_ACTION(editCustomX264Params, QIcon(":/buttons/page_paste.png"), tr("Paste from Clipboard"), pasteActionTriggered);
267 ADD_CONTEXTMENU_ACTION(editCustomAvs2YUVParams, QIcon(":/buttons/page_paste.png"), tr("Paste from Clipboard"), pasteActionTriggered);
269 //Setup template selector
271 connect(cbxTemplate, SIGNAL(currentIndexChanged(int)), this, SLOT(templateSelected()));
274 AddJobDialog::~AddJobDialog(void)
277 for(int i = 0; i < cbxTemplate->model()->rowCount(); i++)
279 if(cbxTemplate->itemText(i).startsWith("<") || cbxTemplate->itemText(i).endsWith(">"))
283 OptionsModel *item = reinterpret_cast<OptionsModel*>(cbxTemplate->itemData(i).value<void*>());
284 cbxTemplate->setItemData(i, QVariant::fromValue<void*>(NULL));
289 if(const QValidator *tmp = editCustomX264Params->validator())
291 editCustomX264Params->setValidator(NULL);
294 if(const QValidator *tmp = editCustomAvs2YUVParams->validator())
296 editCustomAvs2YUVParams->setValidator(NULL);
300 X264_DELETE(m_defaults);
303 ///////////////////////////////////////////////////////////////////////////////
305 ///////////////////////////////////////////////////////////////////////////////
307 void AddJobDialog::showEvent(QShowEvent *event)
309 QDialog::showEvent(event);
312 if((!editSource->text().isEmpty()) && editOutput->text().isEmpty())
314 QString outPath = generateOutputFileName(QDir::fromNativeSeparators(editSource->text()), m_recentlyUsed->outputDirectory(), m_recentlyUsed->filterIndex(), m_saveToSourceFolder);
315 editOutput->setText(QDir::toNativeSeparators(outPath));
316 buttonAccept->setFocus();
319 labelNotificationX264->hide();
320 iconNotificationX264->hide();
321 labelNotificationAvs2YUV->hide();
322 iconNotificationAvs2YUV->hide();
324 //Enable drag&drop support for this window, required for Qt v4.8.4+
325 setAcceptDrops(true);
328 bool AddJobDialog::eventFilter(QObject *o, QEvent *e)
330 if((o == labelHelpScreenX264) && (e->type() == QEvent::MouseButtonPress))
332 HelpDialog *helpScreen = new HelpDialog(this, false, m_x64supported, m_use10BitEncoding);
334 X264_DELETE(helpScreen);
336 else if((o == labelHelpScreenAvs2YUV) && (e->type() == QEvent::MouseButtonPress))
338 HelpDialog *helpScreen = new HelpDialog(this, true, m_x64supported, m_use10BitEncoding);
340 X264_DELETE(helpScreen);
342 else if((o == editCustomX264Params) && (e->type() == QEvent::FocusOut))
344 editCustomX264Params->setText(editCustomX264Params->text().simplified());
346 else if((o == editCustomAvs2YUVParams) && (e->type() == QEvent::FocusOut))
348 editCustomAvs2YUVParams->setText(editCustomAvs2YUVParams->text().simplified());
353 void AddJobDialog::dragEnterEvent(QDragEnterEvent *event)
355 bool accept[2] = {false, false};
357 foreach(const QString &fmt, event->mimeData()->formats())
359 accept[0] = accept[0] || fmt.contains("text/uri-list", Qt::CaseInsensitive);
360 accept[1] = accept[1] || fmt.contains("FileNameW", Qt::CaseInsensitive);
363 if(accept[0] && accept[1])
365 event->acceptProposedAction();
369 void AddJobDialog::dropEvent(QDropEvent *event)
372 QList<QUrl> urls = event->mimeData()->urls();
376 QDragEnterEvent dragEvent(event->pos(), event->proposedAction(), event->mimeData(), Qt::NoButton, Qt::NoModifier);
377 if(qApp->notify(parent(), &dragEvent))
379 qApp->notify(parent(), event);
384 while((!urls.isEmpty()) && droppedFile.isEmpty())
386 QUrl currentUrl = urls.takeFirst();
387 QFileInfo file(currentUrl.toLocalFile());
388 if(file.exists() && file.isFile())
390 qDebug("AddJobDialog::dropEvent: %s", file.canonicalFilePath().toUtf8().constData());
391 droppedFile = file.canonicalFilePath();
395 if(!droppedFile.isEmpty())
397 const QString outFileName = generateOutputFileName(droppedFile, currentOutputPath(), currentOutputIndx(), m_saveToSourceFolder);
398 editSource->setText(QDir::toNativeSeparators(droppedFile));
399 editOutput->setText(QDir::toNativeSeparators(outFileName));
403 ///////////////////////////////////////////////////////////////////////////////
405 ///////////////////////////////////////////////////////////////////////////////
407 void AddJobDialog::modeIndexChanged(int index)
409 spinQuantizer->setEnabled(index == 0 || index == 1);
410 spinBitrate->setEnabled(index == 2 || index == 3);
413 void AddJobDialog::accept(void)
415 //Selection complete?
416 if(editSource->text().trimmed().isEmpty())
418 QMessageBox::warning(this, tr("Not Found!"), tr("Please select a valid source file first!"));
421 if(editOutput->text().trimmed().isEmpty())
423 QMessageBox::warning(this, tr("Not Selected!"), tr("<nobr>Please select a valid output file first!</nobr>"));
428 QFileInfo sourceFile = QFileInfo(this->sourceFile());
429 if(!(sourceFile.exists() && sourceFile.isFile()))
431 QMessageBox::warning(this, tr("Not Found!"), tr("<nobr>The selected source file could not be found!</nobr>"));
435 //Does output file already exist?
436 QFileInfo outputFile = QFileInfo(this->outputFile());
437 if(outputFile.exists() && outputFile.isFile())
439 int ret = QMessageBox::question(this, tr("Already Exists!"), tr("<nobr>Output file already exists! Overwrite?</nobr>"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
440 if(ret != QMessageBox::Yes) return;
442 if(outputFile.exists() && (!outputFile.isFile()))
444 QMessageBox::warning(this, tr("Not a File!"), tr("<nobr>Selected output file does not appear to be a valid file!</nobr>"));
448 //Is destination dir writable?
449 QFileInfo outputDir = QFileInfo(outputFile.absolutePath());
450 if(!(outputDir.exists() && outputDir.isDir() && outputDir.isWritable()))
452 QMessageBox::warning(this, tr("Not Writable!"), tr("<nobr>Output directory does not exist or is not writable!</nobr>"));
456 //Custom parameters okay?
457 if(!editCustomX264Params->hasAcceptableInput())
459 int ret = QMessageBox::warning(this, tr("Invalid Params"), tr("<nobr>Your custom parameters are invalid and will be discarded!</nobr>"), QMessageBox::Ignore | QMessageBox::Cancel, QMessageBox::Cancel);
460 if(ret != QMessageBox::Ignore) return;
463 //Update recently used
464 m_recentlyUsed->setFilterIndex(currentOutputIndx());
465 m_recentlyUsed->setSourceDirectory(currentSourcePath());
466 m_recentlyUsed->setOutputDirectory(currentOutputPath());
467 RecentlyUsed::saveRecentlyUsed(m_recentlyUsed);
470 saveOptions(m_options);
474 void AddJobDialog::browseButtonClicked(void)
476 if(QObject::sender() == buttonBrowseSource)
478 QString filePath = QFileDialog::getOpenFileName(this, tr("Open Source File"), currentSourcePath(true), getInputFilterLst(), NULL, QFileDialog::DontUseNativeDialog);
479 if(!(filePath.isNull() || filePath.isEmpty()))
481 QString destFile = generateOutputFileName(filePath, currentOutputPath(), currentOutputIndx(), m_saveToSourceFolder);
482 editSource->setText(QDir::toNativeSeparators(filePath));
483 editOutput->setText(QDir::toNativeSeparators(destFile));
486 else if(QObject::sender() == buttonBrowseOutput)
488 QString selectedType = getFilterStr(currentOutputIndx());
489 QString filePath = QFileDialog::getSaveFileName(this, tr("Choose Output File"), currentOutputPath(true), getFilterLst(), &selectedType, QFileDialog::DontUseNativeDialog | QFileDialog::DontConfirmOverwrite);
491 if(!(filePath.isNull() || filePath.isEmpty()))
493 if(getFilterIdx(QFileInfo(filePath).suffix()) < 0)
496 QRegExp regExp("\\(\\*\\.(\\w+)\\)");
497 if(regExp.lastIndexIn(selectedType) >= 0)
499 tempIndex = getFilterIdx(regExp.cap(1));
503 tempIndex = m_recentlyUsed->filterIndex();
505 filePath = QString("%1.%2").arg(filePath, getFilterExt(tempIndex));
507 editOutput->setText(QDir::toNativeSeparators(filePath));
512 void AddJobDialog::configurationChanged(void)
514 OptionsModel* options = reinterpret_cast<OptionsModel*>(cbxTemplate->itemData(cbxTemplate->currentIndex()).value<void*>());
517 cbxTemplate->blockSignals(true);
518 cbxTemplate->insertItem(0, tr("<Unsaved Configuration>"), QVariant::fromValue<void*>(NULL));
519 cbxTemplate->setCurrentIndex(0);
520 cbxTemplate->blockSignals(false);
524 void AddJobDialog::templateSelected(void)
526 OptionsModel* options = reinterpret_cast<OptionsModel*>(cbxTemplate->itemData(cbxTemplate->currentIndex()).value<void*>());
529 qDebug("Loading options!");
531 restoreOptions(options);
534 modeIndexChanged(cbxRateControlMode->currentIndex());
537 void AddJobDialog::saveTemplateButtonClicked(void)
539 qDebug("Saving template");
540 QString name = tr("New Template");
543 while(OptionsModel::templateExists(name))
545 name = tr("New Template (%1)").arg(QString::number(n++));
548 OptionsModel *options = new OptionsModel();
549 saveOptions(options);
551 if(options->equals(m_defaults))
553 QMessageBox::warning (this, tr("Oups"), tr("<nobr>It makes no sense to save the default settings!</nobr>"));
554 cbxTemplate->blockSignals(true);
555 cbxTemplate->setCurrentIndex(0);
556 cbxTemplate->blockSignals(false);
558 X264_DELETE(options);
562 for(int i = 0; i < cbxTemplate->count(); i++)
564 const QString tempName = cbxTemplate->itemText(i);
565 if(tempName.contains('<') || tempName.contains('>'))
569 OptionsModel* test = reinterpret_cast<OptionsModel*>(cbxTemplate->itemData(i).value<void*>());
572 if(options->equals(test))
574 QMessageBox::warning (this, tr("Oups"), tr("<nobr>There already is a template for the current settings!</nobr>"));
575 cbxTemplate->blockSignals(true);
576 cbxTemplate->setCurrentIndex(i);
577 cbxTemplate->blockSignals(false);
579 X264_DELETE(options);
588 name = QInputDialog::getText(this, tr("Save Template"), tr("Please enter the name of the template:").leftJustified(144, ' '), QLineEdit::Normal, name, &ok).simplified();
591 X264_DELETE(options);
594 if(name.contains('<') || name.contains('>') || name.contains('\\') || name.contains('/') || name.contains('"'))
596 QMessageBox::warning (this, tr("Invalid Name"), tr("<nobr>Sorry, the name you have entered is invalid!</nobr>"));
597 while(name.contains('<')) name.remove('<');
598 while(name.contains('>')) name.remove('>');
599 while(name.contains('\\')) name.remove('\\');
600 while(name.contains('/')) name.remove('/');
601 while(name.contains('"')) name.remove('"');
602 name = name.simplified();
605 if(OptionsModel::templateExists(name))
607 int ret = QMessageBox::warning (this, tr("Already Exists"), tr("<nobr>A template of that name already exists! Overwrite?</nobr>"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
608 if(ret != QMessageBox::Yes)
616 if(!OptionsModel::saveTemplate(options, name))
618 QMessageBox::critical(this, tr("Save Failed"), tr("Sorry, the template could not be saved!"));
619 X264_DELETE(options);
623 int index = cbxTemplate->model()->rowCount();
624 cbxTemplate->blockSignals(true);
625 for(int i = 0; i < cbxTemplate->count(); i++)
627 if(cbxTemplate->itemText(i).compare(name, Qt::CaseInsensitive) == 0)
629 index = -1; //Do not append new template
630 OptionsModel *oldItem = reinterpret_cast<OptionsModel*>(cbxTemplate->itemData(i).value<void*>());
631 cbxTemplate->setItemData(i, QVariant::fromValue<void*>(options));
632 cbxTemplate->setCurrentIndex(i);
633 X264_DELETE(oldItem);
638 cbxTemplate->insertItem(index, name, QVariant::fromValue<void*>(options));
639 cbxTemplate->setCurrentIndex(index);
641 cbxTemplate->blockSignals(false);
646 void AddJobDialog::deleteTemplateButtonClicked(void)
648 const int index = cbxTemplate->currentIndex();
649 QString name = cbxTemplate->itemText(index);
651 if(name.contains('<') || name.contains('>') || name.contains('\\') || name.contains('/'))
653 QMessageBox::warning (this, tr("Invalid Item"), tr("Sorry, the selected item cannot be deleted!"));
657 int ret = QMessageBox::question (this, tr("Delete Template"), tr("<nobr>Do you really want to delete the selected template?</nobr>"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
658 if(ret != QMessageBox::Yes)
664 OptionsModel::deleteTemplate(name);
665 OptionsModel *item = reinterpret_cast<OptionsModel*>(cbxTemplate->itemData(index).value<void*>());
666 cbxTemplate->removeItem(index);
670 void AddJobDialog::editorActionTriggered(void)
673 if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
675 QLineEdit *lineEdit = reinterpret_cast<QLineEdit*>(action->data().value<void*>());
677 EditorDialog *editor = new EditorDialog(this);
678 editor->setEditText(lineEdit->text());
680 if(editor->exec() == QDialog::Accepted)
682 lineEdit->setText(editor->getEditText());
689 void AddJobDialog::copyActionTriggered(void)
691 if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
693 QClipboard *clipboard = QApplication::clipboard();
694 QLineEdit *lineEdit = reinterpret_cast<QLineEdit*>(action->data().value<void*>());
695 QString text = lineEdit->hasSelectedText() ? lineEdit->selectedText() : lineEdit->text();
696 clipboard->setText(text);
700 void AddJobDialog::pasteActionTriggered(void)
702 if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
704 QClipboard *clipboard = QApplication::clipboard();
705 QLineEdit *lineEdit = reinterpret_cast<QLineEdit*>(action->data().value<void*>());
706 QString text = clipboard->text();
707 if(!text.isEmpty()) lineEdit->setText(text);
711 ///////////////////////////////////////////////////////////////////////////////
713 ///////////////////////////////////////////////////////////////////////////////
715 QString AddJobDialog::sourceFile(void)
717 return QDir::fromNativeSeparators(editSource->text());
720 QString AddJobDialog::outputFile(void)
722 return QDir::fromNativeSeparators(editOutput->text());
725 ///////////////////////////////////////////////////////////////////////////////
727 ///////////////////////////////////////////////////////////////////////////////
729 void AddJobDialog::loadTemplateList(void)
731 cbxTemplate->addItem(tr("<Default>"), QVariant::fromValue<void*>(m_defaults));
732 cbxTemplate->setCurrentIndex(0);
734 QMap<QString, OptionsModel*> templates = OptionsModel::loadAllTemplates();
735 QStringList templateNames = templates.keys();
736 templateNames.sort();
738 while(!templateNames.isEmpty())
740 QString current = templateNames.takeFirst();
741 cbxTemplate->addItem(current, QVariant::fromValue<void*>(templates.value(current)));
743 if(templates.value(current)->equals(m_options))
745 cbxTemplate->setCurrentIndex(cbxTemplate->count() - 1);
749 if((cbxTemplate->currentIndex() == 0) && (!m_options->equals(m_defaults)))
751 cbxTemplate->insertItem(1, tr("<Recently Used>"), QVariant::fromValue<void*>(m_options));
752 cbxTemplate->setCurrentIndex(1);
756 void AddJobDialog::updateComboBox(QComboBox *cbox, const QString &text)
758 for(int i = 0; i < cbox->model()->rowCount(); i++)
760 if(cbox->model()->data(cbox->model()->index(i, 0, QModelIndex())).toString().compare(text, Qt::CaseInsensitive) == 0)
762 cbox->setCurrentIndex(i);
768 void AddJobDialog::restoreOptions(OptionsModel *options)
770 cbxRateControlMode->blockSignals(true);
771 spinQuantizer->blockSignals(true);
772 spinBitrate->blockSignals(true);
773 cbxPreset->blockSignals(true);
774 cbxTuning->blockSignals(true);
775 cbxProfile->blockSignals(true);
776 editCustomX264Params->blockSignals(true);
777 editCustomAvs2YUVParams->blockSignals(true);
779 cbxRateControlMode->setCurrentIndex(options->rcMode());
780 spinQuantizer->setValue(options->quantizer());
781 spinBitrate->setValue(options->bitrate());
782 updateComboBox(cbxPreset, options->preset());
783 updateComboBox(cbxTuning, options->tune());
784 updateComboBox(cbxProfile, options->profile());
785 editCustomX264Params->setText(options->customX264());
786 editCustomAvs2YUVParams->setText(options->customAvs2YUV());
788 cbxRateControlMode->blockSignals(false);
789 spinQuantizer->blockSignals(false);
790 spinBitrate->blockSignals(false);
791 cbxPreset->blockSignals(false);
792 cbxTuning->blockSignals(false);
793 cbxProfile->blockSignals(false);
794 editCustomX264Params->blockSignals(false);
795 editCustomAvs2YUVParams->blockSignals(false);
798 void AddJobDialog::saveOptions(OptionsModel *options)
800 options->setRCMode(static_cast<OptionsModel::RCMode>(cbxRateControlMode->currentIndex()));
801 options->setQuantizer(spinQuantizer->value());
802 options->setBitrate(spinBitrate->value());
803 options->setPreset(cbxPreset->model()->data(cbxPreset->model()->index(cbxPreset->currentIndex(), 0)).toString());
804 options->setTune(cbxTuning->model()->data(cbxTuning->model()->index(cbxTuning->currentIndex(), 0)).toString());
805 options->setProfile(cbxProfile->model()->data(cbxProfile->model()->index(cbxProfile->currentIndex(), 0)).toString());
806 options->setCustomX264(editCustomX264Params->hasAcceptableInput() ? editCustomX264Params->text().simplified() : QString());
807 options->setCustomAvs2YUV(editCustomAvs2YUVParams->hasAcceptableInput() ? editCustomAvs2YUVParams->text().simplified() : QString());
810 QString AddJobDialog::currentSourcePath(const bool bWithName)
812 QString path = m_recentlyUsed->sourceDirectory();
813 QString currentSourceFile = this->sourceFile();
815 if(!currentSourceFile.isEmpty())
817 QString currentSourceDir = QFileInfo(currentSourceFile).absolutePath();
818 if(VALID_DIR(currentSourceDir))
820 path = currentSourceDir;
824 path.append("/").append(QFileInfo(currentSourceFile).fileName());
831 QString AddJobDialog::currentOutputPath(const bool bWithName)
833 QString path = m_recentlyUsed->outputDirectory();
834 QString currentOutputFile = this->outputFile();
836 if(!currentOutputFile.isEmpty())
838 QString currentOutputDir = QFileInfo(currentOutputFile).absolutePath();
839 if(VALID_DIR(currentOutputDir))
841 path = currentOutputDir;
845 path.append("/").append(QFileInfo(currentOutputFile).fileName());
852 int AddJobDialog::currentOutputIndx(void)
854 int index = m_recentlyUsed->filterIndex();
855 QString currentOutputFile = this->outputFile();
857 if(!currentOutputFile.isEmpty())
859 const QString currentOutputExtn = QFileInfo(currentOutputFile).suffix();
860 const int tempIndex = getFilterIdx(currentOutputExtn);
870 ///////////////////////////////////////////////////////////////////////////////
872 ///////////////////////////////////////////////////////////////////////////////
874 QString AddJobDialog::generateOutputFileName(const QString &sourceFilePath, const QString &destinationDirectory, const int filterIndex, const bool saveToSourceDir)
876 QString name = QFileInfo(sourceFilePath).completeBaseName();
877 QString path = saveToSourceDir ? QFileInfo(sourceFilePath).canonicalPath() : destinationDirectory;
878 QString fext = getFilterExt(filterIndex);
882 RecentlyUsed defaults;
883 path = defaults.outputDirectory();
886 QString outPath = QString("%1/%2.%3").arg(path, name, fext);
889 while(QFileInfo(outPath).exists())
891 outPath = QString("%1/%2 (%3).%4").arg(path, name, QString::number(n++), fext);
897 /* ------------------------------------------------------------------------- */
899 QString AddJobDialog::getFilterExt(const int filterIndex)
901 const int count = ARRAY_SIZE(X264_FILE_TYPE_FILTERS);
903 if((filterIndex >= 0) && (filterIndex < count))
905 return QString::fromLatin1(X264_FILE_TYPE_FILTERS[filterIndex].pcExt);
908 return QString::fromLatin1(X264_FILE_TYPE_FILTERS[0].pcExt);
911 int AddJobDialog::getFilterIdx(const QString &fileExt)
913 const int count = ARRAY_SIZE(X264_FILE_TYPE_FILTERS);
915 for(int i = 0; i < count; i++)
917 if(fileExt.compare(QString::fromLatin1(X264_FILE_TYPE_FILTERS[i].pcExt), Qt::CaseInsensitive) == 0)
926 QString AddJobDialog::getFilterStr(const int filterIndex)
928 const int count = ARRAY_SIZE(X264_FILE_TYPE_FILTERS);
930 if((filterIndex >= 0) && (filterIndex < count))
932 return QString("%1 (*.%2)").arg(QString::fromLatin1(X264_FILE_TYPE_FILTERS[filterIndex].pcStr), QString::fromLatin1(X264_FILE_TYPE_FILTERS[filterIndex].pcExt));
935 return QString("%1 (*.%2)").arg(QString::fromLatin1(X264_FILE_TYPE_FILTERS[0].pcStr), QString::fromLatin1(X264_FILE_TYPE_FILTERS[0].pcExt));
938 QString AddJobDialog::getFilterLst(void)
941 const int count = ARRAY_SIZE(X264_FILE_TYPE_FILTERS);
943 for(int i = 0; i < count; i++)
945 filters << QString("%1 (*.%2)").arg(QString::fromLatin1(X264_FILE_TYPE_FILTERS[i].pcStr), QString::fromLatin1(X264_FILE_TYPE_FILTERS[i].pcExt));
948 return filters.join(";;");
951 QString AddJobDialog::getInputFilterLst(void)
960 {"Avisynth Scripts", "avs"},
961 {"VapourSynth Scripts", "vpy"},
962 {"Matroska Files", "mkv"},
963 {"MPEG-4 Part 14 Container", "mp4"},
964 {"Audio Video Interleaved", "avi"},
965 {"Flash Video", "flv"},
966 {"YUV4MPEG2 Stream", "y4m"},
967 {"Uncompresses YUV Data", "yuv"},
970 const int count = ARRAY_SIZE(s_filters);
973 for(size_t index = 0; index < count; index++)
976 allTypes += QString((index > 0) ? " *.%1" : "*.%1").arg(QString::fromLatin1(s_filters[index].fext));
980 filters << QString("All supported files (%1)").arg(allTypes);
982 for(size_t index = 0; index < count; index++)
984 filters << QString("%1 (*.%2)").arg(QString::fromLatin1(s_filters[index].name), QString::fromLatin1(s_filters[index].fext));
987 filters << QString("All files (*.*)");
988 return filters.join(";;");