OSDN Git Service

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