OSDN Git Service

dbcb086d79b5fc23af9fb03443217d615e4e8e5e
[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 unsigned int timeout = 8U;
1160
1161         const QString announceText = QString("%1<br><br>%2<br><nobr><tt>%3</tt></nobr><br>").arg
1162         (
1163                 NOBR("We are still looking for LameXP translators!"),
1164                 NOBR("If you are willing to translate LameXP to your language or to complete an existing translation, please refer to:"),
1165                 LINK("http://mulder.brhack.net/public/doc/lamexp_translate.html")
1166         );
1167
1168         QMessageBox *announceBox = new QMessageBox(QMessageBox::Warning, "We want you!", announceText, QMessageBox::NoButton, this);
1169         announceBox->setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
1170         announceBox->setIconPixmap(QIcon(":/images/Announcement.png").pixmap(64,79));
1171         
1172         QTimer *timers[timeout+1];
1173         QPushButton *buttons[timeout+1];
1174
1175         for(unsigned int i = 0; i <= timeout; i++)
1176         {
1177                 QString text = (i > 0) ? QString("%1 (%2)").arg(tr("Discard"), QString::number(i)) : tr("Discard");
1178                 buttons[i] = announceBox->addButton(text, (i > 0) ? QMessageBox::NoRole : QMessageBox::AcceptRole);
1179         }
1180
1181         for(unsigned int i = 0; i <= timeout; i++)
1182         {
1183                 buttons[i]->setEnabled(i == 0);
1184                 buttons[i]->setVisible(i == timeout);
1185         }
1186
1187         for(unsigned int i = 0; i < timeout; i++)
1188         {
1189                 timers[i] = new QTimer(this);
1190                 timers[i]->setSingleShot(true);
1191                 timers[i]->setInterval(1000);
1192                 connect(timers[i], SIGNAL(timeout()), buttons[i+1], SLOT(hide()));
1193                 connect(timers[i], SIGNAL(timeout()), buttons[i], SLOT(show()));
1194                 if(i > 0)
1195                 {
1196                         connect(timers[i], SIGNAL(timeout()), timers[i-1], SLOT(start()));
1197                 }
1198         }
1199
1200         timers[timeout-1]->start();
1201         announceBox->exec();
1202
1203         for(unsigned int i = 0; i < timeout; i++)
1204         {
1205                 timers[i]->stop();
1206                 LAMEXP_DELETE(timers[i]);
1207         }
1208
1209         LAMEXP_DELETE(announceBox);
1210 }
1211
1212 // =========================================================
1213 // Main button solots
1214 // =========================================================
1215
1216 /*
1217  * Encode button
1218  */
1219 void MainWindow::encodeButtonClicked(void)
1220 {
1221         static const unsigned __int64 oneGigabyte = 1073741824ui64; 
1222         static const unsigned __int64 minimumFreeDiskspaceMultiplier = 2ui64;
1223         static const char *writeTestBuffer = "LAMEXP_WRITE_TEST";
1224         
1225         ABORT_IF_BUSY;
1226
1227         if(m_fileListModel->rowCount() < 1)
1228         {
1229                 QMessageBox::warning(this, tr("LameXP"), NOBR(tr("You must add at least one file to the list before proceeding!")));
1230                 tabWidget->setCurrentIndex(0);
1231                 return;
1232         }
1233         
1234         QString tempFolder = m_settings->customTempPathEnabled() ? m_settings->customTempPath() : lamexp_temp_folder2();
1235         if(!QFileInfo(tempFolder).exists() || !QFileInfo(tempFolder).isDir())
1236         {
1237                 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)
1238                 {
1239                         while(checkBoxUseSystemTempFolder->isChecked() == m_settings->customTempPathEnabledDefault()) checkBoxUseSystemTempFolder->click();
1240                 }
1241                 return;
1242         }
1243
1244         bool ok = false;
1245         unsigned __int64 currentFreeDiskspace = lamexp_free_diskspace(tempFolder, &ok);
1246
1247         if(ok && (currentFreeDiskspace < (oneGigabyte * minimumFreeDiskspaceMultiplier)))
1248         {
1249                 QStringList tempFolderParts = tempFolder.split("/", QString::SkipEmptyParts, Qt::CaseInsensitive);
1250                 tempFolderParts.takeLast();
1251                 if(m_settings->soundsEnabled()) PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
1252                 QString lowDiskspaceMsg = QString("%1<br>%2<br><br>%3<br>%4<br>").arg
1253                 (
1254                         NOBR(tr("There are less than %1 GB of free diskspace available on your system's TEMP folder.").arg(QString::number(minimumFreeDiskspaceMultiplier))),
1255                         NOBR(tr("It is highly recommend to free up more diskspace before proceeding with the encode!")),
1256                         NOBR(tr("Your TEMP folder is located at:")),
1257                         QString("<nobr><tt>%1</tt></nobr>").arg(FSLINK(tempFolderParts.join("\\")))
1258                 );
1259                 switch(QMessageBox::warning(this, tr("Low Diskspace Warning"), lowDiskspaceMsg, tr("Abort Encoding Process"), tr("Clean Disk Now"), tr("Ignore")))
1260                 {
1261                 case 1:
1262                         QProcess::startDetached(QString("%1/cleanmgr.exe").arg(lamexp_known_folder(lamexp_folder_systemfolder)), QStringList() << "/D" << tempFolderParts.first());
1263                 case 0:
1264                         return;
1265                         break;
1266                 default:
1267                         QMessageBox::warning(this, tr("Low Diskspace"), tr("You are proceeding with low diskspace. Problems might occur!"));
1268                         break;
1269                 }
1270         }
1271
1272         switch(m_settings->compressionEncoder())
1273         {
1274         case SettingsModel::MP3Encoder:
1275         case SettingsModel::VorbisEncoder:
1276         case SettingsModel::AACEncoder:
1277         case SettingsModel::AC3Encoder:
1278         case SettingsModel::FLACEncoder:
1279         case SettingsModel::DCAEncoder:
1280         case SettingsModel::PCMEncoder:
1281                 break;
1282         default:
1283                 QMessageBox::warning(this, tr("LameXP"), tr("Sorry, an unsupported encoder has been chosen!"));
1284                 tabWidget->setCurrentIndex(3);
1285                 return;
1286         }
1287
1288         if(!m_settings->outputToSourceDir())
1289         {
1290                 QFile writeTest(QString("%1/~%2.txt").arg(m_settings->outputDir(), lamexp_rand_str()));
1291                 if(!(writeTest.open(QIODevice::ReadWrite) && (writeTest.write(writeTestBuffer) == strlen(writeTestBuffer))))
1292                 {
1293                         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!")));
1294                         tabWidget->setCurrentIndex(1);
1295                         return;
1296                 }
1297                 else
1298                 {
1299                         writeTest.close();
1300                         writeTest.remove();
1301                 }
1302         }
1303                 
1304         m_accepted = true;
1305         close();
1306 }
1307
1308 /*
1309  * About button
1310  */
1311 void MainWindow::aboutButtonClicked(void)
1312 {
1313         ABORT_IF_BUSY;
1314
1315         TEMP_HIDE_DROPBOX
1316         (
1317                 AboutDialog *aboutBox = new AboutDialog(m_settings, this);
1318                 aboutBox->exec();
1319                 LAMEXP_DELETE(aboutBox);
1320         )
1321 }
1322
1323 /*
1324  * Close button
1325  */
1326 void MainWindow::closeButtonClicked(void)
1327 {
1328         ABORT_IF_BUSY;
1329         close();
1330 }
1331
1332 // =========================================================
1333 // Tab widget slots
1334 // =========================================================
1335
1336 /*
1337  * Tab page changed
1338  */
1339 void MainWindow::tabPageChanged(int idx)
1340 {
1341         QList<QAction*> actions = m_tabActionGroup->actions();
1342         for(int i = 0; i < actions.count(); i++)
1343         {
1344                 bool ok = false;
1345                 int actionIndex = actions.at(i)->data().toInt(&ok);
1346                 if(ok && actionIndex == idx)
1347                 {
1348                         actions.at(i)->setChecked(true);
1349                 }
1350         }
1351
1352         int initialWidth = this->width();
1353         int maximumWidth = QApplication::desktop()->width();
1354
1355         if(this->isVisible())
1356         {
1357                 while(tabWidget->width() < tabWidget->sizeHint().width())
1358                 {
1359                         int previousWidth = this->width();
1360                         this->resize(this->width() + 1, this->height());
1361                         if(this->frameGeometry().width() >= maximumWidth) break;
1362                         if(this->width() <= previousWidth) break;
1363                 }
1364         }
1365
1366         if(idx == tabWidget->indexOf(tabOptions) && scrollArea->widget() && this->isVisible())
1367         {
1368                 for(int i = 0; i < 2; i++)
1369                 {
1370                         QApplication::processEvents();
1371                         while(scrollArea->viewport()->width() < scrollArea->widget()->width())
1372                         {
1373                                 int previousWidth = this->width();
1374                                 this->resize(this->width() + 1, this->height());
1375                                 if(this->frameGeometry().width() >= maximumWidth) break;
1376                                 if(this->width() <= previousWidth) break;
1377                         }
1378                 }
1379         }
1380         else if(idx == tabWidget->indexOf(tabSourceFiles))
1381         {
1382                 m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
1383         }
1384         else if(idx == tabWidget->indexOf(tabOutputDir))
1385         {
1386                 if(!m_OutputFolderViewInitialized)
1387                 {
1388                         QTimer::singleShot(0, this, SLOT(initOutputFolderModel()));
1389                 }
1390         }
1391
1392         if(initialWidth < this->width())
1393         {
1394                 QPoint prevPos = this->pos();
1395                 int delta = (this->width() - initialWidth) >> 2;
1396                 move(prevPos.x() - delta, prevPos.y());
1397         }
1398 }
1399
1400 /*
1401  * Tab action triggered
1402  */
1403 void MainWindow::tabActionActivated(QAction *action)
1404 {
1405         if(action && action->data().isValid())
1406         {
1407                 bool ok = false;
1408                 int index = action->data().toInt(&ok);
1409                 if(ok)
1410                 {
1411                         tabWidget->setCurrentIndex(index);
1412                 }
1413         }
1414 }
1415
1416 // =========================================================
1417 // View menu slots
1418 // =========================================================
1419
1420 /*
1421  * Style action triggered
1422  */
1423 void MainWindow::styleActionActivated(QAction *action)
1424 {
1425         //Change style setting
1426         if(action && action->data().isValid())
1427         {
1428                 bool ok = false;
1429                 int actionIndex = action->data().toInt(&ok);
1430                 if(ok)
1431                 {
1432                         m_settings->interfaceStyle(actionIndex);
1433                 }
1434         }
1435
1436         //Set up the new style
1437         switch(m_settings->interfaceStyle())
1438         {
1439         case 1:
1440                 if(actionStyleCleanlooks->isEnabled())
1441                 {
1442                         actionStyleCleanlooks->setChecked(true);
1443                         QApplication::setStyle(new QCleanlooksStyle());
1444                         break;
1445                 }
1446         case 2:
1447                 if(actionStyleWindowsVista->isEnabled())
1448                 {
1449                         actionStyleWindowsVista->setChecked(true);
1450                         QApplication::setStyle(new QWindowsVistaStyle());
1451                         break;
1452                 }
1453         case 3:
1454                 if(actionStyleWindowsXP->isEnabled())
1455                 {
1456                         actionStyleWindowsXP->setChecked(true);
1457                         QApplication::setStyle(new QWindowsXPStyle());
1458                         break;
1459                 }
1460         case 4:
1461                 if(actionStyleWindowsClassic->isEnabled())
1462                 {
1463                         actionStyleWindowsClassic->setChecked(true);
1464                         QApplication::setStyle(new QWindowsStyle());
1465                         break;
1466                 }
1467         default:
1468                 actionStylePlastique->setChecked(true);
1469                 QApplication::setStyle(new QPlastiqueStyle());
1470                 break;
1471         }
1472
1473         //Force re-translate after style change
1474         changeEvent(new QEvent(QEvent::LanguageChange));
1475 }
1476
1477 /*
1478  * Language action triggered
1479  */
1480 void MainWindow::languageActionActivated(QAction *action)
1481 {
1482         if(action->data().type() == QVariant::String)
1483         {
1484                 QString langId = action->data().toString();
1485
1486                 if(lamexp_install_translator(langId))
1487                 {
1488                         action->setChecked(true);
1489                         m_settings->currentLanguage(langId);
1490                 }
1491         }
1492 }
1493
1494 /*
1495  * Load language from file action triggered
1496  */
1497 void MainWindow::languageFromFileActionActivated(bool checked)
1498 {
1499         QFileDialog dialog(this, tr("Load Translation"));
1500         dialog.setFileMode(QFileDialog::ExistingFile);
1501         dialog.setNameFilter(QString("%1 (*.qm)").arg(tr("Translation Files")));
1502
1503         if(dialog.exec())
1504         {
1505                 QStringList selectedFiles = dialog.selectedFiles();
1506                 if(lamexp_install_translator_from_file(selectedFiles.first()))
1507                 {
1508                         QList<QAction*> actions = m_languageActionGroup->actions();
1509                         while(!actions.isEmpty())
1510                         {
1511                                 actions.takeFirst()->setChecked(false);
1512                         }
1513                 }
1514                 else
1515                 {
1516                         languageActionActivated(m_languageActionGroup->actions().first());
1517                 }
1518         }
1519 }
1520
1521 // =========================================================
1522 // Tools menu slots
1523 // =========================================================
1524
1525 /*
1526  * Disable update reminder action
1527  */
1528 void MainWindow::disableUpdateReminderActionTriggered(bool checked)
1529 {
1530         if(checked)
1531         {
1532                 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))
1533                 {
1534                         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!"))));
1535                         m_settings->autoUpdateEnabled(false);
1536                 }
1537                 else
1538                 {
1539                         m_settings->autoUpdateEnabled(true);
1540                 }
1541         }
1542         else
1543         {
1544                         QMessageBox::information(this, tr("Update Reminder"), NOBR(tr("The update reminder has been re-enabled.")));
1545                         m_settings->autoUpdateEnabled(true);
1546         }
1547
1548         actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
1549 }
1550
1551 /*
1552  * Disable sound effects action
1553  */
1554 void MainWindow::disableSoundsActionTriggered(bool checked)
1555 {
1556         if(checked)
1557         {
1558                 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))
1559                 {
1560                         QMessageBox::information(this, tr("Sound Effects"), NOBR(tr("All sound effects have been disabled.")));
1561                         m_settings->soundsEnabled(false);
1562                 }
1563                 else
1564                 {
1565                         m_settings->soundsEnabled(true);
1566                 }
1567         }
1568         else
1569         {
1570                         QMessageBox::information(this, tr("Sound Effects"), NOBR(tr("The sound effects have been re-enabled.")));
1571                         m_settings->soundsEnabled(true);
1572         }
1573
1574         actionDisableSounds->setChecked(!m_settings->soundsEnabled());
1575 }
1576
1577 /*
1578  * Disable Nero AAC encoder action
1579  */
1580 void MainWindow::disableNeroAacNotificationsActionTriggered(bool checked)
1581 {
1582         if(checked)
1583         {
1584                 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))
1585                 {
1586                         QMessageBox::information(this, tr("Nero AAC Notifications"), NOBR(tr("All Nero AAC Encoder notifications have been disabled.")));
1587                         m_settings->neroAacNotificationsEnabled(false);
1588                 }
1589                 else
1590                 {
1591                         m_settings->neroAacNotificationsEnabled(true);
1592                 }
1593         }
1594         else
1595         {
1596                         QMessageBox::information(this, tr("Nero AAC Notifications"), NOBR(tr("The Nero AAC Encoder notifications have been re-enabled.")));
1597                         m_settings->neroAacNotificationsEnabled(true);
1598         }
1599
1600         actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
1601 }
1602
1603 /*
1604  * Disable slow startup action
1605  */
1606 void MainWindow::disableSlowStartupNotificationsActionTriggered(bool checked)
1607 {
1608         if(checked)
1609         {
1610                 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))
1611                 {
1612                         QMessageBox::information(this, tr("Slow Startup Notifications"), NOBR(tr("The slow startup notifications have been disabled.")));
1613                         m_settings->antivirNotificationsEnabled(false);
1614                 }
1615                 else
1616                 {
1617                         m_settings->antivirNotificationsEnabled(true);
1618                 }
1619         }
1620         else
1621         {
1622                         QMessageBox::information(this, tr("Slow Startup Notifications"), NOBR(tr("The slow startup notifications have been re-enabled.")));
1623                         m_settings->antivirNotificationsEnabled(true);
1624         }
1625
1626         actionDisableSlowStartupNotifications->setChecked(!m_settings->antivirNotificationsEnabled());
1627 }
1628
1629 /*
1630  * Import a Cue Sheet file
1631  */
1632 void MainWindow::importCueSheetActionTriggered(bool checked)
1633 {
1634         ABORT_IF_BUSY;
1635         
1636         TEMP_HIDE_DROPBOX
1637         (
1638                 while(true)
1639                 {
1640                         int result = 0;
1641                         QString selectedCueFile;
1642
1643                         if(USE_NATIVE_FILE_DIALOG)
1644                         {
1645                                 selectedCueFile = QFileDialog::getOpenFileName(this, tr("Open Cue Sheet"), m_settings->mostRecentInputPath(), QString("%1 (*.cue)").arg(tr("Cue Sheet File")));
1646                         }
1647                         else
1648                         {
1649                                 QFileDialog dialog(this, tr("Open Cue Sheet"));
1650                                 dialog.setFileMode(QFileDialog::ExistingFile);
1651                                 dialog.setNameFilter(QString("%1 (*.cue)").arg(tr("Cue Sheet File")));
1652                                 dialog.setDirectory(m_settings->mostRecentInputPath());
1653                                 if(dialog.exec())
1654                                 {
1655                                         selectedCueFile = dialog.selectedFiles().first();
1656                                 }
1657                         }
1658
1659                         if(!selectedCueFile.isEmpty())
1660                         {
1661                                 m_settings->mostRecentInputPath(QFileInfo(selectedCueFile).canonicalPath());
1662                                 CueImportDialog *cueImporter  = new CueImportDialog(this, m_fileListModel, selectedCueFile);
1663                                 result = cueImporter->exec();
1664                                 LAMEXP_DELETE(cueImporter);
1665                         }
1666
1667                         if(result != (-1)) break;
1668                 }
1669         )
1670 }
1671
1672 /*
1673  * Show the "drop box" widget
1674  */
1675 void MainWindow::showDropBoxWidgetActionTriggered(bool checked)
1676 {
1677         m_settings->dropBoxWidgetEnabled(true);
1678         
1679         if(!m_dropBox->isVisible())
1680         {
1681                 m_dropBox->show();
1682         }
1683         
1684         lamexp_blink_window(m_dropBox);
1685 }
1686
1687 /*
1688  * Check for beta (pre-release) updates
1689  */
1690 void MainWindow::checkForBetaUpdatesActionTriggered(bool checked)
1691 {       
1692         bool checkUpdatesNow = false;
1693         
1694         if(checked)
1695         {
1696                 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))
1697                 {
1698                         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")))
1699                         {
1700                                 checkUpdatesNow = true;
1701                         }
1702                         m_settings->autoUpdateCheckBeta(true);
1703                 }
1704                 else
1705                 {
1706                         m_settings->autoUpdateCheckBeta(false);
1707                 }
1708         }
1709         else
1710         {
1711                         QMessageBox::information(this, tr("Beta Updates"), NOBR(tr("LameXP will <i>not</i> check for Beta (pre-release) updates from now on.")));
1712                         m_settings->autoUpdateCheckBeta(false);
1713         }
1714
1715         actionCheckForBetaUpdates->setChecked(m_settings->autoUpdateCheckBeta());
1716
1717         if(checkUpdatesNow)
1718         {
1719                 if(checkForUpdates())
1720                 {
1721                         QApplication::quit();
1722                 }
1723         }
1724 }
1725
1726 /*
1727  * Hibernate computer action
1728  */
1729 void MainWindow::hibernateComputerActionTriggered(bool checked)
1730 {
1731         if(checked)
1732         {
1733                 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))
1734                 {
1735                         QMessageBox::information(this, tr("Hibernate Computer"), NOBR(tr("LameXP will hibernate the computer on shutdown from now on.")));
1736                         m_settings->hibernateComputer(true);
1737                 }
1738                 else
1739                 {
1740                         m_settings->hibernateComputer(false);
1741                 }
1742         }
1743         else
1744         {
1745                         QMessageBox::information(this, tr("Hibernate Computer"), NOBR(tr("LameXP will <i>not</i> hibernate the computer on shutdown from now on.")));
1746                         m_settings->hibernateComputer(false);
1747         }
1748
1749         actionHibernateComputer->setChecked(m_settings->hibernateComputer());
1750 }
1751
1752 /*
1753  * Disable shell integration action
1754  */
1755 void MainWindow::disableShellIntegrationActionTriggered(bool checked)
1756 {
1757         if(checked)
1758         {
1759                 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))
1760                 {
1761                         ShellIntegration::remove();
1762                         QMessageBox::information(this, tr("Shell Integration"), NOBR(tr("The LameXP shell integration has been disabled.")));
1763                         m_settings->shellIntegrationEnabled(false);
1764                 }
1765                 else
1766                 {
1767                         m_settings->shellIntegrationEnabled(true);
1768                 }
1769         }
1770         else
1771         {
1772                         ShellIntegration::install();
1773                         QMessageBox::information(this, tr("Shell Integration"), NOBR(tr("The LameXP shell integration has been re-enabled.")));
1774                         m_settings->shellIntegrationEnabled(true);
1775         }
1776
1777         actionDisableShellIntegration->setChecked(!m_settings->shellIntegrationEnabled());
1778         
1779         if(lamexp_portable_mode() && actionDisableShellIntegration->isChecked())
1780         {
1781                 actionDisableShellIntegration->setEnabled(false);
1782         }
1783 }
1784
1785 // =========================================================
1786 // Help menu slots
1787 // =========================================================
1788
1789 /*
1790  * Visit homepage action
1791  */
1792 void MainWindow::visitHomepageActionActivated(void)
1793 {
1794         if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
1795         {
1796                 if(action->data().isValid() && (action->data().type() == QVariant::String))
1797                 {
1798                         QDesktopServices::openUrl(QUrl(action->data().toString()));
1799                 }
1800         }
1801 }
1802
1803 /*
1804  * Show document
1805  */
1806 void MainWindow::documentActionActivated(void)
1807 {
1808         if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
1809         {
1810                 if(action->data().isValid() && (action->data().type() == QVariant::String))
1811                 {
1812                         QFileInfo document(action->data().toString());
1813                         QFileInfo resource(QString(":/doc/%1.html").arg(document.baseName()));
1814                         if(document.exists() && document.isFile() && (document.size() == resource.size()))
1815                         {
1816                                 QDesktopServices::openUrl(QUrl::fromLocalFile(document.canonicalFilePath()));
1817                         }
1818                         else
1819                         {
1820                                 QFile source(resource.filePath());
1821                                 QFile output(QString("%1/%2.%3.html").arg(lamexp_temp_folder2(), document.baseName(), lamexp_rand_str().left(8)));
1822                                 if(source.open(QIODevice::ReadOnly) && output.open(QIODevice::ReadWrite))
1823                                 {
1824                                         output.write(source.readAll());
1825                                         action->setData(output.fileName());
1826                                         source.close();
1827                                         output.close();
1828                                         QDesktopServices::openUrl(QUrl::fromLocalFile(output.fileName()));
1829                                 }
1830                         }
1831                 }
1832         }
1833 }
1834
1835 /*
1836  * Check for updates action
1837  */
1838 void MainWindow::checkUpdatesActionActivated(void)
1839 {
1840         ABORT_IF_BUSY;
1841         bool bFlag = false;
1842
1843         TEMP_HIDE_DROPBOX
1844         (
1845                 bFlag = checkForUpdates();
1846         )
1847         
1848         if(bFlag)
1849         {
1850                 QApplication::quit();
1851         }
1852 }
1853
1854 // =========================================================
1855 // Source file slots
1856 // =========================================================
1857
1858 /*
1859  * Add file(s) button
1860  */
1861 void MainWindow::addFilesButtonClicked(void)
1862 {
1863         ABORT_IF_BUSY;
1864
1865         TEMP_HIDE_DROPBOX
1866         (
1867                 if(USE_NATIVE_FILE_DIALOG)
1868                 {
1869                         QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
1870                         QStringList selectedFiles = QFileDialog::getOpenFileNames(this, tr("Add file(s)"), m_settings->mostRecentInputPath(), fileTypeFilters.join(";;"));
1871                         if(!selectedFiles.isEmpty())
1872                         {
1873                                 m_settings->mostRecentInputPath(QFileInfo(selectedFiles.first()).canonicalPath());
1874                                 addFiles(selectedFiles);
1875                         }
1876                 }
1877                 else
1878                 {
1879                         QFileDialog dialog(this, tr("Add file(s)"));
1880                         QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
1881                         dialog.setFileMode(QFileDialog::ExistingFiles);
1882                         dialog.setNameFilter(fileTypeFilters.join(";;"));
1883                         dialog.setDirectory(m_settings->mostRecentInputPath());
1884                         if(dialog.exec())
1885                         {
1886                                 QStringList selectedFiles = dialog.selectedFiles();
1887                                 if(!selectedFiles.isEmpty())
1888                                 {
1889                                         m_settings->mostRecentInputPath(QFileInfo(selectedFiles.first()).canonicalPath());
1890                                         addFiles(selectedFiles);
1891                                 }
1892                         }
1893                 }
1894         )
1895 }
1896
1897 /*
1898  * Open folder action
1899  */
1900 void MainWindow::openFolderActionActivated(void)
1901 {
1902         ABORT_IF_BUSY;
1903         QString selectedFolder;
1904         
1905         if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
1906         {
1907                 TEMP_HIDE_DROPBOX
1908                 (
1909                         if(USE_NATIVE_FILE_DIALOG)
1910                         {
1911                                 selectedFolder = QFileDialog::getExistingDirectory(this, tr("Add Folder"), m_settings->mostRecentInputPath());
1912                         }
1913                         else
1914                         {
1915                                 QFileDialog dialog(this, tr("Add Folder"));
1916                                 dialog.setFileMode(QFileDialog::DirectoryOnly);
1917                                 dialog.setDirectory(m_settings->mostRecentInputPath());
1918                                 if(dialog.exec())
1919                                 {
1920                                         selectedFolder = dialog.selectedFiles().first();
1921                                 }
1922                         }
1923                         
1924                         if(!selectedFolder.isEmpty())
1925                         {
1926                                 m_settings->mostRecentInputPath(QDir(selectedFolder).canonicalPath());
1927                                 addFolder(selectedFolder, action->data().toBool());
1928                         }
1929                 )
1930         }
1931 }
1932
1933 /*
1934  * Remove file button
1935  */
1936 void MainWindow::removeFileButtonClicked(void)
1937 {
1938         if(sourceFileView->currentIndex().isValid())
1939         {
1940                 int iRow = sourceFileView->currentIndex().row();
1941                 m_fileListModel->removeFile(sourceFileView->currentIndex());
1942                 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
1943         }
1944 }
1945
1946 /*
1947  * Clear files button
1948  */
1949 void MainWindow::clearFilesButtonClicked(void)
1950 {
1951         m_fileListModel->clearFiles();
1952 }
1953
1954 /*
1955  * Move file up button
1956  */
1957 void MainWindow::fileUpButtonClicked(void)
1958 {
1959         if(sourceFileView->currentIndex().isValid())
1960         {
1961                 int iRow = sourceFileView->currentIndex().row() - 1;
1962                 m_fileListModel->moveFile(sourceFileView->currentIndex(), -1);
1963                 sourceFileView->selectRow(iRow >= 0 ? iRow : 0);
1964         }
1965 }
1966
1967 /*
1968  * Move file down button
1969  */
1970 void MainWindow::fileDownButtonClicked(void)
1971 {
1972         if(sourceFileView->currentIndex().isValid())
1973         {
1974                 int iRow = sourceFileView->currentIndex().row() + 1;
1975                 m_fileListModel->moveFile(sourceFileView->currentIndex(), 1);
1976                 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
1977         }
1978 }
1979
1980 /*
1981  * Show details button
1982  */
1983 void MainWindow::showDetailsButtonClicked(void)
1984 {
1985         ABORT_IF_BUSY;
1986
1987         int iResult = 0;
1988         MetaInfoDialog *metaInfoDialog = new MetaInfoDialog(this);
1989         QModelIndex index = sourceFileView->currentIndex();
1990
1991         while(index.isValid())
1992         {
1993                 if(iResult > 0)
1994                 {
1995                         index = m_fileListModel->index(index.row() + 1, index.column()); 
1996                         sourceFileView->selectRow(index.row());
1997                 }
1998                 if(iResult < 0)
1999                 {
2000                         index = m_fileListModel->index(index.row() - 1, index.column()); 
2001                         sourceFileView->selectRow(index.row());
2002                 }
2003
2004                 AudioFileModel &file = (*m_fileListModel)[index];
2005                 TEMP_HIDE_DROPBOX
2006                 (
2007                         iResult = metaInfoDialog->exec(file, index.row() > 0, index.row() < m_fileListModel->rowCount() - 1);
2008                 )
2009                 
2010                 if(iResult == INT_MAX)
2011                 {
2012                         m_metaInfoModel->assignInfoFrom(file);
2013                         tabWidget->setCurrentIndex(tabWidget->indexOf(tabMetaData));
2014                         break;
2015                 }
2016
2017                 if(!iResult) break;
2018         }
2019
2020         LAMEXP_DELETE(metaInfoDialog);
2021         QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2022         sourceFilesScrollbarMoved(0);
2023 }
2024
2025 /*
2026  * Show context menu for source files
2027  */
2028 void MainWindow::sourceFilesContextMenu(const QPoint &pos)
2029 {
2030         QAbstractScrollArea *scrollArea = dynamic_cast<QAbstractScrollArea*>(QObject::sender());
2031         QWidget *sender = scrollArea ? scrollArea->viewport() : dynamic_cast<QWidget*>(QObject::sender());
2032
2033         if(sender)
2034         {
2035                 if(pos.x() <= sender->width() && pos.y() <= sender->height() && pos.x() >= 0 && pos.y() >= 0)
2036                 {
2037                         m_sourceFilesContextMenu->popup(sender->mapToGlobal(pos));
2038                 }
2039         }
2040 }
2041
2042 /*
2043  * Scrollbar of source files moved
2044  */
2045 void MainWindow::sourceFilesScrollbarMoved(int)
2046 {
2047         sourceFileView->resizeColumnToContents(0);
2048 }
2049
2050 /*
2051  * Open selected file in external player
2052  */
2053 void MainWindow::previewContextActionTriggered(void)
2054 {
2055         const static char *appNames[3] = {"smplayer_portable.exe", "smplayer.exe", "mplayer.exe"};
2056         const static wchar_t *registryKey = L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}";
2057         
2058         QModelIndex index = sourceFileView->currentIndex();
2059         if(!index.isValid())
2060         {
2061                 return;
2062         }
2063
2064         QString mplayerPath;
2065         HKEY registryKeyHandle;
2066
2067         if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, registryKey, 0, KEY_READ, &registryKeyHandle) == ERROR_SUCCESS)
2068         {
2069                 wchar_t Buffer[4096];
2070                 DWORD BuffSize = sizeof(wchar_t*) * 4096;
2071                 if(RegQueryValueExW(registryKeyHandle, L"InstallLocation", 0, 0, reinterpret_cast<BYTE*>(Buffer), &BuffSize) == ERROR_SUCCESS)
2072                 {
2073                         mplayerPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(Buffer));
2074                 }
2075         }
2076
2077         if(!mplayerPath.isEmpty())
2078         {
2079                 QDir mplayerDir(mplayerPath);
2080                 if(mplayerDir.exists())
2081                 {
2082                         for(int i = 0; i < 3; i++)
2083                         {
2084                                 if(mplayerDir.exists(appNames[i]))
2085                                 {
2086                                         QProcess::startDetached(mplayerDir.absoluteFilePath(appNames[i]), QStringList() << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
2087                                         return;
2088                                 }
2089                         }
2090                 }
2091         }
2092         
2093         QDesktopServices::openUrl(QString("file:///").append(m_fileListModel->getFile(index).filePath()));
2094 }
2095
2096 /*
2097  * Find selected file in explorer
2098  */
2099 void MainWindow::findFileContextActionTriggered(void)
2100 {
2101         QModelIndex index = sourceFileView->currentIndex();
2102         if(index.isValid())
2103         {
2104                 QString systemRootPath;
2105
2106                 QDir systemRoot(lamexp_known_folder(lamexp_folder_systemfolder));
2107                 if(systemRoot.exists() && systemRoot.cdUp())
2108                 {
2109                         systemRootPath = systemRoot.canonicalPath();
2110                 }
2111
2112                 if(!systemRootPath.isEmpty())
2113                 {
2114                         QFileInfo explorer(QString("%1/explorer.exe").arg(systemRootPath));
2115                         if(explorer.exists() && explorer.isFile())
2116                         {
2117                                 QProcess::execute(explorer.canonicalFilePath(), QStringList() << "/select," << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
2118                                 return;
2119                         }
2120                 }
2121                 else
2122                 {
2123                         qWarning("SystemRoot directory could not be detected!");
2124                 }
2125         }
2126 }
2127
2128 /*
2129  * Add all pending files
2130  */
2131 void MainWindow::handleDelayedFiles(void)
2132 {
2133         m_delayedFileTimer->stop();
2134
2135         if(m_delayedFileList->isEmpty())
2136         {
2137                 return;
2138         }
2139
2140         if(m_banner->isVisible())
2141         {
2142                 m_delayedFileTimer->start(5000);
2143                 return;
2144         }
2145
2146         QStringList selectedFiles;
2147         tabWidget->setCurrentIndex(0);
2148
2149         while(!m_delayedFileList->isEmpty())
2150         {
2151                 QFileInfo currentFile = QFileInfo(m_delayedFileList->takeFirst());
2152                 if(!currentFile.exists() || !currentFile.isFile())
2153                 {
2154                         continue;
2155                 }
2156                 selectedFiles << currentFile.canonicalFilePath();
2157         }
2158         
2159         addFiles(selectedFiles);
2160 }
2161
2162 /*
2163  * Export Meta tags to CSV file
2164  */
2165 void MainWindow::exportCsvContextActionTriggered(void)
2166 {
2167         TEMP_HIDE_DROPBOX
2168         (
2169                 QString selectedCsvFile;
2170         
2171                 if(USE_NATIVE_FILE_DIALOG)
2172                 {
2173                         selectedCsvFile = QFileDialog::getSaveFileName(this, tr("Save CSV file"), m_settings->mostRecentInputPath(), QString("%1 (*.csv)").arg(tr("CSV File")));
2174                 }
2175                 else
2176                 {
2177                         QFileDialog dialog(this, tr("Save CSV file"));
2178                         dialog.setFileMode(QFileDialog::AnyFile);
2179                         dialog.setAcceptMode(QFileDialog::AcceptSave);
2180                         dialog.setNameFilter(QString("%1 (*.csv)").arg(tr("CSV File")));
2181                         dialog.setDirectory(m_settings->mostRecentInputPath());
2182                         if(dialog.exec())
2183                         {
2184                                 selectedCsvFile = dialog.selectedFiles().first();
2185                         }
2186                 }
2187
2188                 if(!selectedCsvFile.isEmpty())
2189                 {
2190                         m_settings->mostRecentInputPath(QFileInfo(selectedCsvFile).canonicalPath());
2191                         switch(m_fileListModel->exportToCsv(selectedCsvFile))
2192                         {
2193                         case FileListModel::CsvError_NoTags:
2194                                 QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, there are no meta tags that can be exported!")));
2195                                 break;
2196                         case FileListModel::CsvError_FileOpen:
2197                                 QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, failed to open CSV file for writing!")));
2198                                 break;
2199                         case FileListModel::CsvError_FileWrite:
2200                                 QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, failed to write to the CSV file!")));
2201                                 break;
2202                         case FileListModel::CsvError_OK:
2203                                 QMessageBox::information(this, tr("CSV Export"), NOBR(tr("The CSV files was created successfully!")));
2204                                 break;
2205                         default:
2206                                 qWarning("exportToCsv: Unknown return code!");
2207                         }
2208                 }
2209         )
2210 }
2211
2212
2213 /*
2214  * Import Meta tags from CSV file
2215  */
2216 void MainWindow::importCsvContextActionTriggered(void)
2217 {
2218         TEMP_HIDE_DROPBOX
2219         (
2220                 QString selectedCsvFile;
2221         
2222                 if(USE_NATIVE_FILE_DIALOG)
2223                 {
2224                         selectedCsvFile = QFileDialog::getOpenFileName(this, tr("Open CSV file"), m_settings->mostRecentInputPath(), QString("%1 (*.csv)").arg(tr("CSV File")));
2225                 }
2226                 else
2227                 {
2228                         QFileDialog dialog(this, tr("Open CSV file"));
2229                         dialog.setFileMode(QFileDialog::ExistingFile);
2230                         dialog.setNameFilter(QString("%1 (*.csv)").arg(tr("CSV File")));
2231                         dialog.setDirectory(m_settings->mostRecentInputPath());
2232                         if(dialog.exec())
2233                         {
2234                                 selectedCsvFile = dialog.selectedFiles().first();
2235                         }
2236                 }
2237
2238                 if(!selectedCsvFile.isEmpty())
2239                 {
2240                         m_settings->mostRecentInputPath(QFileInfo(selectedCsvFile).canonicalPath());
2241                         switch(m_fileListModel->importFromCsv(this, selectedCsvFile))
2242                         {
2243                         case FileListModel::CsvError_FileOpen:
2244                                 QMessageBox::critical(this, tr("CSV Import"), NOBR(tr("Sorry, failed to open CSV file for reading!")));
2245                                 break;
2246                         case FileListModel::CsvError_FileRead:
2247                                 QMessageBox::critical(this, tr("CSV Import"), NOBR(tr("Sorry, failed to read from the CSV file!")));
2248                                 break;
2249                         case FileListModel::CsvError_NoTags:
2250                                 QMessageBox::critical(this, tr("CSV Import"), NOBR(tr("Sorry, the CSV file does not contain any known fields!")));
2251                                 break;
2252                         case FileListModel::CsvError_Incomplete:
2253                                 QMessageBox::warning(this, tr("CSV Import"), NOBR(tr("CSV file is incomplete. Not all files were updated!")));
2254                                 break;
2255                         case FileListModel::CsvError_OK:
2256                                 QMessageBox::information(this, tr("CSV Import"), NOBR(tr("The CSV files was imported successfully!")));
2257                                 break;
2258                         case FileListModel::CsvError_Aborted:
2259                                 /* User aborted, ignore! */
2260                                 break;
2261                         default:
2262                                 qWarning("exportToCsv: Unknown return code!");
2263                         }
2264                 }
2265         )
2266 }
2267
2268 /*
2269  * Show or hide Drag'n'Drop notice after model reset
2270  */
2271 void MainWindow::sourceModelChanged(void)
2272 {
2273         m_dropNoteLabel->setVisible(m_fileListModel->rowCount() <= 0);
2274 }
2275
2276 // =========================================================
2277 // Output folder slots
2278 // =========================================================
2279
2280 /*
2281  * Output folder changed (mouse clicked)
2282  */
2283 void MainWindow::outputFolderViewClicked(const QModelIndex &index)
2284 {
2285         if(outputFolderView->currentIndex() != index)
2286         {
2287                 outputFolderView->setCurrentIndex(index);
2288         }
2289         QString selectedDir = m_fileSystemModel->filePath(index);
2290         if(selectedDir.length() < 3) selectedDir.append(QDir::separator());
2291         outputFolderLabel->setText(QDir::toNativeSeparators(selectedDir));
2292         m_settings->outputDir(selectedDir);
2293 }
2294
2295 /*
2296  * Output folder changed (mouse moved)
2297  */
2298 void MainWindow::outputFolderViewMoved(const QModelIndex &index)
2299 {
2300         if(QApplication::mouseButtons() & Qt::LeftButton)
2301         {
2302                 outputFolderViewClicked(index);
2303         }
2304 }
2305
2306 /*
2307  * Goto desktop button
2308  */
2309 void MainWindow::gotoDesktopButtonClicked(void)
2310 {
2311         QString desktopPath = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
2312         
2313         if(!desktopPath.isEmpty() && QDir(desktopPath).exists())
2314         {
2315                 outputFolderView->setCurrentIndex(m_fileSystemModel->index(desktopPath));
2316                 outputFolderViewClicked(outputFolderView->currentIndex());
2317                 outputFolderView->setFocus();
2318         }
2319         else
2320         {
2321                 buttonGotoDesktop->setEnabled(false);
2322         }
2323 }
2324
2325 /*
2326  * Goto home folder button
2327  */
2328 void MainWindow::gotoHomeFolderButtonClicked(void)
2329 {
2330         QString homePath = QDesktopServices::storageLocation(QDesktopServices::HomeLocation);
2331         
2332         if(!homePath.isEmpty() && QDir(homePath).exists())
2333         {
2334                 outputFolderView->setCurrentIndex(m_fileSystemModel->index(homePath));
2335                 outputFolderViewClicked(outputFolderView->currentIndex());
2336                 outputFolderView->setFocus();
2337         }
2338         else
2339         {
2340                 buttonGotoHome->setEnabled(false);
2341         }
2342 }
2343
2344 /*
2345  * Goto music folder button
2346  */
2347 void MainWindow::gotoMusicFolderButtonClicked(void)
2348 {
2349         QString musicPath = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
2350         
2351         if(!musicPath.isEmpty() && QDir(musicPath).exists())
2352         {
2353                 outputFolderView->setCurrentIndex(m_fileSystemModel->index(musicPath));
2354                 outputFolderViewClicked(outputFolderView->currentIndex());
2355                 outputFolderView->setFocus();
2356         }
2357         else
2358         {
2359                 buttonGotoMusic->setEnabled(false);
2360         }
2361 }
2362
2363 /*
2364  * Goto music favorite output folder
2365  */
2366 void MainWindow::gotoFavoriteFolder(void)
2367 {
2368         QAction *item = dynamic_cast<QAction*>(QObject::sender());
2369         
2370         if(item)
2371         {
2372                 QDir path(item->data().toString());
2373                 if(path.exists())
2374                 {
2375                         outputFolderView->setCurrentIndex(m_fileSystemModel->index(path.canonicalPath()));
2376                         outputFolderViewClicked(outputFolderView->currentIndex());
2377                         outputFolderView->setFocus();
2378                 }
2379                 else
2380                 {
2381                         MessageBeep(MB_ICONERROR);
2382                         m_outputFolderFavoritesMenu->removeAction(item);
2383                         item->deleteLater();
2384                 }
2385         }
2386 }
2387
2388 /*
2389  * Make folder button
2390  */
2391 void MainWindow::makeFolderButtonClicked(void)
2392 {
2393         ABORT_IF_BUSY;
2394
2395         QDir basePath(m_fileSystemModel->fileInfo(outputFolderView->currentIndex()).absoluteFilePath());
2396         QString suggestedName = tr("New Folder");
2397
2398         if(!m_metaData->fileArtist().isEmpty() && !m_metaData->fileAlbum().isEmpty())
2399         {
2400                 suggestedName = QString("%1 - %2").arg(m_metaData->fileArtist(), m_metaData->fileAlbum());
2401         }
2402         else if(!m_metaData->fileArtist().isEmpty())
2403         {
2404                 suggestedName = m_metaData->fileArtist();
2405         }
2406         else if(!m_metaData->fileAlbum().isEmpty())
2407         {
2408                 suggestedName = m_metaData->fileAlbum();
2409         }
2410         else
2411         {
2412                 for(int i = 0; i < m_fileListModel->rowCount(); i++)
2413                 {
2414                         AudioFileModel audioFile = m_fileListModel->getFile(m_fileListModel->index(i, 0));
2415                         if(!audioFile.fileAlbum().isEmpty() || !audioFile.fileArtist().isEmpty())
2416                         {
2417                                 if(!audioFile.fileArtist().isEmpty() && !audioFile.fileAlbum().isEmpty())
2418                                 {
2419                                         suggestedName = QString("%1 - %2").arg(audioFile.fileArtist(), audioFile.fileAlbum());
2420                                 }
2421                                 else if(!audioFile.fileArtist().isEmpty())
2422                                 {
2423                                         suggestedName = audioFile.fileArtist();
2424                                 }
2425                                 else if(!audioFile.fileAlbum().isEmpty())
2426                                 {
2427                                         suggestedName = audioFile.fileAlbum();
2428                                 }
2429                                 break;
2430                         }
2431                 }
2432         }
2433         
2434         suggestedName = lamexp_clean_filename(suggestedName);
2435
2436         while(true)
2437         {
2438                 bool bApplied = false;
2439                 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();
2440
2441                 if(bApplied)
2442                 {
2443                         folderName = lamexp_clean_filepath(folderName.simplified());
2444
2445                         if(folderName.isEmpty())
2446                         {
2447                                 MessageBeep(MB_ICONERROR);
2448                                 continue;
2449                         }
2450
2451                         int i = 1;
2452                         QString newFolder = folderName;
2453
2454                         while(basePath.exists(newFolder))
2455                         {
2456                                 newFolder = QString(folderName).append(QString().sprintf(" (%d)", ++i));
2457                         }
2458                         
2459                         if(basePath.mkpath(newFolder))
2460                         {
2461                                 QDir createdDir = basePath;
2462                                 if(createdDir.cd(newFolder))
2463                                 {
2464                                         outputFolderView->setCurrentIndex(m_fileSystemModel->index(createdDir.canonicalPath()));
2465                                         outputFolderViewClicked(outputFolderView->currentIndex());
2466                                         outputFolderView->setFocus();
2467                                 }
2468                         }
2469                         else
2470                         {
2471                                 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!")));
2472                         }
2473                 }
2474                 break;
2475         }
2476 }
2477
2478 /*
2479  * Output to source dir changed
2480  */
2481 void MainWindow::saveToSourceFolderChanged(void)
2482 {
2483         m_settings->outputToSourceDir(saveToSourceFolderCheckBox->isChecked());
2484 }
2485
2486 /*
2487  * Prepend relative source file path to output file name changed
2488  */
2489 void MainWindow::prependRelativePathChanged(void)
2490 {
2491         m_settings->prependRelativeSourcePath(prependRelativePathCheckBox->isChecked());
2492 }
2493
2494 /*
2495  * Show context menu for output folder
2496  */
2497 void MainWindow::outputFolderContextMenu(const QPoint &pos)
2498 {
2499         QAbstractScrollArea *scrollArea = dynamic_cast<QAbstractScrollArea*>(QObject::sender());
2500         QWidget *sender = scrollArea ? scrollArea->viewport() : dynamic_cast<QWidget*>(QObject::sender());      
2501
2502         if(pos.x() <= sender->width() && pos.y() <= sender->height() && pos.x() >= 0 && pos.y() >= 0)
2503         {
2504                 m_outputFolderContextMenu->popup(sender->mapToGlobal(pos));
2505         }
2506 }
2507
2508 /*
2509  * Show selected folder in explorer
2510  */
2511 void MainWindow::showFolderContextActionTriggered(void)
2512 {
2513         QString path = QDir::toNativeSeparators(m_fileSystemModel->filePath(outputFolderView->currentIndex()));
2514         if(!path.endsWith(QDir::separator())) path.append(QDir::separator());
2515         ShellExecuteW(this->winId(), L"explore", QWCHAR(path), NULL, NULL, SW_SHOW);
2516 }
2517
2518 /*
2519  * Add current folder to favorites
2520  */
2521 void MainWindow::addFavoriteFolderActionTriggered(void)
2522 {
2523         QString path = m_fileSystemModel->filePath(outputFolderView->currentIndex());
2524         QStringList favorites = m_settings->favoriteOutputFolders().split("|", QString::SkipEmptyParts);
2525
2526         if(!favorites.contains(path, Qt::CaseInsensitive))
2527         {
2528                 favorites.append(path);
2529                 while(favorites.count() > 6) favorites.removeFirst();
2530         }
2531         else
2532         {
2533                 MessageBeep(MB_ICONWARNING);
2534         }
2535
2536         m_settings->favoriteOutputFolders(favorites.join("|"));
2537         refreshFavorites();
2538 }
2539
2540 /*
2541  * Initialize file system model
2542  */
2543 void MainWindow::initOutputFolderModel(void)
2544 {
2545         QModelIndex previousIndex = outputFolderView->currentIndex();
2546         m_fileSystemModel->setRootPath(m_fileSystemModel->rootPath());
2547         QApplication::processEvents();
2548         outputFolderView->reset();
2549         outputFolderView->setCurrentIndex(previousIndex);
2550         m_OutputFolderViewInitialized = true;
2551 }
2552
2553 // =========================================================
2554 // Metadata tab slots
2555 // =========================================================
2556
2557 /*
2558  * Edit meta button clicked
2559  */
2560 void MainWindow::editMetaButtonClicked(void)
2561 {
2562         ABORT_IF_BUSY;
2563
2564         const QModelIndex index = metaDataView->currentIndex();
2565
2566         if(index.isValid())
2567         {
2568                 m_metaInfoModel->editItem(index, this);
2569         
2570                 if(index.row() == 4)
2571                 {
2572                         m_settings->metaInfoPosition(m_metaData->filePosition());
2573                 }
2574         }
2575 }
2576
2577 /*
2578  * Reset meta button clicked
2579  */
2580 void MainWindow::clearMetaButtonClicked(void)
2581 {
2582         ABORT_IF_BUSY;
2583         m_metaInfoModel->clearData();
2584 }
2585
2586 /*
2587  * Meta tags enabled changed
2588  */
2589 void MainWindow::metaTagsEnabledChanged(void)
2590 {
2591         m_settings->writeMetaTags(writeMetaDataCheckBox->isChecked());
2592 }
2593
2594 /*
2595  * Playlist enabled changed
2596  */
2597 void MainWindow::playlistEnabledChanged(void)
2598 {
2599         m_settings->createPlaylist(generatePlaylistCheckBox->isChecked());
2600 }
2601
2602 // =========================================================
2603 // Compression tab slots
2604 // =========================================================
2605
2606 /*
2607  * Update encoder
2608  */
2609 void MainWindow::updateEncoder(int id)
2610 {
2611         m_settings->compressionEncoder(id);
2612
2613         switch(m_settings->compressionEncoder())
2614         {
2615         case SettingsModel::VorbisEncoder:
2616                 radioButtonModeQuality->setEnabled(true);
2617                 radioButtonModeAverageBitrate->setEnabled(true);
2618                 radioButtonConstBitrate->setEnabled(false);
2619                 if(radioButtonConstBitrate->isChecked()) radioButtonModeQuality->setChecked(true);
2620                 sliderBitrate->setEnabled(true);
2621                 break;
2622         case SettingsModel::AC3Encoder:
2623                 radioButtonModeQuality->setEnabled(true);
2624                 radioButtonModeQuality->setChecked(true);
2625                 radioButtonModeAverageBitrate->setEnabled(false);
2626                 radioButtonConstBitrate->setEnabled(true);
2627                 sliderBitrate->setEnabled(true);
2628                 break;
2629         case SettingsModel::FLACEncoder:
2630                 radioButtonModeQuality->setEnabled(false);
2631                 radioButtonModeQuality->setChecked(true);
2632                 radioButtonModeAverageBitrate->setEnabled(false);
2633                 radioButtonConstBitrate->setEnabled(false);
2634                 sliderBitrate->setEnabled(true);
2635                 break;
2636         case SettingsModel::PCMEncoder:
2637                 radioButtonModeQuality->setEnabled(false);
2638                 radioButtonModeQuality->setChecked(true);
2639                 radioButtonModeAverageBitrate->setEnabled(false);
2640                 radioButtonConstBitrate->setEnabled(false);
2641                 sliderBitrate->setEnabled(false);
2642                 break;
2643         case SettingsModel::AACEncoder:
2644                 radioButtonModeQuality->setEnabled(true);
2645                 radioButtonModeAverageBitrate->setEnabled(!m_fhgEncoderAvailable);
2646                 if(m_fhgEncoderAvailable && radioButtonModeAverageBitrate->isChecked()) radioButtonConstBitrate->setChecked(true);
2647                 radioButtonConstBitrate->setEnabled(true);
2648                 sliderBitrate->setEnabled(true);
2649                 break;
2650         case SettingsModel::DCAEncoder:
2651                 radioButtonModeQuality->setEnabled(false);
2652                 radioButtonModeAverageBitrate->setEnabled(false);
2653                 radioButtonConstBitrate->setEnabled(true);
2654                 radioButtonConstBitrate->setChecked(true);
2655                 sliderBitrate->setEnabled(true);
2656                 break;
2657         default:
2658                 radioButtonModeQuality->setEnabled(true);
2659                 radioButtonModeAverageBitrate->setEnabled(true);
2660                 radioButtonConstBitrate->setEnabled(true);
2661                 sliderBitrate->setEnabled(true);
2662                 break;
2663         }
2664
2665         updateRCMode(m_modeButtonGroup->checkedId());
2666 }
2667
2668 /*
2669  * Update rate-control mode
2670  */
2671 void MainWindow::updateRCMode(int id)
2672 {
2673         m_settings->compressionRCMode(id);
2674
2675         switch(m_settings->compressionEncoder())
2676         {
2677         case SettingsModel::MP3Encoder:
2678                 switch(m_settings->compressionRCMode())
2679                 {
2680                 case SettingsModel::VBRMode:
2681                         sliderBitrate->setMinimum(0);
2682                         sliderBitrate->setMaximum(9);
2683                         break;
2684                 default:
2685                         sliderBitrate->setMinimum(0);
2686                         sliderBitrate->setMaximum(13);
2687                         break;
2688                 }
2689                 break;
2690         case SettingsModel::VorbisEncoder:
2691                 switch(m_settings->compressionRCMode())
2692                 {
2693                 case SettingsModel::VBRMode:
2694                         sliderBitrate->setMinimum(-2);
2695                         sliderBitrate->setMaximum(10);
2696                         break;
2697                 default:
2698                         sliderBitrate->setMinimum(4);
2699                         sliderBitrate->setMaximum(63);
2700                         break;
2701                 }
2702                 break;
2703         case SettingsModel::AC3Encoder:
2704                 switch(m_settings->compressionRCMode())
2705                 {
2706                 case SettingsModel::VBRMode:
2707                         sliderBitrate->setMinimum(0);
2708                         sliderBitrate->setMaximum(16);
2709                         break;
2710                 default:
2711                         sliderBitrate->setMinimum(0);
2712                         sliderBitrate->setMaximum(18);
2713                         break;
2714                 }
2715                 break;
2716         case SettingsModel::AACEncoder:
2717                 switch(m_settings->compressionRCMode())
2718                 {
2719                 case SettingsModel::VBRMode:
2720                         sliderBitrate->setMinimum(0);
2721                         sliderBitrate->setMaximum(20);
2722                         break;
2723                 default:
2724                         sliderBitrate->setMinimum(4);
2725                         sliderBitrate->setMaximum(63);
2726                         break;
2727                 }
2728                 break;
2729         case SettingsModel::FLACEncoder:
2730                 sliderBitrate->setMinimum(0);
2731                 sliderBitrate->setMaximum(8);
2732                 break;
2733         case SettingsModel::DCAEncoder:
2734                 sliderBitrate->setMinimum(1);
2735                 sliderBitrate->setMaximum(128);
2736                 break;
2737         case SettingsModel::PCMEncoder:
2738                 sliderBitrate->setMinimum(0);
2739                 sliderBitrate->setMaximum(2);
2740                 sliderBitrate->setValue(1);
2741                 break;
2742         default:
2743                 sliderBitrate->setMinimum(0);
2744                 sliderBitrate->setMaximum(0);
2745                 break;
2746         }
2747
2748         updateBitrate(sliderBitrate->value());
2749 }
2750
2751 /*
2752  * Update bitrate
2753  */
2754 void MainWindow::updateBitrate(int value)
2755 {
2756         m_settings->compressionBitrate(value);
2757         
2758         switch(m_settings->compressionRCMode())
2759         {
2760         case SettingsModel::VBRMode:
2761                 switch(m_settings->compressionEncoder())
2762                 {
2763                 case SettingsModel::MP3Encoder:
2764                         labelBitrate->setText(tr("Quality Level %1").arg(9 - value));
2765                         break;
2766                 case SettingsModel::VorbisEncoder:
2767                         labelBitrate->setText(tr("Quality Level %1").arg(value));
2768                         break;
2769                 case SettingsModel::AACEncoder:
2770                         labelBitrate->setText(tr("Quality Level %1").arg(QString().sprintf("%.2f", static_cast<double>(value * 5) / 100.0)));
2771                         break;
2772                 case SettingsModel::FLACEncoder:
2773                         labelBitrate->setText(tr("Compression %1").arg(value));
2774                         break;
2775                 case SettingsModel::AC3Encoder:
2776                         labelBitrate->setText(tr("Quality Level %1").arg(qMin(1024, qMax(0, value * 64))));
2777                         break;
2778                 case SettingsModel::PCMEncoder:
2779                         labelBitrate->setText(tr("Uncompressed"));
2780                         break;
2781                 default:
2782                         labelBitrate->setText(QString::number(value));
2783                         break;
2784                 }
2785                 break;
2786         case SettingsModel::ABRMode:
2787                 switch(m_settings->compressionEncoder())
2788                 {
2789                 case SettingsModel::MP3Encoder:
2790                         labelBitrate->setText(QString("&asymp; %1 kbps").arg(SettingsModel::mp3Bitrates[value]));
2791                         break;
2792                 case SettingsModel::FLACEncoder:
2793                         labelBitrate->setText(tr("Compression %1").arg(value));
2794                         break;
2795                 case SettingsModel::AC3Encoder:
2796                         labelBitrate->setText(QString("&asymp; %1 kbps").arg(SettingsModel::ac3Bitrates[value]));
2797                         break;
2798                 case SettingsModel::PCMEncoder:
2799                         labelBitrate->setText(tr("Uncompressed"));
2800                         break;
2801                 default:
2802                         labelBitrate->setText(QString("&asymp; %1 kbps").arg(qMin(500, value * 8)));
2803                         break;
2804                 }
2805                 break;
2806         default:
2807                 switch(m_settings->compressionEncoder())
2808                 {
2809                 case SettingsModel::MP3Encoder:
2810                         labelBitrate->setText(QString("%1 kbps").arg(SettingsModel::mp3Bitrates[value]));
2811                         break;
2812                 case SettingsModel::FLACEncoder:
2813                         labelBitrate->setText(tr("Compression %1").arg(value));
2814                         break;
2815                 case SettingsModel::AC3Encoder:
2816                         labelBitrate->setText(QString("%1 kbps").arg(SettingsModel::ac3Bitrates[value]));
2817                         break;
2818                 case SettingsModel::DCAEncoder:
2819                         labelBitrate->setText(QString("%1 kbps").arg(value * 32));
2820                         break;
2821                 case SettingsModel::PCMEncoder:
2822                         labelBitrate->setText(tr("Uncompressed"));
2823                         break;
2824                 default:
2825                         labelBitrate->setText(QString("%1 kbps").arg(qMin(500, value * 8)));
2826                         break;
2827                 }
2828                 break;
2829         }
2830 }
2831
2832 // =========================================================
2833 // Advanced option slots
2834 // =========================================================
2835
2836 /*
2837  * Lame algorithm quality changed
2838  */
2839 void MainWindow::updateLameAlgoQuality(int value)
2840 {
2841         QString text;
2842
2843         switch(value)
2844         {
2845         case 4:
2846                 text = tr("Best Quality (Very Slow)");
2847                 break;
2848         case 3:
2849                 text = tr("High Quality (Recommended)");
2850                 break;
2851         case 2:
2852                 text = tr("Average Quality (Default)");
2853                 break;
2854         case 1:
2855                 text = tr("Low Quality (Fast)");
2856                 break;
2857         case 0:
2858                 text = tr("Poor Quality (Very Fast)");
2859                 break;
2860         }
2861
2862         if(!text.isEmpty())
2863         {
2864                 m_settings->lameAlgoQuality(value);
2865                 labelLameAlgoQuality->setText(text);
2866         }
2867
2868         bool warning = (value == 0), notice = (value == 4);
2869         labelLameAlgoQualityWarning->setVisible(warning);
2870         labelLameAlgoQualityWarningIcon->setVisible(warning);
2871         labelLameAlgoQualityNotice->setVisible(notice);
2872         labelLameAlgoQualityNoticeIcon->setVisible(notice);
2873         labelLameAlgoQualitySpacer->setVisible(warning || notice);
2874 }
2875
2876 /*
2877  * Bitrate management endabled/disabled
2878  */
2879 void MainWindow::bitrateManagementEnabledChanged(bool checked)
2880 {
2881         m_settings->bitrateManagementEnabled(checked);
2882 }
2883
2884 /*
2885  * Minimum bitrate has changed
2886  */
2887 void MainWindow::bitrateManagementMinChanged(int value)
2888 {
2889         if(value > spinBoxBitrateManagementMax->value())
2890         {
2891                 spinBoxBitrateManagementMin->setValue(spinBoxBitrateManagementMax->value());
2892                 m_settings->bitrateManagementMinRate(spinBoxBitrateManagementMax->value());
2893         }
2894         else
2895         {
2896                 m_settings->bitrateManagementMinRate(value);
2897         }
2898 }
2899
2900 /*
2901  * Maximum bitrate has changed
2902  */
2903 void MainWindow::bitrateManagementMaxChanged(int value)
2904 {
2905         if(value < spinBoxBitrateManagementMin->value())
2906         {
2907                 spinBoxBitrateManagementMax->setValue(spinBoxBitrateManagementMin->value());
2908                 m_settings->bitrateManagementMaxRate(spinBoxBitrateManagementMin->value());
2909         }
2910         else
2911         {
2912                 m_settings->bitrateManagementMaxRate(value);
2913         }
2914 }
2915
2916 /*
2917  * Channel mode has changed
2918  */
2919 void MainWindow::channelModeChanged(int value)
2920 {
2921         if(value >= 0) m_settings->lameChannelMode(value);
2922 }
2923
2924 /*
2925  * Sampling rate has changed
2926  */
2927 void MainWindow::samplingRateChanged(int value)
2928 {
2929         if(value >= 0) m_settings->samplingRate(value);
2930 }
2931
2932 /*
2933  * Nero AAC 2-Pass mode changed
2934  */
2935 void MainWindow::neroAAC2PassChanged(bool checked)
2936 {
2937         m_settings->neroAACEnable2Pass(checked);
2938 }
2939
2940 /*
2941  * Nero AAC profile mode changed
2942  */
2943 void MainWindow::neroAACProfileChanged(int value)
2944 {
2945         if(value >= 0) m_settings->aacEncProfile(value);
2946 }
2947
2948 /*
2949  * Aften audio coding mode changed
2950  */
2951 void MainWindow::aftenCodingModeChanged(int value)
2952 {
2953         if(value >= 0) m_settings->aftenAudioCodingMode(value);
2954 }
2955
2956 /*
2957  * Aften DRC mode changed
2958  */
2959 void MainWindow::aftenDRCModeChanged(int value)
2960 {
2961         if(value >= 0) m_settings->aftenDynamicRangeCompression(value);
2962 }
2963
2964 /*
2965  * Aften exponent search size changed
2966  */
2967 void MainWindow::aftenSearchSizeChanged(int value)
2968 {
2969         if(value >= 0) m_settings->aftenExponentSearchSize(value);
2970 }
2971
2972 /*
2973  * Aften fast bit allocation changed
2974  */
2975 void MainWindow::aftenFastAllocationChanged(bool checked)
2976 {
2977         m_settings->aftenFastBitAllocation(checked);
2978 }
2979
2980 /*
2981  * Normalization filter enabled changed
2982  */
2983 void MainWindow::normalizationEnabledChanged(bool checked)
2984 {
2985         m_settings->normalizationFilterEnabled(checked);
2986 }
2987
2988 /*
2989  * Normalization max. volume changed
2990  */
2991 void MainWindow::normalizationMaxVolumeChanged(double value)
2992 {
2993         m_settings->normalizationFilterMaxVolume(static_cast<int>(value * 100.0));
2994 }
2995
2996 /*
2997  * Normalization equalization mode changed
2998  */
2999 void MainWindow::normalizationModeChanged(int mode)
3000 {
3001         m_settings->normalizationFilterEqualizationMode(mode);
3002 }
3003
3004 /*
3005  * Tone adjustment has changed (Bass)
3006  */
3007 void MainWindow::toneAdjustBassChanged(double value)
3008 {
3009         m_settings->toneAdjustBass(static_cast<int>(value * 100.0));
3010         spinBoxToneAdjustBass->setPrefix((value > 0) ? "+" : QString());
3011 }
3012
3013 /*
3014  * Tone adjustment has changed (Treble)
3015  */
3016 void MainWindow::toneAdjustTrebleChanged(double value)
3017 {
3018         m_settings->toneAdjustTreble(static_cast<int>(value * 100.0));
3019         spinBoxToneAdjustTreble->setPrefix((value > 0) ? "+" : QString());
3020 }
3021
3022 /*
3023  * Tone adjustment has been reset
3024  */
3025 void MainWindow::toneAdjustTrebleReset(void)
3026 {
3027         spinBoxToneAdjustBass->setValue(m_settings->toneAdjustBassDefault());
3028         spinBoxToneAdjustTreble->setValue(m_settings->toneAdjustTrebleDefault());
3029         toneAdjustBassChanged(spinBoxToneAdjustBass->value());
3030         toneAdjustTrebleChanged(spinBoxToneAdjustTreble->value());
3031 }
3032
3033 /*
3034  * Custom encoder parameters changed
3035  */
3036 void MainWindow::customParamsChanged(void)
3037 {
3038         lineEditCustomParamLAME->setText(lineEditCustomParamLAME->text().simplified());
3039         lineEditCustomParamOggEnc->setText(lineEditCustomParamOggEnc->text().simplified());
3040         lineEditCustomParamNeroAAC->setText(lineEditCustomParamNeroAAC->text().simplified());
3041         lineEditCustomParamFLAC->setText(lineEditCustomParamFLAC->text().simplified());
3042         lineEditCustomParamAften->setText(lineEditCustomParamAften->text().simplified());
3043
3044         bool customParamsUsed = false;
3045         if(!lineEditCustomParamLAME->text().isEmpty()) customParamsUsed = true;
3046         if(!lineEditCustomParamOggEnc->text().isEmpty()) customParamsUsed = true;
3047         if(!lineEditCustomParamNeroAAC->text().isEmpty()) customParamsUsed = true;
3048         if(!lineEditCustomParamFLAC->text().isEmpty()) customParamsUsed = true;
3049         if(!lineEditCustomParamAften->text().isEmpty()) customParamsUsed = true;
3050
3051         labelCustomParamsIcon->setVisible(customParamsUsed);
3052         labelCustomParamsText->setVisible(customParamsUsed);
3053         labelCustomParamsSpacer->setVisible(customParamsUsed);
3054
3055         m_settings->customParametersLAME(lineEditCustomParamLAME->text());
3056         m_settings->customParametersOggEnc(lineEditCustomParamOggEnc->text());
3057         m_settings->customParametersAacEnc(lineEditCustomParamNeroAAC->text());
3058         m_settings->customParametersFLAC(lineEditCustomParamFLAC->text());
3059         m_settings->customParametersAften(lineEditCustomParamAften->text());
3060 }
3061
3062
3063 /*
3064  * Rename output files enabled changed
3065  */
3066 void MainWindow::renameOutputEnabledChanged(bool checked)
3067 {
3068         m_settings->renameOutputFilesEnabled(checked);
3069 }
3070
3071 /*
3072  * Rename output files patterm changed
3073  */
3074 void MainWindow::renameOutputPatternChanged(void)
3075 {
3076         QString temp = lineEditRenamePattern->text().simplified();
3077         lineEditRenamePattern->setText(temp.isEmpty() ? m_settings->renameOutputFilesPatternDefault() : temp);
3078         m_settings->renameOutputFilesPattern(lineEditRenamePattern->text());
3079 }
3080
3081 /*
3082  * Rename output files patterm changed
3083  */
3084 void MainWindow::renameOutputPatternChanged(const QString &text)
3085 {
3086         QString pattern(text.simplified());
3087         
3088         pattern.replace("<BaseName>", "The_White_Stripes_-_Fell_In_Love_With_A_Girl", Qt::CaseInsensitive);
3089         pattern.replace("<TrackNo>", "04", Qt::CaseInsensitive);
3090         pattern.replace("<Title>", "Fell In Love With A Girl", Qt::CaseInsensitive);
3091         pattern.replace("<Artist>", "The White Stripes", Qt::CaseInsensitive);
3092         pattern.replace("<Album>", "White Blood Cells", Qt::CaseInsensitive);
3093         pattern.replace("<Year>", "2001", Qt::CaseInsensitive);
3094         pattern.replace("<Comment>", "Encoded by LameXP", Qt::CaseInsensitive);
3095
3096         if(pattern.compare(lamexp_clean_filename(pattern)))
3097         {
3098                 if(lineEditRenamePattern->palette().color(QPalette::Text) != Qt::red)
3099                 {
3100                         MessageBeep(MB_ICONERROR);
3101                         SET_TEXT_COLOR(lineEditRenamePattern, Qt::red);
3102                 }
3103         }
3104         else
3105         {
3106                 if(lineEditRenamePattern->palette().color(QPalette::Text) != Qt::black)
3107                 {
3108                         MessageBeep(MB_ICONINFORMATION);
3109                         SET_TEXT_COLOR(lineEditRenamePattern, Qt::black);
3110                 }
3111         }
3112
3113         labelRanameExample->setText(lamexp_clean_filename(pattern));
3114 }
3115
3116 /*
3117  * Show list of rename macros
3118  */
3119 void MainWindow::showRenameMacros(const QString &text)
3120 {
3121         if(text.compare("reset", Qt::CaseInsensitive) == 0)
3122         {
3123                 lineEditRenamePattern->setText(m_settings->renameOutputFilesPatternDefault());
3124                 return;
3125         }
3126
3127         const QString format = QString("<tr><td><tt>&lt;%1&gt;</tt></td><td>&nbsp;&nbsp;</td><td>%2</td></tr>");
3128
3129         QString message = QString("<table>");
3130         message += QString(format).arg("BaseName", tr("File name without extension"));
3131         message += QString(format).arg("TrackNo", tr("Track number with leading zero"));
3132         message += QString(format).arg("Title", tr("Track title"));
3133         message += QString(format).arg("Artist", tr("Artist name"));
3134         message += QString(format).arg("Album", tr("Album name"));
3135         message += QString(format).arg("Year", tr("Year with (at least) four digits"));
3136         message += QString(format).arg("Comment", tr("Comment"));
3137         message += "</table><br><br>";
3138         message += QString("%1<br>").arg(tr("Characters forbidden in file names:"));
3139         message += "<b><tt>\\ / : * ? &lt; &gt; |<br>";
3140         
3141         QMessageBox::information(this, tr("Rename Macros"), message, tr("Discard"));
3142 }
3143
3144 void MainWindow::forceStereoDownmixEnabledChanged(bool checked)
3145 {
3146         m_settings->forceStereoDownmix(checked);
3147 }
3148
3149 /*
3150  * Maximum number of instances changed
3151  */
3152 void MainWindow::updateMaximumInstances(int value)
3153 {
3154         labelMaxInstances->setText(tr("%1 Instance(s)").arg(QString::number(value)));
3155         m_settings->maximumInstances(checkBoxAutoDetectInstances->isChecked() ? NULL : value);
3156 }
3157
3158 /*
3159  * Auto-detect number of instances
3160  */
3161 void MainWindow::autoDetectInstancesChanged(bool checked)
3162 {
3163         m_settings->maximumInstances(checked ? NULL : sliderMaxInstances->value());
3164 }
3165
3166 /*
3167  * Browse for custom TEMP folder button clicked
3168  */
3169 void MainWindow::browseCustomTempFolderButtonClicked(void)
3170 {
3171         QString newTempFolder;
3172
3173         if(USE_NATIVE_FILE_DIALOG)
3174         {
3175                 newTempFolder = QFileDialog::getExistingDirectory(this, QString(), m_settings->customTempPath());
3176         }
3177         else
3178         {
3179                 QFileDialog dialog(this);
3180                 dialog.setFileMode(QFileDialog::DirectoryOnly);
3181                 dialog.setDirectory(m_settings->customTempPath());
3182                 if(dialog.exec())
3183                 {
3184                         newTempFolder = dialog.selectedFiles().first();
3185                 }
3186         }
3187
3188         if(!newTempFolder.isEmpty())
3189         {
3190                 QFile writeTest(QString("%1/~%2.tmp").arg(newTempFolder, lamexp_rand_str()));
3191                 if(writeTest.open(QIODevice::ReadWrite))
3192                 {
3193                         writeTest.remove();
3194                         lineEditCustomTempFolder->setText(QDir::toNativeSeparators(newTempFolder));
3195                 }
3196                 else
3197                 {
3198                         QMessageBox::warning(this, tr("Access Denied"), tr("Cannot write to the selected directory. Please choose another directory!"));
3199                 }
3200         }
3201 }
3202
3203 /*
3204  * Custom TEMP folder changed
3205  */
3206 void MainWindow::customTempFolderChanged(const QString &text)
3207 {
3208         m_settings->customTempPath(QDir::fromNativeSeparators(text));
3209 }
3210
3211 /*
3212  * Use custom TEMP folder option changed
3213  */
3214 void MainWindow::useCustomTempFolderChanged(bool checked)
3215 {
3216         m_settings->customTempPathEnabled(!checked);
3217 }
3218
3219 /*
3220  * Reset all advanced options to their defaults
3221  */
3222 void MainWindow::resetAdvancedOptionsButtonClicked(void)
3223 {
3224         sliderLameAlgoQuality->setValue(m_settings->lameAlgoQualityDefault());
3225         spinBoxBitrateManagementMin->setValue(m_settings->bitrateManagementMinRateDefault());
3226         spinBoxBitrateManagementMax->setValue(m_settings->bitrateManagementMaxRateDefault());
3227         spinBoxNormalizationFilter->setValue(static_cast<double>(m_settings->normalizationFilterMaxVolumeDefault()) / 100.0);
3228         spinBoxToneAdjustBass->setValue(static_cast<double>(m_settings->toneAdjustBassDefault()) / 100.0);
3229         spinBoxToneAdjustTreble->setValue(static_cast<double>(m_settings->toneAdjustTrebleDefault()) / 100.0);
3230         spinBoxAftenSearchSize->setValue(m_settings->aftenExponentSearchSizeDefault());
3231         comboBoxMP3ChannelMode->setCurrentIndex(m_settings->lameChannelModeDefault());
3232         comboBoxSamplingRate->setCurrentIndex(m_settings->samplingRateDefault());
3233         comboBoxAACProfile->setCurrentIndex(m_settings->aacEncProfileDefault());
3234         comboBoxAftenCodingMode->setCurrentIndex(m_settings->aftenAudioCodingModeDefault());
3235         comboBoxAftenDRCMode->setCurrentIndex(m_settings->aftenDynamicRangeCompressionDefault());
3236         comboBoxNormalizationMode->setCurrentIndex(m_settings->normalizationFilterEqualizationModeDefault());
3237         while(checkBoxBitrateManagement->isChecked() != m_settings->bitrateManagementEnabledDefault()) checkBoxBitrateManagement->click();
3238         while(checkBoxNeroAAC2PassMode->isChecked() != m_settings->neroAACEnable2PassDefault()) checkBoxNeroAAC2PassMode->click();
3239         while(checkBoxNormalizationFilter->isChecked() != m_settings->normalizationFilterEnabledDefault()) checkBoxNormalizationFilter->click();
3240         while(checkBoxAutoDetectInstances->isChecked() != (m_settings->maximumInstancesDefault() < 1)) checkBoxAutoDetectInstances->click();
3241         while(checkBoxUseSystemTempFolder->isChecked() == m_settings->customTempPathEnabledDefault()) checkBoxUseSystemTempFolder->click();
3242         while(checkBoxAftenFastAllocation->isChecked() != m_settings->aftenFastBitAllocationDefault()) checkBoxAftenFastAllocation->click();
3243         while(checkBoxRenameOutput->isChecked() != m_settings->renameOutputFilesEnabledDefault()) checkBoxRenameOutput->click();
3244         while(checkBoxForceStereoDownmix->isChecked() != m_settings->forceStereoDownmixDefault()) checkBoxForceStereoDownmix->click();
3245         lineEditCustomParamLAME->setText(m_settings->customParametersLAMEDefault());
3246         lineEditCustomParamOggEnc->setText(m_settings->customParametersOggEncDefault());
3247         lineEditCustomParamNeroAAC->setText(m_settings->customParametersAacEncDefault());
3248         lineEditCustomParamFLAC->setText(m_settings->customParametersFLACDefault());
3249         lineEditCustomTempFolder->setText(QDir::toNativeSeparators(m_settings->customTempPathDefault()));
3250         lineEditRenamePattern->setText(m_settings->renameOutputFilesPatternDefault());
3251         customParamsChanged();
3252         scrollArea->verticalScrollBar()->setValue(0);
3253 }
3254
3255 // =========================================================
3256 // Multi-instance handling slots
3257 // =========================================================
3258
3259 /*
3260  * Other instance detected
3261  */
3262 void MainWindow::notifyOtherInstance(void)
3263 {
3264         if(!m_banner->isVisible())
3265         {
3266                 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);
3267                 msgBox.exec();
3268         }
3269 }
3270
3271 /*
3272  * Add file from another instance
3273  */
3274 void MainWindow::addFileDelayed(const QString &filePath, bool tryASAP)
3275 {
3276         if(tryASAP && !m_delayedFileTimer->isActive())
3277         {
3278                 qDebug("Received file: %s", filePath.toUtf8().constData());
3279                 m_delayedFileList->append(filePath);
3280                 QTimer::singleShot(0, this, SLOT(handleDelayedFiles()));
3281         }
3282         
3283         m_delayedFileTimer->stop();
3284         qDebug("Received file: %s", filePath.toUtf8().constData());
3285         m_delayedFileList->append(filePath);
3286         m_delayedFileTimer->start(5000);
3287 }
3288
3289 /*
3290  * Add files from another instance
3291  */
3292 void MainWindow::addFilesDelayed(const QStringList &filePaths, bool tryASAP)
3293 {
3294         if(tryASAP && !m_delayedFileTimer->isActive())
3295         {
3296                 qDebug("Received %d file(s).", filePaths.count());
3297                 m_delayedFileList->append(filePaths);
3298                 QTimer::singleShot(0, this, SLOT(handleDelayedFiles()));
3299         }
3300         else
3301         {
3302                 m_delayedFileTimer->stop();
3303                 qDebug("Received %d file(s).", filePaths.count());
3304                 m_delayedFileList->append(filePaths);
3305                 m_delayedFileTimer->start(5000);
3306         }
3307 }
3308
3309 /*
3310  * Add folder from another instance
3311  */
3312 void MainWindow::addFolderDelayed(const QString &folderPath, bool recursive)
3313 {
3314         if(!m_banner->isVisible())
3315         {
3316                 addFolder(folderPath, recursive, true);
3317         }
3318 }
3319
3320 // =========================================================
3321 // Misc slots
3322 // =========================================================
3323
3324 /*
3325  * Restore the override cursor
3326  */
3327 void MainWindow::restoreCursor(void)
3328 {
3329         QApplication::restoreOverrideCursor();
3330 }