OSDN Git Service

Added detection of 64-Bit QAAC encoder + fixed a regression in def8a9cd6e13defb09a4d2...
[lamexp/LameXP.git] / src / Dialog_MainWindow.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
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, but always including the *additional*
9 // restrictions defined in the "License.txt" file.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 //
20 // http://www.gnu.org/licenses/gpl-2.0.txt
21 ///////////////////////////////////////////////////////////////////////////////
22
23 #include "Dialog_MainWindow.h"
24
25 //UIC includes
26 #include "UIC_MainWindow.h"
27
28 //LameXP includes
29 #include "Global.h"
30 #include "Dialog_WorkingBanner.h"
31 #include "Dialog_MetaInfo.h"
32 #include "Dialog_About.h"
33 #include "Dialog_Update.h"
34 #include "Dialog_DropBox.h"
35 #include "Dialog_CueImport.h"
36 #include "Dialog_LogView.h"
37 #include "Thread_FileAnalyzer.h"
38 #include "Thread_MessageHandler.h"
39 #include "Model_MetaInfo.h"
40 #include "Model_Settings.h"
41 #include "Model_FileList.h"
42 #include "Model_FileSystem.h"
43 #include "Model_FileExts.h"
44 #include "Registry_Encoder.h"
45 #include "Registry_Decoder.h"
46 #include "Encoder_Abstract.h"
47 #include "ShellIntegration.h"
48 #include "CustomEventFilter.h"
49
50 //Mutils includes
51 #include <MUtils/Global.h>
52 #include <MUtils/OSSupport.h>
53 #include <MUtils/GUI.h>
54 #include <MUtils/Exception.h>
55 #include <MUtils/Sound.h>
56 #include <MUtils/Translation.h>
57 #include <MUtils/Version.h>
58
59 //Qt includes
60 #include <QMessageBox>
61 #include <QTimer>
62 #include <QDesktopWidget>
63 #include <QDate>
64 #include <QFileDialog>
65 #include <QInputDialog>
66 #include <QFileSystemModel>
67 #include <QDesktopServices>
68 #include <QUrl>
69 #include <QPlastiqueStyle>
70 #include <QCleanlooksStyle>
71 #include <QWindowsVistaStyle>
72 #include <QWindowsStyle>
73 #include <QSysInfo>
74 #include <QDragEnterEvent>
75 #include <QMimeData>
76 #include <QProcess>
77 #include <QUuid>
78 #include <QProcessEnvironment>
79 #include <QCryptographicHash>
80 #include <QTranslator>
81 #include <QResource>
82 #include <QScrollBar>
83
84 ////////////////////////////////////////////////////////////
85 // Helper macros
86 ////////////////////////////////////////////////////////////
87
88 #define BANNER_VISIBLE ((m_banner != NULL) && m_banner->isVisible())
89
90 #define INIT_BANNER() do \
91 { \
92         if(m_banner == NULL) \
93         { \
94                 m_banner = new WorkingBanner(this); \
95         } \
96 } \
97 while(0)
98
99 #define SHOW_BANNER(TXT) do \
100 { \
101         INIT_BANNER(); \
102         m_banner->show((TXT)); \
103 } \
104 while(0)
105
106 #define SHOW_BANNER_ARG(TXT, ARG) do \
107 { \
108         INIT_BANNER(); \
109         m_banner->show((TXT), (ARG)); \
110 } \
111 while(0)
112
113
114 #define SHOW_BANNER_CONDITIONALLY(FLAG, TEST, TXT) do \
115 { \
116         if((!(FLAG)) && ((TEST))) \
117         { \
118                 INIT_BANNER(); \
119                 m_banner->show((TXT)); \
120                 FLAG = true; \
121         } \
122 } \
123 while(0)
124
125 #define ABORT_IF_BUSY do \
126 { \
127         if(BANNER_VISIBLE || m_delayedFileTimer->isActive() || (QApplication::activeModalWidget() != NULL)) \
128         { \
129                 MUtils::Sound::beep(MUtils::Sound::BEEP_WRN); \
130                 return; \
131         } \
132 } \
133 while(0)
134
135 #define SET_TEXT_COLOR(WIDGET, COLOR) do \
136 { \
137         QPalette _palette = WIDGET->palette(); \
138         _palette.setColor(QPalette::WindowText, (COLOR)); \
139         _palette.setColor(QPalette::Text, (COLOR)); \
140         WIDGET->setPalette(_palette); \
141 } \
142 while(0)
143
144 #define SET_FONT_BOLD(WIDGET,BOLD) do \
145 { \
146         QFont _font = WIDGET->font(); \
147         _font.setBold(BOLD); \
148         WIDGET->setFont(_font); \
149 } \
150 while(0)
151
152 #define TEMP_HIDE_DROPBOX(CMD) do \
153 { \
154         bool _dropBoxVisible = m_dropBox->isVisible(); \
155         if(_dropBoxVisible) m_dropBox->hide(); \
156         do { CMD } while(0); \
157         if(_dropBoxVisible) m_dropBox->show(); \
158 } \
159 while(0)
160
161 #define SET_MODEL(VIEW, MODEL) do \
162 { \
163         QItemSelectionModel *_tmp = (VIEW)->selectionModel(); \
164         (VIEW)->setModel(MODEL); \
165         MUTILS_DELETE(_tmp); \
166 } \
167 while(0)
168
169 #define SET_CHECKBOX_STATE(CHCKBX, STATE) do \
170 { \
171         const bool isDisabled = (!(CHCKBX)->isEnabled()); \
172         if(isDisabled) \
173         { \
174                 (CHCKBX)->setEnabled(true); \
175         } \
176         if((CHCKBX)->isChecked() != (STATE)) \
177         { \
178                 (CHCKBX)->click(); \
179         } \
180         if((CHCKBX)->isChecked() != (STATE)) \
181         { \
182                 qWarning("Warning: Failed to set checkbox " #CHCKBX " state!"); \
183         } \
184         if(isDisabled) \
185         { \
186                 (CHCKBX)->setEnabled(false); \
187         } \
188 } \
189 while(0)
190
191 #define TRIM_STRING_RIGHT(STR) do \
192 { \
193         while((STR.length() > 0) && STR[STR.length()-1].isSpace()) STR.chop(1); \
194 } \
195 while(0)
196
197 #define MAKE_TRANSPARENT(WIDGET, FLAG) do \
198 { \
199         QPalette _p = (WIDGET)->palette(); \
200         _p.setColor(QPalette::Background, Qt::transparent); \
201         (WIDGET)->setPalette(FLAG ? _p : QPalette()); \
202 } \
203 while(0)
204
205 #define WITH_BLOCKED_SIGNALS(WIDGET, CMD, ...) do \
206 { \
207         const bool _flag = (WIDGET)->blockSignals(true); \
208         (WIDGET)->CMD(__VA_ARGS__); \
209         if(!(_flag)) { (WIDGET)->blockSignals(false); } \
210 } \
211 while(0)
212
213 #define PLAY_SOUND_OPTIONAL(NAME, ASYNC) do \
214 { \
215         if(m_settings->soundsEnabled()) MUtils::Sound::play_sound((NAME), (ASYNC)); \
216 } \
217 while(0)
218
219 #define SHOW_CORNER_WIDGET(FLAG) do \
220 { \
221         if(QWidget *cornerWidget = ui->menubar->cornerWidget()) \
222         { \
223                 cornerWidget->setVisible((FLAG)); \
224         } \
225 } \
226 while(0)
227
228 #define LINK(URL) QString("<a href=\"%1\">%2</a>").arg(URL).arg(QString(URL).replace("-", "&minus;"))
229 #define FSLINK(PATH) QString("<a href=\"file:///%1\">%2</a>").arg(PATH).arg(QString(PATH).replace("-", "&minus;"))
230 #define CENTER_CURRENT_OUTPUT_FOLDER_DELAYED QTimer::singleShot(125, this, SLOT(centerOutputFolderModel()))
231
232 static const unsigned int IDM_ABOUTBOX = 0xEFF0;
233 static const char *g_hydrogen_audio_url = "http://wiki.hydrogenaud.io/index.php?title=Main_Page";
234 static const char *g_documents_base_url = "http://lamexp.sourceforge.net/doc";
235
236 ////////////////////////////////////////////////////////////
237 // Constructor
238 ////////////////////////////////////////////////////////////
239
240 MainWindow::MainWindow(MUtils::IPCChannel *const ipcChannel, FileListModel *const fileListModel, AudioFileModel_MetaInfo *const metaInfo, SettingsModel *const settingsModel, QWidget *const parent)
241 :
242         QMainWindow(parent),
243         ui(new Ui::MainWindow),
244         m_fileListModel(fileListModel),
245         m_metaData(metaInfo),
246         m_settings(settingsModel),
247         m_fileSystemModel(NULL),
248         m_banner(NULL),
249         m_accepted(false),
250         m_firstTimeShown(true),
251         m_outputFolderViewCentering(false),
252         m_outputFolderViewInitCounter(0)
253 {
254         //Init the dialog, from the .ui file
255         ui->setupUi(this);
256         setWindowFlags(windowFlags() ^ Qt::WindowMaximizeButtonHint);
257
258         //Create window icon
259         MUtils::GUI::set_window_icon(this, lamexp_app_icon(), true);
260
261         //Register meta types
262         qRegisterMetaType<AudioFileModel>("AudioFileModel");
263
264         //Enabled main buttons
265         connect(ui->buttonAbout, SIGNAL(clicked()), this, SLOT(aboutButtonClicked()));
266         connect(ui->buttonStart, SIGNAL(clicked()), this, SLOT(encodeButtonClicked()));
267         connect(ui->buttonQuit,  SIGNAL(clicked()), this, SLOT(closeButtonClicked()));
268
269         //Setup tab widget
270         ui->tabWidget->setCurrentIndex(0);
271         connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabPageChanged(int)));
272
273         //Add system menu
274         MUtils::GUI::sysmenu_append(this, IDM_ABOUTBOX, "About...");
275
276         //Setup corner widget
277         QLabel *cornerWidget = new QLabel(ui->menubar);
278         m_evenFilterCornerWidget = new CustomEventFilter;
279         cornerWidget->setText("N/A");
280         cornerWidget->setFixedHeight(ui->menubar->height());
281         cornerWidget->setCursor(QCursor(Qt::PointingHandCursor));
282         cornerWidget->hide();
283         cornerWidget->installEventFilter(m_evenFilterCornerWidget);
284         connect(m_evenFilterCornerWidget, SIGNAL(eventOccurred(QWidget*, QEvent*)), this, SLOT(cornerWidgetEventOccurred(QWidget*, QEvent*)));
285         ui->menubar->setCornerWidget(cornerWidget);
286
287         //--------------------------------
288         // Setup "Source" tab
289         //--------------------------------
290
291         ui->sourceFileView->setModel(m_fileListModel);
292         ui->sourceFileView->verticalHeader()  ->setResizeMode(QHeaderView::ResizeToContents);
293         ui->sourceFileView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
294         ui->sourceFileView->setContextMenuPolicy(Qt::CustomContextMenu);
295         ui->sourceFileView->viewport()->installEventFilter(this);
296         m_dropNoteLabel = new QLabel(ui->sourceFileView);
297         m_dropNoteLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
298         SET_FONT_BOLD(m_dropNoteLabel, true);
299         SET_TEXT_COLOR(m_dropNoteLabel, Qt::darkGray);
300         m_sourceFilesContextMenu = new QMenu();
301         m_showDetailsContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/zoom.png"), "N/A");
302         m_previewContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/sound.png"), "N/A");
303         m_findFileContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/folder_go.png"), "N/A");
304         m_sourceFilesContextMenu->addSeparator();
305         m_exportCsvContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/table_save.png"), "N/A");
306         m_importCsvContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/folder_table.png"), "N/A");
307         SET_FONT_BOLD(m_showDetailsContextAction, true);
308
309         connect(ui->buttonAddFiles,                      SIGNAL(clicked()),                          this, SLOT(addFilesButtonClicked()));
310         connect(ui->buttonRemoveFile,                    SIGNAL(clicked()),                          this, SLOT(removeFileButtonClicked()));
311         connect(ui->buttonClearFiles,                    SIGNAL(clicked()),                          this, SLOT(clearFilesButtonClicked()));
312         connect(ui->buttonFileUp,                        SIGNAL(clicked()),                          this, SLOT(fileUpButtonClicked()));
313         connect(ui->buttonFileDown,                      SIGNAL(clicked()),                          this, SLOT(fileDownButtonClicked()));
314         connect(ui->buttonShowDetails,                   SIGNAL(clicked()),                          this, SLOT(showDetailsButtonClicked()));
315         connect(m_fileListModel,                         SIGNAL(rowsInserted(QModelIndex,int,int)),  this, SLOT(sourceModelChanged()));
316         connect(m_fileListModel,                         SIGNAL(rowsRemoved(QModelIndex,int,int)),   this, SLOT(sourceModelChanged()));
317         connect(m_fileListModel,                         SIGNAL(modelReset()),                       this, SLOT(sourceModelChanged()));
318         connect(ui->sourceFileView,                      SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(sourceFilesContextMenu(QPoint)));
319         connect(ui->sourceFileView->verticalScrollBar(), SIGNAL(sliderMoved(int)),                   this, SLOT(sourceFilesScrollbarMoved(int)));
320         connect(ui->sourceFileView->verticalScrollBar(), SIGNAL(valueChanged(int)),                  this, SLOT(sourceFilesScrollbarMoved(int)));
321         connect(m_showDetailsContextAction,              SIGNAL(triggered(bool)),                    this, SLOT(showDetailsButtonClicked()));
322         connect(m_previewContextAction,                  SIGNAL(triggered(bool)),                    this, SLOT(previewContextActionTriggered()));
323         connect(m_findFileContextAction,                 SIGNAL(triggered(bool)),                    this, SLOT(findFileContextActionTriggered()));
324         connect(m_exportCsvContextAction,                SIGNAL(triggered(bool)),                    this, SLOT(exportCsvContextActionTriggered()));
325         connect(m_importCsvContextAction,                SIGNAL(triggered(bool)),                    this, SLOT(importCsvContextActionTriggered()));
326
327         //--------------------------------
328         // Setup "Output" tab
329         //--------------------------------
330
331         ui->outputFolderView->setHeaderHidden(true);
332         ui->outputFolderView->setAnimated(false);
333         ui->outputFolderView->setMouseTracking(false);
334         ui->outputFolderView->setContextMenuPolicy(Qt::CustomContextMenu);
335         ui->outputFolderView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
336
337         m_evenFilterOutputFolderMouse = new CustomEventFilter;
338         ui->outputFoldersGoUpLabel->installEventFilter(m_evenFilterOutputFolderMouse);
339         ui->outputFoldersEditorLabel->installEventFilter(m_evenFilterOutputFolderMouse);
340         ui->outputFoldersFovoritesLabel->installEventFilter(m_evenFilterOutputFolderMouse);
341         ui->outputFolderLabel->installEventFilter(m_evenFilterOutputFolderMouse);
342
343         m_evenFilterOutputFolderView = new CustomEventFilter;
344         ui->outputFolderView->installEventFilter(m_evenFilterOutputFolderView);
345
346         SET_CHECKBOX_STATE(ui->saveToSourceFolderCheckBox, m_settings->outputToSourceDir());
347         ui->prependRelativePathCheckBox->setChecked(m_settings->prependRelativeSourcePath());
348         
349         connect(ui->outputFolderView, SIGNAL(clicked(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
350         connect(ui->outputFolderView, SIGNAL(activated(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
351         connect(ui->outputFolderView, SIGNAL(pressed(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
352         connect(ui->outputFolderView, SIGNAL(entered(QModelIndex)), this, SLOT(outputFolderViewMoved(QModelIndex)));
353         connect(ui->outputFolderView, SIGNAL(expanded(QModelIndex)), this, SLOT(outputFolderItemExpanded(QModelIndex)));
354         connect(ui->buttonMakeFolder, SIGNAL(clicked()), this, SLOT(makeFolderButtonClicked()));
355         connect(ui->buttonGotoHome, SIGNAL(clicked()), SLOT(gotoHomeFolderButtonClicked()));
356         connect(ui->buttonGotoDesktop, SIGNAL(clicked()), this, SLOT(gotoDesktopButtonClicked()));
357         connect(ui->buttonGotoMusic, SIGNAL(clicked()), this, SLOT(gotoMusicFolderButtonClicked()));
358         connect(ui->saveToSourceFolderCheckBox, SIGNAL(clicked()), this, SLOT(saveToSourceFolderChanged()));
359         connect(ui->prependRelativePathCheckBox, SIGNAL(clicked()), this, SLOT(prependRelativePathChanged()));
360         connect(ui->outputFolderEdit, SIGNAL(editingFinished()), this, SLOT(outputFolderEditFinished()));
361         connect(m_evenFilterOutputFolderMouse, SIGNAL(eventOccurred(QWidget*, QEvent*)), this, SLOT(outputFolderMouseEventOccurred(QWidget*, QEvent*)));
362         connect(m_evenFilterOutputFolderView, SIGNAL(eventOccurred(QWidget*, QEvent*)), this, SLOT(outputFolderViewEventOccurred(QWidget*, QEvent*)));
363
364         if(m_outputFolderContextMenu = new QMenu())
365         {
366                 m_showFolderContextAction = m_outputFolderContextMenu->addAction(QIcon(":/icons/zoom.png"), "N/A");
367                 m_goUpFolderContextAction = m_outputFolderContextMenu->addAction(QIcon(":/icons/folder_up.png"), "N/A");
368                 m_outputFolderContextMenu->addSeparator();
369                 m_refreshFolderContextAction = m_outputFolderContextMenu->addAction(QIcon(":/icons/arrow_refresh.png"), "N/A");
370                 m_outputFolderContextMenu->setDefaultAction(m_showFolderContextAction);
371                 connect(ui->outputFolderView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(outputFolderContextMenu(QPoint)));
372                 connect(m_showFolderContextAction, SIGNAL(triggered(bool)), this, SLOT(showFolderContextActionTriggered()));
373                 connect(m_refreshFolderContextAction, SIGNAL(triggered(bool)), this, SLOT(refreshFolderContextActionTriggered()));
374                 connect(m_goUpFolderContextAction, SIGNAL(triggered(bool)), this, SLOT(goUpFolderContextActionTriggered()));
375         }
376
377         if(m_outputFolderFavoritesMenu = new QMenu())
378         {
379                 m_addFavoriteFolderAction = m_outputFolderFavoritesMenu->addAction(QIcon(":/icons/add.png"), "N/A");
380                 m_outputFolderFavoritesMenu->insertSeparator(m_addFavoriteFolderAction);
381                 connect(m_addFavoriteFolderAction, SIGNAL(triggered(bool)), this, SLOT(addFavoriteFolderActionTriggered()));
382         }
383
384         ui->outputFolderEdit->setVisible(false);
385         if(m_outputFolderNoteBox = new QLabel(ui->outputFolderView))
386         {
387                 m_outputFolderNoteBox->setAutoFillBackground(true);
388                 m_outputFolderNoteBox->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
389                 m_outputFolderNoteBox->setFrameShape(QFrame::StyledPanel);
390                 SET_FONT_BOLD(m_outputFolderNoteBox, true);
391                 m_outputFolderNoteBox->hide();
392
393         }
394
395         outputFolderViewClicked(QModelIndex());
396         refreshFavorites();
397         
398         //--------------------------------
399         // Setup "Meta Data" tab
400         //--------------------------------
401
402         m_metaInfoModel = new MetaInfoModel(m_metaData);
403         m_metaInfoModel->clearData();
404         m_metaInfoModel->setData(m_metaInfoModel->index(4, 1), m_settings->metaInfoPosition());
405         ui->metaDataView->setModel(m_metaInfoModel);
406         ui->metaDataView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
407         ui->metaDataView->verticalHeader()->hide();
408         ui->metaDataView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
409         SET_CHECKBOX_STATE(ui->writeMetaDataCheckBox, m_settings->writeMetaTags());
410         ui->generatePlaylistCheckBox->setChecked(m_settings->createPlaylist());
411         connect(ui->buttonEditMeta, SIGNAL(clicked()), this, SLOT(editMetaButtonClicked()));
412         connect(ui->buttonClearMeta, SIGNAL(clicked()), this, SLOT(clearMetaButtonClicked()));
413         connect(ui->writeMetaDataCheckBox, SIGNAL(clicked()), this, SLOT(metaTagsEnabledChanged()));
414         connect(ui->generatePlaylistCheckBox, SIGNAL(clicked()), this, SLOT(playlistEnabledChanged()));
415
416         //--------------------------------
417         //Setup "Compression" tab
418         //--------------------------------
419
420         m_encoderButtonGroup = new QButtonGroup(this);
421         m_encoderButtonGroup->addButton(ui->radioButtonEncoderMP3, SettingsModel::MP3Encoder);
422         m_encoderButtonGroup->addButton(ui->radioButtonEncoderVorbis, SettingsModel::VorbisEncoder);
423         m_encoderButtonGroup->addButton(ui->radioButtonEncoderAAC, SettingsModel::AACEncoder);
424         m_encoderButtonGroup->addButton(ui->radioButtonEncoderAC3, SettingsModel::AC3Encoder);
425         m_encoderButtonGroup->addButton(ui->radioButtonEncoderFLAC, SettingsModel::FLACEncoder);
426         m_encoderButtonGroup->addButton(ui->radioButtonEncoderAPE, SettingsModel::MACEncoder);
427         m_encoderButtonGroup->addButton(ui->radioButtonEncoderOpus, SettingsModel::OpusEncoder);
428         m_encoderButtonGroup->addButton(ui->radioButtonEncoderDCA, SettingsModel::DCAEncoder);
429         m_encoderButtonGroup->addButton(ui->radioButtonEncoderPCM, SettingsModel::PCMEncoder);
430
431         const int aacEncoder = EncoderRegistry::getAacEncoder();
432         ui->radioButtonEncoderAAC->setEnabled(aacEncoder > SettingsModel::AAC_ENCODER_NONE);
433
434         m_modeButtonGroup = new QButtonGroup(this);
435         m_modeButtonGroup->addButton(ui->radioButtonModeQuality, SettingsModel::VBRMode);
436         m_modeButtonGroup->addButton(ui->radioButtonModeAverageBitrate, SettingsModel::ABRMode);
437         m_modeButtonGroup->addButton(ui->radioButtonConstBitrate, SettingsModel::CBRMode);
438
439         ui->radioButtonEncoderMP3->setChecked(true);
440         foreach(QAbstractButton *currentButton, m_encoderButtonGroup->buttons())
441         {
442                 if(currentButton->isEnabled() && (m_encoderButtonGroup->id(currentButton) == m_settings->compressionEncoder()))
443                 {
444                         currentButton->setChecked(true);
445                         break;
446                 }
447         }
448
449         m_evenFilterCompressionTab = new CustomEventFilter();
450         ui->labelCompressionHelp->installEventFilter(m_evenFilterCompressionTab);
451         ui->labelResetEncoders ->installEventFilter(m_evenFilterCompressionTab);
452
453         connect(m_encoderButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateEncoder(int)));
454         connect(m_modeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateRCMode(int)));
455         connect(m_evenFilterCompressionTab, SIGNAL(eventOccurred(QWidget*, QEvent*)), this, SLOT(compressionTabEventOccurred(QWidget*, QEvent*)));
456         connect(ui->sliderBitrate, SIGNAL(valueChanged(int)), this, SLOT(updateBitrate(int)));
457
458         updateEncoder(m_encoderButtonGroup->checkedId());
459
460         //--------------------------------
461         //Setup "Advanced Options" tab
462         //--------------------------------
463
464         ui->sliderLameAlgoQuality->setValue(m_settings->lameAlgoQuality());
465         if(m_settings->maximumInstances() > 0) ui->sliderMaxInstances->setValue(m_settings->maximumInstances());
466
467         ui->spinBoxBitrateManagementMin   ->setValue(m_settings->bitrateManagementMinRate());
468         ui->spinBoxBitrateManagementMax   ->setValue(m_settings->bitrateManagementMaxRate());
469         ui->spinBoxNormalizationFilterPeak->setValue(static_cast<double>(m_settings->normalizationFilterMaxVolume()) / 100.0);
470         ui->spinBoxNormalizationFilterSize->setValue(m_settings->normalizationFilterSize());
471         ui->spinBoxToneAdjustBass         ->setValue(static_cast<double>(m_settings->toneAdjustBass()) / 100.0);
472         ui->spinBoxToneAdjustTreble       ->setValue(static_cast<double>(m_settings->toneAdjustTreble()) / 100.0);
473         ui->spinBoxAftenSearchSize        ->setValue(m_settings->aftenExponentSearchSize());
474         ui->spinBoxOpusComplexity         ->setValue(m_settings->opusComplexity());
475         
476         ui->comboBoxMP3ChannelMode   ->setCurrentIndex(m_settings->lameChannelMode());
477         ui->comboBoxSamplingRate     ->setCurrentIndex(m_settings->samplingRate());
478         ui->comboBoxAACProfile       ->setCurrentIndex(m_settings->aacEncProfile());
479         ui->comboBoxAftenCodingMode  ->setCurrentIndex(m_settings->aftenAudioCodingMode());
480         ui->comboBoxAftenDRCMode     ->setCurrentIndex(m_settings->aftenDynamicRangeCompression());
481         ui->comboBoxOpusFramesize    ->setCurrentIndex(m_settings->opusFramesize());
482         
483         SET_CHECKBOX_STATE(ui->checkBoxBitrateManagement,          m_settings->bitrateManagementEnabled());
484         SET_CHECKBOX_STATE(ui->checkBoxNeroAAC2PassMode,           m_settings->neroAACEnable2Pass());
485         SET_CHECKBOX_STATE(ui->checkBoxAftenFastAllocation,        m_settings->aftenFastBitAllocation());
486         SET_CHECKBOX_STATE(ui->checkBoxNormalizationFilterEnabled, m_settings->normalizationFilterEnabled());
487         SET_CHECKBOX_STATE(ui->checkBoxNormalizationFilterDynamic, m_settings->normalizationFilterDynamic());
488         SET_CHECKBOX_STATE(ui->checkBoxNormalizationFilterCoupled, m_settings->normalizationFilterCoupled());
489         SET_CHECKBOX_STATE(ui->checkBoxAutoDetectInstances,        (m_settings->maximumInstances() < 1));
490         SET_CHECKBOX_STATE(ui->checkBoxUseSystemTempFolder,        (!m_settings->customTempPathEnabled()));
491         SET_CHECKBOX_STATE(ui->checkBoxRename_Rename,              m_settings->renameFiles_renameEnabled());
492         SET_CHECKBOX_STATE(ui->checkBoxRename_RegExp,              m_settings->renameFiles_regExpEnabled());
493         SET_CHECKBOX_STATE(ui->checkBoxForceStereoDownmix,         m_settings->forceStereoDownmix());
494         SET_CHECKBOX_STATE(ui->checkBoxOpusDisableResample,        m_settings->opusDisableResample());
495
496         ui->checkBoxNeroAAC2PassMode->setEnabled(aacEncoder == SettingsModel::AAC_ENCODER_NERO);
497         
498         ui->lineEditCustomParamLAME     ->setText(EncoderRegistry::loadEncoderCustomParams(m_settings, SettingsModel::MP3Encoder));
499         ui->lineEditCustomParamOggEnc   ->setText(EncoderRegistry::loadEncoderCustomParams(m_settings, SettingsModel::VorbisEncoder));
500         ui->lineEditCustomParamNeroAAC  ->setText(EncoderRegistry::loadEncoderCustomParams(m_settings, SettingsModel::AACEncoder));
501         ui->lineEditCustomParamFLAC     ->setText(EncoderRegistry::loadEncoderCustomParams(m_settings, SettingsModel::FLACEncoder));
502         ui->lineEditCustomParamAften    ->setText(EncoderRegistry::loadEncoderCustomParams(m_settings, SettingsModel::AC3Encoder));
503         ui->lineEditCustomParamOpus     ->setText(EncoderRegistry::loadEncoderCustomParams(m_settings, SettingsModel::OpusEncoder));
504         ui->lineEditCustomTempFolder    ->setText(QDir::toNativeSeparators(m_settings->customTempPath()));
505         ui->lineEditRenamePattern       ->setText(m_settings->renameFiles_renamePattern());
506         ui->lineEditRenameRegExp_Search ->setText(m_settings->renameFiles_regExpSearch ());
507         ui->lineEditRenameRegExp_Replace->setText(m_settings->renameFiles_regExpReplace());
508         
509         m_evenFilterCustumParamsHelp = new CustomEventFilter();
510         ui->helpCustomParamLAME->installEventFilter(m_evenFilterCustumParamsHelp);
511         ui->helpCustomParamOggEnc->installEventFilter(m_evenFilterCustumParamsHelp);
512         ui->helpCustomParamNeroAAC->installEventFilter(m_evenFilterCustumParamsHelp);
513         ui->helpCustomParamFLAC->installEventFilter(m_evenFilterCustumParamsHelp);
514         ui->helpCustomParamAften->installEventFilter(m_evenFilterCustumParamsHelp);
515         ui->helpCustomParamOpus->installEventFilter(m_evenFilterCustumParamsHelp);
516         
517         m_overwriteButtonGroup = new QButtonGroup(this);
518         m_overwriteButtonGroup->addButton(ui->radioButtonOverwriteModeKeepBoth, SettingsModel::Overwrite_KeepBoth);
519         m_overwriteButtonGroup->addButton(ui->radioButtonOverwriteModeSkipFile, SettingsModel::Overwrite_SkipFile);
520         m_overwriteButtonGroup->addButton(ui->radioButtonOverwriteModeReplaces, SettingsModel::Overwrite_Replaces);
521
522         ui->radioButtonOverwriteModeKeepBoth->setChecked(m_settings->overwriteMode() == SettingsModel::Overwrite_KeepBoth);
523         ui->radioButtonOverwriteModeSkipFile->setChecked(m_settings->overwriteMode() == SettingsModel::Overwrite_SkipFile);
524         ui->radioButtonOverwriteModeReplaces->setChecked(m_settings->overwriteMode() == SettingsModel::Overwrite_Replaces);
525
526         FileExtsModel *fileExtModel = new FileExtsModel(this);
527         fileExtModel->importItems(m_settings->renameFiles_fileExtension());
528         ui->tableViewFileExts->setModel(fileExtModel);
529         ui->tableViewFileExts->verticalHeader()  ->setResizeMode(QHeaderView::ResizeToContents);
530         ui->tableViewFileExts->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
531
532         connect(ui->sliderLameAlgoQuality,              SIGNAL(valueChanged(int)),                this, SLOT(updateLameAlgoQuality(int)));
533         connect(ui->checkBoxBitrateManagement,          SIGNAL(clicked(bool)),                    this, SLOT(bitrateManagementEnabledChanged(bool)));
534         connect(ui->spinBoxBitrateManagementMin,        SIGNAL(valueChanged(int)),                this, SLOT(bitrateManagementMinChanged(int)));
535         connect(ui->spinBoxBitrateManagementMax,        SIGNAL(valueChanged(int)),                this, SLOT(bitrateManagementMaxChanged(int)));
536         connect(ui->comboBoxMP3ChannelMode,             SIGNAL(currentIndexChanged(int)),         this, SLOT(channelModeChanged(int)));
537         connect(ui->comboBoxSamplingRate,               SIGNAL(currentIndexChanged(int)),         this, SLOT(samplingRateChanged(int)));
538         connect(ui->checkBoxNeroAAC2PassMode,           SIGNAL(clicked(bool)),                    this, SLOT(neroAAC2PassChanged(bool)));
539         connect(ui->comboBoxAACProfile,                 SIGNAL(currentIndexChanged(int)),         this, SLOT(neroAACProfileChanged(int)));
540         connect(ui->checkBoxNormalizationFilterEnabled, SIGNAL(clicked(bool)),                    this, SLOT(normalizationEnabledChanged(bool)));
541         connect(ui->checkBoxNormalizationFilterDynamic, SIGNAL(clicked(bool)),                    this, SLOT(normalizationDynamicChanged(bool)));
542         connect(ui->checkBoxNormalizationFilterCoupled, SIGNAL(clicked(bool)),                    this, SLOT(normalizationCoupledChanged(bool)));
543         connect(ui->comboBoxAftenCodingMode,            SIGNAL(currentIndexChanged(int)),         this, SLOT(aftenCodingModeChanged(int)));
544         connect(ui->comboBoxAftenDRCMode,               SIGNAL(currentIndexChanged(int)),         this, SLOT(aftenDRCModeChanged(int)));
545         connect(ui->spinBoxAftenSearchSize,             SIGNAL(valueChanged(int)),                this, SLOT(aftenSearchSizeChanged(int)));
546         connect(ui->checkBoxAftenFastAllocation,        SIGNAL(clicked(bool)),                    this, SLOT(aftenFastAllocationChanged(bool)));
547         connect(ui->spinBoxNormalizationFilterPeak,     SIGNAL(valueChanged(double)),             this, SLOT(normalizationMaxVolumeChanged(double)));
548         connect(ui->spinBoxNormalizationFilterSize,     SIGNAL(valueChanged(int)),                this, SLOT(normalizationFilterSizeChanged(int)));
549         connect(ui->spinBoxNormalizationFilterSize,     SIGNAL(editingFinished()),                this, SLOT(normalizationFilterSizeFinished()));
550         connect(ui->spinBoxToneAdjustBass,              SIGNAL(valueChanged(double)),             this, SLOT(toneAdjustBassChanged(double)));
551         connect(ui->spinBoxToneAdjustTreble,            SIGNAL(valueChanged(double)),             this, SLOT(toneAdjustTrebleChanged(double)));
552         connect(ui->buttonToneAdjustReset,              SIGNAL(clicked()),                        this, SLOT(toneAdjustTrebleReset()));
553         connect(ui->lineEditCustomParamLAME,            SIGNAL(editingFinished()),                this, SLOT(customParamsChanged()));
554         connect(ui->lineEditCustomParamOggEnc,          SIGNAL(editingFinished()),                this, SLOT(customParamsChanged()));
555         connect(ui->lineEditCustomParamNeroAAC,         SIGNAL(editingFinished()),                this, SLOT(customParamsChanged()));
556         connect(ui->lineEditCustomParamFLAC,            SIGNAL(editingFinished()),                this, SLOT(customParamsChanged()));
557         connect(ui->lineEditCustomParamAften,           SIGNAL(editingFinished()),                this, SLOT(customParamsChanged()));
558         connect(ui->lineEditCustomParamOpus,            SIGNAL(editingFinished()),                this, SLOT(customParamsChanged()));
559         connect(ui->sliderMaxInstances,                 SIGNAL(valueChanged(int)),                this, SLOT(updateMaximumInstances(int)));
560         connect(ui->checkBoxAutoDetectInstances,        SIGNAL(clicked(bool)),                    this, SLOT(autoDetectInstancesChanged(bool)));
561         connect(ui->buttonBrowseCustomTempFolder,       SIGNAL(clicked()),                        this, SLOT(browseCustomTempFolderButtonClicked()));
562         connect(ui->lineEditCustomTempFolder,           SIGNAL(textChanged(QString)),             this, SLOT(customTempFolderChanged(QString)));
563         connect(ui->checkBoxUseSystemTempFolder,        SIGNAL(clicked(bool)),                    this, SLOT(useCustomTempFolderChanged(bool)));
564         connect(ui->buttonResetAdvancedOptions,         SIGNAL(clicked()),                        this, SLOT(resetAdvancedOptionsButtonClicked()));
565         connect(ui->checkBoxRename_Rename,              SIGNAL(clicked(bool)),                    this, SLOT(renameOutputEnabledChanged(bool)));
566         connect(ui->checkBoxRename_RegExp,              SIGNAL(clicked(bool)),                    this, SLOT(renameRegExpEnabledChanged(bool)));
567         connect(ui->lineEditRenamePattern,              SIGNAL(editingFinished()),                this, SLOT(renameOutputPatternChanged()));
568         connect(ui->lineEditRenamePattern,              SIGNAL(textChanged(QString)),             this, SLOT(renameOutputPatternChanged(QString)));
569         connect(ui->lineEditRenameRegExp_Search,        SIGNAL(editingFinished()),                this, SLOT(renameRegExpValueChanged()));
570         connect(ui->lineEditRenameRegExp_Search,        SIGNAL(textChanged(QString)),             this, SLOT(renameRegExpSearchChanged(QString)));
571         connect(ui->lineEditRenameRegExp_Replace,       SIGNAL(editingFinished()),                this, SLOT(renameRegExpValueChanged()));
572         connect(ui->lineEditRenameRegExp_Replace,       SIGNAL(textChanged(QString)),             this, SLOT(renameRegExpReplaceChanged(QString)));
573         connect(ui->labelShowRenameMacros,              SIGNAL(linkActivated(QString)),           this, SLOT(showRenameMacros(QString)));
574         connect(ui->labelShowRegExpHelp,                SIGNAL(linkActivated(QString)),           this, SLOT(showRenameMacros(QString)));
575         connect(ui->checkBoxForceStereoDownmix,         SIGNAL(clicked(bool)),                    this, SLOT(forceStereoDownmixEnabledChanged(bool)));
576         connect(ui->comboBoxOpusFramesize,              SIGNAL(currentIndexChanged(int)),         this, SLOT(opusSettingsChanged()));
577         connect(ui->spinBoxOpusComplexity,              SIGNAL(valueChanged(int)),                this, SLOT(opusSettingsChanged()));
578         connect(ui->checkBoxOpusDisableResample,        SIGNAL(clicked(bool)),                    this, SLOT(opusSettingsChanged()));
579         connect(ui->buttonRename_Rename,                SIGNAL(clicked(bool)),                    this, SLOT(renameButtonClicked(bool)));
580         connect(ui->buttonRename_RegExp,                SIGNAL(clicked(bool)),                    this, SLOT(renameButtonClicked(bool)));
581         connect(ui->buttonRename_FileEx,                SIGNAL(clicked(bool)),                    this, SLOT(renameButtonClicked(bool)));
582         connect(ui->buttonFileExts_Add,                 SIGNAL(clicked()),                        this, SLOT(fileExtAddButtonClicked()));
583         connect(ui->buttonFileExts_Remove,              SIGNAL(clicked()),                        this, SLOT(fileExtRemoveButtonClicked()));
584         connect(m_overwriteButtonGroup,                 SIGNAL(buttonClicked(int)),               this, SLOT(overwriteModeChanged(int)));
585         connect(m_evenFilterCustumParamsHelp,           SIGNAL(eventOccurred(QWidget*, QEvent*)), this, SLOT(customParamsHelpRequested(QWidget*, QEvent*)));
586         connect(fileExtModel,                           SIGNAL(modelReset()),                     this, SLOT(fileExtModelChanged()));
587
588         //--------------------------------
589         // Force initial GUI update
590         //--------------------------------
591
592         updateLameAlgoQuality(ui->sliderLameAlgoQuality->value());
593         updateMaximumInstances(ui->sliderMaxInstances->value());
594         toneAdjustTrebleChanged(ui->spinBoxToneAdjustTreble->value());
595         toneAdjustBassChanged(ui->spinBoxToneAdjustBass->value());
596         normalizationEnabledChanged(ui->checkBoxNormalizationFilterEnabled->isChecked());
597         customParamsChanged();
598         
599         //--------------------------------
600         // Initialize actions
601         //--------------------------------
602
603         //Activate file menu actions
604         ui->actionOpenFolder->setData(QVariant::fromValue<bool>(false));
605         ui->actionOpenFolderRecursively->setData(QVariant::fromValue<bool>(true));
606         connect(ui->actionOpenFolder, SIGNAL(triggered()), this, SLOT(openFolderActionActivated()));
607         connect(ui->actionOpenFolderRecursively, SIGNAL(triggered()), this, SLOT(openFolderActionActivated()));
608
609         //Activate view menu actions
610         m_tabActionGroup = new QActionGroup(this);
611         m_tabActionGroup->addAction(ui->actionSourceFiles);
612         m_tabActionGroup->addAction(ui->actionOutputDirectory);
613         m_tabActionGroup->addAction(ui->actionCompression);
614         m_tabActionGroup->addAction(ui->actionMetaData);
615         m_tabActionGroup->addAction(ui->actionAdvancedOptions);
616         ui->actionSourceFiles->setData(0);
617         ui->actionOutputDirectory->setData(1);
618         ui->actionMetaData->setData(2);
619         ui->actionCompression->setData(3);
620         ui->actionAdvancedOptions->setData(4);
621         ui->actionSourceFiles->setChecked(true);
622         connect(m_tabActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(tabActionActivated(QAction*)));
623
624         //Activate style menu actions
625         m_styleActionGroup = new QActionGroup(this);
626         m_styleActionGroup->addAction(ui->actionStylePlastique);
627         m_styleActionGroup->addAction(ui->actionStyleCleanlooks);
628         m_styleActionGroup->addAction(ui->actionStyleWindowsVista);
629         m_styleActionGroup->addAction(ui->actionStyleWindowsXP);
630         m_styleActionGroup->addAction(ui->actionStyleWindowsClassic);
631         ui->actionStylePlastique->setData(0);
632         ui->actionStyleCleanlooks->setData(1);
633         ui->actionStyleWindowsVista->setData(2);
634         ui->actionStyleWindowsXP->setData(3);
635         ui->actionStyleWindowsClassic->setData(4);
636         ui->actionStylePlastique->setChecked(true);
637         ui->actionStyleWindowsXP->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_XP && MUtils::GUI::themes_enabled());
638         ui->actionStyleWindowsVista->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_VISTA && MUtils::GUI::themes_enabled());
639         connect(m_styleActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(styleActionActivated(QAction*)));
640         styleActionActivated(NULL);
641
642         //Populate the language menu
643         m_languageActionGroup = new QActionGroup(this);
644         QStringList translations;
645         if(MUtils::Translation::enumerate(translations) > 0)
646         {
647                 for(QStringList::ConstIterator iter = translations.constBegin(); iter != translations.constEnd(); iter++)
648                 {
649                         QAction *currentLanguage = new QAction(this);
650                         currentLanguage->setData(*iter);
651                         currentLanguage->setText(MUtils::Translation::get_name(*iter));
652                         currentLanguage->setIcon(QIcon(QString(":/flags/%1.png").arg(*iter)));
653                         currentLanguage->setCheckable(true);
654                         currentLanguage->setChecked(false);
655                         m_languageActionGroup->addAction(currentLanguage);
656                         ui->menuLanguage->insertAction(ui->actionLoadTranslationFromFile, currentLanguage);
657                 }
658         }
659         ui->menuLanguage->insertSeparator(ui->actionLoadTranslationFromFile);
660         connect(ui->actionLoadTranslationFromFile, SIGNAL(triggered(bool)), this, SLOT(languageFromFileActionActivated(bool)));
661         connect(m_languageActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(languageActionActivated(QAction*)));
662         ui->actionLoadTranslationFromFile->setChecked(false);
663
664         //Activate tools menu actions
665         ui->actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
666         ui->actionDisableSounds->setChecked(!m_settings->soundsEnabled());
667         ui->actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
668         ui->actionDisableSlowStartupNotifications->setChecked(!m_settings->antivirNotificationsEnabled());
669         ui->actionDisableShellIntegration->setChecked(!m_settings->shellIntegrationEnabled());
670         ui->actionDisableShellIntegration->setDisabled(lamexp_version_portable() && ui->actionDisableShellIntegration->isChecked());
671         ui->actionCheckForBetaUpdates->setChecked(m_settings->autoUpdateCheckBeta() || lamexp_version_demo());
672         ui->actionCheckForBetaUpdates->setEnabled(!lamexp_version_demo());
673         ui->actionHibernateComputer->setChecked(m_settings->hibernateComputer());
674         ui->actionHibernateComputer->setEnabled(MUtils::OS::is_hibernation_supported());
675         connect(ui->actionDisableUpdateReminder, SIGNAL(triggered(bool)), this, SLOT(disableUpdateReminderActionTriggered(bool)));
676         connect(ui->actionDisableSounds, SIGNAL(triggered(bool)), this, SLOT(disableSoundsActionTriggered(bool)));
677         connect(ui->actionDisableNeroAacNotifications, SIGNAL(triggered(bool)), this, SLOT(disableNeroAacNotificationsActionTriggered(bool)));
678         connect(ui->actionDisableSlowStartupNotifications, SIGNAL(triggered(bool)), this, SLOT(disableSlowStartupNotificationsActionTriggered(bool)));
679         connect(ui->actionDisableShellIntegration, SIGNAL(triggered(bool)), this, SLOT(disableShellIntegrationActionTriggered(bool)));
680         connect(ui->actionShowDropBoxWidget, SIGNAL(triggered(bool)), this, SLOT(showDropBoxWidgetActionTriggered(bool)));
681         connect(ui->actionHibernateComputer, SIGNAL(triggered(bool)), this, SLOT(hibernateComputerActionTriggered(bool)));
682         connect(ui->actionCheckForBetaUpdates, SIGNAL(triggered(bool)), this, SLOT(checkForBetaUpdatesActionTriggered(bool)));
683         connect(ui->actionImportCueSheet, SIGNAL(triggered(bool)), this, SLOT(importCueSheetActionTriggered(bool)));
684                 
685         //Activate help menu actions
686         ui->actionVisitHomepage    ->setData(QString::fromLatin1(lamexp_website_url()));
687         ui->actionVisitSupport     ->setData(QString::fromLatin1(lamexp_support_url()));
688         ui->actionVisitMuldersSite ->setData(QString::fromLatin1(lamexp_mulders_url()));
689         ui->actionVisitTracker     ->setData(QString::fromLatin1(lamexp_tracker_url()));
690         ui->actionVisitHAK         ->setData(QString::fromLatin1(g_hydrogen_audio_url));
691         ui->actionDocumentManual   ->setData(QString("%1/Manual.html")   .arg(QApplication::applicationDirPath()));
692         ui->actionDocumentChangelog->setData(QString("%1/Changelog.html").arg(QApplication::applicationDirPath()));
693         ui->actionDocumentTranslate->setData(QString("%1/Translate.html").arg(QApplication::applicationDirPath()));
694         connect(ui->actionCheckUpdates,      SIGNAL(triggered()), this, SLOT(checkUpdatesActionActivated()));
695         connect(ui->actionVisitSupport,      SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
696         connect(ui->actionVisitTracker,      SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
697         connect(ui->actionVisitHomepage,     SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
698         connect(ui->actionVisitMuldersSite,  SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
699         connect(ui->actionVisitHAK,          SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
700         connect(ui->actionDocumentManual,    SIGNAL(triggered()), this, SLOT(documentActionActivated()));
701         connect(ui->actionDocumentChangelog, SIGNAL(triggered()), this, SLOT(documentActionActivated()));
702         connect(ui->actionDocumentTranslate, SIGNAL(triggered()), this, SLOT(documentActionActivated()));
703         
704         //--------------------------------
705         // Prepare to show window
706         //--------------------------------
707
708         //Center window in screen
709         QRect desktopRect = QApplication::desktop()->screenGeometry();
710         QRect thisRect = this->geometry();
711         move((desktopRect.width() - thisRect.width()) / 2, (desktopRect.height() - thisRect.height()) / 2);
712         setMinimumSize(thisRect.width(), thisRect.height());
713
714         //Create DropBox widget
715         m_dropBox = new DropBox(this, m_fileListModel, m_settings);
716         connect(m_fileListModel, SIGNAL(modelReset()), m_dropBox, SLOT(modelChanged()));
717         connect(m_fileListModel, SIGNAL(rowsInserted(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
718         connect(m_fileListModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
719         connect(m_fileListModel, SIGNAL(rowAppended()), m_dropBox, SLOT(modelChanged()));
720
721         //Create message handler thread
722         m_messageHandler = new MessageHandlerThread(ipcChannel);
723         connect(m_messageHandler, SIGNAL(otherInstanceDetected()), this, SLOT(notifyOtherInstance()), Qt::QueuedConnection);
724         connect(m_messageHandler, SIGNAL(fileReceived(QString)), this, SLOT(addFileDelayed(QString)), Qt::QueuedConnection);
725         connect(m_messageHandler, SIGNAL(folderReceived(QString, bool)), this, SLOT(addFolderDelayed(QString, bool)), Qt::QueuedConnection);
726         connect(m_messageHandler, SIGNAL(killSignalReceived()), this, SLOT(close()), Qt::QueuedConnection);
727         m_messageHandler->start();
728
729         //Init delayed file handling
730         m_delayedFileList = new QStringList();
731         m_delayedFileTimer = new QTimer();
732         m_delayedFileTimer->setSingleShot(true);
733         m_delayedFileTimer->setInterval(5000);
734         connect(m_delayedFileTimer, SIGNAL(timeout()), this, SLOT(handleDelayedFiles()));
735
736         //Load translation
737         initializeTranslation();
738
739         //Re-translate (make sure we translate once)
740         QEvent languageChangeEvent(QEvent::LanguageChange);
741         changeEvent(&languageChangeEvent);
742
743         //Enable Drag & Drop
744         m_droppedFileList = new QList<QUrl>();
745         this->setAcceptDrops(true);
746 }
747
748 ////////////////////////////////////////////////////////////
749 // Destructor
750 ////////////////////////////////////////////////////////////
751
752 MainWindow::~MainWindow(void)
753 {
754         //Stop message handler thread
755         if(m_messageHandler && m_messageHandler->isRunning())
756         {
757                 m_messageHandler->stop();
758                 if(!m_messageHandler->wait(2500))
759                 {
760                         m_messageHandler->terminate();
761                         m_messageHandler->wait();
762                 }
763         }
764
765         //Unset models
766         SET_MODEL(ui->sourceFileView, NULL);
767         SET_MODEL(ui->outputFolderView, NULL);
768         SET_MODEL(ui->metaDataView, NULL);
769
770         //Free memory
771         MUTILS_DELETE(m_tabActionGroup);
772         MUTILS_DELETE(m_styleActionGroup);
773         MUTILS_DELETE(m_languageActionGroup);
774         MUTILS_DELETE(m_banner);
775         MUTILS_DELETE(m_fileSystemModel);
776         MUTILS_DELETE(m_messageHandler);
777         MUTILS_DELETE(m_droppedFileList);
778         MUTILS_DELETE(m_delayedFileList);
779         MUTILS_DELETE(m_delayedFileTimer);
780         MUTILS_DELETE(m_metaInfoModel);
781         MUTILS_DELETE(m_encoderButtonGroup);
782         MUTILS_DELETE(m_modeButtonGroup);
783         MUTILS_DELETE(m_overwriteButtonGroup);
784         MUTILS_DELETE(m_sourceFilesContextMenu);
785         MUTILS_DELETE(m_outputFolderFavoritesMenu);
786         MUTILS_DELETE(m_outputFolderContextMenu);
787         MUTILS_DELETE(m_dropBox);
788         MUTILS_DELETE(m_evenFilterCornerWidget);
789         MUTILS_DELETE(m_evenFilterCustumParamsHelp);
790         MUTILS_DELETE(m_evenFilterOutputFolderMouse);
791         MUTILS_DELETE(m_evenFilterOutputFolderView);
792         MUTILS_DELETE(m_evenFilterCompressionTab);
793
794         //Un-initialize the dialog
795         MUTILS_DELETE(ui);
796 }
797
798 ////////////////////////////////////////////////////////////
799 // PRIVATE FUNCTIONS
800 ////////////////////////////////////////////////////////////
801
802 /*
803  * Add file to source list
804  */
805 void MainWindow::addFiles(const QStringList &files)
806 {
807         if(files.isEmpty())
808         {
809                 return;
810         }
811
812         WITH_BLOCKED_SIGNALS(ui->tabWidget, setCurrentIndex, 0);
813         tabPageChanged(ui->tabWidget->currentIndex(), true);
814
815         INIT_BANNER();
816         FileAnalyzer *analyzer = new FileAnalyzer(files);
817
818         connect(analyzer, SIGNAL(fileSelected(QString)), m_banner, SLOT(setText(QString)), Qt::QueuedConnection);
819         connect(analyzer, SIGNAL(progressValChanged(unsigned int)), m_banner, SLOT(setProgressVal(unsigned int)), Qt::QueuedConnection);
820         connect(analyzer, SIGNAL(progressMaxChanged(unsigned int)), m_banner, SLOT(setProgressMax(unsigned int)), Qt::QueuedConnection);
821         connect(analyzer, SIGNAL(fileAnalyzed(AudioFileModel)), m_fileListModel, SLOT(addFile(AudioFileModel)), Qt::QueuedConnection);
822         connect(m_banner, SIGNAL(userAbort()), analyzer, SLOT(abortProcess()), Qt::DirectConnection);
823
824         try
825         {
826                 m_fileListModel->setBlockUpdates(true);
827                 QTime startTime = QTime::currentTime();
828                 m_banner->show(tr("Adding file(s), please wait..."), analyzer);
829         }
830         catch(...)
831         {
832                 /* ignore any exceptions that may occur */
833         }
834
835         m_fileListModel->setBlockUpdates(false);
836         qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
837         ui->sourceFileView->update();
838         qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
839         ui->sourceFileView->scrollToBottom();
840         qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
841
842         if(analyzer->filesDenied())
843         {
844                 QMessageBox::warning(this, tr("Access Denied"), QString("%1<br>%2").arg(NOBR(tr("%n file(s) have been rejected, because read access was not granted!", "", analyzer->filesDenied())), NOBR(tr("This usually means the file is locked by another process."))));
845         }
846         if(analyzer->filesDummyCDDA())
847         {
848                 QMessageBox::warning(this, tr("CDDA Files"), QString("%1<br><br>%2<br>%3").arg(NOBR(tr("%n file(s) have been rejected, because they are dummy CDDA files!", "", analyzer->filesDummyCDDA())), NOBR(tr("Sorry, LameXP cannot extract audio tracks from an Audio-CD at present.")), NOBR(tr("We recommend using %1 for that purpose.").arg("<a href=\"http://www.exactaudiocopy.de/\">Exact Audio Copy</a>"))));
849         }
850         if(analyzer->filesCueSheet())
851         {
852                 QMessageBox::warning(this, tr("Cue Sheet"), QString("%1<br>%2").arg(NOBR(tr("%n file(s) have been rejected, because they appear to be Cue Sheet images!", "",analyzer->filesCueSheet())), NOBR(tr("Please use LameXP's Cue Sheet wizard for importing Cue Sheet files."))));
853         }
854         if(analyzer->filesRejected())
855         {
856                 QMessageBox::warning(this, tr("Files Rejected"), QString("%1<br>%2").arg(NOBR(tr("%n file(s) have been rejected, because the file format could not be recognized!", "", analyzer->filesRejected())), NOBR(tr("This usually means the file is damaged or the file format is not supported."))));
857         }
858
859         MUTILS_DELETE(analyzer);
860         m_banner->close();
861 }
862
863 /*
864  * Add folder to source list
865  */
866 void MainWindow::addFolder(const QString &path, bool recursive, bool delayed)
867 {
868         QFileInfoList folderInfoList;
869         folderInfoList << QFileInfo(path);
870         QStringList fileList;
871         
872         SHOW_BANNER(tr("Scanning folder(s) for files, please wait..."));
873         
874         QApplication::processEvents();
875         MUtils::OS::check_key_state_esc();
876
877         while(!folderInfoList.isEmpty())
878         {
879                 if(MUtils::OS::check_key_state_esc())
880                 {
881                         qWarning("Operation cancelled by user!");
882                         MUtils::Sound::beep(MUtils::Sound::BEEP_ERR);
883                         fileList.clear();
884                         break;
885                 }
886                 
887                 QDir currentDir(folderInfoList.takeFirst().canonicalFilePath());
888                 QFileInfoList fileInfoList = currentDir.entryInfoList(QDir::Files | QDir::NoSymLinks);
889
890                 while(!fileInfoList.isEmpty())
891                 {
892                         fileList << fileInfoList.takeFirst().canonicalFilePath();
893                 }
894
895                 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
896
897                 if(recursive)
898                 {
899                         folderInfoList.append(currentDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks));
900                         QApplication::processEvents();
901                 }
902         }
903         
904         m_banner->close();
905         QApplication::processEvents();
906
907         if(!fileList.isEmpty())
908         {
909                 if(delayed)
910                 {
911                         addFilesDelayed(fileList);
912                 }
913                 else
914                 {
915                         addFiles(fileList);
916                 }
917         }
918 }
919
920 /*
921  * Check for updates
922  */
923 bool MainWindow::checkForUpdates(void)
924 {
925         bool bReadyToInstall = false;
926         
927         UpdateDialog *updateDialog = new UpdateDialog(m_settings, this);
928         updateDialog->exec();
929
930         if(updateDialog->getSuccess())
931         {
932                 SHOW_CORNER_WIDGET(false);
933                 m_settings->autoUpdateLastCheck(QDate::currentDate().toString(Qt::ISODate));
934                 bReadyToInstall = updateDialog->updateReadyToInstall();
935         }
936
937         MUTILS_DELETE(updateDialog);
938         return bReadyToInstall;
939 }
940
941 /*
942  * Refresh list of favorites
943  */
944 void MainWindow::refreshFavorites(void)
945 {
946         QList<QAction*> folderList = m_outputFolderFavoritesMenu->actions();
947         QStringList favorites = m_settings->favoriteOutputFolders().split("|", QString::SkipEmptyParts);
948         while(favorites.count() > 6) favorites.removeFirst();
949
950         while(!folderList.isEmpty())
951         {
952                 QAction *currentItem = folderList.takeFirst();
953                 if(currentItem->isSeparator()) break;
954                 m_outputFolderFavoritesMenu->removeAction(currentItem);
955                 MUTILS_DELETE(currentItem);
956         }
957
958         QAction *lastItem = m_outputFolderFavoritesMenu->actions().first();
959
960         while(!favorites.isEmpty())
961         {
962                 QString path = favorites.takeLast();
963                 if(QDir(path).exists())
964                 {
965                         QAction *action = new QAction(QIcon(":/icons/folder_go.png"), QDir::toNativeSeparators(path), this);
966                         action->setData(path);
967                         m_outputFolderFavoritesMenu->insertAction(lastItem, action);
968                         connect(action, SIGNAL(triggered(bool)), this, SLOT(gotoFavoriteFolder()));
969                         lastItem = action;
970                 }
971         }
972 }
973
974 /*
975  * Initilaize translation
976  */
977 void MainWindow::initializeTranslation(void)
978 {
979         bool translationLoaded = false;
980
981         //Try to load "external" translation file
982         if(!m_settings->currentLanguageFile().isEmpty())
983         {
984                 const QString qmFilePath = QFileInfo(m_settings->currentLanguageFile()).canonicalFilePath();
985                 if((!qmFilePath.isEmpty()) && QFileInfo(qmFilePath).exists() && QFileInfo(qmFilePath).isFile() && (QFileInfo(qmFilePath).suffix().compare("qm", Qt::CaseInsensitive) == 0))
986                 {
987                         if(MUtils::Translation::install_translator_from_file(qmFilePath))
988                         {
989                                 QList<QAction*> actions = m_languageActionGroup->actions();
990                                 while(!actions.isEmpty()) actions.takeFirst()->setChecked(false);
991                                 ui->actionLoadTranslationFromFile->setChecked(true);
992                                 translationLoaded = true;
993                         }
994                 }
995         }
996
997         //Try to load "built-in" translation file
998         if(!translationLoaded)
999         {
1000                 QList<QAction*> languageActions = m_languageActionGroup->actions();
1001                 while(!languageActions.isEmpty())
1002                 {
1003                         QAction *currentLanguage = languageActions.takeFirst();
1004                         if(currentLanguage->data().toString().compare(m_settings->currentLanguage(), Qt::CaseInsensitive) == 0)
1005                         {
1006                                 currentLanguage->setChecked(true);
1007                                 languageActionActivated(currentLanguage);
1008                                 translationLoaded = true;
1009                         }
1010                 }
1011         }
1012
1013         //Fallback to default translation
1014         if(!translationLoaded)
1015         {
1016                 QList<QAction*> languageActions = m_languageActionGroup->actions();
1017                 while(!languageActions.isEmpty())
1018                 {
1019                         QAction *currentLanguage = languageActions.takeFirst();
1020                         if(currentLanguage->data().toString().compare(MUtils::Translation::DEFAULT_LANGID, Qt::CaseInsensitive) == 0)
1021                         {
1022                                 currentLanguage->setChecked(true);
1023                                 languageActionActivated(currentLanguage);
1024                                 translationLoaded = true;
1025                         }
1026                 }
1027         }
1028
1029         //Make sure we loaded some translation
1030         if(!translationLoaded)
1031         {
1032                 qFatal("Failed to load any translation, this is NOT supposed to happen!");
1033         }
1034 }
1035
1036 /*
1037  * Open a document link
1038  */
1039 void MainWindow::openDocumentLink(QAction *const action)
1040 {
1041         if(!(action->data().isValid() && (action->data().type() == QVariant::String)))
1042         {
1043                 qWarning("Cannot open document for this QAction!");
1044                 return;
1045         }
1046
1047         //Try to open exitsing document file
1048         const QFileInfo document(action->data().toString());
1049         if(document.exists() && document.isFile() && (document.size() >= 1024))
1050         {
1051                 QDesktopServices::openUrl(QUrl::fromLocalFile(document.canonicalFilePath()));
1052                 return;
1053         }
1054
1055         //Document not found -> fallback mode!
1056         qWarning("Document '%s' not found -> redirecting to the website!", MUTILS_UTF8(document.fileName()));
1057         const QUrl url(QString("%1/%2").arg(QString::fromLatin1(g_documents_base_url), document.fileName()));
1058         QDesktopServices::openUrl(url);
1059 }
1060
1061 ////////////////////////////////////////////////////////////
1062 // EVENTS
1063 ////////////////////////////////////////////////////////////
1064
1065 /*
1066  * Window is about to be shown
1067  */
1068 void MainWindow::showEvent(QShowEvent *event)
1069 {
1070         m_accepted = false;
1071         resizeEvent(NULL);
1072         sourceModelChanged();
1073
1074         if(!event->spontaneous())
1075         {
1076                 WITH_BLOCKED_SIGNALS(ui->tabWidget, setCurrentIndex, 0);
1077                 tabPageChanged(ui->tabWidget->currentIndex(), true);
1078         }
1079
1080         if(m_firstTimeShown)
1081         {
1082                 m_firstTimeShown = false;
1083                 QTimer::singleShot(0, this, SLOT(windowShown()));
1084         }
1085         else
1086         {
1087                 if(m_settings->dropBoxWidgetEnabled())
1088                 {
1089                         m_dropBox->setVisible(true);
1090                 }
1091         }
1092 }
1093
1094 /*
1095  * Re-translate the UI
1096  */
1097 void MainWindow::changeEvent(QEvent *e)
1098 {
1099         QMainWindow::changeEvent(e);
1100         if(e->type() != QEvent::LanguageChange)
1101         {
1102                 return;
1103         }
1104
1105         int comboBoxIndex[6];
1106                 
1107         //Backup combobox indices, as retranslateUi() resets
1108         comboBoxIndex[0] = ui->comboBoxMP3ChannelMode->currentIndex();
1109         comboBoxIndex[1] = ui->comboBoxSamplingRate->currentIndex();
1110         comboBoxIndex[2] = ui->comboBoxAACProfile->currentIndex();
1111         comboBoxIndex[3] = ui->comboBoxAftenCodingMode->currentIndex();
1112         comboBoxIndex[4] = ui->comboBoxAftenDRCMode->currentIndex();
1113         comboBoxIndex[5] = ui->comboBoxOpusFramesize->currentIndex();
1114                 
1115         //Re-translate from UIC
1116         ui->retranslateUi(this);
1117
1118         //Restore combobox indices
1119         ui->comboBoxMP3ChannelMode->setCurrentIndex(comboBoxIndex[0]);
1120         ui->comboBoxSamplingRate->setCurrentIndex(comboBoxIndex[1]);
1121         ui->comboBoxAACProfile->setCurrentIndex(comboBoxIndex[2]);
1122         ui->comboBoxAftenCodingMode->setCurrentIndex(comboBoxIndex[3]);
1123         ui->comboBoxAftenDRCMode->setCurrentIndex(comboBoxIndex[4]);
1124         ui->comboBoxOpusFramesize->setCurrentIndex(comboBoxIndex[5]);
1125
1126         //Update the window title
1127         if(MUTILS_DEBUG)
1128         {
1129                 setWindowTitle(QString("%1 [!!! DEBUG BUILD !!!]").arg(windowTitle()));
1130         }
1131         else if(lamexp_version_demo())
1132         {
1133                 setWindowTitle(QString("%1 [%2]").arg(windowTitle(), tr("DEMO VERSION")));
1134         }
1135
1136         //Manually re-translate widgets that UIC doesn't handle
1137         m_outputFolderNoteBox->setText(tr("Initializing directory outline, please be patient..."));
1138         m_dropNoteLabel->setText(QString("<br><img src=\":/images/DropZone.png\"><br><br>%1").arg(tr("You can drop in audio files here!")));
1139         if(QLabel *cornerWidget = dynamic_cast<QLabel*>(ui->menubar->cornerWidget()))
1140         {
1141                 cornerWidget->setText(QString("<nobr><img src=\":/icons/exclamation_small.png\">&nbsp;<b style=\"color:darkred\">%1</b>&nbsp;&nbsp;&nbsp;</nobr>").arg(tr("Check for Updates")));
1142         }
1143         m_showDetailsContextAction->setText(tr("Show Details"));
1144         m_previewContextAction->setText(tr("Open File in External Application"));
1145         m_findFileContextAction->setText(tr("Browse File Location"));
1146         m_showFolderContextAction->setText(tr("Browse Selected Folder"));
1147         m_refreshFolderContextAction->setText(tr("Refresh Directory Outline"));
1148         m_goUpFolderContextAction->setText(tr("Go To Parent Directory"));
1149         m_addFavoriteFolderAction->setText(tr("Bookmark Current Output Folder"));
1150         m_exportCsvContextAction->setText(tr("Export Meta Tags to CSV File"));
1151         m_importCsvContextAction->setText(tr("Import Meta Tags from CSV File"));
1152
1153         //Force GUI update
1154         m_metaInfoModel->clearData();
1155         m_metaInfoModel->setData(m_metaInfoModel->index(4, 1), m_settings->metaInfoPosition());
1156         updateEncoder(m_settings->compressionEncoder());
1157         updateLameAlgoQuality(ui->sliderLameAlgoQuality->value());
1158         updateMaximumInstances(ui->sliderMaxInstances->value());
1159         renameOutputPatternChanged(ui->lineEditRenamePattern->text(), true);
1160         renameRegExpSearchChanged (ui->lineEditRenameRegExp_Search ->text(), true);
1161         renameRegExpReplaceChanged(ui->lineEditRenameRegExp_Replace->text(), true);
1162
1163         //Re-install shell integration
1164         if(m_settings->shellIntegrationEnabled())
1165         {
1166                 ShellIntegration::install();
1167         }
1168
1169         //Translate system menu
1170         MUtils::GUI::sysmenu_update(this, IDM_ABOUTBOX, ui->buttonAbout->text());
1171         
1172         //Force resize event
1173         QApplication::postEvent(this, new QResizeEvent(this->size(), QSize()));
1174         for(QObjectList::ConstIterator iter = this->children().constBegin(); iter != this->children().constEnd(); iter++)
1175         {
1176                 if(QWidget *child = dynamic_cast<QWidget*>(*iter))
1177                 {
1178                         QApplication::postEvent(child, new QResizeEvent(child->size(), QSize()));
1179                 }
1180         }
1181
1182         //Force tabe page change
1183         tabPageChanged(ui->tabWidget->currentIndex(), true);
1184 }
1185
1186 /*
1187  * File dragged over window
1188  */
1189 void MainWindow::dragEnterEvent(QDragEnterEvent *event)
1190 {
1191         QStringList formats = event->mimeData()->formats();
1192         
1193         if(formats.contains("application/x-qt-windows-mime;value=\"FileNameW\"", Qt::CaseInsensitive) && formats.contains("text/uri-list", Qt::CaseInsensitive))
1194         {
1195                 event->acceptProposedAction();
1196         }
1197 }
1198
1199 /*
1200  * File dropped onto window
1201  */
1202 void MainWindow::dropEvent(QDropEvent *event)
1203 {
1204         m_droppedFileList->clear();
1205         (*m_droppedFileList) << event->mimeData()->urls();
1206         if(!m_droppedFileList->isEmpty())
1207         {
1208                 PLAY_SOUND_OPTIONAL("drop", true);
1209                 QTimer::singleShot(0, this, SLOT(handleDroppedFiles()));
1210         }
1211 }
1212
1213 /*
1214  * Window tries to close
1215  */
1216 void MainWindow::closeEvent(QCloseEvent *event)
1217 {
1218         if(BANNER_VISIBLE || m_delayedFileTimer->isActive())
1219         {
1220                 MUtils::Sound::beep(MUtils::Sound::BEEP_WRN);
1221                 event->ignore();
1222         }
1223         
1224         if(m_dropBox)
1225         {
1226                 m_dropBox->hide();
1227         }
1228 }
1229
1230 /*
1231  * Window was resized
1232  */
1233 void MainWindow::resizeEvent(QResizeEvent *event)
1234 {
1235         if(event) QMainWindow::resizeEvent(event);
1236
1237         if(QWidget *port = ui->sourceFileView->viewport())
1238         {
1239                 m_dropNoteLabel->setGeometry(port->geometry());
1240         }
1241
1242         if(QWidget *port = ui->outputFolderView->viewport())
1243         {
1244                 m_outputFolderNoteBox->setGeometry(16, (port->height() - 64) / 2, port->width() - 32, 64);
1245         }
1246 }
1247
1248 /*
1249  * Key press event filter
1250  */
1251 void MainWindow::keyPressEvent(QKeyEvent *e)
1252 {
1253         if(e->key() == Qt::Key_Delete)
1254         {
1255                 if(ui->sourceFileView->isVisible())
1256                 {
1257                         QTimer::singleShot(0, this, SLOT(removeFileButtonClicked()));
1258                         return;
1259                 }
1260         }
1261
1262         if(e->modifiers().testFlag(Qt::ControlModifier) && (e->key() == Qt::Key_F5))
1263         {
1264                 initializeTranslation();
1265                 MUtils::Sound::beep(MUtils::Sound::BEEP_NFO);
1266                 return;
1267         }
1268
1269         if(e->key() == Qt::Key_F5)
1270         {
1271                 if(ui->outputFolderView->isVisible())
1272                 {
1273                         QTimer::singleShot(0, this, SLOT(refreshFolderContextActionTriggered()));
1274                         return;
1275                 }
1276         }
1277
1278         QMainWindow::keyPressEvent(e);
1279 }
1280
1281 /*
1282  * Event filter
1283  */
1284 bool MainWindow::eventFilter(QObject *obj, QEvent *event)
1285 {
1286         if(obj == m_fileSystemModel)
1287         {
1288                 if(QApplication::overrideCursor() == NULL)
1289                 {
1290                         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1291                         QTimer::singleShot(250, this, SLOT(restoreCursor()));
1292                 }
1293         }
1294
1295         return QMainWindow::eventFilter(obj, event);
1296 }
1297
1298 bool MainWindow::event(QEvent *e)
1299 {
1300         switch(e->type())
1301         {
1302         case MUtils::GUI::USER_EVENT_QUERYENDSESSION:
1303                 qWarning("System is shutting down, main window prepares to close...");
1304                 if(BANNER_VISIBLE) m_banner->close();
1305                 if(m_delayedFileTimer->isActive()) m_delayedFileTimer->stop();
1306                 return true;
1307         case MUtils::GUI::USER_EVENT_ENDSESSION:
1308                 qWarning("System is shutting down, main window will close now...");
1309                 if(isVisible())
1310                 {
1311                         while(!close())
1312                         {
1313                                 QApplication::processEvents(QEventLoop::WaitForMoreEvents & QEventLoop::ExcludeUserInputEvents);
1314                         }
1315                 }
1316                 m_fileListModel->clearFiles();
1317                 return true;
1318         case QEvent::MouseButtonPress:
1319                 if(ui->outputFolderEdit->isVisible())
1320                 {
1321                         QTimer::singleShot(0, this, SLOT(outputFolderEditFinished()));
1322                 }
1323         default:
1324                 return QMainWindow::event(e);
1325         }
1326 }
1327
1328 bool MainWindow::winEvent(MSG *message, long *result)
1329 {
1330         if(MUtils::GUI::sysmenu_check_msg(message, IDM_ABOUTBOX))
1331         {
1332                 QTimer::singleShot(0, ui->buttonAbout, SLOT(click()));
1333                 *result = 0;
1334                 return true;
1335         }
1336         return false;
1337 }
1338
1339 ////////////////////////////////////////////////////////////
1340 // Slots
1341 ////////////////////////////////////////////////////////////
1342
1343 // =========================================================
1344 // Show window slots
1345 // =========================================================
1346
1347 /*
1348  * Window shown
1349  */
1350 void MainWindow::windowShown(void)
1351 {
1352         const MUtils::OS::ArgumentMap &arguments = MUtils::OS::arguments(); //QApplication::arguments();
1353
1354         //Force resize event
1355         resizeEvent(NULL);
1356
1357         //First run?
1358         const bool firstRun = arguments.contains("first-run");
1359
1360         //Check license
1361         if((m_settings->licenseAccepted() <= 0) || firstRun)
1362         {
1363                 int iAccepted = m_settings->licenseAccepted();
1364
1365                 if((iAccepted == 0) || firstRun)
1366                 {
1367                         AboutDialog *about = new AboutDialog(m_settings, this, true);
1368                         iAccepted = about->exec();
1369                         if(iAccepted <= 0) iAccepted = -2;
1370                         MUTILS_DELETE(about);
1371                 }
1372
1373                 if(iAccepted <= 0)
1374                 {
1375                         m_settings->licenseAccepted(++iAccepted);
1376                         m_settings->syncNow();
1377                         QApplication::processEvents();
1378                         MUtils::Sound::play_sound("whammy", false);
1379                         QMessageBox::critical(this, tr("License Declined"), tr("You have declined the license. Consequently the application will exit now!"), tr("Goodbye!"));
1380                         QFileInfo uninstallerInfo = QFileInfo(QString("%1/Uninstall.exe").arg(QApplication::applicationDirPath()));
1381                         if(uninstallerInfo.exists())
1382                         {
1383                                 QString uninstallerDir = uninstallerInfo.canonicalPath();
1384                                 QString uninstallerPath = uninstallerInfo.canonicalFilePath();
1385                                 for(int i = 0; i < 3; i++)
1386                                 {
1387                                         if(MUtils::OS::shell_open(this, QDir::toNativeSeparators(uninstallerPath), "/Force", QDir::toNativeSeparators(uninstallerDir))) break;
1388                                 }
1389                         }
1390                         QApplication::quit();
1391                         return;
1392                 }
1393                 
1394                 MUtils::Sound::play_sound("woohoo", false);
1395                 m_settings->licenseAccepted(1);
1396                 m_settings->syncNow();
1397                 if(lamexp_version_demo()) showAnnounceBox();
1398         }
1399         
1400         //Check for expiration
1401         if(lamexp_version_demo())
1402         {
1403                 if(MUtils::OS::current_date() >= lamexp_version_expires())
1404                 {
1405                         qWarning("Binary has expired !!!");
1406                         MUtils::Sound::play_sound("whammy", false);
1407                         if(QMessageBox::warning(this, tr("LameXP - Expired"), QString("%1<br>%2").arg(NOBR(tr("This demo (pre-release) version of LameXP has expired at %1.").arg(lamexp_version_expires().toString(Qt::ISODate))), NOBR(tr("LameXP is free software and release versions won't expire."))), tr("Check for Updates"), tr("Exit Program")) == 0)
1408                         {
1409                                 checkForUpdates();
1410                         }
1411                         QApplication::quit();
1412                         return;
1413                 }
1414         }
1415
1416         //Slow startup indicator
1417         if(m_settings->slowStartup() && m_settings->antivirNotificationsEnabled())
1418         {
1419                 QString message;
1420                 message += NOBR(tr("It seems that a bogus anti-virus software is slowing down the startup of LameXP.")).append("<br>");
1421                 message += NOBR(tr("Please refer to the %1 document for details and solutions!")).arg("<a href=\"http://lamexp.sourceforge.net/doc/FAQ.html#df406578\">F.A.Q.</a>").append("<br>");
1422                 if(QMessageBox::warning(this, tr("Slow Startup"), message, tr("Discard"), tr("Don't Show Again")) == 1)
1423                 {
1424                         m_settings->antivirNotificationsEnabled(false);
1425                         ui->actionDisableSlowStartupNotifications->setChecked(!m_settings->antivirNotificationsEnabled());
1426                 }
1427         }
1428
1429         //Update reminder
1430         if(MUtils::OS::current_date() >= MUtils::Version::app_build_date().addYears(1))
1431         {
1432                 qWarning("Binary is more than a year old, time to update!");
1433                 SHOW_CORNER_WIDGET(true);
1434                 int ret = QMessageBox::warning(this, tr("Urgent Update"), NOBR(tr("Your version of LameXP is more than a year old. Time for an update!")), tr("Check for Updates"), tr("Exit Program"), tr("Ignore"));
1435                 switch(ret)
1436                 {
1437                 case 0:
1438                         if(checkForUpdates())
1439                         {
1440                                 QApplication::quit();
1441                                 return;
1442                         }
1443                         break;
1444                 case 1:
1445                         QApplication::quit();
1446                         return;
1447                 default:
1448                         QEventLoop loop; QTimer::singleShot(7000, &loop, SLOT(quit()));
1449                         MUtils::Sound::play_sound("waiting", true);
1450                         SHOW_BANNER_ARG(tr("Skipping update check this time, please be patient..."), &loop);
1451                         break;
1452                 }
1453         }
1454         else
1455         {
1456                 QDate lastUpdateCheck = QDate::fromString(m_settings->autoUpdateLastCheck(), Qt::ISODate);
1457                 if((!firstRun) && ((!lastUpdateCheck.isValid()) || (MUtils::OS::current_date() >= lastUpdateCheck.addDays(14))))
1458                 {
1459                         SHOW_CORNER_WIDGET(true);
1460                         if(m_settings->autoUpdateEnabled())
1461                         {
1462                                 if(QMessageBox::information(this, tr("Update Reminder"), NOBR(lastUpdateCheck.isValid() ? tr("Your last update check was more than 14 days ago. Check for updates now?") : tr("Your did not check for LameXP updates yet. Check for updates now?")), tr("Check for Updates"), tr("Postpone")) == 0)
1463                                 {
1464                                         if(checkForUpdates())
1465                                         {
1466                                                 QApplication::quit();
1467                                                 return;
1468                                         }
1469                                 }
1470                         }
1471                 }
1472         }
1473
1474         //Check for AAC support
1475         const int aacEncoder = EncoderRegistry::getAacEncoder();
1476         if(aacEncoder == SettingsModel::AAC_ENCODER_NERO)
1477         {
1478                 if(m_settings->neroAacNotificationsEnabled())
1479                 {
1480                         if(lamexp_tools_version("neroAacEnc.exe") < lamexp_toolver_neroaac())
1481                         {
1482                                 QString messageText;
1483                                 messageText += NOBR(tr("LameXP detected that your version of the Nero AAC encoder is outdated!")).append("<br>");
1484                                 messageText += NOBR(tr("The current version available is %1 (or later), but you still have version %2 installed.").arg(lamexp_version2string("?.?.?.?", lamexp_toolver_neroaac(), tr("n/a")), lamexp_version2string("?.?.?.?", lamexp_tools_version("neroAacEnc.exe"), tr("n/a")))).append("<br><br>");
1485                                 messageText += NOBR(tr("You can download the latest version of the Nero AAC encoder from the Nero website at:")).append("<br>");
1486                                 messageText += "<nobr><tt>" + LINK(AboutDialog::neroAacUrl) + "</tt></nobr><br><br>";
1487                                 messageText += NOBR(tr("(Hint: Please ignore the name of the downloaded ZIP file and check the included 'changelog.txt' instead!)")).append("<br>");
1488                                 QMessageBox::information(this, tr("AAC Encoder Outdated"), messageText);
1489                         }
1490                 }
1491         }
1492         else
1493         {
1494                 if(m_settings->neroAacNotificationsEnabled() && (aacEncoder <= SettingsModel::AAC_ENCODER_NONE))
1495                 {
1496                         QString appPath = QDir(QCoreApplication::applicationDirPath()).canonicalPath();
1497                         if(appPath.isEmpty()) appPath = QCoreApplication::applicationDirPath();
1498                         QString messageText;
1499                         messageText += NOBR(tr("The Nero AAC encoder could not be found. AAC encoding support will be disabled.")).append("<br>");
1500                         messageText += NOBR(tr("Please put 'neroAacEnc.exe', 'neroAacDec.exe' and 'neroAacTag.exe' into the LameXP directory!")).append("<br><br>");
1501                         messageText += NOBR(tr("Your LameXP directory is located here:")).append("<br>");
1502                         messageText += QString("<nobr><tt>%1</tt></nobr><br><br>").arg(FSLINK(QDir::toNativeSeparators(appPath)));
1503                         messageText += NOBR(tr("You can download the Nero AAC encoder for free from the official Nero website at:")).append("<br>");
1504                         messageText += "<nobr><tt>" + LINK(AboutDialog::neroAacUrl) + "</tt></nobr><br>";
1505                         if(QMessageBox::information(this, tr("AAC Support Disabled"), messageText, tr("Discard"), tr("Don't Show Again")) == 1)
1506                         {
1507                                 m_settings->neroAacNotificationsEnabled(false);
1508                                 ui->actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
1509                         }
1510                 }
1511         }
1512
1513         //Add files from the command-line
1514         QStringList addedFiles;
1515         foreach(const QString &value, arguments.values("add"))
1516         {
1517                 if(!value.isEmpty())
1518                 {
1519                         QFileInfo currentFile(value);
1520                         qDebug("Adding file from CLI: %s", MUTILS_UTF8(currentFile.absoluteFilePath()));
1521                         addedFiles.append(currentFile.absoluteFilePath());
1522                 }
1523         }
1524         if(!addedFiles.isEmpty())
1525         {
1526                 addFilesDelayed(addedFiles);
1527         }
1528
1529         //Add folders from the command-line
1530         foreach(const QString &value, arguments.values("add-folder"))
1531         {
1532                 if(!value.isEmpty())
1533                 {
1534                         const QFileInfo currentFile(value);
1535                         qDebug("Adding folder from CLI: %s", MUTILS_UTF8(currentFile.absoluteFilePath()));
1536                         addFolder(currentFile.absoluteFilePath(), false, true);
1537                 }
1538         }
1539         foreach(const QString &value, arguments.values("add-recursive"))
1540         {
1541                 if(!value.isEmpty())
1542                 {
1543                         const QFileInfo currentFile(value);
1544                         qDebug("Adding folder recursively from CLI: %s", MUTILS_UTF8(currentFile.absoluteFilePath()));
1545                         addFolder(currentFile.absoluteFilePath(), true, true);
1546                 }
1547         }
1548
1549         //Enable shell integration
1550         if(m_settings->shellIntegrationEnabled())
1551         {
1552                 ShellIntegration::install();
1553         }
1554
1555         //Make DropBox visible
1556         if(m_settings->dropBoxWidgetEnabled())
1557         {
1558                 m_dropBox->setVisible(true);
1559         }
1560 }
1561
1562 /*
1563  * Show announce box
1564  */
1565 void MainWindow::showAnnounceBox(void)
1566 {
1567         const unsigned int timeout = 8U;
1568
1569         const QString announceText = QString("%1<br><br>%2<br><nobr><tt>%3</tt></nobr><br>").arg
1570         (
1571                 NOBR("We are still looking for LameXP translators!"),
1572                 NOBR("If you are willing to translate LameXP to your language or to complete an existing translation, please refer to:"),
1573                 LINK("http://lamexp.sourceforge.net/doc/Translate.html")
1574         );
1575
1576         QMessageBox *announceBox = new QMessageBox(QMessageBox::Warning, "We want you!", announceText, QMessageBox::NoButton, this);
1577         announceBox->setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
1578         announceBox->setIconPixmap(QIcon(":/images/Announcement.png").pixmap(64,79));
1579         
1580         QTimer *timers[timeout+1];
1581         QPushButton *buttons[timeout+1];
1582
1583         for(unsigned int i = 0; i <= timeout; i++)
1584         {
1585                 QString text = (i > 0) ? QString("%1 (%2)").arg(tr("Discard"), QString::number(i)) : tr("Discard");
1586                 buttons[i] = announceBox->addButton(text, (i > 0) ? QMessageBox::NoRole : QMessageBox::AcceptRole);
1587         }
1588
1589         for(unsigned int i = 0; i <= timeout; i++)
1590         {
1591                 buttons[i]->setEnabled(i == 0);
1592                 buttons[i]->setVisible(i == timeout);
1593         }
1594
1595         for(unsigned int i = 0; i < timeout; i++)
1596         {
1597                 timers[i] = new QTimer(this);
1598                 timers[i]->setSingleShot(true);
1599                 timers[i]->setInterval(1000);
1600                 connect(timers[i], SIGNAL(timeout()), buttons[i+1], SLOT(hide()));
1601                 connect(timers[i], SIGNAL(timeout()), buttons[i], SLOT(show()));
1602                 if(i > 0)
1603                 {
1604                         connect(timers[i], SIGNAL(timeout()), timers[i-1], SLOT(start()));
1605                 }
1606         }
1607
1608         timers[timeout-1]->start();
1609         announceBox->exec();
1610
1611         for(unsigned int i = 0; i < timeout; i++)
1612         {
1613                 timers[i]->stop();
1614                 MUTILS_DELETE(timers[i]);
1615         }
1616
1617         MUTILS_DELETE(announceBox);
1618 }
1619
1620 // =========================================================
1621 // Main button solots
1622 // =========================================================
1623
1624 /*
1625  * Encode button
1626  */
1627 void MainWindow::encodeButtonClicked(void)
1628 {
1629         static const unsigned __int64 oneGigabyte = 1073741824ui64; 
1630         static const unsigned __int64 minimumFreeDiskspaceMultiplier = 2ui64;
1631         static const char *writeTestBuffer = "LAMEXP_WRITE_TEST";
1632         
1633         ABORT_IF_BUSY;
1634
1635         if(m_fileListModel->rowCount() < 1)
1636         {
1637                 QMessageBox::warning(this, tr("LameXP"), NOBR(tr("You must add at least one file to the list before proceeding!")));
1638                 ui->tabWidget->setCurrentIndex(0);
1639                 return;
1640         }
1641         
1642         QString tempFolder = m_settings->customTempPathEnabled() ? m_settings->customTempPath() : MUtils::temp_folder();
1643         if(!QFileInfo(tempFolder).exists() || !QFileInfo(tempFolder).isDir())
1644         {
1645                 if(QMessageBox::warning(this, tr("Not Found"), QString("%1<br><tt>%2</tt>").arg(NOBR(tr("Your currently selected TEMP folder does not exist anymore:")), NOBR(QDir::toNativeSeparators(tempFolder))), tr("Restore Default"), tr("Cancel")) == 0)
1646                 {
1647                         SET_CHECKBOX_STATE(ui->checkBoxUseSystemTempFolder, (!m_settings->customTempPathEnabledDefault()));
1648                 }
1649                 return;
1650         }
1651
1652         quint64 currentFreeDiskspace = 0;
1653         if(MUtils::OS::free_diskspace(tempFolder, currentFreeDiskspace))
1654         {
1655                 if(currentFreeDiskspace < (oneGigabyte * minimumFreeDiskspaceMultiplier))
1656                 {
1657                         QStringList tempFolderParts = tempFolder.split("/", QString::SkipEmptyParts, Qt::CaseInsensitive);
1658                         tempFolderParts.takeLast();
1659                         PLAY_SOUND_OPTIONAL("whammy", false);
1660                         QString lowDiskspaceMsg = QString("%1<br>%2<br><br>%3<br>%4<br>").arg
1661                         (
1662                                 NOBR(tr("There are less than %1 GB of free diskspace available on your system's TEMP folder.").arg(QString::number(minimumFreeDiskspaceMultiplier))),
1663                                 NOBR(tr("It is highly recommend to free up more diskspace before proceeding with the encode!")),
1664                                 NOBR(tr("Your TEMP folder is located at:")),
1665                                 QString("<nobr><tt>%1</tt></nobr>").arg(FSLINK(tempFolderParts.join("\\")))
1666                         );
1667                         switch(QMessageBox::warning(this, tr("Low Diskspace Warning"), lowDiskspaceMsg, tr("Abort Encoding Process"), tr("Clean Disk Now"), tr("Ignore")))
1668                         {
1669                         case 1:
1670                                 QProcess::startDetached(QString("%1/cleanmgr.exe").arg(MUtils::OS::known_folder(MUtils::OS::FOLDER_SYSTEMFOLDER)), QStringList() << "/D" << tempFolderParts.first());
1671                         case 0:
1672                                 return;
1673                                 break;
1674                         default:
1675                                 QMessageBox::warning(this, tr("Low Diskspace"), NOBR(tr("You are proceeding with low diskspace. Problems might occur!")));
1676                                 break;
1677                         }
1678                 }
1679         }
1680
1681         switch(m_settings->compressionEncoder())
1682         {
1683         case SettingsModel::MP3Encoder:
1684         case SettingsModel::VorbisEncoder:
1685         case SettingsModel::AACEncoder:
1686         case SettingsModel::AC3Encoder:
1687         case SettingsModel::FLACEncoder:
1688         case SettingsModel::OpusEncoder:
1689         case SettingsModel::DCAEncoder:
1690         case SettingsModel::MACEncoder:
1691         case SettingsModel::PCMEncoder:
1692                 break;
1693         default:
1694                 QMessageBox::warning(this, tr("LameXP"), tr("Sorry, an unsupported encoder has been chosen!"));
1695                 ui->tabWidget->setCurrentIndex(3);
1696                 return;
1697         }
1698
1699         if(!m_settings->outputToSourceDir())
1700         {
1701                 QFile writeTest(QString("%1/~%2.txt").arg(m_settings->outputDir(), MUtils::rand_str()));
1702                 if(!(writeTest.open(QIODevice::ReadWrite) && (writeTest.write(writeTestBuffer) == strlen(writeTestBuffer))))
1703                 {
1704                         QMessageBox::warning(this, tr("LameXP"), QString("%1<br><nobr>%2</nobr><br><br>%3").arg(tr("Cannot write to the selected output directory."), m_settings->outputDir(), tr("Please choose a different directory!")));
1705                         ui->tabWidget->setCurrentIndex(1);
1706                         return;
1707                 }
1708                 else
1709                 {
1710                         writeTest.close();
1711                         writeTest.remove();
1712                 }
1713         }
1714
1715         m_accepted = true;
1716         close();
1717 }
1718
1719 /*
1720  * About button
1721  */
1722 void MainWindow::aboutButtonClicked(void)
1723 {
1724         ABORT_IF_BUSY;
1725
1726         TEMP_HIDE_DROPBOX
1727         (
1728                 AboutDialog *aboutBox = new AboutDialog(m_settings, this);
1729                 aboutBox->exec();
1730                 MUTILS_DELETE(aboutBox);
1731         );
1732 }
1733
1734 /*
1735  * Close button
1736  */
1737 void MainWindow::closeButtonClicked(void)
1738 {
1739         ABORT_IF_BUSY;
1740         close();
1741 }
1742
1743 // =========================================================
1744 // Tab widget slots
1745 // =========================================================
1746
1747 /*
1748  * Tab page changed
1749  */
1750 void MainWindow::tabPageChanged(int idx, const bool silent)
1751 {
1752         resizeEvent(NULL);
1753         
1754         //Update "view" menu
1755         QList<QAction*> actions = m_tabActionGroup->actions();
1756         for(int i = 0; i < actions.count(); i++)
1757         {
1758                 bool ok = false;
1759                 int actionIndex = actions.at(i)->data().toInt(&ok);
1760                 if(ok && actionIndex == idx)
1761                 {
1762                         actions.at(i)->setChecked(true);
1763                 }
1764         }
1765
1766         //Play tick sound
1767         if(!silent)
1768         {
1769                 PLAY_SOUND_OPTIONAL("tick", true);
1770         }
1771
1772         int initialWidth = this->width();
1773         int maximumWidth = QApplication::desktop()->availableGeometry().width();
1774
1775         //Make sure all tab headers are fully visible
1776         if(this->isVisible())
1777         {
1778                 int delta = ui->tabWidget->sizeHint().width() - ui->tabWidget->width();
1779                 if(delta > 0)
1780                 {
1781                         this->resize(qMin(this->width() + delta, maximumWidth), this->height());
1782                 }
1783         }
1784
1785         //Tab specific operations
1786         if(idx == ui->tabWidget->indexOf(ui->tabOptions) && ui->scrollArea->widget() && this->isVisible())
1787         {
1788                 ui->scrollArea->widget()->updateGeometry();
1789                 ui->scrollArea->viewport()->updateGeometry();
1790                 qApp->processEvents();
1791                 int delta = ui->scrollArea->widget()->width() - ui->scrollArea->viewport()->width();
1792                 if(delta > 0)
1793                 {
1794                         this->resize(qMin(this->width() + delta, maximumWidth), this->height());
1795                 }
1796         }
1797         else if(idx == ui->tabWidget->indexOf(ui->tabSourceFiles))
1798         {
1799                 m_dropNoteLabel->setGeometry(0, 0, ui->sourceFileView->width(), ui->sourceFileView->height());
1800         }
1801         else if(idx == ui->tabWidget->indexOf(ui->tabOutputDir))
1802         {
1803                 if(!m_fileSystemModel)
1804                 {
1805                         QTimer::singleShot(125, this, SLOT(initOutputFolderModel()));
1806                 }
1807                 else
1808                 {
1809                         CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
1810                 }
1811         }
1812
1813         //Center window around previous position
1814         if(initialWidth < this->width())
1815         {
1816                 QPoint prevPos = this->pos();
1817                 int delta = (this->width() - initialWidth) >> 2;
1818                 move(prevPos.x() - delta, prevPos.y());
1819         }
1820 }
1821
1822 /*
1823  * Tab action triggered
1824  */
1825 void MainWindow::tabActionActivated(QAction *action)
1826 {
1827         if(action && action->data().isValid())
1828         {
1829                 bool ok = false;
1830                 int index = action->data().toInt(&ok);
1831                 if(ok)
1832                 {
1833                         ui->tabWidget->setCurrentIndex(index);
1834                 }
1835         }
1836 }
1837
1838 // =========================================================
1839 // Menubar slots
1840 // =========================================================
1841
1842 /*
1843  * Handle corner widget Event
1844  */
1845 void MainWindow::cornerWidgetEventOccurred(QWidget *sender, QEvent *event)
1846 {
1847         if(event->type() == QEvent::MouseButtonPress)
1848         {
1849                 QTimer::singleShot(0, this, SLOT(checkUpdatesActionActivated()));
1850         }
1851 }
1852
1853 // =========================================================
1854 // View menu slots
1855 // =========================================================
1856
1857 /*
1858  * Style action triggered
1859  */
1860 void MainWindow::styleActionActivated(QAction *action)
1861 {
1862         //Change style setting
1863         if(action && action->data().isValid())
1864         {
1865                 bool ok = false;
1866                 int actionIndex = action->data().toInt(&ok);
1867                 if(ok)
1868                 {
1869                         m_settings->interfaceStyle(actionIndex);
1870                 }
1871         }
1872
1873         //Set up the new style
1874         switch(m_settings->interfaceStyle())
1875         {
1876         case 1:
1877                 if(ui->actionStyleCleanlooks->isEnabled())
1878                 {
1879                         ui->actionStyleCleanlooks->setChecked(true);
1880                         QApplication::setStyle(new QCleanlooksStyle());
1881                         break;
1882                 }
1883         case 2:
1884                 if(ui->actionStyleWindowsVista->isEnabled())
1885                 {
1886                         ui->actionStyleWindowsVista->setChecked(true);
1887                         QApplication::setStyle(new QWindowsVistaStyle());
1888                         break;
1889                 }
1890         case 3:
1891                 if(ui->actionStyleWindowsXP->isEnabled())
1892                 {
1893                         ui->actionStyleWindowsXP->setChecked(true);
1894                         QApplication::setStyle(new QWindowsXPStyle());
1895                         break;
1896                 }
1897         case 4:
1898                 if(ui->actionStyleWindowsClassic->isEnabled())
1899                 {
1900                         ui->actionStyleWindowsClassic->setChecked(true);
1901                         QApplication::setStyle(new QWindowsStyle());
1902                         break;
1903                 }
1904         default:
1905                 ui->actionStylePlastique->setChecked(true);
1906                 QApplication::setStyle(new QPlastiqueStyle());
1907                 break;
1908         }
1909
1910         //Force re-translate after style change
1911         if(QEvent *e = new QEvent(QEvent::LanguageChange))
1912         {
1913                 changeEvent(e);
1914                 MUTILS_DELETE(e);
1915         }
1916
1917         //Make transparent
1918         const type_info &styleType = typeid(*qApp->style());
1919         const bool bTransparent = ((typeid(QWindowsVistaStyle) == styleType) || (typeid(QWindowsXPStyle) == styleType));
1920         MAKE_TRANSPARENT(ui->scrollArea, bTransparent);
1921
1922         //Also force a re-size event
1923         QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1924         resizeEvent(NULL);
1925 }
1926
1927 /*
1928  * Language action triggered
1929  */
1930 void MainWindow::languageActionActivated(QAction *action)
1931 {
1932         if(action->data().type() == QVariant::String)
1933         {
1934                 QString langId = action->data().toString();
1935
1936                 if(MUtils::Translation::install_translator(langId))
1937                 {
1938                         action->setChecked(true);
1939                         ui->actionLoadTranslationFromFile->setChecked(false);
1940                         m_settings->currentLanguage(langId);
1941                         m_settings->currentLanguageFile(QString());
1942                 }
1943         }
1944 }
1945
1946 /*
1947  * Load language from file action triggered
1948  */
1949 void MainWindow::languageFromFileActionActivated(bool checked)
1950 {
1951         QFileDialog dialog(this, tr("Load Translation"));
1952         dialog.setFileMode(QFileDialog::ExistingFile);
1953         dialog.setNameFilter(QString("%1 (*.qm)").arg(tr("Translation Files")));
1954
1955         if(dialog.exec())
1956         {
1957                 QStringList selectedFiles = dialog.selectedFiles();
1958                 const QString qmFile = QFileInfo(selectedFiles.first()).canonicalFilePath();
1959                 if(MUtils::Translation::install_translator_from_file(qmFile))
1960                 {
1961                         QList<QAction*> actions = m_languageActionGroup->actions();
1962                         while(!actions.isEmpty())
1963                         {
1964                                 actions.takeFirst()->setChecked(false);
1965                         }
1966                         ui->actionLoadTranslationFromFile->setChecked(true);
1967                         m_settings->currentLanguageFile(qmFile);
1968                 }
1969                 else
1970                 {
1971                         languageActionActivated(m_languageActionGroup->actions().first());
1972                 }
1973         }
1974 }
1975
1976 // =========================================================
1977 // Tools menu slots
1978 // =========================================================
1979
1980 /*
1981  * Disable update reminder action
1982  */
1983 void MainWindow::disableUpdateReminderActionTriggered(bool checked)
1984 {
1985         if(checked)
1986         {
1987                 if(0 == QMessageBox::question(this, tr("Disable Update Reminder"), NOBR(tr("Do you really want to disable the update reminder?")), tr("Yes"), tr("No"), QString(), 1))
1988                 {
1989                         QMessageBox::information(this, tr("Update Reminder"), QString("%1<br>%2").arg(NOBR(tr("The update reminder has been disabled.")), NOBR(tr("Please remember to check for updates at regular intervals!"))));
1990                         m_settings->autoUpdateEnabled(false);
1991                 }
1992                 else
1993                 {
1994                         m_settings->autoUpdateEnabled(true);
1995                 }
1996         }
1997         else
1998         {
1999                         QMessageBox::information(this, tr("Update Reminder"), NOBR(tr("The update reminder has been re-enabled.")));
2000                         m_settings->autoUpdateEnabled(true);
2001         }
2002
2003         ui->actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
2004 }
2005
2006 /*
2007  * Disable sound effects action
2008  */
2009 void MainWindow::disableSoundsActionTriggered(bool checked)
2010 {
2011         if(checked)
2012         {
2013                 if(0 == QMessageBox::question(this, tr("Disable Sound Effects"), NOBR(tr("Do you really want to disable all sound effects?")), tr("Yes"), tr("No"), QString(), 1))
2014                 {
2015                         QMessageBox::information(this, tr("Sound Effects"), NOBR(tr("All sound effects have been disabled.")));
2016                         m_settings->soundsEnabled(false);
2017                 }
2018                 else
2019                 {
2020                         m_settings->soundsEnabled(true);
2021                 }
2022         }
2023         else
2024         {
2025                         QMessageBox::information(this, tr("Sound Effects"), NOBR(tr("The sound effects have been re-enabled.")));
2026                         m_settings->soundsEnabled(true);
2027         }
2028
2029         ui->actionDisableSounds->setChecked(!m_settings->soundsEnabled());
2030 }
2031
2032 /*
2033  * Disable Nero AAC encoder action
2034  */
2035 void MainWindow::disableNeroAacNotificationsActionTriggered(bool checked)
2036 {
2037         if(checked)
2038         {
2039                 if(0 == QMessageBox::question(this, tr("Nero AAC Notifications"), NOBR(tr("Do you really want to disable all Nero AAC Encoder notifications?")), tr("Yes"), tr("No"), QString(), 1))
2040                 {
2041                         QMessageBox::information(this, tr("Nero AAC Notifications"), NOBR(tr("All Nero AAC Encoder notifications have been disabled.")));
2042                         m_settings->neroAacNotificationsEnabled(false);
2043                 }
2044                 else
2045                 {
2046                         m_settings->neroAacNotificationsEnabled(true);
2047                 }
2048         }
2049         else
2050         {
2051                         QMessageBox::information(this, tr("Nero AAC Notifications"), NOBR(tr("The Nero AAC Encoder notifications have been re-enabled.")));
2052                         m_settings->neroAacNotificationsEnabled(true);
2053         }
2054
2055         ui->actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
2056 }
2057
2058 /*
2059  * Disable slow startup action
2060  */
2061 void MainWindow::disableSlowStartupNotificationsActionTriggered(bool checked)
2062 {
2063         if(checked)
2064         {
2065                 if(0 == QMessageBox::question(this, tr("Slow Startup Notifications"), NOBR(tr("Do you really want to disable the slow startup notifications?")), tr("Yes"), tr("No"), QString(), 1))
2066                 {
2067                         QMessageBox::information(this, tr("Slow Startup Notifications"), NOBR(tr("The slow startup notifications have been disabled.")));
2068                         m_settings->antivirNotificationsEnabled(false);
2069                 }
2070                 else
2071                 {
2072                         m_settings->antivirNotificationsEnabled(true);
2073                 }
2074         }
2075         else
2076         {
2077                         QMessageBox::information(this, tr("Slow Startup Notifications"), NOBR(tr("The slow startup notifications have been re-enabled.")));
2078                         m_settings->antivirNotificationsEnabled(true);
2079         }
2080
2081         ui->actionDisableSlowStartupNotifications->setChecked(!m_settings->antivirNotificationsEnabled());
2082 }
2083
2084 /*
2085  * Import a Cue Sheet file
2086  */
2087 void MainWindow::importCueSheetActionTriggered(bool checked)
2088 {
2089         ABORT_IF_BUSY;
2090         
2091         TEMP_HIDE_DROPBOX
2092         (
2093                 while(true)
2094                 {
2095                         int result = 0;
2096                         QString selectedCueFile;
2097
2098                         if(MUtils::GUI::themes_enabled())
2099                         {
2100                                 selectedCueFile = QFileDialog::getOpenFileName(this, tr("Open Cue Sheet"), m_settings->mostRecentInputPath(), QString("%1 (*.cue)").arg(tr("Cue Sheet File")));
2101                         }
2102                         else
2103                         {
2104                                 QFileDialog dialog(this, tr("Open Cue Sheet"));
2105                                 dialog.setFileMode(QFileDialog::ExistingFile);
2106                                 dialog.setNameFilter(QString("%1 (*.cue)").arg(tr("Cue Sheet File")));
2107                                 dialog.setDirectory(m_settings->mostRecentInputPath());
2108                                 if(dialog.exec())
2109                                 {
2110                                         selectedCueFile = dialog.selectedFiles().first();
2111                                 }
2112                         }
2113
2114                         if(!selectedCueFile.isEmpty())
2115                         {
2116                                 m_settings->mostRecentInputPath(QFileInfo(selectedCueFile).canonicalPath());
2117                                 CueImportDialog *cueImporter  = new CueImportDialog(this, m_fileListModel, selectedCueFile, m_settings);
2118                                 result = cueImporter->exec();
2119                                 MUTILS_DELETE(cueImporter);
2120                         }
2121
2122                         if(result == QDialog::Accepted)
2123                         {
2124                                 qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
2125                                 ui->sourceFileView->update();
2126                                 qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
2127                                 ui->sourceFileView->scrollToBottom();
2128                                 qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
2129                         }
2130
2131                         if(result != (-1)) break;
2132                 }
2133         );
2134 }
2135
2136 /*
2137  * Show the "drop box" widget
2138  */
2139 void MainWindow::showDropBoxWidgetActionTriggered(bool checked)
2140 {
2141         m_settings->dropBoxWidgetEnabled(true);
2142         
2143         if(!m_dropBox->isVisible())
2144         {
2145                 m_dropBox->show();
2146                 QTimer::singleShot(2500, m_dropBox, SLOT(showToolTip()));
2147         }
2148         
2149         MUtils::GUI::blink_window(m_dropBox);
2150 }
2151
2152 /*
2153  * Check for beta (pre-release) updates
2154  */
2155 void MainWindow::checkForBetaUpdatesActionTriggered(bool checked)
2156 {       
2157         bool checkUpdatesNow = false;
2158         
2159         if(checked)
2160         {
2161                 if(0 == QMessageBox::question(this, tr("Beta Updates"), NOBR(tr("Do you really want LameXP to check for Beta (pre-release) updates?")), tr("Yes"), tr("No"), QString(), 1))
2162                 {
2163                         if(0 == QMessageBox::information(this, tr("Beta Updates"), NOBR(tr("LameXP will check for Beta (pre-release) updates from now on.")), tr("Check Now"), tr("Discard")))
2164                         {
2165                                 checkUpdatesNow = true;
2166                         }
2167                         m_settings->autoUpdateCheckBeta(true);
2168                 }
2169                 else
2170                 {
2171                         m_settings->autoUpdateCheckBeta(false);
2172                 }
2173         }
2174         else
2175         {
2176                         QMessageBox::information(this, tr("Beta Updates"), NOBR(tr("LameXP will <i>not</i> check for Beta (pre-release) updates from now on.")));
2177                         m_settings->autoUpdateCheckBeta(false);
2178         }
2179
2180         ui->actionCheckForBetaUpdates->setChecked(m_settings->autoUpdateCheckBeta());
2181
2182         if(checkUpdatesNow)
2183         {
2184                 if(checkForUpdates())
2185                 {
2186                         QApplication::quit();
2187                 }
2188         }
2189 }
2190
2191 /*
2192  * Hibernate computer action
2193  */
2194 void MainWindow::hibernateComputerActionTriggered(bool checked)
2195 {
2196         if(checked)
2197         {
2198                 if(0 == QMessageBox::question(this, tr("Hibernate Computer"), NOBR(tr("Do you really want the computer to be hibernated on shutdown?")), tr("Yes"), tr("No"), QString(), 1))
2199                 {
2200                         QMessageBox::information(this, tr("Hibernate Computer"), NOBR(tr("LameXP will hibernate the computer on shutdown from now on.")));
2201                         m_settings->hibernateComputer(true);
2202                 }
2203                 else
2204                 {
2205                         m_settings->hibernateComputer(false);
2206                 }
2207         }
2208         else
2209         {
2210                         QMessageBox::information(this, tr("Hibernate Computer"), NOBR(tr("LameXP will <i>not</i> hibernate the computer on shutdown from now on.")));
2211                         m_settings->hibernateComputer(false);
2212         }
2213
2214         ui->actionHibernateComputer->setChecked(m_settings->hibernateComputer());
2215 }
2216
2217 /*
2218  * Disable shell integration action
2219  */
2220 void MainWindow::disableShellIntegrationActionTriggered(bool checked)
2221 {
2222         if(checked)
2223         {
2224                 if(0 == QMessageBox::question(this, tr("Shell Integration"), NOBR(tr("Do you really want to disable the LameXP shell integration?")), tr("Yes"), tr("No"), QString(), 1))
2225                 {
2226                         ShellIntegration::remove();
2227                         QMessageBox::information(this, tr("Shell Integration"), NOBR(tr("The LameXP shell integration has been disabled.")));
2228                         m_settings->shellIntegrationEnabled(false);
2229                 }
2230                 else
2231                 {
2232                         m_settings->shellIntegrationEnabled(true);
2233                 }
2234         }
2235         else
2236         {
2237                         ShellIntegration::install();
2238                         QMessageBox::information(this, tr("Shell Integration"), NOBR(tr("The LameXP shell integration has been re-enabled.")));
2239                         m_settings->shellIntegrationEnabled(true);
2240         }
2241
2242         ui->actionDisableShellIntegration->setChecked(!m_settings->shellIntegrationEnabled());
2243         
2244         if(lamexp_version_portable() && ui->actionDisableShellIntegration->isChecked())
2245         {
2246                 ui->actionDisableShellIntegration->setEnabled(false);
2247         }
2248 }
2249
2250 // =========================================================
2251 // Help menu slots
2252 // =========================================================
2253
2254 /*
2255  * Visit homepage action
2256  */
2257 void MainWindow::visitHomepageActionActivated(void)
2258 {
2259         if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
2260         {
2261                 if(action->data().isValid() && (action->data().type() == QVariant::String))
2262                 {
2263                         QDesktopServices::openUrl(QUrl(action->data().toString()));
2264                 }
2265         }
2266 }
2267
2268 /*
2269  * Show document
2270  */
2271 void MainWindow::documentActionActivated(void)
2272 {
2273         if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
2274         {
2275                 openDocumentLink(action);
2276         }
2277 }
2278
2279 /*
2280  * Check for updates action
2281  */
2282 void MainWindow::checkUpdatesActionActivated(void)
2283 {
2284         ABORT_IF_BUSY;
2285         bool bFlag = false;
2286
2287         TEMP_HIDE_DROPBOX
2288         (
2289                 bFlag = checkForUpdates();
2290         );
2291         
2292         if(bFlag)
2293         {
2294                 QApplication::quit();
2295         }
2296 }
2297
2298 // =========================================================
2299 // Source file slots
2300 // =========================================================
2301
2302 /*
2303  * Add file(s) button
2304  */
2305 void MainWindow::addFilesButtonClicked(void)
2306 {
2307         ABORT_IF_BUSY;
2308
2309         TEMP_HIDE_DROPBOX
2310         (
2311                 if(MUtils::GUI::themes_enabled())
2312                 {
2313                         QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
2314                         QStringList selectedFiles = QFileDialog::getOpenFileNames(this, tr("Add file(s)"), m_settings->mostRecentInputPath(), fileTypeFilters.join(";;"));
2315                         if(!selectedFiles.isEmpty())
2316                         {
2317                                 m_settings->mostRecentInputPath(QFileInfo(selectedFiles.first()).canonicalPath());
2318                                 addFiles(selectedFiles);
2319                         }
2320                 }
2321                 else
2322                 {
2323                         QFileDialog dialog(this, tr("Add file(s)"));
2324                         QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
2325                         dialog.setFileMode(QFileDialog::ExistingFiles);
2326                         dialog.setNameFilter(fileTypeFilters.join(";;"));
2327                         dialog.setDirectory(m_settings->mostRecentInputPath());
2328                         if(dialog.exec())
2329                         {
2330                                 QStringList selectedFiles = dialog.selectedFiles();
2331                                 if(!selectedFiles.isEmpty())
2332                                 {
2333                                         m_settings->mostRecentInputPath(QFileInfo(selectedFiles.first()).canonicalPath());
2334                                         addFiles(selectedFiles);
2335                                 }
2336                         }
2337                 }
2338         );
2339 }
2340
2341 /*
2342  * Open folder action
2343  */
2344 void MainWindow::openFolderActionActivated(void)
2345 {
2346         ABORT_IF_BUSY;
2347         QString selectedFolder;
2348         
2349         if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
2350         {
2351                 TEMP_HIDE_DROPBOX
2352                 (
2353                         if(MUtils::GUI::themes_enabled())
2354                         {
2355                                 selectedFolder = QFileDialog::getExistingDirectory(this, tr("Add Folder"), m_settings->mostRecentInputPath());
2356                         }
2357                         else
2358                         {
2359                                 QFileDialog dialog(this, tr("Add Folder"));
2360                                 dialog.setFileMode(QFileDialog::DirectoryOnly);
2361                                 dialog.setDirectory(m_settings->mostRecentInputPath());
2362                                 if(dialog.exec())
2363                                 {
2364                                         selectedFolder = dialog.selectedFiles().first();
2365                                 }
2366                         }
2367                         
2368                         if(!selectedFolder.isEmpty())
2369                         {
2370                                 m_settings->mostRecentInputPath(QDir(selectedFolder).canonicalPath());
2371                                 addFolder(selectedFolder, action->data().toBool());
2372                         }
2373                 );
2374         }
2375 }
2376
2377 /*
2378  * Remove file button
2379  */
2380 void MainWindow::removeFileButtonClicked(void)
2381 {
2382         if(ui->sourceFileView->currentIndex().isValid())
2383         {
2384                 int iRow = ui->sourceFileView->currentIndex().row();
2385                 m_fileListModel->removeFile(ui->sourceFileView->currentIndex());
2386                 ui->sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
2387         }
2388 }
2389
2390 /*
2391  * Clear files button
2392  */
2393 void MainWindow::clearFilesButtonClicked(void)
2394 {
2395         m_fileListModel->clearFiles();
2396 }
2397
2398 /*
2399  * Move file up button
2400  */
2401 void MainWindow::fileUpButtonClicked(void)
2402 {
2403         if(ui->sourceFileView->currentIndex().isValid())
2404         {
2405                 int iRow = ui->sourceFileView->currentIndex().row() - 1;
2406                 m_fileListModel->moveFile(ui->sourceFileView->currentIndex(), -1);
2407                 ui->sourceFileView->selectRow(iRow >= 0 ? iRow : 0);
2408         }
2409 }
2410
2411 /*
2412  * Move file down button
2413  */
2414 void MainWindow::fileDownButtonClicked(void)
2415 {
2416         if(ui->sourceFileView->currentIndex().isValid())
2417         {
2418                 int iRow = ui->sourceFileView->currentIndex().row() + 1;
2419                 m_fileListModel->moveFile(ui->sourceFileView->currentIndex(), 1);
2420                 ui->sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
2421         }
2422 }
2423
2424 /*
2425  * Show details button
2426  */
2427 void MainWindow::showDetailsButtonClicked(void)
2428 {
2429         ABORT_IF_BUSY;
2430
2431         int iResult = 0;
2432         MetaInfoDialog *metaInfoDialog = new MetaInfoDialog(this);
2433         QModelIndex index = ui->sourceFileView->currentIndex();
2434
2435         while(index.isValid())
2436         {
2437                 if(iResult > 0)
2438                 {
2439                         index = m_fileListModel->index(index.row() + 1, index.column()); 
2440                         ui->sourceFileView->selectRow(index.row());
2441                 }
2442                 if(iResult < 0)
2443                 {
2444                         index = m_fileListModel->index(index.row() - 1, index.column()); 
2445                         ui->sourceFileView->selectRow(index.row());
2446                 }
2447
2448                 AudioFileModel &file = (*m_fileListModel)[index];
2449                 TEMP_HIDE_DROPBOX
2450                 (
2451                         iResult = metaInfoDialog->exec(file, index.row() > 0, index.row() < m_fileListModel->rowCount() - 1);
2452                 );
2453                 
2454                 //Copy all info to Meta Info tab
2455                 if(iResult == INT_MAX)
2456                 {
2457                         m_metaInfoModel->assignInfoFrom(file);
2458                         ui->tabWidget->setCurrentIndex(ui->tabWidget->indexOf(ui->tabMetaData));
2459                         break;
2460                 }
2461
2462                 if(!iResult) break;
2463         }
2464
2465         MUTILS_DELETE(metaInfoDialog);
2466         QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2467         sourceFilesScrollbarMoved(0);
2468 }
2469
2470 /*
2471  * Show context menu for source files
2472  */
2473 void MainWindow::sourceFilesContextMenu(const QPoint &pos)
2474 {
2475         QAbstractScrollArea *scrollArea = dynamic_cast<QAbstractScrollArea*>(QObject::sender());
2476         QWidget *sender = scrollArea ? scrollArea->viewport() : dynamic_cast<QWidget*>(QObject::sender());
2477
2478         if(sender)
2479         {
2480                 if(pos.x() <= sender->width() && pos.y() <= sender->height() && pos.x() >= 0 && pos.y() >= 0)
2481                 {
2482                         m_sourceFilesContextMenu->popup(sender->mapToGlobal(pos));
2483                 }
2484         }
2485 }
2486
2487 /*
2488  * Scrollbar of source files moved
2489  */
2490 void MainWindow::sourceFilesScrollbarMoved(int)
2491 {
2492         ui->sourceFileView->resizeColumnToContents(0);
2493 }
2494
2495 /*
2496  * Open selected file in external player
2497  */
2498 void MainWindow::previewContextActionTriggered(void)
2499 {
2500         QModelIndex index = ui->sourceFileView->currentIndex();
2501         if(!index.isValid())
2502         {
2503                 return;
2504         }
2505
2506         if(!MUtils::OS::open_media_file(m_fileListModel->getFile(index).filePath()))
2507         {
2508                 qDebug("Player not found, falling back to default application...");
2509                 QDesktopServices::openUrl(QString("file:///").append(m_fileListModel->getFile(index).filePath()));
2510         }
2511 }
2512
2513 /*
2514  * Find selected file in explorer
2515  */
2516 void MainWindow::findFileContextActionTriggered(void)
2517 {
2518         QModelIndex index = ui->sourceFileView->currentIndex();
2519         if(index.isValid())
2520         {
2521                 QString systemRootPath;
2522
2523                 QDir systemRoot(MUtils::OS::known_folder(MUtils::OS::FOLDER_SYSTEMFOLDER));
2524                 if(systemRoot.exists() && systemRoot.cdUp())
2525                 {
2526                         systemRootPath = systemRoot.canonicalPath();
2527                 }
2528
2529                 if(!systemRootPath.isEmpty())
2530                 {
2531                         QFileInfo explorer(QString("%1/explorer.exe").arg(systemRootPath));
2532                         if(explorer.exists() && explorer.isFile())
2533                         {
2534                                 QProcess::execute(explorer.canonicalFilePath(), QStringList() << "/select," << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
2535                                 return;
2536                         }
2537                 }
2538                 else
2539                 {
2540                         qWarning("SystemRoot directory could not be detected!");
2541                 }
2542         }
2543 }
2544
2545 /*
2546  * Add all dropped files
2547  */
2548 void MainWindow::handleDroppedFiles(void)
2549 {
2550         ABORT_IF_BUSY;
2551
2552         static const int MIN_COUNT = 16;
2553         const QString bannerText = tr("Loading dropped files or folders, please wait...");
2554         bool bUseBanner = false;
2555
2556         SHOW_BANNER_CONDITIONALLY(bUseBanner, (m_droppedFileList->count() >= MIN_COUNT), bannerText);
2557
2558         QStringList droppedFiles;
2559         while(!m_droppedFileList->isEmpty())
2560         {
2561                 QFileInfo file(m_droppedFileList->takeFirst().toLocalFile());
2562                 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2563
2564                 if(!file.exists())
2565                 {
2566                         continue;
2567                 }
2568
2569                 if(file.isFile())
2570                 {
2571                         qDebug("Dropped File: %s", MUTILS_UTF8(file.canonicalFilePath()));
2572                         droppedFiles << file.canonicalFilePath();
2573                         continue;
2574                 }
2575
2576                 if(file.isDir())
2577                 {
2578                         qDebug("Dropped Folder: %s", MUTILS_UTF8(file.canonicalFilePath()));
2579                         QFileInfoList list = QDir(file.canonicalFilePath()).entryInfoList(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
2580                         if(list.count() > 0)
2581                         {
2582                                 SHOW_BANNER_CONDITIONALLY(bUseBanner, (list.count() >= MIN_COUNT), bannerText);
2583                                 for(QFileInfoList::ConstIterator iter = list.constBegin(); iter != list.constEnd(); iter++)
2584                                 {
2585                                         droppedFiles << (*iter).canonicalFilePath();
2586                                 }
2587                         }
2588                         else
2589                         {
2590                                 list = QDir(file.canonicalFilePath()).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
2591                                 SHOW_BANNER_CONDITIONALLY(bUseBanner, (list.count() >= MIN_COUNT), bannerText);
2592                                 for(QFileInfoList::ConstIterator iter = list.constBegin(); iter != list.constEnd(); iter++)
2593                                 {
2594                                         qDebug("Descending to Folder: %s", MUTILS_UTF8((*iter).canonicalFilePath()));
2595                                         m_droppedFileList->prepend(QUrl::fromLocalFile((*iter).canonicalFilePath()));
2596                                 }
2597                         }
2598                 }
2599         }
2600         
2601         if(bUseBanner)
2602         {
2603                 m_banner->close();
2604         }
2605
2606         if(!droppedFiles.isEmpty())
2607         {
2608                 addFiles(droppedFiles);
2609         }
2610 }
2611
2612 /*
2613  * Add all pending files
2614  */
2615 void MainWindow::handleDelayedFiles(void)
2616 {
2617         m_delayedFileTimer->stop();
2618
2619         if(m_delayedFileList->isEmpty())
2620         {
2621                 return;
2622         }
2623
2624         if(BANNER_VISIBLE)
2625         {
2626                 m_delayedFileTimer->start(5000);
2627                 return;
2628         }
2629         
2630         WITH_BLOCKED_SIGNALS(ui->tabWidget, setCurrentIndex, 0);
2631         tabPageChanged(ui->tabWidget->currentIndex(), true);
2632         
2633         QStringList selectedFiles;
2634         while(!m_delayedFileList->isEmpty())
2635         {
2636                 QFileInfo currentFile = QFileInfo(m_delayedFileList->takeFirst());
2637                 if(!currentFile.exists() || !currentFile.isFile())
2638                 {
2639                         continue;
2640                 }
2641                 selectedFiles << currentFile.canonicalFilePath();
2642         }
2643         
2644         addFiles(selectedFiles);
2645 }
2646
2647 /*
2648  * Export Meta tags to CSV file
2649  */
2650 void MainWindow::exportCsvContextActionTriggered(void)
2651 {
2652         TEMP_HIDE_DROPBOX
2653         (
2654                 QString selectedCsvFile;
2655         
2656                 if(MUtils::GUI::themes_enabled())
2657                 {
2658                         selectedCsvFile = QFileDialog::getSaveFileName(this, tr("Save CSV file"), m_settings->mostRecentInputPath(), QString("%1 (*.csv)").arg(tr("CSV File")));
2659                 }
2660                 else
2661                 {
2662                         QFileDialog dialog(this, tr("Save CSV file"));
2663                         dialog.setFileMode(QFileDialog::AnyFile);
2664                         dialog.setAcceptMode(QFileDialog::AcceptSave);
2665                         dialog.setNameFilter(QString("%1 (*.csv)").arg(tr("CSV File")));
2666                         dialog.setDirectory(m_settings->mostRecentInputPath());
2667                         if(dialog.exec())
2668                         {
2669                                 selectedCsvFile = dialog.selectedFiles().first();
2670                         }
2671                 }
2672
2673                 if(!selectedCsvFile.isEmpty())
2674                 {
2675                         m_settings->mostRecentInputPath(QFileInfo(selectedCsvFile).canonicalPath());
2676                         switch(m_fileListModel->exportToCsv(selectedCsvFile))
2677                         {
2678                         case FileListModel::CsvError_NoTags:
2679                                 QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, there are no meta tags that can be exported!")));
2680                                 break;
2681                         case FileListModel::CsvError_FileOpen:
2682                                 QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, failed to open CSV file for writing!")));
2683                                 break;
2684                         case FileListModel::CsvError_FileWrite:
2685                                 QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, failed to write to the CSV file!")));
2686                                 break;
2687                         case FileListModel::CsvError_OK:
2688                                 QMessageBox::information(this, tr("CSV Export"), NOBR(tr("The CSV files was created successfully!")));
2689                                 break;
2690                         default:
2691                                 qWarning("exportToCsv: Unknown return code!");
2692                         }
2693                 }
2694         );
2695 }
2696
2697
2698 /*
2699  * Import Meta tags from CSV file
2700  */
2701 void MainWindow::importCsvContextActionTriggered(void)
2702 {
2703         TEMP_HIDE_DROPBOX
2704         (
2705                 QString selectedCsvFile;
2706         
2707                 if(MUtils::GUI::themes_enabled())
2708                 {
2709                         selectedCsvFile = QFileDialog::getOpenFileName(this, tr("Open CSV file"), m_settings->mostRecentInputPath(), QString("%1 (*.csv)").arg(tr("CSV File")));
2710                 }
2711                 else
2712                 {
2713                         QFileDialog dialog(this, tr("Open CSV file"));
2714                         dialog.setFileMode(QFileDialog::ExistingFile);
2715                         dialog.setNameFilter(QString("%1 (*.csv)").arg(tr("CSV File")));
2716                         dialog.setDirectory(m_settings->mostRecentInputPath());
2717                         if(dialog.exec())
2718                         {
2719                                 selectedCsvFile = dialog.selectedFiles().first();
2720                         }
2721                 }
2722
2723                 if(!selectedCsvFile.isEmpty())
2724                 {
2725                         m_settings->mostRecentInputPath(QFileInfo(selectedCsvFile).canonicalPath());
2726                         switch(m_fileListModel->importFromCsv(this, selectedCsvFile))
2727                         {
2728                         case FileListModel::CsvError_FileOpen:
2729                                 QMessageBox::critical(this, tr("CSV Import"), NOBR(tr("Sorry, failed to open CSV file for reading!")));
2730                                 break;
2731                         case FileListModel::CsvError_FileRead:
2732                                 QMessageBox::critical(this, tr("CSV Import"), NOBR(tr("Sorry, failed to read from the CSV file!")));
2733                                 break;
2734                         case FileListModel::CsvError_NoTags:
2735                                 QMessageBox::critical(this, tr("CSV Import"), NOBR(tr("Sorry, the CSV file does not contain any known fields!")));
2736                                 break;
2737                         case FileListModel::CsvError_Incomplete:
2738                                 QMessageBox::warning(this, tr("CSV Import"), NOBR(tr("CSV file is incomplete. Not all files were updated!")));
2739                                 break;
2740                         case FileListModel::CsvError_OK:
2741                                 QMessageBox::information(this, tr("CSV Import"), NOBR(tr("The CSV files was imported successfully!")));
2742                                 break;
2743                         case FileListModel::CsvError_Aborted:
2744                                 /* User aborted, ignore! */
2745                                 break;
2746                         default:
2747                                 qWarning("exportToCsv: Unknown return code!");
2748                         }
2749                 }
2750         );
2751 }
2752
2753 /*
2754  * Show or hide Drag'n'Drop notice after model reset
2755  */
2756 void MainWindow::sourceModelChanged(void)
2757 {
2758         m_dropNoteLabel->setVisible(m_fileListModel->rowCount() <= 0);
2759 }
2760
2761 // =========================================================
2762 // Output folder slots
2763 // =========================================================
2764
2765 /*
2766  * Output folder changed (mouse clicked)
2767  */
2768 void MainWindow::outputFolderViewClicked(const QModelIndex &index)
2769 {
2770         if(index.isValid() && (ui->outputFolderView->currentIndex() != index))
2771         {
2772                 ui->outputFolderView->setCurrentIndex(index);
2773         }
2774         
2775         if(m_fileSystemModel && index.isValid())
2776         {
2777                 QString selectedDir = m_fileSystemModel->filePath(index);
2778                 if(selectedDir.length() < 3) selectedDir.append(QDir::separator());
2779                 ui->outputFolderLabel->setText(QDir::toNativeSeparators(selectedDir));
2780                 ui->outputFolderLabel->setToolTip(ui->outputFolderLabel->text());
2781                 m_settings->outputDir(selectedDir);
2782         }
2783         else
2784         {
2785                 ui->outputFolderLabel->setText(QDir::toNativeSeparators(m_settings->outputDir()));
2786                 ui->outputFolderLabel->setToolTip(ui->outputFolderLabel->text());
2787         }
2788 }
2789
2790 /*
2791  * Output folder changed (mouse moved)
2792  */
2793 void MainWindow::outputFolderViewMoved(const QModelIndex &index)
2794 {
2795         if(QApplication::mouseButtons() & Qt::LeftButton)
2796         {
2797                 outputFolderViewClicked(index);
2798         }
2799 }
2800
2801 /*
2802  * Goto desktop button
2803  */
2804 void MainWindow::gotoDesktopButtonClicked(void)
2805 {
2806         if(!m_fileSystemModel)
2807         {
2808                 qWarning("File system model not initialized yet!");
2809                 return;
2810         }
2811         
2812         QString desktopPath = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
2813         
2814         if(!desktopPath.isEmpty() && QDir(desktopPath).exists())
2815         {
2816                 ui->outputFolderView->setCurrentIndex(m_fileSystemModel->index(desktopPath));
2817                 outputFolderViewClicked(ui->outputFolderView->currentIndex());
2818                 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2819         }
2820         else
2821         {
2822                 ui->buttonGotoDesktop->setEnabled(false);
2823         }
2824 }
2825
2826 /*
2827  * Goto home folder button
2828  */
2829 void MainWindow::gotoHomeFolderButtonClicked(void)
2830 {
2831         if(!m_fileSystemModel)
2832         {
2833                 qWarning("File system model not initialized yet!");
2834                 return;
2835         }
2836
2837         QString homePath = QDesktopServices::storageLocation(QDesktopServices::HomeLocation);
2838         
2839         if(!homePath.isEmpty() && QDir(homePath).exists())
2840         {
2841                 ui->outputFolderView->setCurrentIndex(m_fileSystemModel->index(homePath));
2842                 outputFolderViewClicked(ui->outputFolderView->currentIndex());
2843                 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2844         }
2845         else
2846         {
2847                 ui->buttonGotoHome->setEnabled(false);
2848         }
2849 }
2850
2851 /*
2852  * Goto music folder button
2853  */
2854 void MainWindow::gotoMusicFolderButtonClicked(void)
2855 {
2856         if(!m_fileSystemModel)
2857         {
2858                 qWarning("File system model not initialized yet!");
2859                 return;
2860         }
2861
2862         QString musicPath = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
2863         
2864         if(!musicPath.isEmpty() && QDir(musicPath).exists())
2865         {
2866                 ui->outputFolderView->setCurrentIndex(m_fileSystemModel->index(musicPath));
2867                 outputFolderViewClicked(ui->outputFolderView->currentIndex());
2868                 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2869         }
2870         else
2871         {
2872                 ui->buttonGotoMusic->setEnabled(false);
2873         }
2874 }
2875
2876 /*
2877  * Goto music favorite output folder
2878  */
2879 void MainWindow::gotoFavoriteFolder(void)
2880 {
2881         if(!m_fileSystemModel)
2882         {
2883                 qWarning("File system model not initialized yet!");
2884                 return;
2885         }
2886
2887         QAction *item = dynamic_cast<QAction*>(QObject::sender());
2888         
2889         if(item)
2890         {
2891                 QDir path(item->data().toString());
2892                 if(path.exists())
2893                 {
2894                         ui->outputFolderView->setCurrentIndex(m_fileSystemModel->index(path.canonicalPath()));
2895                         outputFolderViewClicked(ui->outputFolderView->currentIndex());
2896                         CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2897                 }
2898                 else
2899                 {
2900                         MUtils::Sound::beep(MUtils::Sound::BEEP_ERR);
2901                         m_outputFolderFavoritesMenu->removeAction(item);
2902                         item->deleteLater();
2903                 }
2904         }
2905 }
2906
2907 /*
2908  * Make folder button
2909  */
2910 void MainWindow::makeFolderButtonClicked(void)
2911 {
2912         ABORT_IF_BUSY;
2913
2914         if(!m_fileSystemModel)
2915         {
2916                 qWarning("File system model not initialized yet!");
2917                 return;
2918         }
2919
2920         QDir basePath(m_fileSystemModel->fileInfo(ui->outputFolderView->currentIndex()).absoluteFilePath());
2921         QString suggestedName = tr("New Folder");
2922
2923         if(!m_metaData->artist().isEmpty() && !m_metaData->album().isEmpty())
2924         {
2925                 suggestedName = QString("%1 - %2").arg(m_metaData->artist(),m_metaData->album());
2926         }
2927         else if(!m_metaData->artist().isEmpty())
2928         {
2929                 suggestedName = m_metaData->artist();
2930         }
2931         else if(!m_metaData->album().isEmpty())
2932         {
2933                 suggestedName =m_metaData->album();
2934         }
2935         else
2936         {
2937                 for(int i = 0; i < m_fileListModel->rowCount(); i++)
2938                 {
2939                         const AudioFileModel &audioFile = m_fileListModel->getFile(m_fileListModel->index(i, 0));
2940                         const AudioFileModel_MetaInfo &fileMetaInfo = audioFile.metaInfo();
2941
2942                         if(!fileMetaInfo.album().isEmpty() || !fileMetaInfo.artist().isEmpty())
2943                         {
2944                                 if(!fileMetaInfo.artist().isEmpty() && !fileMetaInfo.album().isEmpty())
2945                                 {
2946                                         suggestedName = QString("%1 - %2").arg(fileMetaInfo.artist(), fileMetaInfo.album());
2947                                 }
2948                                 else if(!fileMetaInfo.artist().isEmpty())
2949                                 {
2950                                         suggestedName = fileMetaInfo.artist();
2951                                 }
2952                                 else if(!fileMetaInfo.album().isEmpty())
2953                                 {
2954                                         suggestedName = fileMetaInfo.album();
2955                                 }
2956                                 break;
2957                         }
2958                 }
2959         }
2960         
2961         suggestedName = MUtils::clean_file_name(suggestedName);
2962
2963         while(true)
2964         {
2965                 bool bApplied = false;
2966                 QString folderName = QInputDialog::getText(this, tr("New Folder"), tr("Enter the name of the new folder:").leftJustified(96, ' '), QLineEdit::Normal, suggestedName, &bApplied, Qt::WindowStaysOnTopHint).simplified();
2967
2968                 if(bApplied)
2969                 {
2970                         folderName = MUtils::clean_file_path(folderName.simplified());
2971
2972                         if(folderName.isEmpty())
2973                         {
2974                                 MUtils::Sound::beep(MUtils::Sound::BEEP_ERR);
2975                                 continue;
2976                         }
2977
2978                         int i = 1;
2979                         QString newFolder = folderName;
2980
2981                         while(basePath.exists(newFolder))
2982                         {
2983                                 newFolder = QString(folderName).append(QString().sprintf(" (%d)", ++i));
2984                         }
2985                         
2986                         if(basePath.mkpath(newFolder))
2987                         {
2988                                 QDir createdDir = basePath;
2989                                 if(createdDir.cd(newFolder))
2990                                 {
2991                                         QModelIndex newIndex = m_fileSystemModel->index(createdDir.canonicalPath());
2992                                         ui->outputFolderView->setCurrentIndex(newIndex);
2993                                         outputFolderViewClicked(newIndex);
2994                                         CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2995                                 }
2996                         }
2997                         else
2998                         {
2999                                 QMessageBox::warning(this, tr("Failed to create folder"), QString("%1<br><nobr>%2</nobr><br><br>%3").arg(tr("The new folder could not be created:"), basePath.absoluteFilePath(newFolder), tr("Drive is read-only or insufficient access rights!")));
3000                         }
3001                 }
3002                 break;
3003         }
3004 }
3005
3006 /*
3007  * Output to source dir changed
3008  */
3009 void MainWindow::saveToSourceFolderChanged(void)
3010 {
3011         m_settings->outputToSourceDir(ui->saveToSourceFolderCheckBox->isChecked());
3012 }
3013
3014 /*
3015  * Prepend relative source file path to output file name changed
3016  */
3017 void MainWindow::prependRelativePathChanged(void)
3018 {
3019         m_settings->prependRelativeSourcePath(ui->prependRelativePathCheckBox->isChecked());
3020 }
3021
3022 /*
3023  * Show context menu for output folder
3024  */
3025 void MainWindow::outputFolderContextMenu(const QPoint &pos)
3026 {
3027         QAbstractScrollArea *scrollArea = dynamic_cast<QAbstractScrollArea*>(QObject::sender());
3028         QWidget *sender = scrollArea ? scrollArea->viewport() : dynamic_cast<QWidget*>(QObject::sender());      
3029
3030         if(pos.x() <= sender->width() && pos.y() <= sender->height() && pos.x() >= 0 && pos.y() >= 0)
3031         {
3032                 m_outputFolderContextMenu->popup(sender->mapToGlobal(pos));
3033         }
3034 }
3035
3036 /*
3037  * Show selected folder in explorer
3038  */
3039 void MainWindow::showFolderContextActionTriggered(void)
3040 {
3041         if(!m_fileSystemModel)
3042         {
3043                 qWarning("File system model not initialized yet!");
3044                 return;
3045         }
3046
3047         QString path = QDir::toNativeSeparators(m_fileSystemModel->filePath(ui->outputFolderView->currentIndex()));
3048         if(!path.endsWith(QDir::separator())) path.append(QDir::separator());
3049         MUtils::OS::shell_open(this, path, true);
3050 }
3051
3052 /*
3053  * Refresh the directory outline
3054  */
3055 void MainWindow::refreshFolderContextActionTriggered(void)
3056 {
3057         //force re-initialization
3058         QTimer::singleShot(0, this, SLOT(initOutputFolderModel()));
3059 }
3060
3061 /*
3062  * Go one directory up
3063  */
3064 void MainWindow::goUpFolderContextActionTriggered(void)
3065 {
3066         QModelIndex current = ui->outputFolderView->currentIndex();
3067         if(current.isValid())
3068         {
3069                 QModelIndex parent = current.parent();
3070                 if(parent.isValid())
3071                 {
3072                         
3073                         ui->outputFolderView->setCurrentIndex(parent);
3074                         outputFolderViewClicked(parent);
3075                 }
3076                 else
3077                 {
3078                         MUtils::Sound::beep(MUtils::Sound::BEEP_WRN);
3079                 }
3080                 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
3081         }
3082 }
3083
3084 /*
3085  * Add current folder to favorites
3086  */
3087 void MainWindow::addFavoriteFolderActionTriggered(void)
3088 {
3089         QString path = m_fileSystemModel->filePath(ui->outputFolderView->currentIndex());
3090         QStringList favorites = m_settings->favoriteOutputFolders().split("|", QString::SkipEmptyParts);
3091
3092         if(!favorites.contains(path, Qt::CaseInsensitive))
3093         {
3094                 favorites.append(path);
3095                 while(favorites.count() > 6) favorites.removeFirst();
3096         }
3097         else
3098         {
3099                 MUtils::Sound::beep(MUtils::Sound::BEEP_WRN);
3100         }
3101
3102         m_settings->favoriteOutputFolders(favorites.join("|"));
3103         refreshFavorites();
3104 }
3105
3106 /*
3107  * Output folder edit finished
3108  */
3109 void MainWindow::outputFolderEditFinished(void)
3110 {
3111         if(ui->outputFolderEdit->isHidden())
3112         {
3113                 return; //Not currently in edit mode!
3114         }
3115         
3116         bool ok = false;
3117         
3118         QString text = QDir::fromNativeSeparators(ui->outputFolderEdit->text().trimmed());
3119         while(text.startsWith('"') || text.startsWith('/')) text = text.right(text.length() - 1).trimmed();
3120         while(text.endsWith('"') || text.endsWith('/')) text = text.left(text.length() - 1).trimmed();
3121
3122         static const char *str = "?*<>|\"";
3123         for(size_t i = 0; str[i]; i++) text.replace(str[i], "_");
3124
3125         if(!((text.length() >= 2) && text.at(0).isLetter() && text.at(1) == QChar(':')))
3126         {
3127                 text = QString("%1/%2").arg(QDir::fromNativeSeparators(ui->outputFolderLabel->text()), text);
3128         }
3129
3130         if(text.length() == 2) text += "/"; /* "X:" => "X:/" */
3131
3132         while(text.length() > 2)
3133         {
3134                 QFileInfo info(text);
3135                 if(info.exists() && info.isDir())
3136                 {
3137                         QModelIndex index = m_fileSystemModel->index(QFileInfo(info.canonicalFilePath()).absoluteFilePath());
3138                         if(index.isValid())
3139                         {
3140                                 ok = true;
3141                                 ui->outputFolderView->setCurrentIndex(index);
3142                                 outputFolderViewClicked(index);
3143                                 break;
3144                         }
3145                 }
3146                 else if(info.exists() && info.isFile())
3147                 {
3148                         QModelIndex index = m_fileSystemModel->index(QFileInfo(info.canonicalPath()).absoluteFilePath());
3149                         if(index.isValid())
3150                         {
3151                                 ok = true;
3152                                 ui->outputFolderView->setCurrentIndex(index);
3153                                 outputFolderViewClicked(index);
3154                                 break;
3155                         }
3156                 }
3157
3158                 text = text.left(text.length() - 1).trimmed();
3159         }
3160
3161         ui->outputFolderEdit->setVisible(false);
3162         ui->outputFolderLabel->setVisible(true);
3163         ui->outputFolderView->setEnabled(true);
3164
3165         if(!ok) MUtils::Sound::beep(MUtils::Sound::BEEP_ERR);
3166         CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
3167 }
3168
3169 /*
3170  * Initialize file system model
3171  */
3172 void MainWindow::initOutputFolderModel(void)
3173 {
3174         if(m_outputFolderNoteBox->isHidden())
3175         {
3176                 m_outputFolderNoteBox->show();
3177                 m_outputFolderNoteBox->repaint();
3178                 m_outputFolderViewInitCounter = 4;
3179
3180                 if(m_fileSystemModel)
3181                 {
3182                         SET_MODEL(ui->outputFolderView, NULL);
3183                         MUTILS_DELETE(m_fileSystemModel);
3184                         ui->outputFolderView->repaint();
3185                 }
3186
3187                 if(m_fileSystemModel = new QFileSystemModelEx())
3188                 {
3189                         m_fileSystemModel->installEventFilter(this);
3190                         connect(m_fileSystemModel, SIGNAL(directoryLoaded(QString)), this, SLOT(outputFolderDirectoryLoaded(QString)));
3191                         connect(m_fileSystemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(outputFolderRowsInserted(QModelIndex,int,int)));
3192
3193                         SET_MODEL(ui->outputFolderView, m_fileSystemModel);
3194                         ui->outputFolderView->header()->setStretchLastSection(true);
3195                         ui->outputFolderView->header()->hideSection(1);
3196                         ui->outputFolderView->header()->hideSection(2);
3197                         ui->outputFolderView->header()->hideSection(3);
3198                 
3199                         m_fileSystemModel->setRootPath("");
3200                         QModelIndex index = m_fileSystemModel->index(m_settings->outputDir());
3201                         if(index.isValid()) ui->outputFolderView->setCurrentIndex(index);
3202                         outputFolderViewClicked(ui->outputFolderView->currentIndex());
3203                 }
3204
3205                 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
3206                 QTimer::singleShot(125, this, SLOT(initOutputFolderModel_doAsync()));
3207         }
3208 }
3209
3210 /*
3211  * Initialize file system model (do NOT call this one directly!)
3212  */
3213 void MainWindow::initOutputFolderModel_doAsync(void)
3214 {
3215         if(m_outputFolderViewInitCounter > 0)
3216         {
3217                 m_outputFolderViewInitCounter--;
3218                 QTimer::singleShot(125, this, SLOT(initOutputFolderModel_doAsync()));
3219         }
3220         else
3221         {
3222                 QTimer::singleShot(125, m_outputFolderNoteBox, SLOT(hide()));
3223                 ui->outputFolderView->setFocus();
3224         }
3225 }
3226
3227 /*
3228  * Center current folder in view
3229  */
3230 void MainWindow::centerOutputFolderModel(void)
3231 {
3232         if(ui->outputFolderView->isVisible())
3233         {
3234                 centerOutputFolderModel_doAsync();
3235                 QTimer::singleShot(125, this, SLOT(centerOutputFolderModel_doAsync()));
3236         }
3237 }
3238
3239 /*
3240  * Center current folder in view (do NOT call this one directly!)
3241  */
3242 void MainWindow::centerOutputFolderModel_doAsync(void)
3243 {
3244         if(ui->outputFolderView->isVisible())
3245         {
3246                 m_outputFolderViewCentering = true;
3247                 const QModelIndex index = ui->outputFolderView->currentIndex();
3248                 ui->outputFolderView->scrollTo(index, QAbstractItemView::PositionAtCenter);
3249                 ui->outputFolderView->setFocus();
3250         }
3251 }
3252
3253 /*
3254  * File system model asynchronously loaded a dir
3255  */
3256 void MainWindow::outputFolderDirectoryLoaded(const QString &path)
3257 {
3258         if(m_outputFolderViewCentering)
3259         {
3260                 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
3261         }
3262 }
3263
3264 /*
3265  * File system model inserted new items
3266  */
3267 void MainWindow::outputFolderRowsInserted(const QModelIndex &parent, int start, int end)
3268 {
3269         if(m_outputFolderViewCentering)
3270         {
3271                 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
3272         }
3273 }
3274
3275 /*
3276  * Directory view item was expanded by user
3277  */
3278 void MainWindow::outputFolderItemExpanded(const QModelIndex &item)
3279 {
3280         //We need to stop centering as soon as the user has expanded an item manually!
3281         m_outputFolderViewCentering = false;
3282 }
3283
3284 /*
3285  * View event for output folder control occurred
3286  */
3287 void MainWindow::outputFolderViewEventOccurred(QWidget *sender, QEvent *event)
3288 {
3289         switch(event->type())
3290         {
3291         case QEvent::Enter:
3292         case QEvent::Leave:
3293         case QEvent::KeyPress:
3294         case QEvent::KeyRelease:
3295         case QEvent::FocusIn:
3296         case QEvent::FocusOut:
3297         case QEvent::TouchEnd:
3298                 outputFolderViewClicked(ui->outputFolderView->currentIndex());
3299                 break;
3300         }
3301 }
3302
3303 /*
3304  * Mouse event for output folder control occurred
3305  */
3306 void MainWindow::outputFolderMouseEventOccurred(QWidget *sender, QEvent *event)
3307 {
3308         QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(event);
3309         QPoint pos = (mouseEvent) ? mouseEvent->pos() : QPoint();
3310
3311         if(sender == ui->outputFolderLabel)
3312         {
3313                 switch(event->type())
3314                 {
3315                 case QEvent::MouseButtonPress:
3316                         if(mouseEvent && (mouseEvent->button() == Qt::LeftButton))
3317                         {
3318                                 QString path = ui->outputFolderLabel->text();
3319                                 if(!path.endsWith(QDir::separator())) path.append(QDir::separator());
3320                                 MUtils::OS::shell_open(this, path, true);
3321                         }
3322                         break;
3323                 case QEvent::Enter:
3324                         ui->outputFolderLabel->setForegroundRole(QPalette::Link);
3325                         break;
3326                 case QEvent::Leave:
3327                         ui->outputFolderLabel->setForegroundRole(QPalette::WindowText);
3328                         break;
3329                 }
3330         }
3331
3332         if((sender == ui->outputFoldersFovoritesLabel) || (sender == ui->outputFoldersEditorLabel) || (sender == ui->outputFoldersGoUpLabel))
3333         {
3334                 const type_info &styleType = typeid(*qApp->style());
3335                 if((typeid(QPlastiqueStyle) == styleType) || (typeid(QWindowsStyle) == styleType))
3336                 {
3337                         switch(event->type())
3338                         {
3339                         case QEvent::Enter:
3340                                 dynamic_cast<QLabel*>(sender)->setFrameShadow(ui->outputFolderView->isEnabled() ? QFrame::Raised : QFrame::Plain);
3341                                 break;
3342                         case QEvent::MouseButtonPress:
3343                                 dynamic_cast<QLabel*>(sender)->setFrameShadow(ui->outputFolderView->isEnabled() ? QFrame::Sunken : QFrame::Plain);
3344                                 break;
3345                         case QEvent::MouseButtonRelease:
3346                                 dynamic_cast<QLabel*>(sender)->setFrameShadow(ui->outputFolderView->isEnabled() ? QFrame::Raised : QFrame::Plain);
3347                                 break;
3348                         case QEvent::Leave:
3349                                 dynamic_cast<QLabel*>(sender)->setFrameShadow(ui->outputFolderView->isEnabled() ? QFrame::Plain : QFrame::Plain);
3350                                 break;
3351                         }
3352                 }
3353                 else
3354                 {
3355                         dynamic_cast<QLabel*>(sender)->setFrameShadow(QFrame::Plain);
3356                 }
3357
3358                 if((event->type() == QEvent::MouseButtonRelease) && ui->outputFolderView->isEnabled() && (mouseEvent))
3359                 {
3360                         if(pos.x() <= sender->width() && pos.y() <= sender->height() && pos.x() >= 0 && pos.y() >= 0 && mouseEvent->button() != Qt::MidButton)
3361                         {
3362                                 if(sender == ui->outputFoldersFovoritesLabel)
3363                                 {
3364                                         m_outputFolderFavoritesMenu->popup(sender->mapToGlobal(pos));
3365                                 }
3366                                 else if(sender == ui->outputFoldersEditorLabel)
3367                                 {
3368                                         ui->outputFolderView->setEnabled(false);
3369                                         ui->outputFolderLabel->setVisible(false);
3370                                         ui->outputFolderEdit->setVisible(true);
3371                                         ui->outputFolderEdit->setText(ui->outputFolderLabel->text());
3372                                         ui->outputFolderEdit->selectAll();
3373                                         ui->outputFolderEdit->setFocus();
3374                                 }
3375                                 else if(sender == ui->outputFoldersGoUpLabel)
3376                                 {
3377                                         QTimer::singleShot(0, this, SLOT(goUpFolderContextActionTriggered()));
3378                                 }
3379                                 else
3380                                 {
3381                                         MUTILS_THROW("Oups, this is not supposed to happen!");
3382                                 }
3383                         }
3384                 }
3385         }
3386 }
3387
3388 // =========================================================
3389 // Metadata tab slots
3390 // =========================================================
3391
3392 /*
3393  * Edit meta button clicked
3394  */
3395 void MainWindow::editMetaButtonClicked(void)
3396 {
3397         ABORT_IF_BUSY;
3398
3399         const QModelIndex index = ui->metaDataView->currentIndex();
3400
3401         if(index.isValid())
3402         {
3403                 m_metaInfoModel->editItem(index, this);
3404         
3405                 if(index.row() == 4)
3406                 {
3407                         m_settings->metaInfoPosition(m_metaData->position());
3408                 }
3409         }
3410 }
3411
3412 /*
3413  * Reset meta button clicked
3414  */
3415 void MainWindow::clearMetaButtonClicked(void)
3416 {
3417         ABORT_IF_BUSY;
3418         m_metaInfoModel->clearData();
3419 }
3420
3421 /*
3422  * Meta tags enabled changed
3423  */
3424 void MainWindow::metaTagsEnabledChanged(void)
3425 {
3426         m_settings->writeMetaTags(ui->writeMetaDataCheckBox->isChecked());
3427 }
3428
3429 /*
3430  * Playlist enabled changed
3431  */
3432 void MainWindow::playlistEnabledChanged(void)
3433 {
3434         m_settings->createPlaylist(ui->generatePlaylistCheckBox->isChecked());
3435 }
3436
3437 // =========================================================
3438 // Compression tab slots
3439 // =========================================================
3440
3441 /*
3442  * Update encoder
3443  */
3444 void MainWindow::updateEncoder(int id)
3445 {
3446         /*qWarning("\nupdateEncoder(%d)", id);*/
3447
3448         m_settings->compressionEncoder(id);
3449         const AbstractEncoderInfo *info = EncoderRegistry::getEncoderInfo(id);
3450
3451         //Update UI controls
3452         ui->radioButtonModeQuality       ->setEnabled(info->isModeSupported(SettingsModel::VBRMode));
3453         ui->radioButtonModeAverageBitrate->setEnabled(info->isModeSupported(SettingsModel::ABRMode));
3454         ui->radioButtonConstBitrate      ->setEnabled(info->isModeSupported(SettingsModel::CBRMode));
3455         
3456         //Initialize checkbox state
3457         if(ui->radioButtonModeQuality->isEnabled())             ui->radioButtonModeQuality->setChecked(true);
3458         else if(ui->radioButtonModeAverageBitrate->isEnabled()) ui->radioButtonModeAverageBitrate->setChecked(true);
3459         else if(ui->radioButtonConstBitrate->isEnabled())       ui->radioButtonConstBitrate->setChecked(true);
3460         else MUTILS_THROW("It appears that the encoder does not support *any* RC mode!");
3461
3462         //Apply current RC mode
3463         const int currentRCMode = EncoderRegistry::loadEncoderMode(m_settings, id);
3464         switch(currentRCMode)
3465         {
3466                 case SettingsModel::VBRMode: if(ui->radioButtonModeQuality->isEnabled())        ui->radioButtonModeQuality->setChecked(true);        break;
3467                 case SettingsModel::ABRMode: if(ui->radioButtonModeAverageBitrate->isEnabled()) ui->radioButtonModeAverageBitrate->setChecked(true); break;
3468                 case SettingsModel::CBRMode: if(ui->radioButtonConstBitrate->isEnabled())       ui->radioButtonConstBitrate->setChecked(true);       break;
3469                 default: MUTILS_THROW("updateEncoder(): Unknown rc-mode encountered!");
3470         }
3471
3472         //Display encoder description
3473         if(const char* description = info->description())
3474         {
3475                 ui->labelEncoderInfo->setVisible(true);
3476                 ui->labelEncoderInfo->setText(tr("Current Encoder: %1").arg(QString::fromUtf8(description)));
3477         }
3478         else
3479         {
3480                 ui->labelEncoderInfo->setVisible(false);
3481         }
3482
3483         //Update RC mode!
3484         updateRCMode(m_modeButtonGroup->checkedId());
3485 }
3486
3487 /*
3488  * Update rate-control mode
3489  */
3490 void MainWindow::updateRCMode(int id)
3491 {
3492         /*qWarning("updateRCMode(%d)", id);*/
3493
3494         //Store new RC mode
3495         const int currentEncoder = m_encoderButtonGroup->checkedId();
3496         EncoderRegistry::saveEncoderMode(m_settings, currentEncoder, id);
3497
3498         //Fetch encoder info
3499         const AbstractEncoderInfo *info = EncoderRegistry::getEncoderInfo(currentEncoder);
3500         const int valueCount = info->valueCount(id);
3501
3502         //Sanity check
3503         if(!info->isModeSupported(id))
3504         {
3505                 qWarning("Attempting to use an unsupported RC mode (%d) with current encoder (%d)!", id, currentEncoder);
3506                 ui->labelBitrate->setText("(ERROR)");
3507                 return;
3508         }
3509
3510         //Update slider min/max values
3511         if(valueCount > 0)
3512         {
3513                 WITH_BLOCKED_SIGNALS(ui->sliderBitrate, setEnabled, true);
3514                 WITH_BLOCKED_SIGNALS(ui->sliderBitrate, setMinimum, 0);
3515                 WITH_BLOCKED_SIGNALS(ui->sliderBitrate, setMaximum, valueCount-1);
3516         }
3517         else
3518         {
3519                 WITH_BLOCKED_SIGNALS(ui->sliderBitrate, setEnabled, false);
3520                 WITH_BLOCKED_SIGNALS(ui->sliderBitrate, setMinimum, 0);
3521                 WITH_BLOCKED_SIGNALS(ui->sliderBitrate, setMaximum, 2);
3522         }
3523
3524         //Now update bitrate/quality value!
3525         if(valueCount > 0)
3526         {
3527                 const int currentValue = EncoderRegistry::loadEncoderValue(m_settings, currentEncoder, id);
3528                 ui->sliderBitrate->setValue(qBound(0, currentValue, valueCount-1));
3529                 updateBitrate(qBound(0, currentValue, valueCount-1));
3530         }
3531         else
3532         {
3533                 ui->sliderBitrate->setValue(1);
3534                 updateBitrate(0);
3535         }
3536 }
3537
3538 /*
3539  * Update bitrate
3540  */
3541 void MainWindow::updateBitrate(int value)
3542 {
3543         /*qWarning("updateBitrate(%d)", value);*/
3544
3545         //Load current encoder and RC mode
3546         const int currentEncoder = m_encoderButtonGroup->checkedId();
3547         const int currentRCMode = m_modeButtonGroup->checkedId();
3548
3549         //Fetch encoder info
3550         const AbstractEncoderInfo *info = EncoderRegistry::getEncoderInfo(currentEncoder);
3551         const int valueCount = info->valueCount(currentRCMode);
3552
3553         //Sanity check
3554         if(!info->isModeSupported(currentRCMode))
3555         {
3556                 qWarning("Attempting to use an unsupported RC mode (%d) with current encoder (%d)!", currentRCMode, currentEncoder);
3557                 ui->labelBitrate->setText("(ERROR)");
3558                 return;
3559         }
3560
3561         //Store new bitrate value
3562         if(valueCount > 0)
3563         {
3564                 EncoderRegistry::saveEncoderValue(m_settings, currentEncoder, currentRCMode, qBound(0, value, valueCount-1));
3565         }
3566
3567         //Update bitrate value
3568         const int displayValue = (valueCount > 0) ? info->valueAt(currentRCMode, qBound(0, value, valueCount-1)) : INT_MAX;
3569         switch(info->valueType(currentRCMode))
3570         {
3571         case AbstractEncoderInfo::TYPE_BITRATE:
3572                 ui->labelBitrate->setText(QString("%1 kbps").arg(QString::number(displayValue)));
3573                 break;
3574         case AbstractEncoderInfo::TYPE_APPROX_BITRATE:
3575                 ui->labelBitrate->setText(QString("&asymp; %1 kbps").arg(QString::number(displayValue)));
3576                 break;
3577         case AbstractEncoderInfo::TYPE_QUALITY_LEVEL_INT:
3578                 ui->labelBitrate->setText(tr("Quality Level %1").arg(QString::number(displayValue)));
3579                 break;
3580         case AbstractEncoderInfo::TYPE_QUALITY_LEVEL_FLT:
3581                 ui->labelBitrate->setText(tr("Quality Level %1").arg(QString().sprintf("%.2f", double(displayValue)/100.0)));
3582                 break;
3583         case AbstractEncoderInfo::TYPE_COMPRESSION_LEVEL:
3584                 ui->labelBitrate->setText(tr("Compression %1").arg(QString::number(displayValue)));
3585                 break;
3586         case AbstractEncoderInfo::TYPE_UNCOMPRESSED:
3587                 ui->labelBitrate->setText(tr("Uncompressed"));
3588                 break;
3589         default:
3590                 MUTILS_THROW("Unknown display value type encountered!");
3591                 break;
3592         }
3593 }
3594
3595 /*
3596  * Event for compression tab occurred
3597  */
3598 void MainWindow::compressionTabEventOccurred(QWidget *sender, QEvent *event)
3599 {
3600         static const QUrl helpUrl("http://lamexp.sourceforge.net/doc/FAQ.html#054010d9");
3601         
3602         if((sender == ui->labelCompressionHelp) && (event->type() == QEvent::MouseButtonPress))
3603         {
3604                 QDesktopServices::openUrl(helpUrl);
3605         }
3606         else if((sender == ui->labelResetEncoders) && (event->type() == QEvent::MouseButtonPress))
3607         {
3608                 PLAY_SOUND_OPTIONAL("blast", true);
3609                 EncoderRegistry::resetAllEncoders(m_settings);
3610                 m_settings->compressionEncoder(SettingsModel::MP3Encoder);
3611                 ui->radioButtonEncoderMP3->setChecked(true);
3612                 QTimer::singleShot(0, this, SLOT(updateEncoder()));
3613         }
3614 }
3615
3616 // =========================================================
3617 // Advanced option slots
3618 // =========================================================
3619
3620 /*
3621  * Lame algorithm quality changed
3622  */
3623 void MainWindow::updateLameAlgoQuality(int value)
3624 {
3625         QString text;
3626
3627         switch(value)
3628         {
3629         case 3:
3630                 text = tr("Best Quality (Slow)");
3631                 break;
3632         case 2:
3633                 text = tr("High Quality (Recommended)");
3634                 break;
3635         case 1:
3636                 text = tr("Acceptable Quality (Fast)");
3637                 break;
3638         case 0:
3639                 text = tr("Poor Quality (Very Fast)");
3640                 break;
3641         }
3642
3643         if(!text.isEmpty())
3644         {
3645                 m_settings->lameAlgoQuality(value);
3646                 ui->labelLameAlgoQuality->setText(text);
3647         }
3648
3649         bool warning = (value == 0), notice = (value == 3);
3650         ui->labelLameAlgoQualityWarning->setVisible(warning);
3651         ui->labelLameAlgoQualityWarningIcon->setVisible(warning);
3652         ui->labelLameAlgoQualityNotice->setVisible(notice);
3653         ui->labelLameAlgoQualityNoticeIcon->setVisible(notice);
3654         ui->labelLameAlgoQualitySpacer->setVisible(warning || notice);
3655 }
3656
3657 /*
3658  * Bitrate management endabled/disabled
3659  */
3660 void MainWindow::bitrateManagementEnabledChanged(bool checked)
3661 {
3662         m_settings->bitrateManagementEnabled(checked);
3663 }
3664
3665 /*
3666  * Minimum bitrate has changed
3667  */
3668 void MainWindow::bitrateManagementMinChanged(int value)
3669 {
3670         if(value > ui->spinBoxBitrateManagementMax->value())
3671         {
3672                 ui->spinBoxBitrateManagementMin->setValue(ui->spinBoxBitrateManagementMax->value());
3673                 m_settings->bitrateManagementMinRate(ui->spinBoxBitrateManagementMax->value());
3674         }
3675         else
3676         {
3677                 m_settings->bitrateManagementMinRate(value);
3678         }
3679 }
3680
3681 /*
3682  * Maximum bitrate has changed
3683  */
3684 void MainWindow::bitrateManagementMaxChanged(int value)
3685 {
3686         if(value < ui->spinBoxBitrateManagementMin->value())
3687         {
3688                 ui->spinBoxBitrateManagementMax->setValue(ui->spinBoxBitrateManagementMin->value());
3689                 m_settings->bitrateManagementMaxRate(ui->spinBoxBitrateManagementMin->value());
3690         }
3691         else
3692         {
3693                 m_settings->bitrateManagementMaxRate(value);
3694         }
3695 }
3696
3697 /*
3698  * Channel mode has changed
3699  */
3700 void MainWindow::channelModeChanged(int value)
3701 {
3702         if(value >= 0) m_settings->lameChannelMode(value);
3703 }
3704
3705 /*
3706  * Sampling rate has changed
3707  */
3708 void MainWindow::samplingRateChanged(int value)
3709 {
3710         if(value >= 0) m_settings->samplingRate(value);
3711 }
3712
3713 /*
3714  * Nero AAC 2-Pass mode changed
3715  */
3716 void MainWindow::neroAAC2PassChanged(bool checked)
3717 {
3718         m_settings->neroAACEnable2Pass(checked);
3719 }
3720
3721 /*
3722  * Nero AAC profile mode changed
3723  */
3724 void MainWindow::neroAACProfileChanged(int value)
3725 {
3726         if(value >= 0) m_settings->aacEncProfile(value);
3727 }
3728
3729 /*
3730  * Aften audio coding mode changed
3731  */
3732 void MainWindow::aftenCodingModeChanged(int value)
3733 {
3734         if(value >= 0) m_settings->aftenAudioCodingMode(value);
3735 }
3736
3737 /*
3738  * Aften DRC mode changed
3739  */
3740 void MainWindow::aftenDRCModeChanged(int value)
3741 {
3742         if(value >= 0) m_settings->aftenDynamicRangeCompression(value);
3743 }
3744
3745 /*
3746  * Aften exponent search size changed
3747  */
3748 void MainWindow::aftenSearchSizeChanged(int value)
3749 {
3750         if(value >= 0) m_settings->aftenExponentSearchSize(value);
3751 }
3752
3753 /*
3754  * Aften fast bit allocation changed
3755  */
3756 void MainWindow::aftenFastAllocationChanged(bool checked)
3757 {
3758         m_settings->aftenFastBitAllocation(checked);
3759 }
3760
3761
3762 /*
3763  * Opus encoder settings changed
3764  */
3765 void MainWindow::opusSettingsChanged(void)
3766 {
3767         m_settings->opusFramesize(ui->comboBoxOpusFramesize->currentIndex());
3768         m_settings->opusComplexity(ui->spinBoxOpusComplexity->value());
3769         m_settings->opusDisableResample(ui->checkBoxOpusDisableResample->isChecked());
3770 }
3771
3772 /*
3773  * Normalization filter enabled changed
3774  */
3775 void MainWindow::normalizationEnabledChanged(bool checked)
3776 {
3777         m_settings->normalizationFilterEnabled(checked);
3778         normalizationDynamicChanged(ui->checkBoxNormalizationFilterDynamic->isChecked());
3779 }
3780
3781 /*
3782  * Dynamic normalization enabled changed
3783  */
3784 void MainWindow::normalizationDynamicChanged(bool checked)
3785 {
3786         ui->spinBoxNormalizationFilterSize->setEnabled(ui->checkBoxNormalizationFilterEnabled->isChecked() && checked);
3787         m_settings->normalizationFilterDynamic(checked);
3788 }
3789
3790 /*
3791  * Normalization max. volume changed
3792  */
3793 void MainWindow::normalizationMaxVolumeChanged(double value)
3794 {
3795         m_settings->normalizationFilterMaxVolume(static_cast<int>(value * 100.0));
3796 }
3797
3798 /*
3799  * Normalization equalization mode changed
3800  */
3801 void MainWindow::normalizationCoupledChanged(bool checked)
3802 {
3803         m_settings->normalizationFilterCoupled(checked);
3804 }
3805
3806 /*
3807  * Normalization filter size changed
3808  */
3809 void MainWindow::normalizationFilterSizeChanged(int value)
3810 {
3811         m_settings->normalizationFilterSize(value);
3812 }
3813
3814 /*
3815  * Normalization filter size editing finished
3816  */
3817 void MainWindow::normalizationFilterSizeFinished(void)
3818 {
3819         const int value = ui->spinBoxNormalizationFilterSize->value();
3820         if((value % 2) != 1)
3821         {
3822                 bool rnd = MUtils::parity(MUtils::next_rand32());
3823                 ui->spinBoxNormalizationFilterSize->setValue(rnd ? value+1 : value-1);
3824         }
3825 }
3826
3827 /*
3828  * Tone adjustment has changed (Bass)
3829  */
3830 void MainWindow::toneAdjustBassChanged(double value)
3831 {
3832         m_settings->toneAdjustBass(static_cast<int>(value * 100.0));
3833         ui->spinBoxToneAdjustBass->setPrefix((value > 0) ? "+" : QString());
3834 }
3835
3836 /*
3837  * Tone adjustment has changed (Treble)
3838  */
3839 void MainWindow::toneAdjustTrebleChanged(double value)
3840 {
3841         m_settings->toneAdjustTreble(static_cast<int>(value * 100.0));
3842         ui->spinBoxToneAdjustTreble->setPrefix((value > 0) ? "+" : QString());
3843 }
3844
3845 /*
3846  * Tone adjustment has been reset
3847  */
3848 void MainWindow::toneAdjustTrebleReset(void)
3849 {
3850         ui->spinBoxToneAdjustBass->setValue(m_settings->toneAdjustBassDefault());
3851         ui->spinBoxToneAdjustTreble->setValue(m_settings->toneAdjustTrebleDefault());
3852         toneAdjustBassChanged(ui->spinBoxToneAdjustBass->value());
3853         toneAdjustTrebleChanged(ui->spinBoxToneAdjustTreble->value());
3854 }
3855
3856 /*
3857  * Custom encoder parameters changed
3858  */
3859 void MainWindow::customParamsChanged(void)
3860 {
3861         ui->lineEditCustomParamLAME->setText(ui->lineEditCustomParamLAME->text().simplified());
3862         ui->lineEditCustomParamOggEnc->setText(ui->lineEditCustomParamOggEnc->text().simplified());
3863         ui->lineEditCustomParamNeroAAC->setText(ui->lineEditCustomParamNeroAAC->text().simplified());
3864         ui->lineEditCustomParamFLAC->setText(ui->lineEditCustomParamFLAC->text().simplified());
3865         ui->lineEditCustomParamAften->setText(ui->lineEditCustomParamAften->text().simplified());
3866         ui->lineEditCustomParamOpus->setText(ui->lineEditCustomParamOpus->text().simplified());
3867
3868         bool customParamsUsed = false;
3869         if(!ui->lineEditCustomParamLAME->text().isEmpty()) customParamsUsed = true;
3870         if(!ui->lineEditCustomParamOggEnc->text().isEmpty()) customParamsUsed = true;
3871         if(!ui->lineEditCustomParamNeroAAC->text().isEmpty()) customParamsUsed = true;
3872         if(!ui->lineEditCustomParamFLAC->text().isEmpty()) customParamsUsed = true;
3873         if(!ui->lineEditCustomParamAften->text().isEmpty()) customParamsUsed = true;
3874         if(!ui->lineEditCustomParamOpus->text().isEmpty()) customParamsUsed = true;
3875
3876         ui->labelCustomParamsIcon->setVisible(customParamsUsed);
3877         ui->labelCustomParamsText->setVisible(customParamsUsed);
3878         ui->labelCustomParamsSpacer->setVisible(customParamsUsed);
3879
3880         EncoderRegistry::saveEncoderCustomParams(m_settings, SettingsModel::MP3Encoder,    ui->lineEditCustomParamLAME->text());
3881         EncoderRegistry::saveEncoderCustomParams(m_settings, SettingsModel::VorbisEncoder, ui->lineEditCustomParamOggEnc->text());
3882         EncoderRegistry::saveEncoderCustomParams(m_settings, SettingsModel::AACEncoder,    ui->lineEditCustomParamNeroAAC->text());
3883         EncoderRegistry::saveEncoderCustomParams(m_settings, SettingsModel::FLACEncoder,   ui->lineEditCustomParamFLAC->text());
3884         EncoderRegistry::saveEncoderCustomParams(m_settings, SettingsModel::AC3Encoder,    ui->lineEditCustomParamAften->text());
3885         EncoderRegistry::saveEncoderCustomParams(m_settings, SettingsModel::OpusEncoder,   ui->lineEditCustomParamOpus->text());
3886 }
3887
3888 /*
3889  * One of the rename buttons has been clicked
3890  */
3891 void MainWindow::renameButtonClicked(bool checked)
3892 {
3893         if(QPushButton *const button  = dynamic_cast<QPushButton*>(QObject::sender()))
3894         {
3895                 QWidget *pages[]       = { ui->pageRename_Rename,   ui->pageRename_RegExp,   ui->pageRename_FileEx   };
3896                 QPushButton *buttons[] = { ui->buttonRename_Rename, ui->buttonRename_RegExp, ui->buttonRename_FileEx };
3897                 for(int i = 0; i < 3; i++)
3898                 {
3899                         const bool match = (button == buttons[i]);
3900                         buttons[i]->setChecked(match);
3901                         if(match && checked) ui->stackedWidget->setCurrentWidget(pages[i]);
3902                 }
3903         }
3904 }
3905
3906 /*
3907  * Rename output files enabled changed
3908  */
3909 void MainWindow::renameOutputEnabledChanged(const bool &checked)
3910 {
3911         m_settings->renameFiles_renameEnabled(checked);
3912 }
3913
3914 /*
3915  * Rename output files patterm changed
3916  */
3917 void MainWindow::renameOutputPatternChanged(void)
3918 {
3919         QString temp = ui->lineEditRenamePattern->text().simplified();
3920         ui->lineEditRenamePattern->setText(temp.isEmpty() ? m_settings->renameFiles_renamePatternDefault() : temp);
3921         m_settings->renameFiles_renamePattern(ui->lineEditRenamePattern->text());
3922 }
3923
3924 /*
3925  * Rename output files patterm changed
3926  */
3927 void MainWindow::renameOutputPatternChanged(const QString &text, const bool &silent)
3928 {
3929         QString pattern(text.simplified());
3930         
3931         pattern.replace("<BaseName>", "The_White_Stripes_-_Fell_In_Love_With_A_Girl", Qt::CaseInsensitive);
3932         pattern.replace("<TrackNo>", "04", Qt::CaseInsensitive);
3933         pattern.replace("<Title>", "Fell In Love With A Girl", Qt::CaseInsensitive);
3934         pattern.replace("<Artist>", "The White Stripes", Qt::CaseInsensitive);
3935         pattern.replace("<Album>", "White Blood Cells", Qt::CaseInsensitive);
3936         pattern.replace("<Year>", "2001", Qt::CaseInsensitive);
3937         pattern.replace("<Comment>", "Encoded by LameXP", Qt::CaseInsensitive);
3938
3939         const QString patternClean = MUtils::clean_file_name(pattern);
3940
3941         if(pattern.compare(patternClean))
3942         {
3943                 if(ui->lineEditRenamePattern->palette().color(QPalette::Text) != Qt::red)
3944                 {
3945                         if(!silent) MUtils::Sound::beep(MUtils::Sound::BEEP_ERR);
3946                         SET_TEXT_COLOR(ui->lineEditRenamePattern, Qt::red);
3947                 }
3948         }
3949         else
3950         {
3951                 if(ui->lineEditRenamePattern->palette() != QPalette())
3952                 {
3953                         if(!silent) MUtils::Sound::beep(MUtils::Sound::BEEP_NFO);
3954                         ui->lineEditRenamePattern->setPalette(QPalette());
3955                 }
3956         }
3957
3958         ui->labelRanameExample->setText(patternClean);
3959 }
3960
3961 /*
3962  * Regular expression enabled changed
3963  */
3964 void MainWindow::renameRegExpEnabledChanged(const bool &checked)
3965 {
3966         m_settings->renameFiles_regExpEnabled(checked);
3967 }
3968
3969 /*
3970  * Regular expression value has changed
3971  */
3972 void  MainWindow::renameRegExpValueChanged(void)
3973 {
3974         const QString search  = ui->lineEditRenameRegExp_Search->text() .trimmed();
3975         const QString replace = ui->lineEditRenameRegExp_Replace->text().simplified();
3976         ui->lineEditRenameRegExp_Search ->setText(search.isEmpty()  ? m_settings->renameFiles_regExpSearchDefault()  : search);
3977         ui->lineEditRenameRegExp_Replace->setText(replace.isEmpty() ? m_settings->renameFiles_regExpReplaceDefault() : replace);
3978         m_settings->renameFiles_regExpSearch (ui->lineEditRenameRegExp_Search ->text());
3979         m_settings->renameFiles_regExpReplace(ui->lineEditRenameRegExp_Replace->text());
3980 }
3981
3982 /*
3983  * Regular expression search pattern has changed
3984  */
3985 void  MainWindow::renameRegExpSearchChanged(const QString &text, const bool &silent)
3986 {
3987         const QString pattern(text.trimmed());
3988
3989         if((!pattern.isEmpty()) && (!QRegExp(pattern.trimmed()).isValid()))
3990         {
3991                 if(ui->lineEditRenameRegExp_Search->palette().color(QPalette::Text) != Qt::red)
3992                 {
3993                         if(!silent) MUtils::Sound::beep(MUtils::Sound::BEEP_ERR);
3994                         SET_TEXT_COLOR(ui->lineEditRenameRegExp_Search, Qt::red);
3995                 }
3996         }
3997         else
3998         {
3999                 if(ui->lineEditRenameRegExp_Search->palette() != QPalette())
4000                 {
4001                         if(!silent) MUtils::Sound::beep(MUtils::Sound::BEEP_NFO);
4002                         ui->lineEditRenameRegExp_Search->setPalette(QPalette());
4003                 }
4004         }
4005
4006         renameRegExpReplaceChanged(ui->lineEditRenameRegExp_Replace->text(), silent);
4007 }
4008
4009 /*
4010  * Regular expression replacement string changed
4011  */
4012 void  MainWindow::renameRegExpReplaceChanged(const QString &text, const bool &silent)
4013 {
4014         QString replacement(text.simplified());
4015         const QString search(ui->lineEditRenameRegExp_Search->text().trimmed());
4016
4017         if(!search.isEmpty())
4018         {
4019                 const QRegExp regexp(search);
4020                 if(regexp.isValid())
4021                 {
4022                         const int count = regexp.captureCount();
4023                         const QString blank; 
4024                         for(int i = 0; i < count; i++)
4025                         {
4026                                 replacement.replace(QString("\\%0").arg(QString::number(i+1)), blank);
4027                         }
4028                 }
4029         }
4030
4031         if(replacement.compare(MUtils::clean_file_name(replacement)))
4032         {
4033                 if(ui->lineEditRenameRegExp_Replace->palette().color(QPalette::Text) != Qt::red)
4034                 {
4035                         if(!silent) MUtils::Sound::beep(MUtils::Sound::BEEP_ERR);
4036                         SET_TEXT_COLOR(ui->lineEditRenameRegExp_Replace, Qt::red);
4037                 }
4038         }
4039         else
4040         {
4041                 if(ui->lineEditRenameRegExp_Replace->palette() != QPalette())
4042                 {
4043                         if(!silent) MUtils::Sound::beep(MUtils::Sound::BEEP_NFO);
4044                         ui->lineEditRenameRegExp_Replace->setPalette(QPalette());
4045                 }
4046         }
4047 }
4048
4049 /*
4050  * Show list of rename macros
4051  */
4052 void MainWindow::showRenameMacros(const QString &text)
4053 {
4054         if(text.compare("reset", Qt::CaseInsensitive) == 0)
4055         {
4056                 ui->lineEditRenamePattern->setText(m_settings->renameFiles_renamePatternDefault());
4057                 return;
4058         }
4059
4060         if(text.compare("regexp", Qt::CaseInsensitive) == 0)
4061         {
4062                 MUtils::OS::shell_open(this, "http://www.regular-expressions.info/quickstart.html");
4063                 return;
4064         }
4065
4066         const QString format = QString("<tr><td><tt>&lt;%1&gt;</tt></td><td>&nbsp;&nbsp;</td><td>%2</td></tr>");
4067
4068         QString message = QString("<table>");
4069         message += QString(format).arg("BaseName", tr("File name without extension"));
4070         message += QString(format).arg("TrackNo", tr("Track number with leading zero"));
4071         message += QString(format).arg("Title", tr("Track title"));
4072         message += QString(format).arg("Artist", tr("Artist name"));
4073         message += QString(format).arg("Album", tr("Album name"));
4074         message += QString(format).arg("Year", tr("Year with (at least) four digits"));
4075         message += QString(format).arg("Comment", tr("Comment"));
4076         message += "</table><br><br>";
4077         message += QString("%1<br>").arg(tr("Characters forbidden in file names:"));
4078         message += "<b><tt>\\ / : * ? &lt; &gt; |<br>";
4079         
4080         QMessageBox::information(this, tr("Rename Macros"), message, tr("Discard"));
4081 }
4082
4083 void MainWindow::fileExtAddButtonClicked(void)
4084 {
4085         if(FileExtsModel *const model = dynamic_cast<FileExtsModel*>(ui->tableViewFileExts->model()))
4086         {
4087                 model->addOverwrite(this);
4088         }
4089 }
4090
4091 void MainWindow::fileExtRemoveButtonClicked(void)
4092 {
4093         if(FileExtsModel *const model = dynamic_cast<FileExtsModel*>(ui->tableViewFileExts->model()))
4094         {
4095                 const QModelIndex selected = ui->tableViewFileExts->currentIndex();
4096                 if(selected.isValid())
4097                 {
4098                         model->removeOverwrite(selected);
4099                 }
4100                 else
4101                 {
4102                         MUtils::Sound::beep(MUtils::Sound::BEEP_ERR);
4103                 }
4104         }
4105 }
4106
4107 void MainWindow::fileExtModelChanged(void)
4108 {
4109         if(FileExtsModel *const model = dynamic_cast<FileExtsModel*>(ui->tableViewFileExts->model()))
4110         {
4111                 m_settings->renameFiles_fileExtension(model->exportItems());
4112         }
4113 }
4114
4115 void MainWindow::forceStereoDownmixEnabledChanged(bool checked)
4116 {
4117         m_settings->forceStereoDownmix(checked);
4118 }
4119
4120 /*
4121  * Maximum number of instances changed
4122  */
4123 void MainWindow::updateMaximumInstances(int value)
4124 {
4125         ui->labelMaxInstances->setText(tr("%n Instance(s)", "", value));
4126         m_settings->maximumInstances(ui->checkBoxAutoDetectInstances->isChecked() ? NULL : value);
4127 }
4128
4129 /*
4130  * Auto-detect number of instances
4131  */
4132 void MainWindow::autoDetectInstancesChanged(bool checked)
4133 {
4134         m_settings->maximumInstances(checked ? NULL : ui->sliderMaxInstances->value());
4135 }
4136
4137 /*
4138  * Browse for custom TEMP folder button clicked
4139  */
4140 void MainWindow::browseCustomTempFolderButtonClicked(void)
4141 {
4142         QString newTempFolder;
4143
4144         if(MUtils::GUI::themes_enabled())
4145         {
4146                 newTempFolder = QFileDialog::getExistingDirectory(this, QString(), m_settings->customTempPath());
4147         }
4148         else
4149         {
4150                 QFileDialog dialog(this);
4151                 dialog.setFileMode(QFileDialog::DirectoryOnly);
4152                 dialog.setDirectory(m_settings->customTempPath());
4153                 if(dialog.exec())
4154                 {
4155                         newTempFolder = dialog.selectedFiles().first();
4156                 }
4157         }
4158
4159         if(!newTempFolder.isEmpty())
4160         {
4161                 QFile writeTest(QString("%1/~%2.tmp").arg(newTempFolder, MUtils::rand_str()));
4162                 if(writeTest.open(QIODevice::ReadWrite))
4163                 {
4164                         writeTest.remove();
4165                         ui->lineEditCustomTempFolder->setText(QDir::toNativeSeparators(newTempFolder));
4166                 }
4167                 else
4168                 {
4169                         QMessageBox::warning(this, tr("Access Denied"), tr("Cannot write to the selected directory. Please choose another directory!"));
4170                 }
4171         }
4172 }
4173
4174 /*
4175  * Custom TEMP folder changed
4176  */
4177 void MainWindow::customTempFolderChanged(const QString &text)
4178 {
4179         m_settings->customTempPath(QDir::fromNativeSeparators(text));
4180 }
4181
4182 /*
4183  * Use custom TEMP folder option changed
4184  */
4185 void MainWindow::useCustomTempFolderChanged(bool checked)
4186 {
4187         m_settings->customTempPathEnabled(!checked);
4188 }
4189
4190 /*
4191  * Help for custom parameters was requested
4192  */
4193 void MainWindow::customParamsHelpRequested(QWidget *obj, QEvent *event)
4194 {
4195         if(event->type() != QEvent::MouseButtonRelease)
4196         {
4197                 return;
4198         }
4199
4200         if(QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(event))
4201         {
4202                 QPoint pos = mouseEvent->pos();
4203                 if(!(pos.x() <= obj->width() && pos.y() <= obj->height() && pos.x() >= 0 && pos.y() >= 0 && mouseEvent->button() != Qt::MidButton))
4204                 {
4205                         return;
4206                 }
4207         }
4208
4209         if(obj == ui->helpCustomParamLAME)         showCustomParamsHelpScreen("lame.exe",    "--longhelp");
4210         else if(obj == ui->helpCustomParamOggEnc)  showCustomParamsHelpScreen("oggenc2.exe", "--help");
4211         else if(obj == ui->helpCustomParamNeroAAC)
4212         {
4213                 switch(EncoderRegistry::getAacEncoder())
4214                 {
4215                         case SettingsModel::AAC_ENCODER_QAAC: showCustomParamsHelpScreen("qaac64.exe|qaac.exe", "--help"); break;
4216                         case SettingsModel::AAC_ENCODER_FHG : showCustomParamsHelpScreen("fhgaacenc.exe",       ""      ); break;
4217                         case SettingsModel::AAC_ENCODER_FDK : showCustomParamsHelpScreen("fdkaac.exe",          "--help"); break;
4218                         case SettingsModel::AAC_ENCODER_NERO: showCustomParamsHelpScreen("neroAacEnc.exe",      "-help" ); break;
4219                         default: MUtils::Sound::beep(MUtils::Sound::BEEP_ERR); break;
4220                 }
4221         }
4222         else if(obj == ui->helpCustomParamFLAC)    showCustomParamsHelpScreen("flac.exe",    "--help");
4223         else if(obj == ui->helpCustomParamAften)   showCustomParamsHelpScreen("aften.exe",   "-h"    );
4224         else if(obj == ui->helpCustomParamOpus)    showCustomParamsHelpScreen("opusenc.exe", "--help");
4225         else MUtils::Sound::beep(MUtils::Sound::BEEP_ERR);
4226 }
4227
4228 /*
4229  * Show help for custom parameters
4230  */
4231 void MainWindow::showCustomParamsHelpScreen(const QString &toolName, const QString &command)
4232 {
4233         const QStringList toolNames = toolName.split('|', QString::SkipEmptyParts);
4234         QString binary;
4235         for(QStringList::ConstIterator iter = toolNames.constBegin(); iter != toolNames.constEnd(); iter++)
4236         {
4237                 if(lamexp_tools_check(*iter))
4238                 {
4239                         binary = lamexp_tools_lookup(*iter);
4240                         break;
4241                 }
4242         }
4243
4244         if(binary.isEmpty())
4245         {
4246                 MUtils::Sound::beep(MUtils::Sound::BEEP_ERR);
4247                 qWarning("customParamsHelpRequested: Binary could not be found!");
4248                 return;
4249         }
4250
4251         QProcess process;
4252         MUtils::init_process(process, QFileInfo(binary).absolutePath());
4253
4254         process.start(binary, command.isEmpty() ? QStringList() : QStringList() << command);
4255
4256         qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
4257
4258         if(process.waitForStarted(15000))
4259         {
4260                 qApp->processEvents();
4261                 process.waitForFinished(15000);
4262         }
4263         
4264         if(process.state() != QProcess::NotRunning)
4265         {
4266                 process.kill();
4267                 process.waitForFinished(-1);
4268         }
4269
4270         qApp->restoreOverrideCursor();
4271         QStringList output; bool spaceFlag = true;
4272
4273         while(process.canReadLine())
4274         {
4275                 QString temp = QString::fromUtf8(process.readLine());
4276                 TRIM_STRING_RIGHT(temp);
4277                 if(temp.isEmpty())
4278                 {
4279                         if(!spaceFlag) { output << temp; spaceFlag = true; }
4280                 }
4281                 else
4282                 {
4283                         output << temp; spaceFlag = false;
4284                 }
4285         }
4286
4287         if(output.count() < 1)
4288         {
4289                 qWarning("Empty output, cannot show help screen!");
4290                 MUtils::Sound::beep(MUtils::Sound::BEEP_ERR);
4291         }
4292
4293         LogViewDialog *dialog = new LogViewDialog(this);
4294         TEMP_HIDE_DROPBOX( dialog->exec(output); );
4295         MUTILS_DELETE(dialog);
4296 }
4297
4298 void MainWindow::overwriteModeChanged(int id)
4299 {
4300         if((id == SettingsModel::Overwrite_Replaces) && (m_settings->overwriteMode() != SettingsModel::Overwrite_Replaces))
4301         {
4302                 if(QMessageBox::warning(this, tr("Overwrite Mode"), tr("Warning: This mode may overwrite existing files with no way to revert!"), tr("Continue"), tr("Revert"), QString(), 1) != 0)
4303                 {
4304                         ui->radioButtonOverwriteModeKeepBoth->setChecked(m_settings->overwriteMode() == SettingsModel::Overwrite_KeepBoth);
4305                         ui->radioButtonOverwriteModeSkipFile->setChecked(m_settings->overwriteMode() == SettingsModel::Overwrite_SkipFile);
4306                         return;
4307                 }
4308         }
4309
4310         m_settings->overwriteMode(id);
4311 }
4312
4313 /*
4314  * Reset all advanced options to their defaults
4315  */
4316 void MainWindow::resetAdvancedOptionsButtonClicked(void)
4317 {
4318         PLAY_SOUND_OPTIONAL("blast", true);
4319
4320         ui->sliderLameAlgoQuality         ->setValue(m_settings->lameAlgoQualityDefault());
4321         ui->spinBoxBitrateManagementMin   ->setValue(m_settings->bitrateManagementMinRateDefault());
4322         ui->spinBoxBitrateManagementMax   ->setValue(m_settings->bitrateManagementMaxRateDefault());
4323         ui->spinBoxNormalizationFilterPeak->setValue(static_cast<double>(m_settings->normalizationFilterMaxVolumeDefault()) / 100.0);
4324         ui->spinBoxNormalizationFilterSize->setValue(m_settings->normalizationFilterSizeDefault());
4325         ui->spinBoxToneAdjustBass         ->setValue(static_cast<double>(m_settings->toneAdjustBassDefault()) / 100.0);
4326         ui->spinBoxToneAdjustTreble       ->setValue(static_cast<double>(m_settings->toneAdjustTrebleDefault()) / 100.0);
4327         ui->spinBoxAftenSearchSize        ->setValue(m_settings->aftenExponentSearchSizeDefault());
4328         ui->spinBoxOpusComplexity         ->setValue(m_settings->opusComplexityDefault());
4329         ui->comboBoxMP3ChannelMode        ->setCurrentIndex(m_settings->lameChannelModeDefault());
4330         ui->comboBoxSamplingRate          ->setCurrentIndex(m_settings->samplingRateDefault());
4331         ui->comboBoxAACProfile            ->setCurrentIndex(m_settings->aacEncProfileDefault());
4332         ui->comboBoxAftenCodingMode       ->setCurrentIndex(m_settings->aftenAudioCodingModeDefault());
4333         ui->comboBoxAftenDRCMode          ->setCurrentIndex(m_settings->aftenDynamicRangeCompressionDefault());
4334         ui->comboBoxOpusFramesize         ->setCurrentIndex(m_settings->opusFramesizeDefault());
4335
4336         SET_CHECKBOX_STATE(ui->checkBoxBitrateManagement,          m_settings->bitrateManagementEnabledDefault());
4337         SET_CHECKBOX_STATE(ui->checkBoxNeroAAC2PassMode,           m_settings->neroAACEnable2PassDefault());
4338         SET_CHECKBOX_STATE(ui->checkBoxNormalizationFilterEnabled, m_settings->normalizationFilterEnabledDefault());
4339         SET_CHECKBOX_STATE(ui->checkBoxNormalizationFilterDynamic, m_settings->normalizationFilterDynamicDefault());
4340         SET_CHECKBOX_STATE(ui->checkBoxNormalizationFilterCoupled, m_settings->normalizationFilterCoupledDefault());
4341         SET_CHECKBOX_STATE(ui->checkBoxAutoDetectInstances,        (m_settings->maximumInstancesDefault() < 1));
4342         SET_CHECKBOX_STATE(ui->checkBoxUseSystemTempFolder,        (!m_settings->customTempPathEnabledDefault()));
4343         SET_CHECKBOX_STATE(ui->checkBoxAftenFastAllocation,        m_settings->aftenFastBitAllocationDefault());
4344         SET_CHECKBOX_STATE(ui->checkBoxRename_Rename,              m_settings->renameFiles_renameEnabledDefault());
4345         SET_CHECKBOX_STATE(ui->checkBoxRename_RegExp,              m_settings->renameFiles_regExpEnabledDefault());
4346         SET_CHECKBOX_STATE(ui->checkBoxForceStereoDownmix,         m_settings->forceStereoDownmixDefault());
4347         SET_CHECKBOX_STATE(ui->checkBoxOpusDisableResample,        m_settings->opusDisableResampleDefault());
4348         
4349         ui->lineEditCustomParamLAME     ->setText(m_settings->customParametersLAMEDefault());
4350         ui->lineEditCustomParamOggEnc   ->setText(m_settings->customParametersOggEncDefault());
4351         ui->lineEditCustomParamNeroAAC  ->setText(m_settings->customParametersAacEncDefault());
4352         ui->lineEditCustomParamFLAC     ->setText(m_settings->customParametersFLACDefault());
4353         ui->lineEditCustomParamOpus     ->setText(m_settings->customParametersOpusEncDefault());
4354         ui->lineEditCustomTempFolder    ->setText(QDir::toNativeSeparators(m_settings->customTempPathDefault()));
4355         ui->lineEditRenamePattern       ->setText(m_settings->renameFiles_renamePatternDefault());
4356         ui->lineEditRenameRegExp_Search ->setText(m_settings->renameFiles_regExpSearchDefault());
4357         ui->lineEditRenameRegExp_Replace->setText(m_settings->renameFiles_regExpReplaceDefault());
4358
4359         if(m_settings->overwriteModeDefault() == SettingsModel::Overwrite_KeepBoth) ui->radioButtonOverwriteModeKeepBoth->click();
4360         if(m_settings->overwriteModeDefault() == SettingsModel::Overwrite_SkipFile) ui->radioButtonOverwriteModeSkipFile->click();
4361         if(m_settings->overwriteModeDefault() == SettingsModel::Overwrite_Replaces) ui->radioButtonOverwriteModeReplaces->click();
4362
4363         if(FileExtsModel *const model = dynamic_cast<FileExtsModel*>(ui->tableViewFileExts->model()))
4364         {
4365                 model->importItems(m_settings->renameFiles_fileExtensionDefault());
4366         }
4367
4368         ui->scrollArea->verticalScrollBar()->setValue(0);
4369         ui->buttonRename_Rename->click();
4370         customParamsChanged();
4371         renameOutputPatternChanged();
4372         renameRegExpValueChanged();
4373 }
4374
4375 // =========================================================
4376 // Multi-instance handling slots
4377 // =========================================================
4378
4379 /*
4380  * Other instance detected
4381  */
4382 void MainWindow::notifyOtherInstance(void)
4383 {
4384         if(!(BANNER_VISIBLE))
4385         {
4386                 QMessageBox msgBox(QMessageBox::Warning, tr("Already Running"), tr("LameXP is already running, please use the running instance!"), QMessageBox::NoButton, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowStaysOnTopHint);
4387                 msgBox.exec();
4388         }
4389 }
4390
4391 /*
4392  * Add file from another instance
4393  */
4394 void MainWindow::addFileDelayed(const QString &filePath, bool tryASAP)
4395 {
4396         if(tryASAP && !m_delayedFileTimer->isActive())
4397         {
4398                 qDebug("Received file: %s", MUTILS_UTF8(filePath));
4399                 m_delayedFileList->append(filePath);
4400                 QTimer::singleShot(0, this, SLOT(handleDelayedFiles()));
4401         }
4402         
4403         m_delayedFileTimer->stop();
4404         qDebug("Received file: %s", MUTILS_UTF8(filePath));
4405         m_delayedFileList->append(filePath);
4406         m_delayedFileTimer->start(5000);
4407 }
4408
4409 /*
4410  * Add files from another instance
4411  */
4412 void MainWindow::addFilesDelayed(const QStringList &filePaths, bool tryASAP)
4413 {
4414         if(tryASAP && (!m_delayedFileTimer->isActive()))
4415         {
4416                 qDebug("Received %d file(s).", filePaths.count());
4417                 m_delayedFileList->append(filePaths);
4418                 QTimer::singleShot(0, this, SLOT(handleDelayedFiles()));
4419         }
4420         else
4421         {
4422                 m_delayedFileTimer->stop();
4423                 qDebug("Received %d file(s).", filePaths.count());
4424                 m_delayedFileList->append(filePaths);
4425                 m_delayedFileTimer->start(5000);
4426         }
4427 }
4428
4429 /*
4430  * Add folder from another instance
4431  */
4432 void MainWindow::addFolderDelayed(const QString &folderPath, bool recursive)
4433 {
4434         if(!(BANNER_VISIBLE))
4435         {
4436                 addFolder(folderPath, recursive, true);
4437         }
4438 }
4439
4440 // =========================================================
4441 // Misc slots
4442 // =========================================================
4443
4444 /*
4445  * Restore the override cursor
4446  */
4447 void MainWindow::restoreCursor(void)
4448 {
4449         QApplication::restoreOverrideCursor();
4450 }