OSDN Git Service

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