OSDN Git Service

Allow to select multiple files in non-native FileOpen dialog.
[lamexp/LameXP.git] / src / Dialog_MainWindow.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2011 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 "Thread_FileAnalyzer.h"
33 #include "Thread_MessageHandler.h"
34 #include "Model_MetaInfo.h"
35 #include "Model_Settings.h"
36 #include "Model_FileList.h"
37 #include "Model_FileSystem.h"
38 #include "WinSevenTaskbar.h"
39 #include "Registry_Decoder.h"
40
41 //Qt includes
42 #include <QMessageBox>
43 #include <QTimer>
44 #include <QDesktopWidget>
45 #include <QDate>
46 #include <QFileDialog>
47 #include <QInputDialog>
48 #include <QFileSystemModel>
49 #include <QDesktopServices>
50 #include <QUrl>
51 #include <QPlastiqueStyle>
52 #include <QCleanlooksStyle>
53 #include <QWindowsVistaStyle>
54 #include <QWindowsStyle>
55 #include <QSysInfo>
56 #include <QDragEnterEvent>
57 #include <QWindowsMime>
58 #include <QProcess>
59 #include <QUuid>
60 #include <QProcessEnvironment>
61 #include <QCryptographicHash>
62 #include <QTranslator>
63 #include <QResource>
64
65 //Win32 includes
66 #include <Windows.h>
67
68 //Helper macros
69 #define ABORT_IF_BUSY if(m_banner->isVisible() || m_delayedFileTimer->isActive()) { MessageBeep(MB_ICONEXCLAMATION); return; }
70 #define SET_TEXT_COLOR(WIDGET,COLOR) { QPalette _palette = WIDGET->palette(); _palette.setColor(QPalette::WindowText, COLOR); WIDGET->setPalette(_palette); }
71 #define SET_FONT_BOLD(WIDGET,BOLD) { QFont _font = WIDGET->font(); _font.setBold(BOLD); WIDGET->setFont(_font); }
72 #define FLASH_WINDOW(WND) { FLASHWINFO flashInfo; memset(&flashInfo, 0, sizeof(FLASHWINFO)); flashInfo.cbSize = sizeof(FLASHWINFO); flashInfo.dwFlags = FLASHW_ALL; flashInfo.uCount = 12; flashInfo.dwTimeout = 125; flashInfo.hwnd = WND->winId(); FlashWindowEx(&flashInfo); }
73 #define LINK(URL) QString("<a href=\"%1\">%2</a>").arg(URL).arg(URL)
74 #define TEMP_HIDE_DROPBOX(CMD) { bool __dropBoxVisible = m_dropBox->isVisible(); if(__dropBoxVisible) m_dropBox->hide(); CMD; if(__dropBoxVisible) m_dropBox->show(); }
75
76 //Helper class
77 class Index: public QObjectUserData
78 {
79 public:
80         Index(int index) { m_index = index; }
81         int value(void) { return m_index; }
82 private:
83         int m_index;
84 };
85
86 ////////////////////////////////////////////////////////////
87 // Constructor
88 ////////////////////////////////////////////////////////////
89
90 MainWindow::MainWindow(FileListModel *fileListModel, AudioFileModel *metaInfo, SettingsModel *settingsModel, QWidget *parent)
91 :
92         QMainWindow(parent),
93         m_fileListModel(fileListModel),
94         m_metaData(metaInfo),
95         m_settings(settingsModel),
96         m_accepted(false),
97         m_firstTimeShown(true)
98 {
99         //Init the dialog, from the .ui file
100         setupUi(this);
101         setWindowFlags(windowFlags() ^ Qt::WindowMaximizeButtonHint);
102         
103         //Register meta types
104         qRegisterMetaType<AudioFileModel>("AudioFileModel");
105
106         //Enabled main buttons
107         connect(buttonAbout, SIGNAL(clicked()), this, SLOT(aboutButtonClicked()));
108         connect(buttonStart, SIGNAL(clicked()), this, SLOT(encodeButtonClicked()));
109         connect(buttonQuit, SIGNAL(clicked()), this, SLOT(closeButtonClicked()));
110
111         //Setup tab widget
112         tabWidget->setCurrentIndex(0);
113         connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabPageChanged(int)));
114
115         //Setup "Source" tab
116         sourceFileView->setModel(m_fileListModel);
117         sourceFileView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
118         sourceFileView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
119         sourceFileView->setContextMenuPolicy(Qt::CustomContextMenu);
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         SET_FONT_BOLD(m_showDetailsContextAction, true);
129         connect(buttonAddFiles, SIGNAL(clicked()), this, SLOT(addFilesButtonClicked()));
130         connect(buttonRemoveFile, SIGNAL(clicked()), this, SLOT(removeFileButtonClicked()));
131         connect(buttonClearFiles, SIGNAL(clicked()), this, SLOT(clearFilesButtonClicked()));
132         connect(buttonFileUp, SIGNAL(clicked()), this, SLOT(fileUpButtonClicked()));
133         connect(buttonFileDown, SIGNAL(clicked()), this, SLOT(fileDownButtonClicked()));
134         connect(buttonShowDetails, SIGNAL(clicked()), this, SLOT(showDetailsButtonClicked()));
135         connect(m_fileListModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(sourceModelChanged()));
136         connect(m_fileListModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(sourceModelChanged()));
137         connect(m_fileListModel, SIGNAL(modelReset()), this, SLOT(sourceModelChanged()));
138         connect(sourceFileView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(sourceFilesContextMenu(QPoint)));
139         connect(m_showDetailsContextAction, SIGNAL(triggered(bool)), this, SLOT(showDetailsButtonClicked()));
140         connect(m_previewContextAction, SIGNAL(triggered(bool)), this, SLOT(previewContextActionTriggered()));
141         connect(m_findFileContextAction, SIGNAL(triggered(bool)), this, SLOT(findFileContextActionTriggered()));
142
143         //Setup "Output" tab
144         m_fileSystemModel = new QFileSystemModelEx();
145         m_fileSystemModel->setRootPath(m_fileSystemModel->rootPath());
146         m_fileSystemModel->installEventFilter(this);
147         outputFolderView->setModel(m_fileSystemModel);
148         outputFolderView->header()->setStretchLastSection(true);
149         outputFolderView->header()->hideSection(1);
150         outputFolderView->header()->hideSection(2);
151         outputFolderView->header()->hideSection(3);
152         outputFolderView->setHeaderHidden(true);
153         outputFolderView->setAnimated(true);
154         outputFolderView->setMouseTracking(false);
155         outputFolderView->setContextMenuPolicy(Qt::CustomContextMenu);
156         while(saveToSourceFolderCheckBox->isChecked() != m_settings->outputToSourceDir()) saveToSourceFolderCheckBox->click();
157         prependRelativePathCheckBox->setChecked(m_settings->prependRelativeSourcePath());
158         connect(outputFolderView, SIGNAL(clicked(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
159         connect(outputFolderView, SIGNAL(activated(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
160         connect(outputFolderView, SIGNAL(pressed(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
161         connect(outputFolderView, SIGNAL(entered(QModelIndex)), this, SLOT(outputFolderViewMoved(QModelIndex)));
162         outputFolderView->setCurrentIndex(m_fileSystemModel->index(m_settings->outputDir()));
163         outputFolderViewClicked(outputFolderView->currentIndex());
164         connect(buttonMakeFolder, SIGNAL(clicked()), this, SLOT(makeFolderButtonClicked()));
165         connect(buttonGotoHome, SIGNAL(clicked()), SLOT(gotoHomeFolderButtonClicked()));
166         connect(buttonGotoDesktop, SIGNAL(clicked()), this, SLOT(gotoDesktopButtonClicked()));
167         connect(buttonGotoMusic, SIGNAL(clicked()), this, SLOT(gotoMusicFolderButtonClicked()));
168         connect(saveToSourceFolderCheckBox, SIGNAL(clicked()), this, SLOT(saveToSourceFolderChanged()));
169         connect(prependRelativePathCheckBox, SIGNAL(clicked()), this, SLOT(prependRelativePathChanged()));
170         m_outputFolderContextMenu = new QMenu();
171         m_showFolderContextAction = m_outputFolderContextMenu->addAction(QIcon(":/icons/zoom.png"), "N/A");
172         connect(outputFolderView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(outputFolderContextMenu(QPoint)));
173         connect(m_showFolderContextAction, SIGNAL(triggered(bool)), this, SLOT(showFolderContextActionTriggered()));
174         outputFolderLabel->installEventFilter(this);
175         
176         //Setup "Meta Data" tab
177         m_metaInfoModel = new MetaInfoModel(m_metaData, 6);
178         m_metaInfoModel->clearData();
179         metaDataView->setModel(m_metaInfoModel);
180         metaDataView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
181         metaDataView->verticalHeader()->hide();
182         metaDataView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
183         while(writeMetaDataCheckBox->isChecked() != m_settings->writeMetaTags()) writeMetaDataCheckBox->click();
184         generatePlaylistCheckBox->setChecked(m_settings->createPlaylist());
185         connect(buttonEditMeta, SIGNAL(clicked()), this, SLOT(editMetaButtonClicked()));
186         connect(buttonClearMeta, SIGNAL(clicked()), this, SLOT(clearMetaButtonClicked()));
187         connect(writeMetaDataCheckBox, SIGNAL(clicked()), this, SLOT(metaTagsEnabledChanged()));
188         connect(generatePlaylistCheckBox, SIGNAL(clicked()), this, SLOT(playlistEnabledChanged()));
189
190         //Setup "Compression" tab
191         m_encoderButtonGroup = new QButtonGroup(this);
192         m_encoderButtonGroup->addButton(radioButtonEncoderMP3, SettingsModel::MP3Encoder);
193         m_encoderButtonGroup->addButton(radioButtonEncoderVorbis, SettingsModel::VorbisEncoder);
194         m_encoderButtonGroup->addButton(radioButtonEncoderAAC, SettingsModel::AACEncoder);
195         m_encoderButtonGroup->addButton(radioButtonEncoderFLAC, SettingsModel::FLACEncoder);
196         m_encoderButtonGroup->addButton(radioButtonEncoderPCM, SettingsModel::PCMEncoder);
197         m_modeButtonGroup = new QButtonGroup(this);
198         m_modeButtonGroup->addButton(radioButtonModeQuality, SettingsModel::VBRMode);
199         m_modeButtonGroup->addButton(radioButtonModeAverageBitrate, SettingsModel::ABRMode);
200         m_modeButtonGroup->addButton(radioButtonConstBitrate, SettingsModel::CBRMode);
201         radioButtonEncoderMP3->setChecked(m_settings->compressionEncoder() == SettingsModel::MP3Encoder);
202         radioButtonEncoderVorbis->setChecked(m_settings->compressionEncoder() == SettingsModel::VorbisEncoder);
203         radioButtonEncoderAAC->setChecked(m_settings->compressionEncoder() == SettingsModel::AACEncoder);
204         radioButtonEncoderFLAC->setChecked(m_settings->compressionEncoder() == SettingsModel::FLACEncoder);
205         radioButtonEncoderPCM->setChecked(m_settings->compressionEncoder() == SettingsModel::PCMEncoder);
206         radioButtonModeQuality->setChecked(m_settings->compressionRCMode() == SettingsModel::VBRMode);
207         radioButtonModeAverageBitrate->setChecked(m_settings->compressionRCMode() == SettingsModel::ABRMode);
208         radioButtonConstBitrate->setChecked(m_settings->compressionRCMode() == SettingsModel::CBRMode);
209         sliderBitrate->setValue(m_settings->compressionBitrate());
210         connect(m_encoderButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateEncoder(int)));
211         connect(m_modeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateRCMode(int)));
212         connect(sliderBitrate, SIGNAL(valueChanged(int)), this, SLOT(updateBitrate(int)));
213         updateEncoder(m_encoderButtonGroup->checkedId());
214
215         //Activate file menu actions
216         connect(actionOpenFolder, SIGNAL(triggered()), this, SLOT(openFolderActionActivated()));
217
218         //Activate view menu actions
219         m_tabActionGroup = new QActionGroup(this);
220         m_tabActionGroup->addAction(actionSourceFiles);
221         m_tabActionGroup->addAction(actionOutputDirectory);
222         m_tabActionGroup->addAction(actionCompression);
223         m_tabActionGroup->addAction(actionMetaData);
224         m_tabActionGroup->addAction(actionAdvancedOptions);
225         actionSourceFiles->setUserData(0, new Index(0));
226         actionOutputDirectory->setUserData(0, new Index(1));
227         actionMetaData->setUserData(0, new Index(2));
228         actionCompression->setUserData(0, new Index(3));
229         actionAdvancedOptions->setUserData(0, new Index(4));
230         actionSourceFiles->setChecked(true);
231         connect(m_tabActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(tabActionActivated(QAction*)));
232
233         //Activate style menu actions
234         m_styleActionGroup = new QActionGroup(this);
235         m_styleActionGroup->addAction(actionStylePlastique);
236         m_styleActionGroup->addAction(actionStyleCleanlooks);
237         m_styleActionGroup->addAction(actionStyleWindowsVista);
238         m_styleActionGroup->addAction(actionStyleWindowsXP);
239         m_styleActionGroup->addAction(actionStyleWindowsClassic);
240         actionStylePlastique->setUserData(0, new Index(0));
241         actionStyleCleanlooks->setUserData(0, new Index(1));
242         actionStyleWindowsVista->setUserData(0, new Index(2));
243         actionStyleWindowsXP->setUserData(0, new Index(3));
244         actionStyleWindowsClassic->setUserData(0, new Index(4));
245         actionStylePlastique->setChecked(true);
246         actionStyleWindowsXP->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_XP && lamexp_themes_enabled());
247         actionStyleWindowsVista->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_VISTA && lamexp_themes_enabled());
248         connect(m_styleActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(styleActionActivated(QAction*)));
249         styleActionActivated(NULL);
250
251         //Populate the language menu
252         m_languageActionGroup = new QActionGroup(this);
253         connect(m_languageActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(languageActionActivated(QAction*)));
254         QStringList translations = lamexp_query_translations();
255         while(!translations.isEmpty())
256         {
257                 QString langId = translations.takeFirst();
258                 QAction *currentLanguage = new QAction(this);
259                 currentLanguage->setData(langId);
260                 currentLanguage->setText(lamexp_translation_name(langId));
261                 currentLanguage->setIcon(QIcon(QString(":/flags/%1.png").arg(langId)));
262                 currentLanguage->setCheckable(true);
263                 m_languageActionGroup->addAction(currentLanguage);
264                 menuLanguage->addAction(currentLanguage);
265         }
266
267         //Activate tools menu actions
268         actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
269         actionDisableSounds->setChecked(!m_settings->soundsEnabled());
270         actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
271         actionDisableWmaDecoderNotifications->setChecked(!m_settings->wmaDecoderNotificationsEnabled());
272         connect(actionDisableUpdateReminder, SIGNAL(triggered(bool)), this, SLOT(disableUpdateReminderActionTriggered(bool)));
273         connect(actionDisableSounds, SIGNAL(triggered(bool)), this, SLOT(disableSoundsActionTriggered(bool)));
274         connect(actionInstallWMADecoder, SIGNAL(triggered(bool)), this, SLOT(installWMADecoderActionTriggered(bool)));
275         connect(actionDisableNeroAacNotifications, SIGNAL(triggered(bool)), this, SLOT(disableNeroAacNotificationsActionTriggered(bool)));
276         connect(actionDisableWmaDecoderNotifications, SIGNAL(triggered(bool)), this, SLOT(disableWmaDecoderNotificationsActionTriggered(bool)));
277         connect(actionShowDropBoxWidget, SIGNAL(triggered(bool)), this, SLOT(showDropBoxWidgetActionTriggered(bool)));
278                 
279         //Activate help menu actions
280         connect(actionCheckUpdates, SIGNAL(triggered()), this, SLOT(checkUpdatesActionActivated()));
281         connect(actionVisitHomepage, SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
282         
283         //Center window in screen
284         QRect desktopRect = QApplication::desktop()->screenGeometry();
285         QRect thisRect = this->geometry();
286         move((desktopRect.width() - thisRect.width()) / 2, (desktopRect.height() - thisRect.height()) / 2);
287         setMinimumSize(thisRect.width(), thisRect.height());
288
289         //Create banner
290         m_banner = new WorkingBanner(this);
291
292         //Create DropBox widget
293         m_dropBox = new DropBox(this, m_fileListModel, m_settings);
294         connect(m_fileListModel, SIGNAL(modelReset()), m_dropBox, SLOT(modelChanged()));
295         connect(m_fileListModel, SIGNAL(rowsInserted(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
296         connect(m_fileListModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
297
298         //Create message handler thread
299         m_messageHandler = new MessageHandlerThread();
300         m_delayedFileList = new QStringList();
301         m_delayedFileTimer = new QTimer();
302         connect(m_messageHandler, SIGNAL(otherInstanceDetected()), this, SLOT(notifyOtherInstance()), Qt::QueuedConnection);
303         connect(m_messageHandler, SIGNAL(fileReceived(QString)), this, SLOT(addFileDelayed(QString)), Qt::QueuedConnection);
304         connect(m_messageHandler, SIGNAL(killSignalReceived()), this, SLOT(close()), Qt::QueuedConnection);
305         connect(m_delayedFileTimer, SIGNAL(timeout()), this, SLOT(handleDelayedFiles()));
306         m_messageHandler->start();
307
308         //Load translation file
309         QList<QAction*> languageActions = m_languageActionGroup->actions();
310         while(!languageActions.isEmpty())
311         {
312                 QAction *currentLanguage = languageActions.takeFirst();
313                 if(currentLanguage->data().toString().compare(m_settings->currentLanguage(), Qt::CaseInsensitive) == 0)
314                 {
315                         currentLanguage->setChecked(true);
316                         languageActionActivated(currentLanguage);
317                 }
318         }
319
320         //Re-translate (make sure we translate once)
321         QEvent languageChangeEvent(QEvent::LanguageChange);
322         changeEvent(&languageChangeEvent);
323
324         //Enable Drag & Drop
325         this->setAcceptDrops(true);
326 }
327
328 ////////////////////////////////////////////////////////////
329 // Destructor
330 ////////////////////////////////////////////////////////////
331
332 MainWindow::~MainWindow(void)
333 {
334         //Stop message handler thread
335         if(m_messageHandler && m_messageHandler->isRunning())
336         {
337                 m_messageHandler->stop();
338                 if(!m_messageHandler->wait(10000))
339                 {
340                         m_messageHandler->terminate();
341                         m_messageHandler->wait();
342                 }
343         }
344
345         //Unset models
346         sourceFileView->setModel(NULL);
347         metaDataView->setModel(NULL);
348
349         //Free memory
350         LAMEXP_DELETE(m_tabActionGroup);
351         LAMEXP_DELETE(m_styleActionGroup);
352         LAMEXP_DELETE(m_languageActionGroup);
353         LAMEXP_DELETE(m_banner);
354         LAMEXP_DELETE(m_fileSystemModel);
355         LAMEXP_DELETE(m_messageHandler);
356         LAMEXP_DELETE(m_delayedFileList);
357         LAMEXP_DELETE(m_delayedFileTimer);
358         LAMEXP_DELETE(m_metaInfoModel);
359         LAMEXP_DELETE(m_encoderButtonGroup);
360         LAMEXP_DELETE(m_encoderButtonGroup);
361         LAMEXP_DELETE(m_sourceFilesContextMenu);
362         LAMEXP_DELETE(m_dropBox);
363
364 }
365
366 ////////////////////////////////////////////////////////////
367 // PRIVATE FUNCTIONS
368 ////////////////////////////////////////////////////////////
369
370 /*
371  * Add file to source list
372  */
373 void MainWindow::addFiles(const QStringList &files)
374 {
375         if(files.isEmpty())
376         {
377                 return;
378         }
379
380         tabWidget->setCurrentIndex(0);
381
382         FileAnalyzer *analyzer = new FileAnalyzer(files);
383         connect(analyzer, SIGNAL(fileSelected(QString)), m_banner, SLOT(setText(QString)), Qt::QueuedConnection);
384         connect(analyzer, SIGNAL(fileAnalyzed(AudioFileModel)), m_fileListModel, SLOT(addFile(AudioFileModel)), Qt::QueuedConnection);
385
386         m_banner->show(tr("Adding file(s), please wait..."), analyzer);
387
388         if(analyzer->filesDenied())
389         {
390                 QMessageBox::warning(this, tr("Access Denied"), QString("<nobr>%1<br>%2</nobr>").arg(tr("%1 file(s) have been rejected, because read access was not granted!").arg(analyzer->filesDenied()), tr("This usually means the file is locked by another process.")));
391         }
392         if(analyzer->filesRejected())
393         {
394                 QMessageBox::warning(this, tr("Files Rejected"), QString("<nobr>%1<br>%2</nobr>").arg(tr("%1 file(s) have been rejected, because the file format could not be recognized!").arg(analyzer->filesRejected()), tr("This usually means the file is damaged or the file format is not supported.")));
395         }
396
397         LAMEXP_DELETE(analyzer);
398         sourceFileView->scrollToBottom();
399         m_banner->close();
400 }
401
402 ////////////////////////////////////////////////////////////
403 // EVENTS
404 ////////////////////////////////////////////////////////////
405
406 /*
407  * Window is about to be shown
408  */
409 void MainWindow::showEvent(QShowEvent *event)
410 {
411         m_accepted = false;
412         m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
413         sourceModelChanged();
414         tabWidget->setCurrentIndex(0);
415
416         if(m_firstTimeShown)
417         {
418                 m_firstTimeShown = false;
419                 QTimer::singleShot(0, this, SLOT(windowShown()));
420         }
421         else
422         {
423                 if(m_settings->dropBoxWidgetEnabled())
424                 {
425                         m_dropBox->setVisible(true);
426                 }
427         }
428 }
429
430 /*
431  * Re-translate the UI
432  */
433 void MainWindow::changeEvent(QEvent *e)
434 {
435         if(e->type() == QEvent::LanguageChange)
436         {
437                 Ui::MainWindow::retranslateUi(this);
438
439                 if(lamexp_version_demo())
440                 {
441                         setWindowTitle(QString("%1 [%2]").arg(windowTitle(), tr("DEMO VERSION")));
442                 }
443         
444                 m_dropNoteLabel->setText(QString("» %1 Â«").arg(tr("You can drop in audio files here!")));
445                 m_showDetailsContextAction->setText(tr("Show Details"));
446                 m_previewContextAction->setText(tr("Open File in External Application"));
447                 m_findFileContextAction->setText(tr("Browse File Location"));
448                 m_showFolderContextAction->setText(tr("Browse Selected Folder"));
449         }
450 }
451
452 /*
453  * File dragged over window
454  */
455 void MainWindow::dragEnterEvent(QDragEnterEvent *event)
456 {
457         QStringList formats = event->mimeData()->formats();
458         
459         if(formats.contains("application/x-qt-windows-mime;value=\"FileNameW\"", Qt::CaseInsensitive) && formats.contains("text/uri-list", Qt::CaseInsensitive))
460         {
461                 event->acceptProposedAction();
462         }
463 }
464
465 /*
466  * File dropped onto window
467  */
468 void MainWindow::dropEvent(QDropEvent *event)
469 {
470         ABORT_IF_BUSY;
471
472         QStringList droppedFiles;
473         const QList<QUrl> urls = event->mimeData()->urls();
474
475         for(int i = 0; i < urls.count(); i++)
476         {
477                 QFileInfo file(urls.at(i).toLocalFile());
478                 if(!file.exists())
479                 {
480                         continue;
481                 }
482                 if(file.isFile())
483                 {
484                         droppedFiles << file.canonicalFilePath();
485                         continue;
486                 }
487                 if(file.isDir())
488                 {
489                         QList<QFileInfo> list = QDir(file.canonicalFilePath()).entryInfoList(QDir::Files);
490                         for(int j = 0; j < list.count(); j++)
491                         {
492                                 droppedFiles << list.at(j).canonicalFilePath();
493                         }
494                 }
495         }
496         
497         addFiles(droppedFiles);
498 }
499
500 /*
501  * Window tries to close
502  */
503 void MainWindow::closeEvent(QCloseEvent *event)
504 {
505         if(m_banner->isVisible() || m_delayedFileTimer->isActive())
506         {
507                 MessageBeep(MB_ICONEXCLAMATION);
508                 event->ignore();
509         }
510         
511         if(m_dropBox)
512         {
513                 m_dropBox->hide();
514         }
515 }
516
517 /*
518  * Window was resized
519  */
520 void MainWindow::resizeEvent(QResizeEvent *event)
521 {
522         QMainWindow::resizeEvent(event);
523         m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
524 }
525
526 /*
527  * Event filter
528  */
529 bool MainWindow::eventFilter(QObject *obj, QEvent *event)
530 {
531         if(obj == m_fileSystemModel && QApplication::overrideCursor() == NULL)
532         {
533                 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
534                 QTimer::singleShot(250, this, SLOT(restoreCursor()));
535         }
536         else if(obj == outputFolderLabel)
537         {
538                 switch(event->type())
539                 {
540                 case QEvent::MouseButtonPress:
541                         if(dynamic_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)
542                         {
543                                 QDesktopServices::openUrl(QString("file:///%1").arg(outputFolderLabel->text()));
544                         }
545                         break;
546                 case QEvent::Enter:
547                         outputFolderLabel->setForegroundRole(QPalette::Link);
548                         break;
549                 case QEvent::Leave:
550                         outputFolderLabel->setForegroundRole(QPalette::WindowText);
551                         break;
552                 }
553         }
554         return false;
555 }
556
557 ////////////////////////////////////////////////////////////
558 // Slots
559 ////////////////////////////////////////////////////////////
560
561 /*
562  * Window shown
563  */
564 void MainWindow::windowShown(void)
565 {
566         QStringList arguments = QApplication::arguments();
567
568         //Check license
569         if(m_settings->licenseAccepted() <= 0)
570         {
571                 int iAccepted = -1;
572
573                 if(m_settings->licenseAccepted() == 0)
574                 {
575                         AboutDialog *about = new AboutDialog(m_settings, this, true);
576                         iAccepted = about->exec();
577                         LAMEXP_DELETE(about);
578                 }
579
580                 if(iAccepted <= 0)
581                 {
582                         m_settings->licenseAccepted(-1);
583                         QApplication::processEvents();
584                         PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
585                         QMessageBox::critical(this, tr("License Declined"), tr("You have declined the license. Consequently the application will exit now!"), tr("Goodbye!"));
586                         QProcess::startDetached(QString("%1/Uninstall.exe").arg(QApplication::applicationDirPath()), QStringList());
587                         QApplication::quit();
588                         return;
589                 }
590                 
591                 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WOOHOO), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
592                 m_settings->licenseAccepted(1);
593         }
594         
595         //Check for expiration
596         if(lamexp_version_demo())
597         {
598                 QDate expireDate = lamexp_version_date().addDays(14);
599                 if(QDate::currentDate() >= expireDate)
600                 {
601                         qWarning("Binary has expired !!!");
602                         PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
603                         if(QMessageBox::warning(this, tr("LameXP - Expired"), QString("<nobr>%1<br>%2</nobr>").arg(tr("This demo (pre-release) version of LameXP has expired at %1.").arg(expireDate.toString(Qt::ISODate)), tr("LameXP is free software and release versions won't expire.")), tr("Check for Updates"), tr("Exit Program")) == 0)
604                         {
605                                 checkUpdatesActionActivated();
606                         }
607                         QApplication::quit();
608                         return;
609                 }
610         }
611
612         //Update reminder
613         if(QDate::currentDate() >= lamexp_version_date().addYears(1))
614         {
615                 qWarning("Binary is more than a year old, time to update!");
616                 if(QMessageBox::warning(this, tr("Urgent Update"), tr("Your version of LameXP is more than a year old. Time for an update!"), tr("Check for Updates"), tr("Exit Program")) == 0)
617                 {
618                         checkUpdatesActionActivated();
619                 }
620                 else
621                 {
622                         QApplication::quit();
623                         return;
624                 }
625         }
626         else if(m_settings->autoUpdateEnabled())
627         {
628                 QDate lastUpdateCheck = QDate::fromString(m_settings->autoUpdateLastCheck(), Qt::ISODate);
629                 if(!lastUpdateCheck.isValid() || QDate::currentDate() >= lastUpdateCheck.addDays(14))
630                 {
631                         if(QMessageBox::information(this, tr("Update Reminder"), (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)
632                         {
633                                 checkUpdatesActionActivated();
634                         }
635                 }
636         }
637
638         //Check for AAC support
639         if(m_settings->neroAacNotificationsEnabled())
640         {
641                 if(lamexp_check_tool("neroAacEnc.exe") && lamexp_check_tool("neroAacDec.exe") && lamexp_check_tool("neroAacTag.exe"))
642                 {
643                         if(lamexp_tool_version("neroAacEnc.exe") < lamexp_toolver_neroaac())
644                         {
645                                 QString messageText;
646                                 messageText += QString("<nobr>%1<br>").arg(tr("LameXP detected that your version of the Nero AAC encoder is outdated!"));
647                                 messageText += QString("%1<br><br>").arg(tr("The current version available is %1 (or later), but you still have version %2 installed.").arg(lamexp_version2string("?.?.?.?", lamexp_toolver_neroaac()), lamexp_version2string("?.?.?.?", lamexp_tool_version("neroAacEnc.exe"))));
648                                 messageText += QString("%1<br>").arg(tr("You can download the latest version of the Nero AAC encoder from the Nero website at:"));
649                                 messageText += "<b>" + LINK(AboutDialog::neroAacUrl) + "</b><br></nobr>";
650                                 QMessageBox::information(this, tr("AAC Encoder Outdated"), messageText);
651                         }
652                 }
653                 else
654                 {
655                         radioButtonEncoderAAC->setEnabled(false);
656                         QString messageText;
657                         messageText += QString("<nobr>%1<br>").arg(tr("The Nero AAC encoder could not be found. AAC encoding support will be disabled."));
658                         messageText += QString("%1<br><br>").arg(tr("Please put 'neroAacEnc.exe', 'neroAacDec.exe' and 'neroAacTag.exe' into the LameXP directory!"));
659                         messageText += QString("%1<br>").arg(tr("Your LameXP directory is located here:"));
660                         messageText += QString("<i><nobr><a href=\"file:///%1\">%1</a></nobr></i><br><br>").arg(QDir::toNativeSeparators(QCoreApplication::applicationDirPath()));
661                         messageText += QString("%1<br>").arg(tr("You can download the Nero AAC encoder for free from the official Nero website at:"));
662                         messageText += "<b>" + LINK(AboutDialog::neroAacUrl) + "</b><br></nobr>";
663                         QMessageBox::information(this, tr("AAC Support Disabled"), messageText);
664                 }
665         }
666         
667         //Check for WMA support
668         if(m_settings->wmaDecoderNotificationsEnabled())
669         {
670                 if(!lamexp_check_tool("wmawav.exe"))
671                 {
672                         QString messageText;
673                         messageText += QString("<nobr>%1<br>").arg(tr("LameXP has detected that the WMA File Decoder component is not currently installed on your system."));
674                         messageText += QString("%1</nobr>").arg(tr("You won't be able to process WMA files as input unless the WMA File Decoder component is installed!"));
675                         QMessageBox::information(this, tr("WMA Decoder Missing"), messageText);
676                         installWMADecoderActionTriggered(rand() % 2);
677                 }
678         }
679
680         //Add files from the command-line
681         for(int i = 0; i < arguments.count() - 1; i++)
682         {
683                 if(!arguments[i].compare("--add", Qt::CaseInsensitive))
684                 {
685                         QFileInfo currentFile(arguments[++i].trimmed());
686                         qDebug("Adding file from CLI: %s", currentFile.canonicalFilePath().toUtf8().constData());
687                         m_delayedFileList->append(currentFile.canonicalFilePath());
688                 }
689         }
690
691         //Start delayed files timer
692         if(!m_delayedFileList->isEmpty() && !m_delayedFileTimer->isActive())
693         {
694                 m_delayedFileTimer->start(5000);
695         }
696
697         //Make DropBox visible
698         if(m_settings->dropBoxWidgetEnabled())
699         {
700                 m_dropBox->setVisible(true);
701         }
702 }
703
704 /*
705  * About button
706  */
707 void MainWindow::aboutButtonClicked(void)
708 {
709         ABORT_IF_BUSY;
710
711         TEMP_HIDE_DROPBOX
712         (
713                 AboutDialog *aboutBox = new AboutDialog(m_settings, this);
714                 aboutBox->exec();
715                 LAMEXP_DELETE(aboutBox);
716         )
717 }
718
719 /*
720  * Encode button
721  */
722 void MainWindow::encodeButtonClicked(void)
723 {
724         static const __int64 oneGigabyte = 1073741824; 
725         static const __int64 minimumFreeDiskspaceMultiplier = 2;
726         
727         ABORT_IF_BUSY;
728
729         if(m_fileListModel->rowCount() < 1)
730         {
731                 QMessageBox::warning(this, tr("LameXP"), tr("You must add at least one file to the list before proceeding!"));
732                 tabWidget->setCurrentIndex(0);
733                 return;
734         }
735         
736         __int64 currentFreeDiskspace = lamexp_free_diskspace(lamexp_temp_folder());
737
738         if(currentFreeDiskspace < (oneGigabyte * minimumFreeDiskspaceMultiplier))
739         {
740                 QStringList tempFolderParts = lamexp_temp_folder().split("/", QString::SkipEmptyParts, Qt::CaseInsensitive);
741                 tempFolderParts.takeLast();
742                 if(m_settings->soundsEnabled()) PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
743                 switch(QMessageBox::warning(this, tr("Low Diskspace Warning"), QString("<nobr>%1</nobr><br><nobr>%2</nobr><br><br>%3").arg(tr("There are less than %1 GB of free diskspace available on your system's TEMP folder.").arg(QString::number(minimumFreeDiskspaceMultiplier)), tr("It is highly recommend to free up more diskspace before proceeding with the encode!"), tr("Your TEMP folder is located at:")).append("<br><nobr><i><a href=\"file:///%3\">%3</a></i></nobr><br>").arg(tempFolderParts.join("\\")), tr("Abort Encoding Process"), tr("Clean Disk Now"), tr("Ignore")))
744                 {
745                 case 1:
746                         QProcess::startDetached(QString("%1/cleanmgr.exe").arg(lamexp_known_folder(lamexp_folder_systemfolder)), QStringList() << "/D" << tempFolderParts.first());
747                 case 0:
748                         return;
749                         break;
750                 default:
751                         QMessageBox::warning(this, tr("Low Diskspace"), tr("You are proceeding with low diskspace. Problems might occur!"));
752                         break;
753                 }
754         }
755
756         switch(m_settings->compressionEncoder())
757         {
758         case SettingsModel::MP3Encoder:
759         case SettingsModel::VorbisEncoder:
760         case SettingsModel::AACEncoder:
761         case SettingsModel::FLACEncoder:
762         case SettingsModel::PCMEncoder:
763                 break;
764         default:
765                 QMessageBox::warning(this, tr("LameXP"), tr("Sorry, an unsupported encoder has been chosen!"));
766                 tabWidget->setCurrentIndex(3);
767                 return;
768         }
769
770         if(!m_settings->outputToSourceDir())
771         {
772                 QFile writeTest(QString("%1/~%2.txt").arg(m_settings->outputDir(), QUuid::createUuid().toString()));
773                 if(!writeTest.open(QIODevice::ReadWrite))
774                 {
775                         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!")));
776                         tabWidget->setCurrentIndex(1);
777                         return;
778                 }
779                 else
780                 {
781                         writeTest.close();
782                         writeTest.remove();
783                 }
784         }
785                 
786         m_accepted = true;
787         close();
788 }
789
790 /*
791  * Close button
792  */
793 void MainWindow::closeButtonClicked(void)
794 {
795         ABORT_IF_BUSY;
796         close();
797 }
798
799 /*
800  * Add file(s) button
801  */
802 void MainWindow::addFilesButtonClicked(void)
803 {
804         ABORT_IF_BUSY;
805         
806         TEMP_HIDE_DROPBOX
807         (
808                 if(lamexp_themes_enabled())
809                 {
810                         QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
811                         QStringList selectedFiles = QFileDialog::getOpenFileNames(this, tr("Add file(s)"), QString(), fileTypeFilters.join(";;"));
812                         if(!selectedFiles.isEmpty())
813                         {
814                                 addFiles(selectedFiles);
815                         }
816                 }
817                 else
818                 {
819                         QFileDialog dialog(this, tr("Add file(s)"));
820                         QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
821                         dialog.setFileMode(QFileDialog::ExistingFiles);
822                         dialog.setNameFilter(fileTypeFilters.join(";;"));
823                         if(dialog.exec())
824                         {
825                                 QStringList selectedFiles = dialog.selectedFiles();
826                                 addFiles(selectedFiles);
827                         }
828                 }
829         )
830 }
831
832 /*
833  * Open folder action
834  */
835 void MainWindow::openFolderActionActivated(void)
836 {
837         ABORT_IF_BUSY;
838         QString selectedFolder;
839         
840         TEMP_HIDE_DROPBOX
841         (
842                 if(lamexp_themes_enabled())
843                 {
844                         selectedFolder = QFileDialog::getExistingDirectory(this, tr("Add folder"), QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
845                 }
846                 else
847                 {
848                         QFileDialog dialog(this, tr("Add folder"));
849                         dialog.setFileMode(QFileDialog::DirectoryOnly);
850                         dialog.setDirectory(QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
851                         if(dialog.exec())
852                         {
853                                 selectedFolder = dialog.selectedFiles().first();
854                         }
855                 }
856                 
857                 if(!selectedFolder.isEmpty())
858                 {
859                         QDir sourceDir(selectedFolder);
860                         QFileInfoList fileInfoList = sourceDir.entryInfoList(QDir::Files);
861                         QStringList fileList;
862
863                         while(!fileInfoList.isEmpty())
864                         {
865                                 fileList << fileInfoList.takeFirst().canonicalFilePath();
866                         }
867
868                         addFiles(fileList);
869                 }
870         )
871 }
872
873 /*
874  * Remove file button
875  */
876 void MainWindow::removeFileButtonClicked(void)
877 {
878         if(sourceFileView->currentIndex().isValid())
879         {
880                 int iRow = sourceFileView->currentIndex().row();
881                 m_fileListModel->removeFile(sourceFileView->currentIndex());
882                 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
883         }
884 }
885
886 /*
887  * Clear files button
888  */
889 void MainWindow::clearFilesButtonClicked(void)
890 {
891         m_fileListModel->clearFiles();
892 }
893
894 /*
895  * Move file up button
896  */
897 void MainWindow::fileUpButtonClicked(void)
898 {
899         if(sourceFileView->currentIndex().isValid())
900         {
901                 int iRow = sourceFileView->currentIndex().row() - 1;
902                 m_fileListModel->moveFile(sourceFileView->currentIndex(), -1);
903                 sourceFileView->selectRow(iRow >= 0 ? iRow : 0);
904         }
905 }
906
907 /*
908  * Move file down button
909  */
910 void MainWindow::fileDownButtonClicked(void)
911 {
912         if(sourceFileView->currentIndex().isValid())
913         {
914                 int iRow = sourceFileView->currentIndex().row() + 1;
915                 m_fileListModel->moveFile(sourceFileView->currentIndex(), 1);
916                 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
917         }
918 }
919
920 /*
921  * Show details button
922  */
923 void MainWindow::showDetailsButtonClicked(void)
924 {
925         ABORT_IF_BUSY;
926
927         int iResult = 0;
928         MetaInfoDialog *metaInfoDialog = new MetaInfoDialog(this);
929         QModelIndex index = sourceFileView->currentIndex();
930
931         while(index.isValid())
932         {
933                 if(iResult > 0)
934                 {
935                         index = m_fileListModel->index(index.row() + 1, index.column()); 
936                         sourceFileView->selectRow(index.row());
937                 }
938                 if(iResult < 0)
939                 {
940                         index = m_fileListModel->index(index.row() - 1, index.column()); 
941                         sourceFileView->selectRow(index.row());
942                 }
943
944                 AudioFileModel &file = (*m_fileListModel)[index];
945                 iResult = metaInfoDialog->exec(file, index.row() > 0, index.row() < m_fileListModel->rowCount() - 1);
946
947                 if(!iResult) break;
948         }
949
950         LAMEXP_DELETE(metaInfoDialog);
951 }
952
953 /*
954  * Tab page changed
955  */
956 void MainWindow::tabPageChanged(int idx)
957 {
958         QList<QAction*> actions = m_tabActionGroup->actions();
959         for(int i = 0; i < actions.count(); i++)
960         {
961                 if(actions.at(i)->userData(0) && dynamic_cast<Index*>(actions.at(i)->userData(0))->value() == idx)
962                 {
963                         actions.at(i)->setChecked(true);
964                 }
965         }
966 }
967
968 /*
969  * Tab action triggered
970  */
971 void MainWindow::tabActionActivated(QAction *action)
972 {
973         if(action && action->userData(0))
974         {
975                 int index = dynamic_cast<Index*>(action->userData(0))->value();
976                 tabWidget->setCurrentIndex(index);
977         }
978 }
979
980 /*
981  * Style action triggered
982  */
983 void MainWindow::styleActionActivated(QAction *action)
984 {
985         if(action && action->userData(0))
986         {
987                 m_settings->interfaceStyle(dynamic_cast<Index*>(action->userData(0))->value());
988         }
989
990         switch(m_settings->interfaceStyle())
991         {
992         case 1:
993                 if(actionStyleCleanlooks->isEnabled())
994                 {
995                         actionStyleCleanlooks->setChecked(true);
996                         QApplication::setStyle(new QCleanlooksStyle());
997                         break;
998                 }
999         case 2:
1000                 if(actionStyleWindowsVista->isEnabled())
1001                 {
1002                         actionStyleWindowsVista->setChecked(true);
1003                         QApplication::setStyle(new QWindowsVistaStyle());
1004                         break;
1005                 }
1006         case 3:
1007                 if(actionStyleWindowsXP->isEnabled())
1008                 {
1009                         actionStyleWindowsXP->setChecked(true);
1010                         QApplication::setStyle(new QWindowsXPStyle());
1011                         break;
1012                 }
1013         case 4:
1014                 if(actionStyleWindowsClassic->isEnabled())
1015                 {
1016                         actionStyleWindowsClassic->setChecked(true);
1017                         QApplication::setStyle(new QWindowsStyle());
1018                         break;
1019                 }
1020         default:
1021                 actionStylePlastique->setChecked(true);
1022                 QApplication::setStyle(new QPlastiqueStyle());
1023                 break;
1024         }
1025 }
1026
1027 /*
1028  * Language action triggered
1029  */
1030 void MainWindow::languageActionActivated(QAction *action)
1031 {
1032         QString langId = action->data().toString();
1033
1034         if(lamexp_install_translator(langId))
1035         {
1036                 m_settings->currentLanguage(langId);
1037         }
1038 }
1039
1040 /*
1041  * Output folder changed (mouse clicked)
1042  */
1043 void MainWindow::outputFolderViewClicked(const QModelIndex &index)
1044 {
1045         if(outputFolderView->currentIndex() != index)
1046         {
1047                 outputFolderView->setCurrentIndex(index);
1048         }
1049         QString selectedDir = m_fileSystemModel->filePath(index);
1050         if(selectedDir.length() < 3) selectedDir.append(QDir::separator());
1051         outputFolderLabel->setText(QDir::toNativeSeparators(selectedDir));
1052         m_settings->outputDir(selectedDir);
1053 }
1054
1055 /*
1056  * Output folder changed (mouse moved)
1057  */
1058 void MainWindow::outputFolderViewMoved(const QModelIndex &index)
1059 {
1060         if(QApplication::mouseButtons() & Qt::LeftButton)
1061         {
1062                 outputFolderViewClicked(index);
1063         }
1064 }
1065
1066 /*
1067  * Goto desktop button
1068  */
1069 void MainWindow::gotoDesktopButtonClicked(void)
1070 {
1071         QString desktopPath = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
1072         
1073         if(!desktopPath.isEmpty() && QDir(desktopPath).exists())
1074         {
1075                 outputFolderView->setCurrentIndex(m_fileSystemModel->index(desktopPath));
1076                 outputFolderViewClicked(outputFolderView->currentIndex());
1077                 outputFolderView->setFocus();
1078         }
1079         else
1080         {
1081                 buttonGotoDesktop->setEnabled(false);
1082         }
1083 }
1084
1085 /*
1086  * Goto home folder button
1087  */
1088 void MainWindow::gotoHomeFolderButtonClicked(void)
1089 {
1090         QString homePath = QDesktopServices::storageLocation(QDesktopServices::HomeLocation);
1091         
1092         if(!homePath.isEmpty() && QDir(homePath).exists())
1093         {
1094                 outputFolderView->setCurrentIndex(m_fileSystemModel->index(homePath));
1095                 outputFolderViewClicked(outputFolderView->currentIndex());
1096                 outputFolderView->setFocus();
1097         }
1098         else
1099         {
1100                 buttonGotoHome->setEnabled(false);
1101         }
1102 }
1103
1104 /*
1105  * Goto music folder button
1106  */
1107 void MainWindow::gotoMusicFolderButtonClicked(void)
1108 {
1109         QString musicPath = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
1110         
1111         if(!musicPath.isEmpty() && QDir(musicPath).exists())
1112         {
1113                 outputFolderView->setCurrentIndex(m_fileSystemModel->index(musicPath));
1114                 outputFolderViewClicked(outputFolderView->currentIndex());
1115                 outputFolderView->setFocus();
1116         }
1117         else
1118         {
1119                 buttonGotoMusic->setEnabled(false);
1120         }
1121 }
1122
1123 /*
1124  * Make folder button
1125  */
1126 void MainWindow::makeFolderButtonClicked(void)
1127 {
1128         ABORT_IF_BUSY;
1129
1130         QDir basePath(m_fileSystemModel->fileInfo(outputFolderView->currentIndex()).absoluteFilePath());
1131         QString suggestedName = tr("New Folder");
1132
1133         if(!m_metaData->fileArtist().isEmpty() && !m_metaData->fileAlbum().isEmpty())
1134         {
1135                 suggestedName = QString("%1 - %2").arg(m_metaData->fileArtist(), m_metaData->fileAlbum());
1136         }
1137         else if(!m_metaData->fileArtist().isEmpty())
1138         {
1139                 suggestedName = m_metaData->fileArtist();
1140         }
1141         else if(!m_metaData->fileAlbum().isEmpty())
1142         {
1143                 suggestedName = m_metaData->fileAlbum();
1144         }
1145         else
1146         {
1147                 for(int i = 0; i < m_fileListModel->rowCount(); i++)
1148                 {
1149                         AudioFileModel audioFile = m_fileListModel->getFile(m_fileListModel->index(i, 0));
1150                         if(!audioFile.fileAlbum().isEmpty() || !audioFile.fileArtist().isEmpty())
1151                         {
1152                                 if(!audioFile.fileArtist().isEmpty() && !audioFile.fileAlbum().isEmpty())
1153                                 {
1154                                         suggestedName = QString("%1 - %2").arg(audioFile.fileArtist(), audioFile.fileAlbum());
1155                                 }
1156                                 else if(!audioFile.fileArtist().isEmpty())
1157                                 {
1158                                         suggestedName = audioFile.fileArtist();
1159                                 }
1160                                 else if(!audioFile.fileAlbum().isEmpty())
1161                                 {
1162                                         suggestedName = audioFile.fileAlbum();
1163                                 }
1164                                 break;
1165                         }
1166                 }
1167         }
1168         
1169         while(true)
1170         {
1171                 bool bApplied = false;
1172                 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();
1173
1174                 if(bApplied)
1175                 {
1176                         folderName.remove(":", Qt::CaseInsensitive);
1177                         folderName.remove("/", Qt::CaseInsensitive);
1178                         folderName.remove("\\", Qt::CaseInsensitive);
1179                         folderName.remove("?", Qt::CaseInsensitive);
1180                         folderName.remove("*", Qt::CaseInsensitive);
1181                         folderName.remove("<", Qt::CaseInsensitive);
1182                         folderName.remove(">", Qt::CaseInsensitive);
1183                         
1184                         folderName = folderName.simplified();
1185
1186                         if(folderName.isEmpty())
1187                         {
1188                                 MessageBeep(MB_ICONERROR);
1189                                 continue;
1190                         }
1191
1192                         int i = 1;
1193                         QString newFolder = folderName;
1194
1195                         while(basePath.exists(newFolder))
1196                         {
1197                                 newFolder = QString(folderName).append(QString().sprintf(" (%d)", ++i));
1198                         }
1199                         
1200                         if(basePath.mkdir(newFolder))
1201                         {
1202                                 QDir createdDir = basePath;
1203                                 if(createdDir.cd(newFolder))
1204                                 {
1205                                         outputFolderView->setCurrentIndex(m_fileSystemModel->index(createdDir.canonicalPath()));
1206                                         outputFolderViewClicked(outputFolderView->currentIndex());
1207                                         outputFolderView->setFocus();
1208                                 }
1209                         }
1210                         else
1211                         {
1212                                 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!")));
1213                         }
1214                 }
1215                 break;
1216         }
1217 }
1218
1219 /*
1220  * Edit meta button clicked
1221  */
1222 void MainWindow::editMetaButtonClicked(void)
1223 {
1224         ABORT_IF_BUSY;
1225         m_metaInfoModel->editItem(metaDataView->currentIndex(), this);
1226 }
1227
1228 /*
1229  * Reset meta button clicked
1230  */
1231 void MainWindow::clearMetaButtonClicked(void)
1232 {
1233         ABORT_IF_BUSY;
1234         m_metaInfoModel->clearData();
1235 }
1236
1237 /*
1238  * Visit homepage action
1239  */
1240 void MainWindow::visitHomepageActionActivated(void)
1241 {
1242         QDesktopServices::openUrl(QUrl("http://mulder.dummwiedeutsch.de/"));
1243 }
1244
1245 /*
1246  * Check for updates action
1247  */
1248 void MainWindow::checkUpdatesActionActivated(void)
1249 {
1250         ABORT_IF_BUSY;
1251         
1252         TEMP_HIDE_DROPBOX
1253         (
1254                 UpdateDialog *updateDialog = new UpdateDialog(m_settings, this);
1255                 updateDialog->exec();
1256                 if(updateDialog->getSuccess())
1257                 {
1258                         m_settings->autoUpdateLastCheck(QDate::currentDate().toString(Qt::ISODate));
1259                 }
1260                 LAMEXP_DELETE(updateDialog);
1261         )
1262 }
1263
1264 /*
1265  * Other instance detected
1266  */
1267 void MainWindow::notifyOtherInstance(void)
1268 {
1269         if(!m_banner->isVisible())
1270         {
1271                 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);
1272                 msgBox.exec();
1273         }
1274 }
1275
1276 /*
1277  * Add file from another instance
1278  */
1279 void MainWindow::addFileDelayed(const QString &filePath)
1280 {
1281         m_delayedFileTimer->stop();
1282         qDebug("Received file: %s", filePath.toUtf8().constData());
1283         m_delayedFileList->append(filePath);
1284         m_delayedFileTimer->start(5000);
1285 }
1286
1287 /*
1288  * Add all pending files
1289  */
1290 void MainWindow::handleDelayedFiles(void)
1291 {
1292         if(m_banner->isVisible())
1293         {
1294                 return;
1295         }
1296         
1297         m_delayedFileTimer->stop();
1298         if(m_delayedFileList->isEmpty())
1299         {
1300                 return;
1301         }
1302
1303         QStringList selectedFiles;
1304         tabWidget->setCurrentIndex(0);
1305
1306         while(!m_delayedFileList->isEmpty())
1307         {
1308                 QFileInfo currentFile = QFileInfo(m_delayedFileList->takeFirst());
1309                 if(!currentFile.exists())
1310                 {
1311                         continue;
1312                 }
1313                 if(currentFile.isFile())
1314                 {
1315                         selectedFiles << currentFile.canonicalFilePath();
1316                         continue;
1317                 }
1318                 if(currentFile.isDir())
1319                 {
1320                         QList<QFileInfo> list = QDir(currentFile.canonicalFilePath()).entryInfoList(QDir::Files);
1321                         for(int j = 0; j < list.count(); j++)
1322                         {
1323                                 selectedFiles << list.at(j).canonicalFilePath();
1324                         }
1325                 }
1326         }
1327         
1328         addFiles(selectedFiles);
1329 }
1330
1331 /*
1332  * Update encoder
1333  */
1334 void MainWindow::updateEncoder(int id)
1335 {
1336         m_settings->compressionEncoder(id);
1337
1338         switch(m_settings->compressionEncoder())
1339         {
1340         case SettingsModel::VorbisEncoder:
1341                 radioButtonModeQuality->setEnabled(true);
1342                 radioButtonModeAverageBitrate->setEnabled(true);
1343                 radioButtonConstBitrate->setEnabled(false);
1344                 if(radioButtonConstBitrate->isChecked()) radioButtonModeQuality->setChecked(true);
1345                 sliderBitrate->setEnabled(true);
1346                 break;
1347         case SettingsModel::FLACEncoder:
1348                 radioButtonModeQuality->setEnabled(false);
1349                 radioButtonModeQuality->setChecked(true);
1350                 radioButtonModeAverageBitrate->setEnabled(false);
1351                 radioButtonConstBitrate->setEnabled(false);
1352                 sliderBitrate->setEnabled(true);
1353                 break;
1354         case SettingsModel::PCMEncoder:
1355                 radioButtonModeQuality->setEnabled(false);
1356                 radioButtonModeQuality->setChecked(true);
1357                 radioButtonModeAverageBitrate->setEnabled(false);
1358                 radioButtonConstBitrate->setEnabled(false);
1359                 sliderBitrate->setEnabled(false);
1360                 break;
1361         default:
1362                 radioButtonModeQuality->setEnabled(true);
1363                 radioButtonModeAverageBitrate->setEnabled(true);
1364                 radioButtonConstBitrate->setEnabled(true);
1365                 sliderBitrate->setEnabled(true);
1366                 break;
1367         }
1368
1369         updateRCMode(m_modeButtonGroup->checkedId());
1370 }
1371
1372 /*
1373  * Update rate-control mode
1374  */
1375 void MainWindow::updateRCMode(int id)
1376 {
1377         m_settings->compressionRCMode(id);
1378
1379         switch(m_settings->compressionEncoder())
1380         {
1381         case SettingsModel::MP3Encoder:
1382                 switch(m_settings->compressionRCMode())
1383                 {
1384                 case SettingsModel::VBRMode:
1385                         sliderBitrate->setMinimum(0);
1386                         sliderBitrate->setMaximum(9);
1387                         break;
1388                 default:
1389                         sliderBitrate->setMinimum(0);
1390                         sliderBitrate->setMaximum(13);
1391                         break;
1392                 }
1393                 break;
1394         case SettingsModel::VorbisEncoder:
1395                 switch(m_settings->compressionRCMode())
1396                 {
1397                 case SettingsModel::VBRMode:
1398                         sliderBitrate->setMinimum(-2);
1399                         sliderBitrate->setMaximum(10);
1400                         break;
1401                 default:
1402                         sliderBitrate->setMinimum(4);
1403                         sliderBitrate->setMaximum(63);
1404                         break;
1405                 }
1406                 break;
1407         case SettingsModel::AACEncoder:
1408                 switch(m_settings->compressionRCMode())
1409                 {
1410                 case SettingsModel::VBRMode:
1411                         sliderBitrate->setMinimum(0);
1412                         sliderBitrate->setMaximum(20);
1413                         break;
1414                 default:
1415                         sliderBitrate->setMinimum(4);
1416                         sliderBitrate->setMaximum(63);
1417                         break;
1418                 }
1419                 break;
1420         case SettingsModel::FLACEncoder:
1421                 sliderBitrate->setMinimum(0);
1422                 sliderBitrate->setMaximum(8);
1423                 break;
1424         case SettingsModel::PCMEncoder:
1425                 sliderBitrate->setMinimum(0);
1426                 sliderBitrate->setMaximum(2);
1427                 sliderBitrate->setValue(1);
1428                 break;
1429         default:
1430                 sliderBitrate->setMinimum(0);
1431                 sliderBitrate->setMaximum(0);
1432                 break;
1433         }
1434
1435         updateBitrate(sliderBitrate->value());
1436 }
1437
1438 /*
1439  * Update bitrate
1440  */
1441 void MainWindow::updateBitrate(int value)
1442 {
1443         m_settings->compressionBitrate(value);
1444         
1445         switch(m_settings->compressionRCMode())
1446         {
1447         case SettingsModel::VBRMode:
1448                 switch(m_settings->compressionEncoder())
1449                 {
1450                 case SettingsModel::MP3Encoder:
1451                         labelBitrate->setText(tr("Quality Level %1").arg(9 - value));
1452                         break;
1453                 case SettingsModel::VorbisEncoder:
1454                         labelBitrate->setText(tr("Quality Level %1").arg(value));
1455                         break;
1456                 case SettingsModel::AACEncoder:
1457                         labelBitrate->setText(tr("Quality Level %1").arg(QString().sprintf("%.2f", static_cast<double>(value * 5) / 100.0)));
1458                         break;
1459                 case SettingsModel::FLACEncoder:
1460                         labelBitrate->setText(tr("Compression %1").arg(value));
1461                         break;
1462                 case SettingsModel::PCMEncoder:
1463                         labelBitrate->setText(tr("Uncompressed"));
1464                         break;
1465                 default:
1466                         labelBitrate->setText(QString::number(value));
1467                         break;
1468                 }
1469                 break;
1470         case SettingsModel::ABRMode:
1471                 switch(m_settings->compressionEncoder())
1472                 {
1473                 case SettingsModel::MP3Encoder:
1474                         labelBitrate->setText(QString("&asymp; %1 kbps").arg(SettingsModel::mp3Bitrates[value]));
1475                         break;
1476                 case SettingsModel::FLACEncoder:
1477                         labelBitrate->setText(tr("Compression %1").arg(value));
1478                         break;
1479                 case SettingsModel::PCMEncoder:
1480                         labelBitrate->setText(tr("Uncompressed"));
1481                         break;
1482                 default:
1483                         labelBitrate->setText(QString("&asymp; %1 kbps").arg(min(500, value * 8)));
1484                         break;
1485                 }
1486                 break;
1487         default:
1488                 switch(m_settings->compressionEncoder())
1489                 {
1490                 case SettingsModel::MP3Encoder:
1491                         labelBitrate->setText(QString("%1 kbps").arg(SettingsModel::mp3Bitrates[value]));
1492                         break;
1493                 case SettingsModel::FLACEncoder:
1494                         labelBitrate->setText(tr("Compression %1").arg(value));
1495                         break;
1496                 case SettingsModel::PCMEncoder:
1497                         labelBitrate->setText(tr("Uncompressed"));
1498                         break;
1499                 default:
1500                         labelBitrate->setText(QString("%1 kbps").arg(min(500, value * 8)));
1501                         break;
1502                 }
1503                 break;
1504         }
1505 }
1506
1507 /*
1508  * Model reset
1509  */
1510 void MainWindow::sourceModelChanged(void)
1511 {
1512         m_dropNoteLabel->setVisible(m_fileListModel->rowCount() <= 0);
1513 }
1514
1515 /*
1516  * Meta tags enabled changed
1517  */
1518 void MainWindow::metaTagsEnabledChanged(void)
1519 {
1520         m_settings->writeMetaTags(writeMetaDataCheckBox->isChecked());
1521 }
1522
1523 /*
1524  * Playlist enabled changed
1525  */
1526 void MainWindow::playlistEnabledChanged(void)
1527 {
1528         m_settings->createPlaylist(generatePlaylistCheckBox->isChecked());
1529 }
1530
1531 /*
1532  * Output to source dir changed
1533  */
1534 void MainWindow::saveToSourceFolderChanged(void)
1535 {
1536         m_settings->outputToSourceDir(saveToSourceFolderCheckBox->isChecked());
1537 }
1538
1539 /*
1540  * Prepend relative source file path to output file name changed
1541  */
1542 void MainWindow::prependRelativePathChanged(void)
1543 {
1544         m_settings->prependRelativeSourcePath(prependRelativePathCheckBox->isChecked());
1545 }
1546
1547
1548 /*
1549  * Restore the override cursor
1550  */
1551 void MainWindow::restoreCursor(void)
1552 {
1553         QApplication::restoreOverrideCursor();
1554 }
1555
1556 /*
1557  * Show context menu for source files
1558  */
1559 void MainWindow::sourceFilesContextMenu(const QPoint &pos)
1560 {
1561         if(pos.x() <= sourceFileView->width() && pos.y() <= sourceFileView->height() && pos.x() >= 0 && pos.y() >= 0)
1562         {
1563                 m_sourceFilesContextMenu->popup(sourceFileView->mapToGlobal(pos));
1564         }
1565 }
1566
1567 /*
1568  * Open selected file in external player
1569  */
1570 void MainWindow::previewContextActionTriggered(void)
1571 {
1572         const static char *appNames[3] = {"smplayer_portable.exe", "smplayer.exe", "mplayer.exe"};
1573         const static wchar_t *registryKey = L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}";
1574         
1575         QModelIndex index = sourceFileView->currentIndex();
1576         if(!index.isValid())
1577         {
1578                 return;
1579         }
1580
1581         QString mplayerPath;
1582         HKEY registryKeyHandle;
1583
1584         if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, registryKey, 0, KEY_READ, &registryKeyHandle) == ERROR_SUCCESS)
1585         {
1586                 wchar_t Buffer[4096];
1587                 DWORD BuffSize = sizeof(wchar_t*) * 4096;
1588                 if(RegQueryValueExW(registryKeyHandle, L"InstallLocation", 0, 0, reinterpret_cast<BYTE*>(Buffer), &BuffSize) == ERROR_SUCCESS)
1589                 {
1590                         mplayerPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(Buffer));
1591                 }
1592         }
1593
1594         if(!mplayerPath.isEmpty())
1595         {
1596                 QDir mplayerDir(mplayerPath);
1597                 if(mplayerDir.exists())
1598                 {
1599                         for(int i = 0; i < 3; i++)
1600                         {
1601                                 if(mplayerDir.exists(appNames[i]))
1602                                 {
1603                                         QProcess::startDetached(mplayerDir.absoluteFilePath(appNames[i]), QStringList() << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
1604                                         return;
1605                                 }
1606                         }
1607                 }
1608         }
1609         
1610         QDesktopServices::openUrl(QString("file:///").append(m_fileListModel->getFile(index).filePath()));
1611 }
1612
1613 /*
1614  * Find selected file in explorer
1615  */
1616 void MainWindow::findFileContextActionTriggered(void)
1617 {
1618         QModelIndex index = sourceFileView->currentIndex();
1619         if(index.isValid())
1620         {
1621                 QString systemRootPath;
1622
1623                 QDir systemRoot(lamexp_known_folder(lamexp_folder_systemfolder));
1624                 if(systemRoot.exists() && systemRoot.cdUp())
1625                 {
1626                         systemRootPath = systemRoot.canonicalPath();
1627                 }
1628
1629                 if(!systemRootPath.isEmpty())
1630                 {
1631                         QFileInfo explorer(QString("%1/explorer.exe").arg(systemRootPath));
1632                         if(explorer.exists() && explorer.isFile())
1633                         {
1634                                 QProcess::execute(explorer.canonicalFilePath(), QStringList() << "/select," << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
1635                                 return;
1636                         }
1637                 }
1638                 else
1639                 {
1640                         qWarning("SystemRoot directory could not be detected!");
1641                 }
1642         }
1643 }
1644
1645 /*
1646  * Show context menu for output folder
1647  */
1648 void MainWindow::outputFolderContextMenu(const QPoint &pos)
1649 {
1650         
1651         if(pos.x() <= outputFolderView->width() && pos.y() <= outputFolderView->height() && pos.x() >= 0 && pos.y() >= 0)
1652         {
1653                 m_outputFolderContextMenu->popup(outputFolderView->mapToGlobal(pos));
1654         }
1655 }
1656
1657 /*
1658  * Show selected folder in explorer
1659  */
1660 void MainWindow::showFolderContextActionTriggered(void)
1661 {
1662         QDesktopServices::openUrl(QUrl::fromLocalFile(m_fileSystemModel->filePath(outputFolderView->currentIndex())));
1663 }
1664
1665 /*
1666  * Disable update reminder action
1667  */
1668 void MainWindow::disableUpdateReminderActionTriggered(bool checked)
1669 {
1670         if(checked)
1671         {
1672                 if(0 == QMessageBox::question(this, tr("Disable Update Reminder"), tr("Do you really want to disable the update reminder?"), tr("Yes"), tr("No"), QString(), 1))
1673                 {
1674                         QMessageBox::information(this, tr("Update Reminder"), QString("%1<br>%2").arg(tr("The update reminder has been disabled."), tr("Please remember to check for updates at regular intervals!")));
1675                         m_settings->autoUpdateEnabled(false);
1676                 }
1677                 else
1678                 {
1679                         m_settings->autoUpdateEnabled(true);
1680                 }
1681         }
1682         else
1683         {
1684                         QMessageBox::information(this, tr("Update Reminder"), tr("The update reminder has been re-enabled."));
1685                         m_settings->autoUpdateEnabled(true);
1686         }
1687
1688         actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
1689 }
1690
1691 /*
1692  * Disable sound effects action
1693  */
1694 void MainWindow::disableSoundsActionTriggered(bool checked)
1695 {
1696         if(checked)
1697         {
1698                 if(0 == QMessageBox::question(this, tr("Disable Sound Effects"), tr("Do you really want to disable all sound effects?"), tr("Yes"), tr("No"), QString(), 1))
1699                 {
1700                         QMessageBox::information(this, tr("Sound Effects"), tr("All sound effects have been disabled."));
1701                         m_settings->soundsEnabled(false);
1702                 }
1703                 else
1704                 {
1705                         m_settings->soundsEnabled(true);
1706                 }
1707         }
1708         else
1709         {
1710                         QMessageBox::information(this, tr("Sound Effects"), tr("The sound effects have been re-enabled."));
1711                         m_settings->soundsEnabled(true);
1712         }
1713
1714         actionDisableSounds->setChecked(!m_settings->soundsEnabled());
1715 }
1716
1717 /*
1718  * Disable Nero AAC encoder action
1719  */
1720 void MainWindow::disableNeroAacNotificationsActionTriggered(bool checked)
1721 {
1722         if(checked)
1723         {
1724                 if(0 == QMessageBox::question(this, tr("Nero AAC Notifications"), tr("Do you really want to disable all Nero AAC Encoder notifications?"), tr("Yes"), tr("No"), QString(), 1))
1725                 {
1726                         QMessageBox::information(this, tr("Nero AAC Notifications"), tr("All Nero AAC Encoder notifications have been disabled."));
1727                         m_settings->neroAacNotificationsEnabled(false);
1728                 }
1729                 else
1730                 {
1731                         m_settings->neroAacNotificationsEnabled(true);
1732                 }
1733         }
1734         else
1735         {
1736                         QMessageBox::information(this, tr("Nero AAC Notifications"), tr("The Nero AAC Encoder notifications have been re-enabled."));
1737                         m_settings->neroAacNotificationsEnabled(true);
1738         }
1739
1740         actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
1741 }
1742
1743 /*
1744  * Disable WMA Decoder component action
1745  */
1746 void MainWindow::disableWmaDecoderNotificationsActionTriggered(bool checked)
1747 {
1748         if(checked)
1749         {
1750                 if(0 == QMessageBox::question(this, tr("WMA Decoder Notifications"), tr("Do you really want to disable all WMA Decoder notifications?"), tr("Yes"), tr("No"), QString(), 1))
1751                 {
1752                         QMessageBox::information(this, tr("WMA Decoder Notifications"), tr("All WMA Decoder notifications have been disabled."));
1753                         m_settings->wmaDecoderNotificationsEnabled(false);
1754                 }
1755                 else
1756                 {
1757                         m_settings->wmaDecoderNotificationsEnabled(true);
1758                 }
1759         }
1760         else
1761         {
1762                         QMessageBox::information(this, tr("WMA Decoder Notifications"), tr("The WMA Decoder notifications have been re-enabled."));
1763                         m_settings->wmaDecoderNotificationsEnabled(true);
1764         }
1765
1766         actionDisableWmaDecoderNotifications->setChecked(!m_settings->wmaDecoderNotificationsEnabled());
1767 }
1768
1769 /*
1770  * Download and install WMA Decoder component
1771  */
1772 void MainWindow::installWMADecoderActionTriggered(bool checked)
1773 {
1774         static const char *download_url = "http://www.nch.com.au/components/wmawav.exe";
1775         static const char *download_hash = "52a3b0e6690faf3f830c336d3c0eadfb7a4e9bc6";
1776         
1777         if(QMessageBox::question(this, tr("Install WMA Decoder"), tr("Do you want to download and install the WMA File Decoder component now?"), tr("Download && Install"), tr("Cancel")) != 0)
1778         {
1779                 return;
1780         }
1781
1782         QString binaryWGet = lamexp_lookup_tool("wget.exe");
1783         QString binaryElevator = lamexp_lookup_tool("elevator.exe");
1784         
1785         if(binaryWGet.isEmpty() || binaryElevator.isEmpty())
1786         {
1787                 throw "Required binary is not available!";
1788         }
1789
1790         while(true)
1791         {
1792                 QString setupFile = QString("%1/%2.exe").arg(lamexp_temp_folder(), lamexp_rand_str());
1793
1794                 QProcess process;
1795                 process.setWorkingDirectory(QFileInfo(setupFile).absolutePath());
1796
1797                 QEventLoop loop;
1798                 connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
1799                 connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), &loop, SLOT(quit()));
1800                 
1801                 process.start(binaryWGet, QStringList() << "-O" << QFileInfo(setupFile).fileName() << download_url);
1802                 m_banner->show(tr("Downloading WMA Decoder Setup, please wait..."), &loop);
1803
1804                 if(process.exitCode() != 0 || QFileInfo(setupFile).size() < 10240)
1805                 {
1806                         QFile::remove(setupFile);
1807                         if(QMessageBox::critical(this, tr("Download Failed"), tr("Failed to download the WMA Decoder setup. Check your internet connection!"), tr("Try Again"), tr("Cancel")) == 0)
1808                         {
1809                                 continue;
1810                         }
1811                         return;
1812                 }
1813
1814                 QFile setupFileContent(setupFile);
1815                 QCryptographicHash setupFileHash(QCryptographicHash::Sha1);
1816                 
1817                 setupFileContent.open(QIODevice::ReadOnly);
1818                 if(setupFileContent.isOpen() && setupFileContent.isReadable())
1819                 {
1820                         setupFileHash.addData(setupFileContent.readAll());
1821                         setupFileContent.close();
1822                 }
1823
1824                 if(_stricmp(setupFileHash.result().toHex().constData(), download_hash))
1825                 {
1826                         qWarning("Hash miscompare:\n  Expected %s\n  Detected %s\n", download_hash, setupFileHash.result().toHex().constData());
1827                         QFile::remove(setupFile);
1828                         if(QMessageBox::critical(this, tr("Download Failed"), tr("The download seems to be corrupted. Please try again!"), tr("Try Again"), tr("Cancel")) == 0)
1829                         {
1830                                 continue;
1831                         }
1832                         return;
1833                 }
1834
1835                 QApplication::setOverrideCursor(Qt::WaitCursor);
1836                 process.start(binaryElevator, QStringList() << QString("/exec=%1").arg(setupFile));
1837                 loop.exec(QEventLoop::ExcludeUserInputEvents);
1838                 QFile::remove(setupFile);
1839                 QApplication::restoreOverrideCursor();
1840
1841                 if(QMessageBox::information(this, tr("WMA Decoder"), tr("The WMA File Decoder has been installed. Please restart LameXP now!"), tr("Quit LameXP"), tr("Postpone")) == 0)
1842                 {
1843                         QApplication::quit();
1844                 }
1845                 break;
1846         }
1847 }
1848
1849 void MainWindow::showDropBoxWidgetActionTriggered(bool checked)
1850 {
1851         m_settings->dropBoxWidgetEnabled(true);
1852         
1853         if(!m_dropBox->isVisible())
1854         {
1855                 m_dropBox->show();
1856         }
1857         
1858         FLASH_WINDOW(m_dropBox);
1859 }