OSDN Git Service

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