OSDN Git Service

Each encoder now can return an AbstractEncoderInfo object, which contains the support...
[x264-launcher/x264-launcher.git] / src / win_addJob.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
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.
9 //
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.
14 //
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.
18 //
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
21
22 #include "win_addJob.h"
23 #include "uic_win_addJob.h"
24
25 #include "global.h"
26 #include "model_options.h"
27 #include "model_preferences.h"
28 #include "model_sysinfo.h"
29 #include "model_recently.h"
30 #include "encoder_x264.h"
31 #include "encoder_x265.h"
32 #include "win_help.h"
33 #include "win_editor.h"
34
35 #include <QDate>
36 #include <QTimer>
37 #include <QCloseEvent>
38 #include <QMessageBox>
39 #include <QFileDialog>
40 #include <QDesktopServices>
41 #include <QValidator>
42 #include <QDir>
43 #include <QInputDialog>
44 #include <QSettings>
45 #include <QUrl>
46 #include <QAction>
47 #include <QClipboard>
48 #include <QToolTip>
49
50 #define ARRAY_SIZE(ARRAY) (sizeof((ARRAY))/sizeof((ARRAY[0])))
51 #define VALID_DIR(PATH) ((!(PATH).isEmpty()) && QFileInfo(PATH).exists() && QFileInfo(PATH).isDir())
52
53 #define REMOVE_USAFED_ITEM \
54 { \
55         for(int i = 0; i < ui->cbxTemplate->count(); i++) \
56         { \
57                 const OptionsModel* temp = reinterpret_cast<const OptionsModel*>(ui->cbxTemplate->itemData(i).value<const void*>()); \
58                 if(temp == NULL) \
59                 { \
60                         ui->cbxTemplate->blockSignals(true); \
61                         ui->cbxTemplate->removeItem(i); \
62                         ui->cbxTemplate->blockSignals(false); \
63                         break; \
64                 } \
65         } \
66 }
67
68 #define ADD_CONTEXTMENU_ACTION(WIDGET, ICON, TEXT, SLOTNAME) \
69 { \
70         QAction *_action = new QAction((ICON), (TEXT), this); \
71         _action->setData(QVariant::fromValue<void*>(WIDGET)); \
72         WIDGET->addAction(_action); \
73         connect(_action, SIGNAL(triggered(bool)), this, SLOT(SLOTNAME())); \
74 }
75
76 #define ADD_CONTEXTMENU_SEPARATOR(WIDGET) \
77 { \
78         QAction *_action = new QAction(this); \
79         _action->setSeparator(true); \
80         WIDGET->addAction(_action); \
81
82
83 #define BLOCK_SIGNALS(FLAG) do \
84 { \
85         ui->cbxEncoderType->blockSignals(FLAG); \
86         ui->cbxEncoderArch->blockSignals(FLAG); \
87         ui->cbxEncoderVariant->blockSignals(FLAG); \
88         ui->cbxRateControlMode->blockSignals(FLAG); \
89         ui->spinQuantizer->blockSignals(FLAG); \
90         ui->spinBitrate->blockSignals(FLAG); \
91         ui->cbxPreset->blockSignals(FLAG); \
92         ui->cbxTuning->blockSignals(FLAG); \
93         ui->cbxProfile->blockSignals(FLAG); \
94         ui->editCustomX264Params->blockSignals(FLAG); \
95         ui->editCustomAvs2YUVParams->blockSignals(FLAG); \
96 } \
97 while(0)
98
99 Q_DECLARE_METATYPE(const void*)
100
101 ///////////////////////////////////////////////////////////////////////////////
102 // Validator
103 ///////////////////////////////////////////////////////////////////////////////
104
105 class StringValidator : public QValidator
106 {
107 public:
108         StringValidator(QLabel *notifier, QLabel *icon)
109         :
110                 m_notifier(notifier), m_icon(icon)
111         {
112                 m_notifier->hide();
113                 m_icon->hide();
114         }
115         
116         virtual State validate(QString &input, int &pos) const = 0;
117
118         virtual void fixup(QString &input) const
119         {
120                 input = input.simplified();
121         }
122
123 protected:
124         QLabel *const m_notifier, *const m_icon;
125
126         bool checkParam(const QString &input, const QString &param, const bool doubleMinus) const
127         {
128                 static const char c[20] = {' ', '*', '?', '<', '>', '/', '\\', '"', '\'', '!', '+', '#', '&', '%', '=', ',', ';', '.', 'ยด', '`'};
129                 const QString prefix = doubleMinus ? QLatin1String("--") : QLatin1String("-");
130                 
131                 bool flag = false;
132                 if(param.length() > 1)
133                 {
134                         flag = flag || input.endsWith(QString("%1%2").arg(prefix, param), Qt::CaseInsensitive);
135                         for(size_t i = 0; i < sizeof(c); i++)
136                         {
137                                 flag = flag || input.contains(QString("%1%2%3").arg(prefix, param, QChar::fromLatin1(c[i])), Qt::CaseInsensitive);
138                         }
139                 }
140                 else
141                 {
142                         flag = flag || input.startsWith(QString("-%1").arg(param));
143                         for(size_t i = 0; i < sizeof(c); i++)
144                         {
145                                 flag = flag || input.contains(QString("%1-%2").arg(QChar::fromLatin1(c[i]), param), Qt::CaseSensitive);
146                         }
147                 }
148                 if((flag) && (m_notifier))
149                 {
150                         m_notifier->setText(tr("Invalid parameter: %1").arg((param.length() > 1) ? QString("%1%2").arg(prefix, param) : QString("-%1").arg(param)));
151                 }
152                 return flag;
153         }
154
155         const bool &setStatus(const bool &flag, const QString &toolName) const
156         {
157                 if(flag)
158                 {
159                         if(m_notifier)
160                         {
161                                 if(m_notifier->isHidden()) m_notifier->show();
162                                 if(m_icon) { if(m_icon->isHidden()) m_icon->show(); }
163                                 if(QWidget *w = m_notifier->topLevelWidget()->focusWidget())
164                                 {
165                                         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());
166                                 }
167                         }
168                 }
169                 else
170                 {
171                         if(m_notifier)
172                         {
173                                 if(m_notifier->isVisible()) m_notifier->hide();
174                                 if(m_icon) { if(m_icon->isVisible()) m_icon->hide(); }
175                                 QToolTip::hideText();
176                         }
177                 }
178                 return flag;
179         }
180 };
181
182 class StringValidatorX264 : public StringValidator
183 {
184 public:
185         StringValidatorX264(QLabel *notifier, QLabel *icon) : StringValidator(notifier, icon) {}
186
187         virtual State validate(QString &input, int &pos) const
188         {
189                 static const char* p[] = {"B", "o", "h", "p", "q", /*"fps", "frames",*/ "preset", "tune", "profile",
190                         "stdin", "crf", "bitrate", "qp", "pass", "stats", "output", "help","quiet", NULL};
191
192                 bool invalid = false;
193
194                 for(size_t i = 0; p[i] && (!invalid); i++)
195                 {
196                         invalid = invalid || checkParam(input, QString::fromLatin1(p[i]), true);
197                 }
198
199                 return setStatus(invalid, "x264") ? QValidator::Intermediate : QValidator::Acceptable;
200         }
201 };
202
203 class StringValidatorAvs2YUV : public StringValidator
204 {
205 public:
206         StringValidatorAvs2YUV(QLabel *notifier, QLabel *icon) : StringValidator(notifier, icon) {}
207
208         virtual State validate(QString &input, int &pos) const
209         {
210                 static const char* p[] = {"o", "frames", "seek", "raw", "hfyu", "slave", NULL};
211
212                 bool invalid = false;
213
214                 for(size_t i = 0; p[i] && (!invalid); i++)
215                 {
216                         invalid = invalid || checkParam(input, QString::fromLatin1(p[i]), false);
217                 }
218                 
219                 return setStatus(invalid, "Avs2YUV") ? QValidator::Intermediate : QValidator::Acceptable;
220         }
221 };
222
223 ///////////////////////////////////////////////////////////////////////////////
224 // Constructor & Destructor
225 ///////////////////////////////////////////////////////////////////////////////
226
227 AddJobDialog::AddJobDialog(QWidget *parent, OptionsModel *const options, RecentlyUsed *const recentlyUsed, const SysinfoModel *const sysinfo, const PreferencesModel *const preferences)
228 :
229         QDialog(parent),
230         m_options(options),
231         m_recentlyUsed(recentlyUsed),
232         m_sysinfo(sysinfo),
233         m_preferences(preferences),
234         m_defaults(new OptionsModel(sysinfo)),
235         ui(new Ui::AddJobDialog())
236 {
237         //Init the dialog, from the .ui file
238         ui->setupUi(this);
239         setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
240         
241         //Fix dialog size
242         ui->buttonSaveTemplate->setMaximumHeight(20);
243         ui->buttonDeleteTemplate->setMaximumHeight(20);
244         resize(width(), minimumHeight());
245         setMinimumSize(size());
246         setMaximumHeight(height());
247
248         //Hide optional controls
249         ui->checkBoxApplyToAll->setVisible(false);
250
251         //Monitor combobox changes
252         connect(ui->cbxEncoderType, SIGNAL(currentIndexChanged(int)), this, SLOT(encoderIndexChanged(int)));
253         connect(ui->cbxEncoderVariant, SIGNAL(currentIndexChanged(int)), this, SLOT(variantIndexChanged(int)));
254         connect(ui->cbxRateControlMode, SIGNAL(currentIndexChanged(int)), this, SLOT(modeIndexChanged(int)));
255
256         //Activate buttons
257         connect(ui->buttonBrowseSource, SIGNAL(clicked()), this, SLOT(browseButtonClicked()));
258         connect(ui->buttonBrowseOutput, SIGNAL(clicked()), this, SLOT(browseButtonClicked()));
259         connect(ui->buttonSaveTemplate, SIGNAL(clicked()), this, SLOT(saveTemplateButtonClicked()));
260         connect(ui->buttonDeleteTemplate, SIGNAL(clicked()), this, SLOT(deleteTemplateButtonClicked()));
261
262         //Setup validator
263         ui->editCustomX264Params->installEventFilter(this);
264         ui->editCustomX264Params->setValidator(new StringValidatorX264(ui->labelNotificationX264, ui->iconNotificationX264));
265         ui->editCustomX264Params->clear();
266         ui->editCustomAvs2YUVParams->installEventFilter(this);
267         ui->editCustomAvs2YUVParams->setValidator(new StringValidatorAvs2YUV(ui->labelNotificationAvs2YUV, ui->iconNotificationAvs2YUV));
268         ui->editCustomAvs2YUVParams->clear();
269
270         //Install event filter
271         ui->labelHelpScreenX264->installEventFilter(this);
272         ui->labelHelpScreenAvs2YUV->installEventFilter(this);
273
274         //Monitor for options changes
275         connect(ui->cbxEncoderType, SIGNAL(currentIndexChanged(int)), this, SLOT(configurationChanged()));
276         connect(ui->cbxEncoderArch, SIGNAL(currentIndexChanged(int)), this, SLOT(configurationChanged()));
277         connect(ui->cbxEncoderVariant, SIGNAL(currentIndexChanged(int)), this, SLOT(configurationChanged()));
278         connect(ui->cbxRateControlMode, SIGNAL(currentIndexChanged(int)), this, SLOT(configurationChanged()));
279         connect(ui->spinQuantizer, SIGNAL(valueChanged(double)), this, SLOT(configurationChanged()));
280         connect(ui->spinBitrate, SIGNAL(valueChanged(int)), this, SLOT(configurationChanged()));
281         connect(ui->cbxPreset, SIGNAL(currentIndexChanged(int)), this, SLOT(configurationChanged()));
282         connect(ui->cbxTuning, SIGNAL(currentIndexChanged(int)), this, SLOT(configurationChanged()));
283         connect(ui->cbxProfile, SIGNAL(currentIndexChanged(int)), this, SLOT(configurationChanged()));
284         connect(ui->editCustomX264Params, SIGNAL(textChanged(QString)), this, SLOT(configurationChanged()));
285         connect(ui->editCustomAvs2YUVParams, SIGNAL(textChanged(QString)), this, SLOT(configurationChanged()));
286
287         //Create context menus
288         ADD_CONTEXTMENU_ACTION(ui->editCustomX264Params, QIcon(":/buttons/page_edit.png"), tr("Open the Text-Editor"), editorActionTriggered);
289         ADD_CONTEXTMENU_ACTION(ui->editCustomAvs2YUVParams, QIcon(":/buttons/page_edit.png"), tr("Open the Text-Editor"), editorActionTriggered);
290         ADD_CONTEXTMENU_SEPARATOR(ui->editCustomX264Params);
291         ADD_CONTEXTMENU_SEPARATOR(ui->editCustomAvs2YUVParams);
292         ADD_CONTEXTMENU_ACTION(ui->editCustomX264Params, QIcon(":/buttons/page_copy.png"), tr("Copy to Clipboard"), copyActionTriggered);
293         ADD_CONTEXTMENU_ACTION(ui->editCustomAvs2YUVParams, QIcon(":/buttons/page_copy.png"), tr("Copy to Clipboard"), copyActionTriggered);
294         ADD_CONTEXTMENU_ACTION(ui->editCustomX264Params, QIcon(":/buttons/page_paste.png"), tr("Paste from Clipboard"), pasteActionTriggered);
295         ADD_CONTEXTMENU_ACTION(ui->editCustomAvs2YUVParams, QIcon(":/buttons/page_paste.png"), tr("Paste from Clipboard"), pasteActionTriggered);
296
297         //Setup template selector
298         loadTemplateList();
299         connect(ui->cbxTemplate, SIGNAL(currentIndexChanged(int)), this, SLOT(templateSelected()));
300 }
301
302 AddJobDialog::~AddJobDialog(void)
303 {
304         //Free templates
305         for(int i = 0; i < ui->cbxTemplate->model()->rowCount(); i++)
306         {
307                 if(ui->cbxTemplate->itemText(i).startsWith("<") || ui->cbxTemplate->itemText(i).endsWith(">"))
308                 {
309                         continue;
310                 }
311                 const OptionsModel *item = reinterpret_cast<const OptionsModel*>(ui->cbxTemplate->itemData(i).value<const void*>());
312                 ui->cbxTemplate->setItemData(i, QVariant::fromValue<const void*>(NULL));
313                 X264_DELETE(item);
314         }
315
316         //Free validators
317         if(const QValidator *tmp = ui->editCustomX264Params->validator())
318         {
319                 ui->editCustomX264Params->setValidator(NULL);
320                 X264_DELETE(tmp);
321         }
322         if(const QValidator *tmp = ui->editCustomAvs2YUVParams->validator())
323         {
324                 ui->editCustomAvs2YUVParams->setValidator(NULL);
325                 X264_DELETE(tmp);
326         }
327
328         X264_DELETE(m_defaults);
329         delete ui;
330 }
331
332 ///////////////////////////////////////////////////////////////////////////////
333 // Events
334 ///////////////////////////////////////////////////////////////////////////////
335
336 void AddJobDialog::showEvent(QShowEvent *event)
337 {
338         QDialog::showEvent(event);
339         templateSelected();
340
341         if((!ui->editSource->text().isEmpty()) && ui->editOutput->text().isEmpty())
342         {
343                 QString outPath = generateOutputFileName(QDir::fromNativeSeparators(ui->editSource->text()), m_recentlyUsed->outputDirectory(), m_recentlyUsed->filterIndex(), m_preferences->getSaveToSourcePath());
344                 ui->editOutput->setText(QDir::toNativeSeparators(outPath));
345                 ui->buttonAccept->setFocus();
346         }
347
348         ui->labelNotificationX264->hide();
349         ui->iconNotificationX264->hide();
350         ui->labelNotificationAvs2YUV->hide();
351         ui->iconNotificationAvs2YUV->hide();
352
353         //Enable drag&drop support for this window, required for Qt v4.8.4+
354         setAcceptDrops(true);
355 }
356
357 bool AddJobDialog::eventFilter(QObject *o, QEvent *e)
358 {
359         if((o == ui->labelHelpScreenX264) && (e->type() == QEvent::MouseButtonPress))
360         {
361                 OptionsModel options(m_sysinfo); saveOptions(&options);
362                 HelpDialog *helpScreen = new HelpDialog(this, false, m_sysinfo, &options, m_preferences);
363                 helpScreen->exec();
364                 X264_DELETE(helpScreen);
365         }
366         else if((o == ui->labelHelpScreenAvs2YUV) && (e->type() == QEvent::MouseButtonPress))
367         {
368                 HelpDialog *helpScreen = new HelpDialog(this, false, m_sysinfo, m_defaults, m_preferences);
369                 helpScreen->exec();
370                 X264_DELETE(helpScreen);
371         }
372         else if((o == ui->editCustomX264Params) && (e->type() == QEvent::FocusOut))
373         {
374                 ui->editCustomX264Params->setText(ui->editCustomX264Params->text().simplified());
375         }
376         else if((o == ui->editCustomAvs2YUVParams) && (e->type() == QEvent::FocusOut))
377         {
378                 ui->editCustomAvs2YUVParams->setText(ui->editCustomAvs2YUVParams->text().simplified());
379         }
380         return false;
381 }
382
383 void AddJobDialog::dragEnterEvent(QDragEnterEvent *event)
384 {
385         bool accept[2] = {false, false};
386
387         foreach(const QString &fmt, event->mimeData()->formats())
388         {
389                 accept[0] = accept[0] || fmt.contains("text/uri-list", Qt::CaseInsensitive);
390                 accept[1] = accept[1] || fmt.contains("FileNameW", Qt::CaseInsensitive);
391         }
392
393         if(accept[0] && accept[1])
394         {
395                 event->acceptProposedAction();
396         }
397 }
398
399 void AddJobDialog::dropEvent(QDropEvent *event)
400 {
401         QString droppedFile;
402         QList<QUrl> urls = event->mimeData()->urls();
403
404         if(urls.count() > 1)
405         {
406                 QDragEnterEvent dragEvent(event->pos(), event->proposedAction(), event->mimeData(), Qt::NoButton, Qt::NoModifier);
407                 if(qApp->notify(parent(), &dragEvent))
408                 {
409                         qApp->notify(parent(), event);
410                         reject(); return;
411                 }
412         }
413
414         while((!urls.isEmpty()) && droppedFile.isEmpty())
415         {
416                 QUrl currentUrl = urls.takeFirst();
417                 QFileInfo file(currentUrl.toLocalFile());
418                 if(file.exists() && file.isFile())
419                 {
420                         qDebug("AddJobDialog::dropEvent: %s", file.canonicalFilePath().toUtf8().constData());
421                         droppedFile = file.canonicalFilePath();
422                 }
423         }
424         
425         if(!droppedFile.isEmpty())
426         {
427                 const QString outFileName = generateOutputFileName(droppedFile, currentOutputPath(), currentOutputIndx(), m_preferences->getSaveToSourcePath());
428                 ui->editSource->setText(QDir::toNativeSeparators(droppedFile));
429                 ui->editOutput->setText(QDir::toNativeSeparators(outFileName));
430         }
431 }
432
433 ///////////////////////////////////////////////////////////////////////////////
434 // Slots
435 ///////////////////////////////////////////////////////////////////////////////
436
437 void AddJobDialog::encoderIndexChanged(int index)
438 {
439         const bool isX265 = (index > 0);
440         const bool noProf = isX265 || (ui->cbxEncoderVariant->currentIndex() > 0);
441
442         ui->cbxEncoderVariant->setItemText(1, isX265 ? tr("16-Bit") : tr("10-Bit"));
443         ui->labelProfile->setEnabled(!noProf);
444         ui->cbxProfile->setEnabled(!noProf);
445         if(noProf) ui->cbxProfile->setCurrentIndex(0);
446 }
447
448 void AddJobDialog::variantIndexChanged(int index)
449 {
450         const bool noProf = (index > 0) || (ui->cbxEncoderType->currentIndex() > 0);
451
452         ui->labelProfile->setEnabled(!noProf);
453         ui->cbxProfile->setEnabled(!noProf);
454         if(noProf) ui->cbxProfile->setCurrentIndex(0);
455 }
456
457 void AddJobDialog::modeIndexChanged(int index)
458 {
459         ui->spinQuantizer->setEnabled(index == 0 || index == 1);
460         ui->spinBitrate->setEnabled(index == 2 || index == 3);
461 }
462
463 void AddJobDialog::accept(void)
464 {
465         //Check x265 support
466         if((ui->cbxEncoderType->currentIndex() == OptionsModel::EncType_X265) && (!m_sysinfo->has256Support()))
467         {
468                 QMessageBox::warning(this, tr("x265 unsupported"), tr("<nobr>Sorry, the x265 encoder is <b>not</b> currently available on this computer!<br>Please see the Readme file on how to obtain and install x265...</nobr>"));
469                 ui->cbxEncoderType->setCurrentIndex(OptionsModel::EncType_X264);
470                 return;
471         }
472
473         //Check 64-Bit support
474         if((ui->cbxEncoderArch->currentIndex() == OptionsModel::EncArch_x64) && (!m_sysinfo->hasX64Support()))
475         {
476                 QMessageBox::warning(this, tr("64-Bit unsupported!"), tr("<nobr>Sorry, this computer does <b>not</b> support 64-Bit encoders!</nobr>"));
477                 ui->cbxEncoderArch->setCurrentIndex(OptionsModel::EncArch_x32);
478                 return;
479         }
480         
481         //Selection complete?
482         if(ui->editSource->text().trimmed().isEmpty())
483         {
484                 QMessageBox::warning(this, tr("Not Found!"), tr("<nobr>Please select a valid source file first!<(nobr>"));
485                 return;
486         }
487         if(ui->editOutput->text().trimmed().isEmpty())
488         {
489                 QMessageBox::warning(this, tr("Not Selected!"), tr("<nobr>Please select a valid output file first!</nobr>"));
490                 return;
491         }
492
493         //Does source exist?
494         QFileInfo sourceFile = QFileInfo(this->sourceFile());
495         if(!(sourceFile.exists() && sourceFile.isFile()))
496         {
497                 QMessageBox::warning(this, tr("Not Found!"), tr("<nobr>The selected source file could not be found!</nobr>"));
498                 return;
499         }
500
501         //Get encoder info
502         const AbstractEncoderInfo &encoderInfo = getEncoderInfo(ui->cbxEncoderType->currentIndex());
503
504         //Is the type of the source file supported? (as far as we can tell)
505         if(sourceFile.suffix().compare("AVS", Qt::CaseInsensitive) == 0)
506         {
507                 if(!m_sysinfo->hasAVSSupport())
508                 {
509                         if(QMessageBox::warning(this, tr("Avisynth unsupported!"), tr("<nobr>An Avisynth script was selected as input, although Avisynth is <b>not</b> available!</nobr>"), tr("Abort"), tr("Ingnore (at your own risk!)")) != 1)
510                         {
511                                 return;
512                         }
513                 }
514         }
515         else if((sourceFile.suffix().compare("VPY", Qt::CaseInsensitive) == 0) || (sourceFile.suffix().compare("PY", Qt::CaseInsensitive) == 0))
516         {
517                 if(!m_sysinfo->hasVPSSupport())
518                 {
519                         if(QMessageBox::warning(this, tr("VapurSynth unsupported!"), tr("<nobr>A VapourSynth script was selected as input, although VapourSynth is <b>not/<b> available!</nobr>"), tr("Abort"), tr("Ingnore (at your own risk!)")) != 1)
520                         {
521                                 return;
522                         }
523                 }
524         }
525         else
526         {
527                 const QStringList inputFormats = encoderInfo.supportedInputFormats();
528                 if(!inputFormats.contains(sourceFile.suffix(), Qt::CaseInsensitive))
529                 {
530                         if(QMessageBox::warning(this, tr("Unsupported input format"), tr("<nobr>The selected encoder does <b>not</b> support the selected input format!</nobr>"), tr("Abort"), tr("Ingnore (at your own risk!)")) != 1)
531                         {
532                                 return;
533                         }
534                 }
535         }
536
537
538         //Is output file extension supported by encoder?
539         const QStringList outputFormats = encoderInfo.supportedOutputFormats();
540         QFileInfo outputFile = QFileInfo(this->outputFile());
541         if(!outputFormats.contains(outputFile.suffix(), Qt::CaseInsensitive))
542         {
543                 QMessageBox::warning(this, tr("Unsupported output format"), tr("<nobr>Sorry, the selected encoder does not support the selected output format!</nobr>"));
544                 ui->editOutput->setText(QDir::toNativeSeparators(QString("%1/%2.%3").arg(outputFile.absolutePath(), outputFile.completeBaseName(), outputFormats.first())));
545                 return;
546         }
547
548         //Does output file already exist?
549         if(outputFile.exists() && outputFile.isFile())
550         {
551                 int ret = QMessageBox::question(this, tr("Already Exists!"), tr("<nobr>Output file already exists! Overwrite?</nobr>"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
552                 if(ret != QMessageBox::Yes) return;
553         }
554         if(outputFile.exists() && (!outputFile.isFile()))
555         {
556                 QMessageBox::warning(this, tr("Not a File!"), tr("<nobr>Selected output file does not appear to be a valid file!</nobr>"));
557                 return;
558         }
559
560         //Is destination dir writable?
561         QFileInfo outputDir = QFileInfo(outputFile.absolutePath());
562         if(!(outputDir.exists() && outputDir.isDir() && outputDir.isWritable()))
563         {
564                 QMessageBox::warning(this, tr("Not Writable!"), tr("<nobr>Output directory does not exist or is not writable!</nobr>"));
565                 return;
566         }
567
568         //Custom parameters okay?
569         if(!ui->editCustomX264Params->hasAcceptableInput())
570         {
571                 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);
572                 if(ret != QMessageBox::Ignore) return;
573         }
574
575         //Update recently used
576         m_recentlyUsed->setFilterIndex(currentOutputIndx());
577         m_recentlyUsed->setSourceDirectory(currentSourcePath());
578         m_recentlyUsed->setOutputDirectory(currentOutputPath());
579         RecentlyUsed::saveRecentlyUsed(m_recentlyUsed);
580
581         //Save options
582         saveOptions(m_options);
583         QDialog::accept();
584 }
585
586 void AddJobDialog::browseButtonClicked(void)
587 {
588         if(QObject::sender() == ui->buttonBrowseSource)
589         {
590                 QString filePath = QFileDialog::getOpenFileName(this, tr("Open Source File"), currentSourcePath(true), getInputFilterLst(), NULL, QFileDialog::DontUseNativeDialog);
591                 if(!(filePath.isNull() || filePath.isEmpty()))
592                 {
593                         QString destFile = generateOutputFileName(filePath, currentOutputPath(), currentOutputIndx(), m_preferences->getSaveToSourcePath());
594                         ui->editSource->setText(QDir::toNativeSeparators(filePath));
595                         ui->editOutput->setText(QDir::toNativeSeparators(destFile));
596                 }
597         }
598         else if(QObject::sender() == ui->buttonBrowseOutput)
599         {
600                 QString selectedType = getFilterStr(currentOutputIndx());
601                 QString filePath = QFileDialog::getSaveFileName(this, tr("Choose Output File"), currentOutputPath(true), getFilterLst(), &selectedType, QFileDialog::DontUseNativeDialog | QFileDialog::DontConfirmOverwrite);
602
603                 if(!(filePath.isNull() || filePath.isEmpty()))
604                 {
605                         if(getFilterIdx(QFileInfo(filePath).suffix()) < 0)
606                         {
607                                 int tempIndex = -1;
608                                 QRegExp regExp("\\(\\*\\.(\\w+)\\)");
609                                 if(regExp.lastIndexIn(selectedType) >= 0)
610                                 {
611                                         tempIndex = getFilterIdx(regExp.cap(1));
612                                 }
613                                 if(tempIndex < 0)
614                                 {
615                                         tempIndex = m_recentlyUsed->filterIndex();
616                                 }
617                                 filePath = QString("%1.%2").arg(filePath, getFilterExt(tempIndex));
618                         }
619                         ui->editOutput->setText(QDir::toNativeSeparators(filePath));
620                 }
621         }
622 }
623
624 void AddJobDialog::configurationChanged(void)
625 {
626         const OptionsModel* options = reinterpret_cast<const OptionsModel*>(ui->cbxTemplate->itemData(ui->cbxTemplate->currentIndex()).value<const void*>());
627         if(options)
628         {
629                 ui->cbxTemplate->blockSignals(true);
630                 ui->cbxTemplate->insertItem(0, tr("<Unsaved Configuration>"), QVariant::fromValue<const void*>(NULL));
631                 ui->cbxTemplate->setCurrentIndex(0);
632                 ui->cbxTemplate->blockSignals(false);
633         }
634 }
635
636 void AddJobDialog::templateSelected(void)
637 {
638         const OptionsModel* options = reinterpret_cast<const OptionsModel*>(ui->cbxTemplate->itemData(ui->cbxTemplate->currentIndex()).value<const void*>());
639         if(options)
640         {
641                 qDebug("Loading options!");
642                 REMOVE_USAFED_ITEM;
643                 restoreOptions(options);
644         }
645
646         //Force updates
647         encoderIndexChanged(ui->cbxEncoderType->currentIndex());
648         variantIndexChanged(ui->cbxEncoderVariant->currentIndex());
649         modeIndexChanged(ui->cbxRateControlMode->currentIndex());
650 }
651
652 void AddJobDialog::saveTemplateButtonClicked(void)
653 {
654         qDebug("Saving template");
655         QString name = tr("New Template");
656         int n = 2;
657
658         while(OptionsModel::templateExists(name))
659         {
660                 name = tr("New Template (%1)").arg(QString::number(n++));
661         }
662
663         OptionsModel *options = new OptionsModel(m_sysinfo);
664         saveOptions(options);
665
666         if(options->equals(m_defaults))
667         {
668                 QMessageBox::warning (this, tr("Oups"), tr("<nobr>It makes no sense to save the default settings!</nobr>"));
669                 ui->cbxTemplate->blockSignals(true);
670                 ui->cbxTemplate->setCurrentIndex(0);
671                 ui->cbxTemplate->blockSignals(false);
672                 REMOVE_USAFED_ITEM;
673                 X264_DELETE(options);
674                 return;
675         }
676
677         for(int i = 0; i < ui->cbxTemplate->count(); i++)
678         {
679                 const QString tempName = ui->cbxTemplate->itemText(i);
680                 if(tempName.contains('<') || tempName.contains('>'))
681                 {
682                         continue;
683                 }
684                 const OptionsModel* test = reinterpret_cast<const OptionsModel*>(ui->cbxTemplate->itemData(i).value<const void*>());
685                 if(test != NULL)
686                 {
687                         if(options->equals(test))
688                         {
689                                 QMessageBox::warning (this, tr("Oups"), tr("<nobr>There already is a template for the current settings!</nobr>"));
690                                 ui->cbxTemplate->blockSignals(true);
691                                 ui->cbxTemplate->setCurrentIndex(i);
692                                 ui->cbxTemplate->blockSignals(false);
693                                 REMOVE_USAFED_ITEM;
694                                 X264_DELETE(options);
695                                 return;
696                         }
697                 }
698         }
699
700         forever
701         {
702                 bool ok = false;
703                 name = QInputDialog::getText(this, tr("Save Template"), tr("Please enter the name of the template:").leftJustified(144, ' '), QLineEdit::Normal, name, &ok).simplified();
704                 if(!ok)
705                 {
706                         X264_DELETE(options);
707                         return;
708                 }
709                 if(name.contains('<') || name.contains('>') || name.contains('\\') || name.contains('/') || name.contains('"'))
710                 {
711                         QMessageBox::warning (this, tr("Invalid Name"), tr("<nobr>Sorry, the name you have entered is invalid!</nobr>"));
712                         while(name.contains('<')) name.remove('<');
713                         while(name.contains('>')) name.remove('>');
714                         while(name.contains('\\')) name.remove('\\');
715                         while(name.contains('/')) name.remove('/');
716                         while(name.contains('"')) name.remove('"');
717                         name = name.simplified();
718                         continue;
719                 }
720                 if(OptionsModel::templateExists(name))
721                 {
722                         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);
723                         if(ret != QMessageBox::Yes)
724                         {
725                                 continue;
726                         }
727                 }
728                 break;
729         }
730         
731         if(!OptionsModel::saveTemplate(options, name))
732         {
733                 QMessageBox::critical(this, tr("Save Failed"), tr("Sorry, the template could not be saved!"));
734                 X264_DELETE(options);
735                 return;
736         }
737         
738         int index = ui->cbxTemplate->model()->rowCount();
739         ui->cbxTemplate->blockSignals(true);
740         for(int i = 0; i < ui->cbxTemplate->count(); i++)
741         {
742                 if(ui->cbxTemplate->itemText(i).compare(name, Qt::CaseInsensitive) == 0)
743                 {
744                         index = -1; //Do not append new template
745                         const OptionsModel *oldItem = reinterpret_cast<const OptionsModel*>(ui->cbxTemplate->itemData(i).value<const void*>());
746                         ui->cbxTemplate->setItemData(i, QVariant::fromValue<const void*>(options));
747                         ui->cbxTemplate->setCurrentIndex(i);
748                         X264_DELETE(oldItem);
749                 }
750         }
751         if(index >= 0)
752         {
753                 ui->cbxTemplate->insertItem(index, name, QVariant::fromValue<const void*>(options));
754                 ui->cbxTemplate->setCurrentIndex(index);
755         }
756         ui->cbxTemplate->blockSignals(false);
757
758         REMOVE_USAFED_ITEM;
759 }
760
761 void AddJobDialog::deleteTemplateButtonClicked(void)
762 {
763         const int index = ui->cbxTemplate->currentIndex();
764         QString name = ui->cbxTemplate->itemText(index);
765
766         if(name.contains('<') || name.contains('>') || name.contains('\\') || name.contains('/'))
767         {
768                 QMessageBox::warning (this, tr("Invalid Item"), tr("Sorry, the selected item cannot be deleted!"));
769                 return;
770         }
771
772         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);
773         if(ret != QMessageBox::Yes)
774         {
775                 return;
776         }
777
778
779         OptionsModel::deleteTemplate(name);
780         const OptionsModel *item = reinterpret_cast<const OptionsModel*>(ui->cbxTemplate->itemData(index).value<const void*>());
781         ui->cbxTemplate->removeItem(index);
782         X264_DELETE(item);
783 }
784
785 void AddJobDialog::editorActionTriggered(void)
786 {
787
788         if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
789         {
790                 QLineEdit *lineEdit = reinterpret_cast<QLineEdit*>(action->data().value<void*>());
791                 
792                 EditorDialog *editor = new EditorDialog(this);
793                 editor->setEditText(lineEdit->text());
794
795                 if(editor->exec() == QDialog::Accepted)
796                 {
797                         lineEdit->setText(editor->getEditText());
798                 }
799
800                 X264_DELETE(editor);
801         }
802 }
803
804 void AddJobDialog::copyActionTriggered(void)
805 {
806         if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
807         {
808                 QClipboard *clipboard = QApplication::clipboard();
809                 QLineEdit *lineEdit = reinterpret_cast<QLineEdit*>(action->data().value<void*>());
810                 QString text = lineEdit->hasSelectedText() ? lineEdit->selectedText() : lineEdit->text();
811                 clipboard->setText(text);
812         }
813 }
814
815 void AddJobDialog::pasteActionTriggered(void)
816 {
817         if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
818         {
819                 QClipboard *clipboard = QApplication::clipboard();
820                 QLineEdit *lineEdit = reinterpret_cast<QLineEdit*>(action->data().value<void*>());
821                 QString text = clipboard->text();
822                 if(!text.isEmpty()) lineEdit->setText(text);
823         }
824 }
825
826 ///////////////////////////////////////////////////////////////////////////////
827 // Public functions
828 ///////////////////////////////////////////////////////////////////////////////
829
830 QString AddJobDialog::sourceFile(void)
831 {
832         return QDir::fromNativeSeparators(ui->editSource->text());
833 }
834
835 QString AddJobDialog::outputFile(void)
836 {
837         return QDir::fromNativeSeparators(ui->editOutput->text());
838 }
839
840 bool AddJobDialog::runImmediately(void)
841 {
842         return ui->checkBoxRun->isChecked();
843 }
844
845 bool AddJobDialog::applyToAll(void)
846 {
847         return ui->checkBoxApplyToAll->isChecked();
848 }
849
850 void AddJobDialog::setRunImmediately(bool run)
851 {
852         ui->checkBoxRun->setChecked(run);
853 }
854
855 void AddJobDialog::setSourceFile(const QString &path)
856 {
857         ui->editSource->setText(QDir::toNativeSeparators(path));
858 }
859
860 void AddJobDialog::setOutputFile(const QString &path)
861 {
862         ui->editOutput->setText(QDir::toNativeSeparators(path));}
863
864 void AddJobDialog::setSourceEditable(const bool editable)
865 {
866         ui->buttonBrowseSource->setEnabled(editable);
867 }
868
869 void AddJobDialog::setApplyToAllVisible(const bool visible)
870 {
871         ui->checkBoxApplyToAll->setVisible(visible);
872 }
873
874 ///////////////////////////////////////////////////////////////////////////////
875 // Private functions
876 ///////////////////////////////////////////////////////////////////////////////
877
878 void AddJobDialog::loadTemplateList(void)
879 {
880         ui->cbxTemplate->addItem(tr("<Default>"), QVariant::fromValue<const void*>(m_defaults));
881         ui->cbxTemplate->setCurrentIndex(0);
882
883         QMap<QString, OptionsModel*> templates = OptionsModel::loadAllTemplates(m_sysinfo);
884         QStringList templateNames = templates.keys();
885         templateNames.sort();
886
887         for(QStringList::ConstIterator current = templateNames.constBegin(); current != templateNames.constEnd(); current++)
888         {
889                 OptionsModel *currentTemplate = templates.take(*current);
890                 ui->cbxTemplate->addItem(*current, QVariant::fromValue<const void*>(currentTemplate));
891                 if(currentTemplate->equals(m_options))
892                 {
893                         ui->cbxTemplate->setCurrentIndex(ui->cbxTemplate->count() - 1);
894                 }
895         }
896
897         if((ui->cbxTemplate->currentIndex() == 0) && (!m_options->equals(m_defaults)))
898         {
899                 qWarning("Not the default -> recently used!");
900                 ui->cbxTemplate->insertItem(1, tr("<Recently Used>"), QVariant::fromValue<const void*>(m_options));
901                 ui->cbxTemplate->setCurrentIndex(1);
902         }
903 }
904
905 void AddJobDialog::updateComboBox(QComboBox *cbox, const QString &text)
906 {
907         int index = -1;
908         if(QAbstractItemModel *model = cbox->model())
909         {
910                 for(int i = 0; i < cbox->model()->rowCount(); i++)
911                 {
912                         if(model->data(model->index(i, 0, QModelIndex())).toString().compare(text, Qt::CaseInsensitive) == 0)
913                         {
914                                 index = i;
915                                 break;
916                         }
917                 }
918         }
919         cbox->setCurrentIndex(index);
920 }
921
922 void AddJobDialog::restoreOptions(const OptionsModel *options)
923 {
924         BLOCK_SIGNALS(true);
925
926         ui->cbxEncoderType->setCurrentIndex(options->encType());
927         ui->cbxEncoderArch->setCurrentIndex(options->encArch());
928         ui->cbxEncoderVariant->setCurrentIndex(options->encVariant());
929         ui->cbxRateControlMode->setCurrentIndex(options->rcMode());
930         ui->spinQuantizer->setValue(options->quantizer());
931         ui->spinBitrate->setValue(options->bitrate());
932         updateComboBox(ui->cbxPreset, options->preset());
933         updateComboBox(ui->cbxTuning, options->tune());
934         updateComboBox(ui->cbxProfile, options->profile());
935         ui->editCustomX264Params->setText(options->customEncParams());
936         ui->editCustomAvs2YUVParams->setText(options->customAvs2YUV());
937
938         BLOCK_SIGNALS(false);
939 }
940
941 void AddJobDialog::saveOptions(OptionsModel *options)
942 {
943         options->setEncType(static_cast<OptionsModel::EncType>(ui->cbxEncoderType->currentIndex()));
944         options->setEncArch(static_cast<OptionsModel::EncArch>(ui->cbxEncoderArch->currentIndex()));
945         options->setEncVariant(static_cast<OptionsModel::EncVariant>(ui->cbxEncoderVariant->currentIndex()));
946         options->setRCMode(static_cast<OptionsModel::RCMode>(ui->cbxRateControlMode->currentIndex()));
947         options->setQuantizer(ui->spinQuantizer->value());
948         options->setBitrate(ui->spinBitrate->value());
949         options->setPreset(ui->cbxPreset->model()->data(ui->cbxPreset->model()->index(ui->cbxPreset->currentIndex(), 0)).toString());
950         options->setTune(ui->cbxTuning->model()->data(ui->cbxTuning->model()->index(ui->cbxTuning->currentIndex(), 0)).toString());
951         options->setProfile(ui->cbxProfile->model()->data(ui->cbxProfile->model()->index(ui->cbxProfile->currentIndex(), 0)).toString());
952         options->setCustomEncParams(ui->editCustomX264Params->hasAcceptableInput() ? ui->editCustomX264Params->text().simplified() : QString());
953         options->setCustomAvs2YUV(ui->editCustomAvs2YUVParams->hasAcceptableInput() ? ui->editCustomAvs2YUVParams->text().simplified() : QString());
954 }
955
956 QString AddJobDialog::currentSourcePath(const bool bWithName)
957 {
958         QString path = m_recentlyUsed->sourceDirectory();
959         QString currentSourceFile = this->sourceFile();
960         
961         if(!currentSourceFile.isEmpty())
962         {
963                 QString currentSourceDir = QFileInfo(currentSourceFile).absolutePath();
964                 if(VALID_DIR(currentSourceDir))
965                 {
966                         path = currentSourceDir;
967                 }
968                 if(bWithName)
969                 {
970                         path.append("/").append(QFileInfo(currentSourceFile).fileName());
971                 }
972         }
973
974         return path;
975 }
976
977 QString AddJobDialog::currentOutputPath(const bool bWithName)
978 {
979         QString path = m_recentlyUsed->outputDirectory();
980         QString currentOutputFile = this->outputFile();
981         
982         if(!currentOutputFile.isEmpty())
983         {
984                 QString currentOutputDir = QFileInfo(currentOutputFile).absolutePath();
985                 if(VALID_DIR(currentOutputDir))
986                 {
987                         path = currentOutputDir;
988                 }
989                 if(bWithName)
990                 {
991                         path.append("/").append(QFileInfo(currentOutputFile).fileName());
992                 }
993         }
994
995         return path;
996 }
997
998 int AddJobDialog::currentOutputIndx(void)
999 {
1000         if(ui->cbxEncoderType->currentIndex() == OptionsModel::EncType_X265)
1001         {
1002                 return ARRAY_SIZE(X264_FILE_TYPE_FILTERS) - 1;
1003         }
1004         
1005         int index = m_recentlyUsed->filterIndex();
1006         const QString currentOutputFile = this->outputFile();
1007
1008         if(!currentOutputFile.isEmpty())
1009         {
1010                 const QString currentOutputExtn = QFileInfo(currentOutputFile).suffix();
1011                 const int tempIndex = getFilterIdx(currentOutputExtn);
1012                 if(tempIndex >= 0)
1013                 {
1014                         index = tempIndex;
1015                 }
1016         }
1017
1018         return index;
1019 }
1020
1021 ///////////////////////////////////////////////////////////////////////////////
1022 // Static functions
1023 ///////////////////////////////////////////////////////////////////////////////
1024
1025 QString AddJobDialog::generateOutputFileName(const QString &sourceFilePath, const QString &destinationDirectory, const int filterIndex, const bool saveToSourceDir)
1026 {
1027         QString name = QFileInfo(sourceFilePath).completeBaseName();
1028         QString path = saveToSourceDir ? QFileInfo(sourceFilePath).canonicalPath() : destinationDirectory;
1029         QString fext = getFilterExt(filterIndex);
1030         
1031         if(!VALID_DIR(path))
1032         {
1033                 RecentlyUsed defaults;
1034                 path = defaults.outputDirectory();
1035         }
1036
1037         QString outPath = QString("%1/%2.%3").arg(path, name, fext);
1038
1039         int n = 2;
1040         while(QFileInfo(outPath).exists())
1041         {
1042                 outPath = QString("%1/%2 (%3).%4").arg(path, name, QString::number(n++), fext);
1043         }
1044
1045         return outPath;
1046 }
1047
1048 /* ------------------------------------------------------------------------- */
1049
1050 QString AddJobDialog::getFilterExt(const int filterIndex)
1051 {
1052         const int count = ARRAY_SIZE(X264_FILE_TYPE_FILTERS);
1053
1054         if((filterIndex >= 0) && (filterIndex < count))
1055         {
1056                 return QString::fromLatin1(X264_FILE_TYPE_FILTERS[filterIndex].pcExt);
1057         }
1058
1059         return QString::fromLatin1(X264_FILE_TYPE_FILTERS[0].pcExt);
1060 }
1061
1062 int AddJobDialog::getFilterIdx(const QString &fileExt)
1063 {
1064         const int count = ARRAY_SIZE(X264_FILE_TYPE_FILTERS);
1065
1066         for(int i = 0; i < count; i++)
1067         {
1068                 if(fileExt.compare(QString::fromLatin1(X264_FILE_TYPE_FILTERS[i].pcExt), Qt::CaseInsensitive) == 0)
1069                 {
1070                         return i;
1071                 }
1072         }
1073
1074         return -1;
1075 }
1076
1077 QString AddJobDialog::getFilterStr(const int filterIndex)
1078 {
1079         const int count = ARRAY_SIZE(X264_FILE_TYPE_FILTERS);
1080
1081         if((filterIndex >= 0) && (filterIndex < count))
1082         {
1083                 return QString("%1 (*.%2)").arg(QString::fromLatin1(X264_FILE_TYPE_FILTERS[filterIndex].pcStr), QString::fromLatin1(X264_FILE_TYPE_FILTERS[filterIndex].pcExt));
1084         }
1085
1086         return QString("%1 (*.%2)").arg(QString::fromLatin1(X264_FILE_TYPE_FILTERS[0].pcStr), QString::fromLatin1(X264_FILE_TYPE_FILTERS[0].pcExt));
1087 }
1088
1089 QString AddJobDialog::getFilterLst(void)
1090 {
1091         QStringList filters;
1092         const int count = ARRAY_SIZE(X264_FILE_TYPE_FILTERS);
1093         
1094         for(int i = 0; i < count; i++)
1095         {
1096                 filters << QString("%1 (*.%2)").arg(QString::fromLatin1(X264_FILE_TYPE_FILTERS[i].pcStr), QString::fromLatin1(X264_FILE_TYPE_FILTERS[i].pcExt));
1097         }
1098
1099         return filters.join(";;");
1100 }
1101
1102 QString AddJobDialog::getInputFilterLst(void)
1103 {
1104         static const struct
1105         {
1106                 const char *name;
1107                 const char *fext;
1108         }
1109         s_filters[] =
1110         {
1111                 {"Avisynth Scripts", "avs"},
1112                 {"VapourSynth Scripts", "vpy"},
1113                 {"Matroska Files", "mkv"},
1114                 {"MPEG-4 Part 14 Container", "mp4"},
1115                 {"Audio Video Interleaved", "avi"},
1116                 {"Flash Video", "flv"},
1117                 {"YUV4MPEG2 Stream", "y4m"},
1118                 {"Uncompresses YUV Data", "yuv"},
1119         };
1120
1121         const int count = ARRAY_SIZE(s_filters);
1122
1123         QString allTypes;
1124         for(size_t index = 0; index < count; index++)
1125         {
1126
1127                 allTypes += QString((index > 0) ? " *.%1" : "*.%1").arg(QString::fromLatin1(s_filters[index].fext));
1128         }
1129         
1130         QStringList filters;
1131         filters << QString("All supported files (%1)").arg(allTypes);
1132
1133         for(size_t index = 0; index < count; index++)
1134         {
1135                 filters << QString("%1 (*.%2)").arg(QString::fromLatin1(s_filters[index].name), QString::fromLatin1(s_filters[index].fext));
1136         }
1137                 
1138         filters << QString("All files (*.*)");
1139         return filters.join(";;");
1140 }
1141
1142 const AbstractEncoderInfo& AddJobDialog::getEncoderInfo(const int &encoder)
1143 {
1144         switch(encoder)
1145         {
1146         case OptionsModel::EncType_X264:
1147                 return X264Encoder::getEncoderInfo();
1148         case OptionsModel::EncType_X265:
1149                 return X265Encoder::getEncoderInfo();
1150                 break;
1151         default:
1152                 THROW("Unsupported encoder type!");
1153         }
1154 }