OSDN Git Service

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