Prepare UI for "volume normalization" filter.
[LameXP.git] / src / Dialog_MainWindow.cpp
blob0b55a0f2b2407317386944dce35a1c49078db531
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.
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.
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
22 #include "Dialog_MainWindow.h"
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"
41 //Qt includes
42 #include <QMessageBox>
43 #include <QTimer>
44 #include <QDesktopWidget>
45 #include <QDate>
46 #include <QFileDialog>
47 #include <QInputDialog>
48 #include <QFileSystemModel>
49 #include <QDesktopServices>
50 #include <QUrl>
51 #include <QPlastiqueStyle>
52 #include <QCleanlooksStyle>
53 #include <QWindowsVistaStyle>
54 #include <QWindowsStyle>
55 #include <QSysInfo>
56 #include <QDragEnterEvent>
57 #include <QWindowsMime>
58 #include <QProcess>
59 #include <QUuid>
60 #include <QProcessEnvironment>
61 #include <QCryptographicHash>
62 #include <QTranslator>
63 #include <QResource>
64 #include <QScrollBar>
66 //Win32 includes
67 #include <Windows.h>
69 //Helper macros
70 #define ABORT_IF_BUSY if(m_banner->isVisible() || m_delayedFileTimer->isActive()) { MessageBeep(MB_ICONEXCLAMATION); return; }
71 #define SET_TEXT_COLOR(WIDGET,COLOR) { QPalette _palette = WIDGET->palette(); _palette.setColor(QPalette::WindowText, COLOR); WIDGET->setPalette(_palette); }
72 #define SET_FONT_BOLD(WIDGET,BOLD) { QFont _font = WIDGET->font(); _font.setBold(BOLD); WIDGET->setFont(_font); }
73 #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); }
74 #define LINK(URL) QString("<a href=\"%1\">%2</a>").arg(URL).arg(URL)
75 #define TEMP_HIDE_DROPBOX(CMD) { bool __dropBoxVisible = m_dropBox->isVisible(); if(__dropBoxVisible) m_dropBox->hide(); CMD; if(__dropBoxVisible) m_dropBox->show(); }
77 //Helper class
78 //class Index: public QObjectUserData
79 //{
80 //public:
81 // Index(int index) { m_index = index; }
82 // int value(void) { return m_index; }
83 //private:
84 // int m_index;
85 //};
87 ////////////////////////////////////////////////////////////
88 // Constructor
89 ////////////////////////////////////////////////////////////
91 MainWindow::MainWindow(FileListModel *fileListModel, AudioFileModel *metaInfo, SettingsModel *settingsModel, QWidget *parent)
93 QMainWindow(parent),
94 m_fileListModel(fileListModel),
95 m_metaData(metaInfo),
96 m_settings(settingsModel),
97 m_accepted(false),
98 m_firstTimeShown(true)
100 //Init the dialog, from the .ui file
101 setupUi(this);
102 setWindowFlags(windowFlags() ^ Qt::WindowMaximizeButtonHint);
104 //Register meta types
105 qRegisterMetaType<AudioFileModel>("AudioFileModel");
107 //Enabled main buttons
108 connect(buttonAbout, SIGNAL(clicked()), this, SLOT(aboutButtonClicked()));
109 connect(buttonStart, SIGNAL(clicked()), this, SLOT(encodeButtonClicked()));
110 connect(buttonQuit, SIGNAL(clicked()), this, SLOT(closeButtonClicked()));
112 //Setup tab widget
113 tabWidget->setCurrentIndex(0);
114 connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabPageChanged(int)));
116 //Setup "Source" tab
117 sourceFileView->setModel(m_fileListModel);
118 sourceFileView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
119 sourceFileView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
120 sourceFileView->setContextMenuPolicy(Qt::CustomContextMenu);
121 m_dropNoteLabel = new QLabel(sourceFileView);
122 m_dropNoteLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
123 SET_FONT_BOLD(m_dropNoteLabel, true);
124 SET_TEXT_COLOR(m_dropNoteLabel, Qt::darkGray);
125 m_sourceFilesContextMenu = new QMenu();
126 m_showDetailsContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/zoom.png"), "N/A");
127 m_previewContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/sound.png"), "N/A");
128 m_findFileContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/folder_go.png"), "N/A");
129 SET_FONT_BOLD(m_showDetailsContextAction, true);
130 connect(buttonAddFiles, SIGNAL(clicked()), this, SLOT(addFilesButtonClicked()));
131 connect(buttonRemoveFile, SIGNAL(clicked()), this, SLOT(removeFileButtonClicked()));
132 connect(buttonClearFiles, SIGNAL(clicked()), this, SLOT(clearFilesButtonClicked()));
133 connect(buttonFileUp, SIGNAL(clicked()), this, SLOT(fileUpButtonClicked()));
134 connect(buttonFileDown, SIGNAL(clicked()), this, SLOT(fileDownButtonClicked()));
135 connect(buttonShowDetails, SIGNAL(clicked()), this, SLOT(showDetailsButtonClicked()));
136 connect(m_fileListModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(sourceModelChanged()));
137 connect(m_fileListModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(sourceModelChanged()));
138 connect(m_fileListModel, SIGNAL(modelReset()), this, SLOT(sourceModelChanged()));
139 connect(sourceFileView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(sourceFilesContextMenu(QPoint)));
140 connect(m_showDetailsContextAction, SIGNAL(triggered(bool)), this, SLOT(showDetailsButtonClicked()));
141 connect(m_previewContextAction, SIGNAL(triggered(bool)), this, SLOT(previewContextActionTriggered()));
142 connect(m_findFileContextAction, SIGNAL(triggered(bool)), this, SLOT(findFileContextActionTriggered()));
144 //Setup "Output" tab
145 m_fileSystemModel = new QFileSystemModelEx();
146 m_fileSystemModel->setRootPath(m_fileSystemModel->rootPath());
147 m_fileSystemModel->installEventFilter(this);
148 outputFolderView->setModel(m_fileSystemModel);
149 outputFolderView->header()->setStretchLastSection(true);
150 outputFolderView->header()->hideSection(1);
151 outputFolderView->header()->hideSection(2);
152 outputFolderView->header()->hideSection(3);
153 outputFolderView->setHeaderHidden(true);
154 outputFolderView->setAnimated(true);
155 outputFolderView->setMouseTracking(false);
156 outputFolderView->setContextMenuPolicy(Qt::CustomContextMenu);
157 while(saveToSourceFolderCheckBox->isChecked() != m_settings->outputToSourceDir()) saveToSourceFolderCheckBox->click();
158 prependRelativePathCheckBox->setChecked(m_settings->prependRelativeSourcePath());
159 connect(outputFolderView, SIGNAL(clicked(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
160 connect(outputFolderView, SIGNAL(activated(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
161 connect(outputFolderView, SIGNAL(pressed(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
162 connect(outputFolderView, SIGNAL(entered(QModelIndex)), this, SLOT(outputFolderViewMoved(QModelIndex)));
163 outputFolderView->setCurrentIndex(m_fileSystemModel->index(m_settings->outputDir()));
164 outputFolderViewClicked(outputFolderView->currentIndex());
165 connect(buttonMakeFolder, SIGNAL(clicked()), this, SLOT(makeFolderButtonClicked()));
166 connect(buttonGotoHome, SIGNAL(clicked()), SLOT(gotoHomeFolderButtonClicked()));
167 connect(buttonGotoDesktop, SIGNAL(clicked()), this, SLOT(gotoDesktopButtonClicked()));
168 connect(buttonGotoMusic, SIGNAL(clicked()), this, SLOT(gotoMusicFolderButtonClicked()));
169 connect(saveToSourceFolderCheckBox, SIGNAL(clicked()), this, SLOT(saveToSourceFolderChanged()));
170 connect(prependRelativePathCheckBox, SIGNAL(clicked()), this, SLOT(prependRelativePathChanged()));
171 m_outputFolderContextMenu = new QMenu();
172 m_showFolderContextAction = m_outputFolderContextMenu->addAction(QIcon(":/icons/zoom.png"), "N/A");
173 connect(outputFolderView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(outputFolderContextMenu(QPoint)));
174 connect(m_showFolderContextAction, SIGNAL(triggered(bool)), this, SLOT(showFolderContextActionTriggered()));
175 outputFolderLabel->installEventFilter(this);
177 //Setup "Meta Data" tab
178 m_metaInfoModel = new MetaInfoModel(m_metaData, 6);
179 m_metaInfoModel->clearData();
180 metaDataView->setModel(m_metaInfoModel);
181 metaDataView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
182 metaDataView->verticalHeader()->hide();
183 metaDataView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
184 while(writeMetaDataCheckBox->isChecked() != m_settings->writeMetaTags()) writeMetaDataCheckBox->click();
185 generatePlaylistCheckBox->setChecked(m_settings->createPlaylist());
186 connect(buttonEditMeta, SIGNAL(clicked()), this, SLOT(editMetaButtonClicked()));
187 connect(buttonClearMeta, SIGNAL(clicked()), this, SLOT(clearMetaButtonClicked()));
188 connect(writeMetaDataCheckBox, SIGNAL(clicked()), this, SLOT(metaTagsEnabledChanged()));
189 connect(generatePlaylistCheckBox, SIGNAL(clicked()), this, SLOT(playlistEnabledChanged()));
191 //Setup "Compression" tab
192 m_encoderButtonGroup = new QButtonGroup(this);
193 m_encoderButtonGroup->addButton(radioButtonEncoderMP3, SettingsModel::MP3Encoder);
194 m_encoderButtonGroup->addButton(radioButtonEncoderVorbis, SettingsModel::VorbisEncoder);
195 m_encoderButtonGroup->addButton(radioButtonEncoderAAC, SettingsModel::AACEncoder);
196 m_encoderButtonGroup->addButton(radioButtonEncoderFLAC, SettingsModel::FLACEncoder);
197 m_encoderButtonGroup->addButton(radioButtonEncoderPCM, SettingsModel::PCMEncoder);
198 m_modeButtonGroup = new QButtonGroup(this);
199 m_modeButtonGroup->addButton(radioButtonModeQuality, SettingsModel::VBRMode);
200 m_modeButtonGroup->addButton(radioButtonModeAverageBitrate, SettingsModel::ABRMode);
201 m_modeButtonGroup->addButton(radioButtonConstBitrate, SettingsModel::CBRMode);
202 radioButtonEncoderMP3->setChecked(m_settings->compressionEncoder() == SettingsModel::MP3Encoder);
203 radioButtonEncoderVorbis->setChecked(m_settings->compressionEncoder() == SettingsModel::VorbisEncoder);
204 radioButtonEncoderAAC->setChecked(m_settings->compressionEncoder() == SettingsModel::AACEncoder);
205 radioButtonEncoderFLAC->setChecked(m_settings->compressionEncoder() == SettingsModel::FLACEncoder);
206 radioButtonEncoderPCM->setChecked(m_settings->compressionEncoder() == SettingsModel::PCMEncoder);
207 radioButtonModeQuality->setChecked(m_settings->compressionRCMode() == SettingsModel::VBRMode);
208 radioButtonModeAverageBitrate->setChecked(m_settings->compressionRCMode() == SettingsModel::ABRMode);
209 radioButtonConstBitrate->setChecked(m_settings->compressionRCMode() == SettingsModel::CBRMode);
210 sliderBitrate->setValue(m_settings->compressionBitrate());
211 connect(m_encoderButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateEncoder(int)));
212 connect(m_modeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateRCMode(int)));
213 connect(sliderBitrate, SIGNAL(valueChanged(int)), this, SLOT(updateBitrate(int)));
214 updateEncoder(m_encoderButtonGroup->checkedId());
216 //Setup "Advanced Options" tab
217 sliderLameAlgoQuality->setValue(m_settings->lameAlgoQuality());
218 spinBoxBitrateManagementMin->setValue(m_settings->bitrateManagementMinRate());
219 spinBoxBitrateManagementMax->setValue(m_settings->bitrateManagementMaxRate());
220 spinBoxNormalizationFilter->setValue(static_cast<double>(m_settings->normalizationFilterMaxVolume()) / 100.0);
221 comboBoxMP3ChannelMode->setCurrentIndex(m_settings->lameChannelMode());
222 comboBoxSamplingRate->setCurrentIndex(m_settings->samplingRate());
223 comboBoxNeroAACProfile->setCurrentIndex(m_settings->neroAACProfile());
224 while(checkBoxBitrateManagement->isChecked() != m_settings->bitrateManagementEnabled()) checkBoxBitrateManagement->click();
225 while(checkBoxNeroAAC2PassMode->isChecked() != m_settings->neroAACEnable2Pass()) checkBoxNeroAAC2PassMode->click();
226 while(checkBoxNormalizationFilter->isChecked() != m_settings->normalizationFilterEnabled()) checkBoxNormalizationFilter->click();
227 connect(sliderLameAlgoQuality, SIGNAL(valueChanged(int)), this, SLOT(updateLameAlgoQuality(int)));
228 connect(checkBoxBitrateManagement, SIGNAL(clicked(bool)), this, SLOT(bitrateManagementEnabledChanged(bool)));
229 connect(spinBoxBitrateManagementMin, SIGNAL(valueChanged(int)), this, SLOT(bitrateManagementMinChanged(int)));
230 connect(spinBoxBitrateManagementMax, SIGNAL(valueChanged(int)), this, SLOT(bitrateManagementMaxChanged(int)));
231 connect(comboBoxMP3ChannelMode, SIGNAL(currentIndexChanged(int)), this, SLOT(channelModeChanged(int)));
232 connect(comboBoxSamplingRate, SIGNAL(currentIndexChanged(int)), this, SLOT(samplingRateChanged(int)));
233 connect(checkBoxNeroAAC2PassMode, SIGNAL(clicked(bool)), this, SLOT(neroAAC2PassChanged(bool)));
234 connect(comboBoxNeroAACProfile, SIGNAL(currentIndexChanged(int)), this, SLOT(neroAACProfileChanged(int)));
235 connect(checkBoxNormalizationFilter, SIGNAL(clicked(bool)), this, SLOT(normalizationEnabledChanged(bool)));
236 connect(spinBoxNormalizationFilter, SIGNAL(valueChanged(double)), this, SLOT(normalizationMaxVolumeChanged(double)));
237 connect(buttonResetAdvancedOptions, SIGNAL(clicked()), this, SLOT(resetAdvancedOptionsButtonClicked()));
238 updateLameAlgoQuality(sliderLameAlgoQuality->value());
240 //Activate file menu actions
241 connect(actionOpenFolder, SIGNAL(triggered()), this, SLOT(openFolderActionActivated()));
243 //Activate view menu actions
244 m_tabActionGroup = new QActionGroup(this);
245 m_tabActionGroup->addAction(actionSourceFiles);
246 m_tabActionGroup->addAction(actionOutputDirectory);
247 m_tabActionGroup->addAction(actionCompression);
248 m_tabActionGroup->addAction(actionMetaData);
249 m_tabActionGroup->addAction(actionAdvancedOptions);
250 actionSourceFiles->setData(0);
251 actionOutputDirectory->setData(1);
252 actionMetaData->setData(2);
253 actionCompression->setData(3);
254 actionAdvancedOptions->setData(4);
255 actionSourceFiles->setChecked(true);
256 connect(m_tabActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(tabActionActivated(QAction*)));
258 //Activate style menu actions
259 m_styleActionGroup = new QActionGroup(this);
260 m_styleActionGroup->addAction(actionStylePlastique);
261 m_styleActionGroup->addAction(actionStyleCleanlooks);
262 m_styleActionGroup->addAction(actionStyleWindowsVista);
263 m_styleActionGroup->addAction(actionStyleWindowsXP);
264 m_styleActionGroup->addAction(actionStyleWindowsClassic);
265 actionStylePlastique->setData(0);
266 actionStyleCleanlooks->setData(1);
267 actionStyleWindowsVista->setData(2);
268 actionStyleWindowsXP->setData(3);
269 actionStyleWindowsClassic->setData(4);
270 actionStylePlastique->setChecked(true);
271 actionStyleWindowsXP->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_XP && lamexp_themes_enabled());
272 actionStyleWindowsVista->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_VISTA && lamexp_themes_enabled());
273 connect(m_styleActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(styleActionActivated(QAction*)));
274 styleActionActivated(NULL);
276 //Populate the language menu
277 m_languageActionGroup = new QActionGroup(this);
278 QStringList translations = lamexp_query_translations();
279 while(!translations.isEmpty())
281 QString langId = translations.takeFirst();
282 QAction *currentLanguage = new QAction(this);
283 currentLanguage->setData(langId);
284 currentLanguage->setText(lamexp_translation_name(langId));
285 currentLanguage->setIcon(QIcon(QString(":/flags/%1.png").arg(langId)));
286 currentLanguage->setCheckable(true);
287 m_languageActionGroup->addAction(currentLanguage);
288 menuLanguage->insertAction(actionLoadTranslationFromFile, currentLanguage);
290 menuLanguage->insertSeparator(actionLoadTranslationFromFile);
291 connect(actionLoadTranslationFromFile, SIGNAL(triggered(bool)), this, SLOT(languageFromFileActionActivated(bool)));
292 connect(m_languageActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(languageActionActivated(QAction*)));
294 //Activate tools menu actions
295 actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
296 actionDisableSounds->setChecked(!m_settings->soundsEnabled());
297 actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
298 actionDisableWmaDecoderNotifications->setChecked(!m_settings->wmaDecoderNotificationsEnabled());
299 connect(actionDisableUpdateReminder, SIGNAL(triggered(bool)), this, SLOT(disableUpdateReminderActionTriggered(bool)));
300 connect(actionDisableSounds, SIGNAL(triggered(bool)), this, SLOT(disableSoundsActionTriggered(bool)));
301 connect(actionInstallWMADecoder, SIGNAL(triggered(bool)), this, SLOT(installWMADecoderActionTriggered(bool)));
302 connect(actionDisableNeroAacNotifications, SIGNAL(triggered(bool)), this, SLOT(disableNeroAacNotificationsActionTriggered(bool)));
303 connect(actionDisableWmaDecoderNotifications, SIGNAL(triggered(bool)), this, SLOT(disableWmaDecoderNotificationsActionTriggered(bool)));
304 connect(actionShowDropBoxWidget, SIGNAL(triggered(bool)), this, SLOT(showDropBoxWidgetActionTriggered(bool)));
306 //Activate help menu actions
307 connect(actionCheckUpdates, SIGNAL(triggered()), this, SLOT(checkUpdatesActionActivated()));
308 connect(actionVisitHomepage, SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
310 //Center window in screen
311 QRect desktopRect = QApplication::desktop()->screenGeometry();
312 QRect thisRect = this->geometry();
313 move((desktopRect.width() - thisRect.width()) / 2, (desktopRect.height() - thisRect.height()) / 2);
314 setMinimumSize(thisRect.width(), thisRect.height());
316 //Create banner
317 m_banner = new WorkingBanner(this);
319 //Create DropBox widget
320 m_dropBox = new DropBox(this, m_fileListModel, m_settings);
321 connect(m_fileListModel, SIGNAL(modelReset()), m_dropBox, SLOT(modelChanged()));
322 connect(m_fileListModel, SIGNAL(rowsInserted(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
323 connect(m_fileListModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
325 //Create message handler thread
326 m_messageHandler = new MessageHandlerThread();
327 m_delayedFileList = new QStringList();
328 m_delayedFileTimer = new QTimer();
329 connect(m_messageHandler, SIGNAL(otherInstanceDetected()), this, SLOT(notifyOtherInstance()), Qt::QueuedConnection);
330 connect(m_messageHandler, SIGNAL(fileReceived(QString)), this, SLOT(addFileDelayed(QString)), Qt::QueuedConnection);
331 connect(m_messageHandler, SIGNAL(killSignalReceived()), this, SLOT(close()), Qt::QueuedConnection);
332 connect(m_delayedFileTimer, SIGNAL(timeout()), this, SLOT(handleDelayedFiles()));
333 m_messageHandler->start();
335 //Load translation file
336 QList<QAction*> languageActions = m_languageActionGroup->actions();
337 while(!languageActions.isEmpty())
339 QAction *currentLanguage = languageActions.takeFirst();
340 if(currentLanguage->data().toString().compare(m_settings->currentLanguage(), Qt::CaseInsensitive) == 0)
342 currentLanguage->setChecked(true);
343 languageActionActivated(currentLanguage);
347 //Re-translate (make sure we translate once)
348 QEvent languageChangeEvent(QEvent::LanguageChange);
349 changeEvent(&languageChangeEvent);
351 //Enable Drag & Drop
352 this->setAcceptDrops(true);
355 ////////////////////////////////////////////////////////////
356 // Destructor
357 ////////////////////////////////////////////////////////////
359 MainWindow::~MainWindow(void)
361 //Stop message handler thread
362 if(m_messageHandler && m_messageHandler->isRunning())
364 m_messageHandler->stop();
365 if(!m_messageHandler->wait(10000))
367 m_messageHandler->terminate();
368 m_messageHandler->wait();
372 //Unset models
373 sourceFileView->setModel(NULL);
374 metaDataView->setModel(NULL);
376 //Free memory
377 LAMEXP_DELETE(m_tabActionGroup);
378 LAMEXP_DELETE(m_styleActionGroup);
379 LAMEXP_DELETE(m_languageActionGroup);
380 LAMEXP_DELETE(m_banner);
381 LAMEXP_DELETE(m_fileSystemModel);
382 LAMEXP_DELETE(m_messageHandler);
383 LAMEXP_DELETE(m_delayedFileList);
384 LAMEXP_DELETE(m_delayedFileTimer);
385 LAMEXP_DELETE(m_metaInfoModel);
386 LAMEXP_DELETE(m_encoderButtonGroup);
387 LAMEXP_DELETE(m_encoderButtonGroup);
388 LAMEXP_DELETE(m_sourceFilesContextMenu);
389 LAMEXP_DELETE(m_dropBox);
393 ////////////////////////////////////////////////////////////
394 // PRIVATE FUNCTIONS
395 ////////////////////////////////////////////////////////////
398 * Add file to source list
400 void MainWindow::addFiles(const QStringList &files)
402 if(files.isEmpty())
404 return;
407 tabWidget->setCurrentIndex(0);
409 FileAnalyzer *analyzer = new FileAnalyzer(files);
410 connect(analyzer, SIGNAL(fileSelected(QString)), m_banner, SLOT(setText(QString)), Qt::QueuedConnection);
411 connect(analyzer, SIGNAL(fileAnalyzed(AudioFileModel)), m_fileListModel, SLOT(addFile(AudioFileModel)), Qt::QueuedConnection);
413 m_banner->show(tr("Adding file(s), please wait..."), analyzer);
415 if(analyzer->filesDenied())
417 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.")));
419 if(analyzer->filesRejected())
421 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.")));
424 LAMEXP_DELETE(analyzer);
425 sourceFileView->scrollToBottom();
426 m_banner->close();
429 ////////////////////////////////////////////////////////////
430 // EVENTS
431 ////////////////////////////////////////////////////////////
434 * Window is about to be shown
436 void MainWindow::showEvent(QShowEvent *event)
438 m_accepted = false;
439 m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
440 sourceModelChanged();
441 tabWidget->setCurrentIndex(0);
443 if(m_firstTimeShown)
445 m_firstTimeShown = false;
446 QTimer::singleShot(0, this, SLOT(windowShown()));
448 else
450 if(m_settings->dropBoxWidgetEnabled())
452 m_dropBox->setVisible(true);
458 * Re-translate the UI
460 void MainWindow::changeEvent(QEvent *e)
462 if(e->type() == QEvent::LanguageChange)
464 int comboBoxIndex[3];
466 //Backup combobox indices
467 comboBoxIndex[0] = comboBoxMP3ChannelMode->currentIndex();
468 comboBoxIndex[1] = comboBoxSamplingRate->currentIndex();
469 comboBoxIndex[2] = comboBoxNeroAACProfile->currentIndex();
471 //Re.translate from UIC
472 Ui::MainWindow::retranslateUi(this);
474 //Restore combobox indices
475 comboBoxMP3ChannelMode->setCurrentIndex(comboBoxIndex[0]);
476 comboBoxSamplingRate->setCurrentIndex(comboBoxIndex[1]);
477 comboBoxNeroAACProfile->setCurrentIndex(comboBoxIndex[2]);
479 if(lamexp_version_demo())
481 setWindowTitle(QString("%1 [%2]").arg(windowTitle(), tr("DEMO VERSION")));
484 //Manual re-translate
485 m_dropNoteLabel->setText(QString("» %1 «").arg(tr("You can drop in audio files here!")));
486 m_showDetailsContextAction->setText(tr("Show Details"));
487 m_previewContextAction->setText(tr("Open File in External Application"));
488 m_findFileContextAction->setText(tr("Browse File Location"));
489 m_showFolderContextAction->setText(tr("Browse Selected Folder"));
491 //Force GUI update
492 m_metaInfoModel->clearData();
493 updateEncoder(m_settings->compressionEncoder());
494 updateLameAlgoQuality(sliderLameAlgoQuality->value());
499 * File dragged over window
501 void MainWindow::dragEnterEvent(QDragEnterEvent *event)
503 QStringList formats = event->mimeData()->formats();
505 if(formats.contains("application/x-qt-windows-mime;value=\"FileNameW\"", Qt::CaseInsensitive) && formats.contains("text/uri-list", Qt::CaseInsensitive))
507 event->acceptProposedAction();
512 * File dropped onto window
514 void MainWindow::dropEvent(QDropEvent *event)
516 ABORT_IF_BUSY;
518 QStringList droppedFiles;
519 const QList<QUrl> urls = event->mimeData()->urls();
521 for(int i = 0; i < urls.count(); i++)
523 QFileInfo file(urls.at(i).toLocalFile());
524 if(!file.exists())
526 continue;
528 if(file.isFile())
530 droppedFiles << file.canonicalFilePath();
531 continue;
533 if(file.isDir())
535 QList<QFileInfo> list = QDir(file.canonicalFilePath()).entryInfoList(QDir::Files);
536 for(int j = 0; j < list.count(); j++)
538 droppedFiles << list.at(j).canonicalFilePath();
543 addFiles(droppedFiles);
547 * Window tries to close
549 void MainWindow::closeEvent(QCloseEvent *event)
551 if(m_banner->isVisible() || m_delayedFileTimer->isActive())
553 MessageBeep(MB_ICONEXCLAMATION);
554 event->ignore();
557 if(m_dropBox)
559 m_dropBox->hide();
564 * Window was resized
566 void MainWindow::resizeEvent(QResizeEvent *event)
568 QMainWindow::resizeEvent(event);
569 m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
573 * Event filter
575 bool MainWindow::eventFilter(QObject *obj, QEvent *event)
577 if(obj == m_fileSystemModel && QApplication::overrideCursor() == NULL)
579 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
580 QTimer::singleShot(250, this, SLOT(restoreCursor()));
582 else if(obj == outputFolderLabel)
584 switch(event->type())
586 case QEvent::MouseButtonPress:
587 if(dynamic_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)
589 QDesktopServices::openUrl(QString("file:///%1").arg(outputFolderLabel->text()));
591 break;
592 case QEvent::Enter:
593 outputFolderLabel->setForegroundRole(QPalette::Link);
594 break;
595 case QEvent::Leave:
596 outputFolderLabel->setForegroundRole(QPalette::WindowText);
597 break;
600 return false;
603 ////////////////////////////////////////////////////////////
604 // Slots
605 ////////////////////////////////////////////////////////////
608 * Window shown
610 void MainWindow::windowShown(void)
612 QStringList arguments = QApplication::arguments();
614 //Check license
615 if(m_settings->licenseAccepted() <= 0)
617 int iAccepted = -1;
619 if(m_settings->licenseAccepted() == 0)
621 AboutDialog *about = new AboutDialog(m_settings, this, true);
622 iAccepted = about->exec();
623 LAMEXP_DELETE(about);
626 if(iAccepted <= 0)
628 m_settings->licenseAccepted(-1);
629 QApplication::processEvents();
630 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
631 QMessageBox::critical(this, tr("License Declined"), tr("You have declined the license. Consequently the application will exit now!"), tr("Goodbye!"));
632 QProcess::startDetached(QString("%1/Uninstall.exe").arg(QApplication::applicationDirPath()), QStringList());
633 QApplication::quit();
634 return;
637 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WOOHOO), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
638 m_settings->licenseAccepted(1);
641 //Check for expiration
642 if(lamexp_version_demo())
644 if(QDate::currentDate() >= lamexp_version_expires())
646 qWarning("Binary has expired !!!");
647 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
648 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)
650 checkUpdatesActionActivated();
652 QApplication::quit();
653 return;
657 //Update reminder
658 if(QDate::currentDate() >= lamexp_version_date().addYears(1))
660 qWarning("Binary is more than a year old, time to update!");
661 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)
663 checkUpdatesActionActivated();
665 else
667 QApplication::quit();
668 return;
671 else if(m_settings->autoUpdateEnabled())
673 QDate lastUpdateCheck = QDate::fromString(m_settings->autoUpdateLastCheck(), Qt::ISODate);
674 if(!lastUpdateCheck.isValid() || QDate::currentDate() >= lastUpdateCheck.addDays(14))
676 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)
678 checkUpdatesActionActivated();
683 //Check for AAC support
684 if(m_settings->neroAacNotificationsEnabled())
686 if(lamexp_check_tool("neroAacEnc.exe") && lamexp_check_tool("neroAacDec.exe") && lamexp_check_tool("neroAacTag.exe"))
688 if(lamexp_tool_version("neroAacEnc.exe") < lamexp_toolver_neroaac())
690 QString messageText;
691 messageText += QString("<nobr>%1<br>").arg(tr("LameXP detected that your version of the Nero AAC encoder is outdated!"));
692 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"))));
693 messageText += QString("%1<br>").arg(tr("You can download the latest version of the Nero AAC encoder from the Nero website at:"));
694 messageText += "<b>" + LINK(AboutDialog::neroAacUrl) + "</b><br></nobr>";
695 QMessageBox::information(this, tr("AAC Encoder Outdated"), messageText);
698 else
700 radioButtonEncoderAAC->setEnabled(false);
701 QString appPath = QDir(QCoreApplication::applicationDirPath()).canonicalPath();
702 if(appPath.isEmpty()) appPath = QCoreApplication::applicationDirPath();
703 QString messageText;
704 messageText += QString("<nobr>%1<br>").arg(tr("The Nero AAC encoder could not be found. AAC encoding support will be disabled."));
705 messageText += QString("%1<br><br>").arg(tr("Please put 'neroAacEnc.exe', 'neroAacDec.exe' and 'neroAacTag.exe' into the LameXP directory!"));
706 messageText += QString("%1<br>").arg(tr("Your LameXP directory is located here:"));
707 messageText += QString("<i><nobr><a href=\"file:///%1\">%1</a></nobr></i><br><br>").arg(QDir::toNativeSeparators(appPath));
708 messageText += QString("%1<br>").arg(tr("You can download the Nero AAC encoder for free from the official Nero website at:"));
709 messageText += "<b>" + LINK(AboutDialog::neroAacUrl) + "</b><br></nobr>";
710 QMessageBox::information(this, tr("AAC Support Disabled"), messageText);
714 //Check for WMA support
715 if(m_settings->wmaDecoderNotificationsEnabled())
717 if(!lamexp_check_tool("wmawav.exe"))
719 QString messageText;
720 messageText += QString("<nobr>%1<br>").arg(tr("LameXP has detected that the WMA File Decoder component is not currently installed on your system."));
721 messageText += QString("%1</nobr>").arg(tr("You won't be able to process WMA files as input unless the WMA File Decoder component is installed!"));
722 QMessageBox::information(this, tr("WMA Decoder Missing"), messageText);
723 installWMADecoderActionTriggered(rand() % 2);
727 //Add files from the command-line
728 for(int i = 0; i < arguments.count() - 1; i++)
730 if(!arguments[i].compare("--add", Qt::CaseInsensitive))
732 QFileInfo currentFile(arguments[++i].trimmed());
733 qDebug("Adding file from CLI: %s", currentFile.canonicalFilePath().toUtf8().constData());
734 m_delayedFileList->append(currentFile.canonicalFilePath());
738 //Start delayed files timer
739 if(!m_delayedFileList->isEmpty() && !m_delayedFileTimer->isActive())
741 m_delayedFileTimer->start(5000);
744 //Make DropBox visible
745 if(m_settings->dropBoxWidgetEnabled())
747 m_dropBox->setVisible(true);
752 * About button
754 void MainWindow::aboutButtonClicked(void)
756 ABORT_IF_BUSY;
758 TEMP_HIDE_DROPBOX
760 AboutDialog *aboutBox = new AboutDialog(m_settings, this);
761 aboutBox->exec();
762 LAMEXP_DELETE(aboutBox);
767 * Encode button
769 void MainWindow::encodeButtonClicked(void)
771 static const __int64 oneGigabyte = 1073741824;
772 static const __int64 minimumFreeDiskspaceMultiplier = 2;
774 ABORT_IF_BUSY;
776 if(m_fileListModel->rowCount() < 1)
778 QMessageBox::warning(this, tr("LameXP"), QString("<nobr>%1</nobr>").arg(tr("You must add at least one file to the list before proceeding!")));
779 tabWidget->setCurrentIndex(0);
780 return;
783 __int64 currentFreeDiskspace = lamexp_free_diskspace(lamexp_temp_folder());
785 if(currentFreeDiskspace < (oneGigabyte * minimumFreeDiskspaceMultiplier))
787 QStringList tempFolderParts = lamexp_temp_folder().split("/", QString::SkipEmptyParts, Qt::CaseInsensitive);
788 tempFolderParts.takeLast();
789 if(m_settings->soundsEnabled()) PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
790 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")))
792 case 1:
793 QProcess::startDetached(QString("%1/cleanmgr.exe").arg(lamexp_known_folder(lamexp_folder_systemfolder)), QStringList() << "/D" << tempFolderParts.first());
794 case 0:
795 return;
796 break;
797 default:
798 QMessageBox::warning(this, tr("Low Diskspace"), tr("You are proceeding with low diskspace. Problems might occur!"));
799 break;
803 switch(m_settings->compressionEncoder())
805 case SettingsModel::MP3Encoder:
806 case SettingsModel::VorbisEncoder:
807 case SettingsModel::AACEncoder:
808 case SettingsModel::FLACEncoder:
809 case SettingsModel::PCMEncoder:
810 break;
811 default:
812 QMessageBox::warning(this, tr("LameXP"), tr("Sorry, an unsupported encoder has been chosen!"));
813 tabWidget->setCurrentIndex(3);
814 return;
817 if(!m_settings->outputToSourceDir())
819 QFile writeTest(QString("%1/~%2.txt").arg(m_settings->outputDir(), QUuid::createUuid().toString()));
820 if(!writeTest.open(QIODevice::ReadWrite))
822 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!")));
823 tabWidget->setCurrentIndex(1);
824 return;
826 else
828 writeTest.close();
829 writeTest.remove();
833 m_accepted = true;
834 close();
838 * Close button
840 void MainWindow::closeButtonClicked(void)
842 ABORT_IF_BUSY;
843 close();
847 * Add file(s) button
849 void MainWindow::addFilesButtonClicked(void)
851 ABORT_IF_BUSY;
853 TEMP_HIDE_DROPBOX
855 if(lamexp_themes_enabled())
857 QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
858 QStringList selectedFiles = QFileDialog::getOpenFileNames(this, tr("Add file(s)"), QString(), fileTypeFilters.join(";;"));
859 if(!selectedFiles.isEmpty())
861 addFiles(selectedFiles);
864 else
866 QFileDialog dialog(this, tr("Add file(s)"));
867 QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
868 dialog.setFileMode(QFileDialog::ExistingFiles);
869 dialog.setNameFilter(fileTypeFilters.join(";;"));
870 if(dialog.exec())
872 QStringList selectedFiles = dialog.selectedFiles();
873 addFiles(selectedFiles);
880 * Open folder action
882 void MainWindow::openFolderActionActivated(void)
884 ABORT_IF_BUSY;
885 QString selectedFolder;
887 TEMP_HIDE_DROPBOX
889 if(lamexp_themes_enabled())
891 selectedFolder = QFileDialog::getExistingDirectory(this, tr("Add folder"), QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
893 else
895 QFileDialog dialog(this, tr("Add folder"));
896 dialog.setFileMode(QFileDialog::DirectoryOnly);
897 dialog.setDirectory(QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
898 if(dialog.exec())
900 selectedFolder = dialog.selectedFiles().first();
904 if(!selectedFolder.isEmpty())
906 QDir sourceDir(selectedFolder);
907 QFileInfoList fileInfoList = sourceDir.entryInfoList(QDir::Files);
908 QStringList fileList;
910 while(!fileInfoList.isEmpty())
912 fileList << fileInfoList.takeFirst().canonicalFilePath();
915 addFiles(fileList);
921 * Remove file button
923 void MainWindow::removeFileButtonClicked(void)
925 if(sourceFileView->currentIndex().isValid())
927 int iRow = sourceFileView->currentIndex().row();
928 m_fileListModel->removeFile(sourceFileView->currentIndex());
929 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
934 * Clear files button
936 void MainWindow::clearFilesButtonClicked(void)
938 m_fileListModel->clearFiles();
942 * Move file up button
944 void MainWindow::fileUpButtonClicked(void)
946 if(sourceFileView->currentIndex().isValid())
948 int iRow = sourceFileView->currentIndex().row() - 1;
949 m_fileListModel->moveFile(sourceFileView->currentIndex(), -1);
950 sourceFileView->selectRow(iRow >= 0 ? iRow : 0);
955 * Move file down button
957 void MainWindow::fileDownButtonClicked(void)
959 if(sourceFileView->currentIndex().isValid())
961 int iRow = sourceFileView->currentIndex().row() + 1;
962 m_fileListModel->moveFile(sourceFileView->currentIndex(), 1);
963 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
968 * Show details button
970 void MainWindow::showDetailsButtonClicked(void)
972 ABORT_IF_BUSY;
974 int iResult = 0;
975 MetaInfoDialog *metaInfoDialog = new MetaInfoDialog(this);
976 QModelIndex index = sourceFileView->currentIndex();
978 while(index.isValid())
980 if(iResult > 0)
982 index = m_fileListModel->index(index.row() + 1, index.column());
983 sourceFileView->selectRow(index.row());
985 if(iResult < 0)
987 index = m_fileListModel->index(index.row() - 1, index.column());
988 sourceFileView->selectRow(index.row());
991 AudioFileModel &file = (*m_fileListModel)[index];
992 iResult = metaInfoDialog->exec(file, index.row() > 0, index.row() < m_fileListModel->rowCount() - 1);
994 if(!iResult) break;
997 LAMEXP_DELETE(metaInfoDialog);
1001 * Tab page changed
1003 void MainWindow::tabPageChanged(int idx)
1005 QList<QAction*> actions = m_tabActionGroup->actions();
1006 for(int i = 0; i < actions.count(); i++)
1008 bool ok = false;
1009 int actionIndex = actions.at(i)->data().toInt(&ok);
1010 if(ok && actionIndex == idx)
1012 actions.at(i)->setChecked(true);
1018 * Tab action triggered
1020 void MainWindow::tabActionActivated(QAction *action)
1022 if(action && action->data().isValid())
1024 bool ok = false;
1025 int index = action->data().toInt(&ok);
1026 if(ok)
1028 tabWidget->setCurrentIndex(index);
1034 * Style action triggered
1036 void MainWindow::styleActionActivated(QAction *action)
1038 if(action && action->data().isValid())
1040 bool ok = false;
1041 int actionIndex = action->data().toInt(&ok);
1042 m_settings->interfaceStyle(actionIndex);
1045 switch(m_settings->interfaceStyle())
1047 case 1:
1048 if(actionStyleCleanlooks->isEnabled())
1050 actionStyleCleanlooks->setChecked(true);
1051 QApplication::setStyle(new QCleanlooksStyle());
1052 break;
1054 case 2:
1055 if(actionStyleWindowsVista->isEnabled())
1057 actionStyleWindowsVista->setChecked(true);
1058 QApplication::setStyle(new QWindowsVistaStyle());
1059 break;
1061 case 3:
1062 if(actionStyleWindowsXP->isEnabled())
1064 actionStyleWindowsXP->setChecked(true);
1065 QApplication::setStyle(new QWindowsXPStyle());
1066 break;
1068 case 4:
1069 if(actionStyleWindowsClassic->isEnabled())
1071 actionStyleWindowsClassic->setChecked(true);
1072 QApplication::setStyle(new QWindowsStyle());
1073 break;
1075 default:
1076 actionStylePlastique->setChecked(true);
1077 QApplication::setStyle(new QPlastiqueStyle());
1078 break;
1083 * Language action triggered
1085 void MainWindow::languageActionActivated(QAction *action)
1087 if(action->data().type() == QVariant::String)
1089 QString langId = action->data().toString();
1091 if(lamexp_install_translator(langId))
1093 action->setChecked(true);
1094 m_settings->currentLanguage(langId);
1100 * Load language from file action triggered
1102 void MainWindow::languageFromFileActionActivated(bool checked)
1104 QFileDialog dialog(this, tr("Load Translation"));
1105 dialog.setFileMode(QFileDialog::ExistingFile);
1106 dialog.setNameFilter(QString("%1 (*.qm)").arg(tr("Translation Files")));
1108 if(dialog.exec())
1110 QStringList selectedFiles = dialog.selectedFiles();
1111 if(lamexp_install_translator_from_file(selectedFiles.first()))
1113 QList<QAction*> actions = m_languageActionGroup->actions();
1114 while(!actions.isEmpty())
1116 actions.takeFirst()->setChecked(false);
1119 else
1121 languageActionActivated(m_languageActionGroup->actions().first());
1127 * Output folder changed (mouse clicked)
1129 void MainWindow::outputFolderViewClicked(const QModelIndex &index)
1131 if(outputFolderView->currentIndex() != index)
1133 outputFolderView->setCurrentIndex(index);
1135 QString selectedDir = m_fileSystemModel->filePath(index);
1136 if(selectedDir.length() < 3) selectedDir.append(QDir::separator());
1137 outputFolderLabel->setText(QDir::toNativeSeparators(selectedDir));
1138 m_settings->outputDir(selectedDir);
1142 * Output folder changed (mouse moved)
1144 void MainWindow::outputFolderViewMoved(const QModelIndex &index)
1146 if(QApplication::mouseButtons() & Qt::LeftButton)
1148 outputFolderViewClicked(index);
1153 * Goto desktop button
1155 void MainWindow::gotoDesktopButtonClicked(void)
1157 QString desktopPath = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
1159 if(!desktopPath.isEmpty() && QDir(desktopPath).exists())
1161 outputFolderView->setCurrentIndex(m_fileSystemModel->index(desktopPath));
1162 outputFolderViewClicked(outputFolderView->currentIndex());
1163 outputFolderView->setFocus();
1165 else
1167 buttonGotoDesktop->setEnabled(false);
1172 * Goto home folder button
1174 void MainWindow::gotoHomeFolderButtonClicked(void)
1176 QString homePath = QDesktopServices::storageLocation(QDesktopServices::HomeLocation);
1178 if(!homePath.isEmpty() && QDir(homePath).exists())
1180 outputFolderView->setCurrentIndex(m_fileSystemModel->index(homePath));
1181 outputFolderViewClicked(outputFolderView->currentIndex());
1182 outputFolderView->setFocus();
1184 else
1186 buttonGotoHome->setEnabled(false);
1191 * Goto music folder button
1193 void MainWindow::gotoMusicFolderButtonClicked(void)
1195 QString musicPath = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
1197 if(!musicPath.isEmpty() && QDir(musicPath).exists())
1199 outputFolderView->setCurrentIndex(m_fileSystemModel->index(musicPath));
1200 outputFolderViewClicked(outputFolderView->currentIndex());
1201 outputFolderView->setFocus();
1203 else
1205 buttonGotoMusic->setEnabled(false);
1210 * Make folder button
1212 void MainWindow::makeFolderButtonClicked(void)
1214 ABORT_IF_BUSY;
1216 QDir basePath(m_fileSystemModel->fileInfo(outputFolderView->currentIndex()).absoluteFilePath());
1217 QString suggestedName = tr("New Folder");
1219 if(!m_metaData->fileArtist().isEmpty() && !m_metaData->fileAlbum().isEmpty())
1221 suggestedName = QString("%1 - %2").arg(m_metaData->fileArtist(), m_metaData->fileAlbum());
1223 else if(!m_metaData->fileArtist().isEmpty())
1225 suggestedName = m_metaData->fileArtist();
1227 else if(!m_metaData->fileAlbum().isEmpty())
1229 suggestedName = m_metaData->fileAlbum();
1231 else
1233 for(int i = 0; i < m_fileListModel->rowCount(); i++)
1235 AudioFileModel audioFile = m_fileListModel->getFile(m_fileListModel->index(i, 0));
1236 if(!audioFile.fileAlbum().isEmpty() || !audioFile.fileArtist().isEmpty())
1238 if(!audioFile.fileArtist().isEmpty() && !audioFile.fileAlbum().isEmpty())
1240 suggestedName = QString("%1 - %2").arg(audioFile.fileArtist(), audioFile.fileAlbum());
1242 else if(!audioFile.fileArtist().isEmpty())
1244 suggestedName = audioFile.fileArtist();
1246 else if(!audioFile.fileAlbum().isEmpty())
1248 suggestedName = audioFile.fileAlbum();
1250 break;
1255 while(true)
1257 bool bApplied = false;
1258 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();
1260 if(bApplied)
1262 folderName.remove(":", Qt::CaseInsensitive);
1263 folderName.remove("/", Qt::CaseInsensitive);
1264 folderName.remove("\\", Qt::CaseInsensitive);
1265 folderName.remove("?", Qt::CaseInsensitive);
1266 folderName.remove("*", Qt::CaseInsensitive);
1267 folderName.remove("<", Qt::CaseInsensitive);
1268 folderName.remove(">", Qt::CaseInsensitive);
1270 folderName = folderName.simplified();
1272 if(folderName.isEmpty())
1274 MessageBeep(MB_ICONERROR);
1275 continue;
1278 int i = 1;
1279 QString newFolder = folderName;
1281 while(basePath.exists(newFolder))
1283 newFolder = QString(folderName).append(QString().sprintf(" (%d)", ++i));
1286 if(basePath.mkdir(newFolder))
1288 QDir createdDir = basePath;
1289 if(createdDir.cd(newFolder))
1291 outputFolderView->setCurrentIndex(m_fileSystemModel->index(createdDir.canonicalPath()));
1292 outputFolderViewClicked(outputFolderView->currentIndex());
1293 outputFolderView->setFocus();
1296 else
1298 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!")));
1301 break;
1306 * Edit meta button clicked
1308 void MainWindow::editMetaButtonClicked(void)
1310 ABORT_IF_BUSY;
1311 m_metaInfoModel->editItem(metaDataView->currentIndex(), this);
1315 * Reset meta button clicked
1317 void MainWindow::clearMetaButtonClicked(void)
1319 ABORT_IF_BUSY;
1320 m_metaInfoModel->clearData();
1324 * Visit homepage action
1326 void MainWindow::visitHomepageActionActivated(void)
1328 QDesktopServices::openUrl(QUrl("http://mulder.dummwiedeutsch.de/"));
1332 * Check for updates action
1334 void MainWindow::checkUpdatesActionActivated(void)
1336 ABORT_IF_BUSY;
1338 TEMP_HIDE_DROPBOX
1340 UpdateDialog *updateDialog = new UpdateDialog(m_settings, this);
1341 updateDialog->exec();
1342 if(updateDialog->getSuccess())
1344 m_settings->autoUpdateLastCheck(QDate::currentDate().toString(Qt::ISODate));
1346 LAMEXP_DELETE(updateDialog);
1351 * Other instance detected
1353 void MainWindow::notifyOtherInstance(void)
1355 if(!m_banner->isVisible())
1357 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);
1358 msgBox.exec();
1363 * Add file from another instance
1365 void MainWindow::addFileDelayed(const QString &filePath)
1367 m_delayedFileTimer->stop();
1368 qDebug("Received file: %s", filePath.toUtf8().constData());
1369 m_delayedFileList->append(filePath);
1370 m_delayedFileTimer->start(5000);
1374 * Add all pending files
1376 void MainWindow::handleDelayedFiles(void)
1378 if(m_banner->isVisible())
1380 return;
1383 m_delayedFileTimer->stop();
1384 if(m_delayedFileList->isEmpty())
1386 return;
1389 QStringList selectedFiles;
1390 tabWidget->setCurrentIndex(0);
1392 while(!m_delayedFileList->isEmpty())
1394 QFileInfo currentFile = QFileInfo(m_delayedFileList->takeFirst());
1395 if(!currentFile.exists())
1397 continue;
1399 if(currentFile.isFile())
1401 selectedFiles << currentFile.canonicalFilePath();
1402 continue;
1404 if(currentFile.isDir())
1406 QList<QFileInfo> list = QDir(currentFile.canonicalFilePath()).entryInfoList(QDir::Files);
1407 for(int j = 0; j < list.count(); j++)
1409 selectedFiles << list.at(j).canonicalFilePath();
1414 addFiles(selectedFiles);
1418 * Update encoder
1420 void MainWindow::updateEncoder(int id)
1422 m_settings->compressionEncoder(id);
1424 switch(m_settings->compressionEncoder())
1426 case SettingsModel::VorbisEncoder:
1427 radioButtonModeQuality->setEnabled(true);
1428 radioButtonModeAverageBitrate->setEnabled(true);
1429 radioButtonConstBitrate->setEnabled(false);
1430 if(radioButtonConstBitrate->isChecked()) radioButtonModeQuality->setChecked(true);
1431 sliderBitrate->setEnabled(true);
1432 break;
1433 case SettingsModel::FLACEncoder:
1434 radioButtonModeQuality->setEnabled(false);
1435 radioButtonModeQuality->setChecked(true);
1436 radioButtonModeAverageBitrate->setEnabled(false);
1437 radioButtonConstBitrate->setEnabled(false);
1438 sliderBitrate->setEnabled(true);
1439 break;
1440 case SettingsModel::PCMEncoder:
1441 radioButtonModeQuality->setEnabled(false);
1442 radioButtonModeQuality->setChecked(true);
1443 radioButtonModeAverageBitrate->setEnabled(false);
1444 radioButtonConstBitrate->setEnabled(false);
1445 sliderBitrate->setEnabled(false);
1446 break;
1447 default:
1448 radioButtonModeQuality->setEnabled(true);
1449 radioButtonModeAverageBitrate->setEnabled(true);
1450 radioButtonConstBitrate->setEnabled(true);
1451 sliderBitrate->setEnabled(true);
1452 break;
1455 updateRCMode(m_modeButtonGroup->checkedId());
1459 * Update rate-control mode
1461 void MainWindow::updateRCMode(int id)
1463 m_settings->compressionRCMode(id);
1465 switch(m_settings->compressionEncoder())
1467 case SettingsModel::MP3Encoder:
1468 switch(m_settings->compressionRCMode())
1470 case SettingsModel::VBRMode:
1471 sliderBitrate->setMinimum(0);
1472 sliderBitrate->setMaximum(9);
1473 break;
1474 default:
1475 sliderBitrate->setMinimum(0);
1476 sliderBitrate->setMaximum(13);
1477 break;
1479 break;
1480 case SettingsModel::VorbisEncoder:
1481 switch(m_settings->compressionRCMode())
1483 case SettingsModel::VBRMode:
1484 sliderBitrate->setMinimum(-2);
1485 sliderBitrate->setMaximum(10);
1486 break;
1487 default:
1488 sliderBitrate->setMinimum(4);
1489 sliderBitrate->setMaximum(63);
1490 break;
1492 break;
1493 case SettingsModel::AACEncoder:
1494 switch(m_settings->compressionRCMode())
1496 case SettingsModel::VBRMode:
1497 sliderBitrate->setMinimum(0);
1498 sliderBitrate->setMaximum(20);
1499 break;
1500 default:
1501 sliderBitrate->setMinimum(4);
1502 sliderBitrate->setMaximum(63);
1503 break;
1505 break;
1506 case SettingsModel::FLACEncoder:
1507 sliderBitrate->setMinimum(0);
1508 sliderBitrate->setMaximum(8);
1509 break;
1510 case SettingsModel::PCMEncoder:
1511 sliderBitrate->setMinimum(0);
1512 sliderBitrate->setMaximum(2);
1513 sliderBitrate->setValue(1);
1514 break;
1515 default:
1516 sliderBitrate->setMinimum(0);
1517 sliderBitrate->setMaximum(0);
1518 break;
1521 updateBitrate(sliderBitrate->value());
1525 * Update bitrate
1527 void MainWindow::updateBitrate(int value)
1529 m_settings->compressionBitrate(value);
1531 switch(m_settings->compressionRCMode())
1533 case SettingsModel::VBRMode:
1534 switch(m_settings->compressionEncoder())
1536 case SettingsModel::MP3Encoder:
1537 labelBitrate->setText(tr("Quality Level %1").arg(9 - value));
1538 break;
1539 case SettingsModel::VorbisEncoder:
1540 labelBitrate->setText(tr("Quality Level %1").arg(value));
1541 break;
1542 case SettingsModel::AACEncoder:
1543 labelBitrate->setText(tr("Quality Level %1").arg(QString().sprintf("%.2f", static_cast<double>(value * 5) / 100.0)));
1544 break;
1545 case SettingsModel::FLACEncoder:
1546 labelBitrate->setText(tr("Compression %1").arg(value));
1547 break;
1548 case SettingsModel::PCMEncoder:
1549 labelBitrate->setText(tr("Uncompressed"));
1550 break;
1551 default:
1552 labelBitrate->setText(QString::number(value));
1553 break;
1555 break;
1556 case SettingsModel::ABRMode:
1557 switch(m_settings->compressionEncoder())
1559 case SettingsModel::MP3Encoder:
1560 labelBitrate->setText(QString("&asymp; %1 kbps").arg(SettingsModel::mp3Bitrates[value]));
1561 break;
1562 case SettingsModel::FLACEncoder:
1563 labelBitrate->setText(tr("Compression %1").arg(value));
1564 break;
1565 case SettingsModel::PCMEncoder:
1566 labelBitrate->setText(tr("Uncompressed"));
1567 break;
1568 default:
1569 labelBitrate->setText(QString("&asymp; %1 kbps").arg(min(500, value * 8)));
1570 break;
1572 break;
1573 default:
1574 switch(m_settings->compressionEncoder())
1576 case SettingsModel::MP3Encoder:
1577 labelBitrate->setText(QString("%1 kbps").arg(SettingsModel::mp3Bitrates[value]));
1578 break;
1579 case SettingsModel::FLACEncoder:
1580 labelBitrate->setText(tr("Compression %1").arg(value));
1581 break;
1582 case SettingsModel::PCMEncoder:
1583 labelBitrate->setText(tr("Uncompressed"));
1584 break;
1585 default:
1586 labelBitrate->setText(QString("%1 kbps").arg(min(500, value * 8)));
1587 break;
1589 break;
1595 * Lame algorithm quality changed
1597 void MainWindow::updateLameAlgoQuality(int value)
1599 QString text;
1601 switch(value)
1603 case 4:
1604 text = tr("Best Quality (Very Slow)");
1605 break;
1606 case 3:
1607 text = tr("High Quality (Recommended)");
1608 break;
1609 case 2:
1610 text = tr("Average Quality (Default)");
1611 break;
1612 case 1:
1613 text = tr("Low Quality (Fast)");
1614 break;
1615 case 0:
1616 text = tr("Poor Quality (Very Fast)");
1617 break;
1620 if(!text.isEmpty())
1622 m_settings->lameAlgoQuality(value);
1623 labelLameAlgoQuality->setText(text);
1628 * Bitrate management endabled/disabled
1630 void MainWindow::bitrateManagementEnabledChanged(bool checked)
1632 m_settings->bitrateManagementEnabled(checked);
1636 * Minimum bitrate has changed
1638 void MainWindow::bitrateManagementMinChanged(int value)
1640 if(value > spinBoxBitrateManagementMax->value())
1642 spinBoxBitrateManagementMin->setValue(spinBoxBitrateManagementMax->value());
1643 m_settings->bitrateManagementMinRate(spinBoxBitrateManagementMax->value());
1645 else
1647 m_settings->bitrateManagementMinRate(value);
1652 * Maximum bitrate has changed
1654 void MainWindow::bitrateManagementMaxChanged(int value)
1656 if(value < spinBoxBitrateManagementMin->value())
1658 spinBoxBitrateManagementMax->setValue(spinBoxBitrateManagementMin->value());
1659 m_settings->bitrateManagementMaxRate(spinBoxBitrateManagementMin->value());
1661 else
1663 m_settings->bitrateManagementMaxRate(value);
1668 * Channel mode has changed
1670 void MainWindow::channelModeChanged(int value)
1672 if(value >= 0) m_settings->lameChannelMode(value);
1676 * Sampling rate has changed
1678 void MainWindow::samplingRateChanged(int value)
1680 if(value >= 0) m_settings->samplingRate(value);
1684 * Nero AAC 2-Pass mode changed
1686 void MainWindow::neroAAC2PassChanged(bool checked)
1688 m_settings->neroAACEnable2Pass(checked);
1692 * Nero AAC profile mode changed
1694 void MainWindow::neroAACProfileChanged(int value)
1696 if(value >= 0) m_settings->neroAACProfile(value);
1700 * Normalization filter enabled changed
1702 void MainWindow::normalizationEnabledChanged(bool checked)
1704 m_settings->normalizationFilterEnabled(checked);
1708 * Normalization max. volume changed
1710 void MainWindow::normalizationMaxVolumeChanged(double value)
1712 m_settings->normalizationFilterMaxVolume(static_cast<int>(value * 100.0));
1716 * Reset all advanced options to their defaults
1718 void MainWindow::resetAdvancedOptionsButtonClicked()
1720 sliderLameAlgoQuality->setValue(m_settings->lameAlgoQualityDefault());
1721 spinBoxBitrateManagementMin->setValue(m_settings->bitrateManagementMinRateDefault());
1722 spinBoxBitrateManagementMax->setValue(m_settings->bitrateManagementMaxRateDefault());
1723 spinBoxNormalizationFilter->setValue(static_cast<double>(m_settings->normalizationFilterMaxVolumeDefault()) / 100.0);
1724 comboBoxMP3ChannelMode->setCurrentIndex(m_settings->lameChannelModeDefault());
1725 comboBoxSamplingRate->setCurrentIndex(m_settings->samplingRateDefault());
1726 comboBoxNeroAACProfile->setCurrentIndex(m_settings->neroAACProfileDefault());
1727 while(checkBoxBitrateManagement->isChecked() != m_settings->bitrateManagementEnabledDefault()) checkBoxBitrateManagement->click();
1728 while(checkBoxNeroAAC2PassMode->isChecked() != m_settings->neroAACEnable2PassDefault()) checkBoxNeroAAC2PassMode->click();
1729 while(checkBoxNormalizationFilter->isChecked() != m_settings->normalizationFilterEnabledDefault()) checkBoxNormalizationFilter->click();
1730 scrollArea->verticalScrollBar()->setValue(0);
1734 * Model reset
1736 void MainWindow::sourceModelChanged(void)
1738 m_dropNoteLabel->setVisible(m_fileListModel->rowCount() <= 0);
1742 * Meta tags enabled changed
1744 void MainWindow::metaTagsEnabledChanged(void)
1746 m_settings->writeMetaTags(writeMetaDataCheckBox->isChecked());
1750 * Playlist enabled changed
1752 void MainWindow::playlistEnabledChanged(void)
1754 m_settings->createPlaylist(generatePlaylistCheckBox->isChecked());
1758 * Output to source dir changed
1760 void MainWindow::saveToSourceFolderChanged(void)
1762 m_settings->outputToSourceDir(saveToSourceFolderCheckBox->isChecked());
1766 * Prepend relative source file path to output file name changed
1768 void MainWindow::prependRelativePathChanged(void)
1770 m_settings->prependRelativeSourcePath(prependRelativePathCheckBox->isChecked());
1775 * Restore the override cursor
1777 void MainWindow::restoreCursor(void)
1779 QApplication::restoreOverrideCursor();
1783 * Show context menu for source files
1785 void MainWindow::sourceFilesContextMenu(const QPoint &pos)
1787 if(pos.x() <= sourceFileView->width() && pos.y() <= sourceFileView->height() && pos.x() >= 0 && pos.y() >= 0)
1789 m_sourceFilesContextMenu->popup(sourceFileView->mapToGlobal(pos));
1794 * Open selected file in external player
1796 void MainWindow::previewContextActionTriggered(void)
1798 const static char *appNames[3] = {"smplayer_portable.exe", "smplayer.exe", "mplayer.exe"};
1799 const static wchar_t *registryKey = L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}";
1801 QModelIndex index = sourceFileView->currentIndex();
1802 if(!index.isValid())
1804 return;
1807 QString mplayerPath;
1808 HKEY registryKeyHandle;
1810 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, registryKey, 0, KEY_READ, &registryKeyHandle) == ERROR_SUCCESS)
1812 wchar_t Buffer[4096];
1813 DWORD BuffSize = sizeof(wchar_t*) * 4096;
1814 if(RegQueryValueExW(registryKeyHandle, L"InstallLocation", 0, 0, reinterpret_cast<BYTE*>(Buffer), &BuffSize) == ERROR_SUCCESS)
1816 mplayerPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(Buffer));
1820 if(!mplayerPath.isEmpty())
1822 QDir mplayerDir(mplayerPath);
1823 if(mplayerDir.exists())
1825 for(int i = 0; i < 3; i++)
1827 if(mplayerDir.exists(appNames[i]))
1829 QProcess::startDetached(mplayerDir.absoluteFilePath(appNames[i]), QStringList() << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
1830 return;
1836 QDesktopServices::openUrl(QString("file:///").append(m_fileListModel->getFile(index).filePath()));
1840 * Find selected file in explorer
1842 void MainWindow::findFileContextActionTriggered(void)
1844 QModelIndex index = sourceFileView->currentIndex();
1845 if(index.isValid())
1847 QString systemRootPath;
1849 QDir systemRoot(lamexp_known_folder(lamexp_folder_systemfolder));
1850 if(systemRoot.exists() && systemRoot.cdUp())
1852 systemRootPath = systemRoot.canonicalPath();
1855 if(!systemRootPath.isEmpty())
1857 QFileInfo explorer(QString("%1/explorer.exe").arg(systemRootPath));
1858 if(explorer.exists() && explorer.isFile())
1860 QProcess::execute(explorer.canonicalFilePath(), QStringList() << "/select," << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
1861 return;
1864 else
1866 qWarning("SystemRoot directory could not be detected!");
1872 * Show context menu for output folder
1874 void MainWindow::outputFolderContextMenu(const QPoint &pos)
1877 if(pos.x() <= outputFolderView->width() && pos.y() <= outputFolderView->height() && pos.x() >= 0 && pos.y() >= 0)
1879 m_outputFolderContextMenu->popup(outputFolderView->mapToGlobal(pos));
1884 * Show selected folder in explorer
1886 void MainWindow::showFolderContextActionTriggered(void)
1888 QDesktopServices::openUrl(QUrl::fromLocalFile(m_fileSystemModel->filePath(outputFolderView->currentIndex())));
1892 * Disable update reminder action
1894 void MainWindow::disableUpdateReminderActionTriggered(bool checked)
1896 if(checked)
1898 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))
1900 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!")));
1901 m_settings->autoUpdateEnabled(false);
1903 else
1905 m_settings->autoUpdateEnabled(true);
1908 else
1910 QMessageBox::information(this, tr("Update Reminder"), tr("The update reminder has been re-enabled."));
1911 m_settings->autoUpdateEnabled(true);
1914 actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
1918 * Disable sound effects action
1920 void MainWindow::disableSoundsActionTriggered(bool checked)
1922 if(checked)
1924 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))
1926 QMessageBox::information(this, tr("Sound Effects"), tr("All sound effects have been disabled."));
1927 m_settings->soundsEnabled(false);
1929 else
1931 m_settings->soundsEnabled(true);
1934 else
1936 QMessageBox::information(this, tr("Sound Effects"), tr("The sound effects have been re-enabled."));
1937 m_settings->soundsEnabled(true);
1940 actionDisableSounds->setChecked(!m_settings->soundsEnabled());
1944 * Disable Nero AAC encoder action
1946 void MainWindow::disableNeroAacNotificationsActionTriggered(bool checked)
1948 if(checked)
1950 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))
1952 QMessageBox::information(this, tr("Nero AAC Notifications"), tr("All Nero AAC Encoder notifications have been disabled."));
1953 m_settings->neroAacNotificationsEnabled(false);
1955 else
1957 m_settings->neroAacNotificationsEnabled(true);
1960 else
1962 QMessageBox::information(this, tr("Nero AAC Notifications"), tr("The Nero AAC Encoder notifications have been re-enabled."));
1963 m_settings->neroAacNotificationsEnabled(true);
1966 actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
1970 * Disable WMA Decoder component action
1972 void MainWindow::disableWmaDecoderNotificationsActionTriggered(bool checked)
1974 if(checked)
1976 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))
1978 QMessageBox::information(this, tr("WMA Decoder Notifications"), tr("All WMA Decoder notifications have been disabled."));
1979 m_settings->wmaDecoderNotificationsEnabled(false);
1981 else
1983 m_settings->wmaDecoderNotificationsEnabled(true);
1986 else
1988 QMessageBox::information(this, tr("WMA Decoder Notifications"), tr("The WMA Decoder notifications have been re-enabled."));
1989 m_settings->wmaDecoderNotificationsEnabled(true);
1992 actionDisableWmaDecoderNotifications->setChecked(!m_settings->wmaDecoderNotificationsEnabled());
1996 * Download and install WMA Decoder component
1998 void MainWindow::installWMADecoderActionTriggered(bool checked)
2000 static const char *download_url = "http://www.nch.com.au/components/wmawav.exe";
2001 static const char *download_hash = "52a3b0e6690faf3f830c336d3c0eadfb7a4e9bc6";
2003 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)
2005 return;
2008 QString binaryWGet = lamexp_lookup_tool("wget.exe");
2009 QString binaryElevator = lamexp_lookup_tool("elevator.exe");
2011 if(binaryWGet.isEmpty() || binaryElevator.isEmpty())
2013 throw "Required binary is not available!";
2016 while(true)
2018 QString setupFile = QString("%1/%2.exe").arg(lamexp_temp_folder(), lamexp_rand_str());
2020 QProcess process;
2021 process.setWorkingDirectory(QFileInfo(setupFile).absolutePath());
2023 QEventLoop loop;
2024 connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
2025 connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), &loop, SLOT(quit()));
2027 process.start(binaryWGet, QStringList() << "-O" << QFileInfo(setupFile).fileName() << download_url);
2028 m_banner->show(tr("Downloading WMA Decoder Setup, please wait..."), &loop);
2030 if(process.exitCode() != 0 || QFileInfo(setupFile).size() < 10240)
2032 QFile::remove(setupFile);
2033 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)
2035 continue;
2037 return;
2040 QFile setupFileContent(setupFile);
2041 QCryptographicHash setupFileHash(QCryptographicHash::Sha1);
2043 setupFileContent.open(QIODevice::ReadOnly);
2044 if(setupFileContent.isOpen() && setupFileContent.isReadable())
2046 setupFileHash.addData(setupFileContent.readAll());
2047 setupFileContent.close();
2050 if(_stricmp(setupFileHash.result().toHex().constData(), download_hash))
2052 qWarning("Hash miscompare:\n Expected %s\n Detected %s\n", download_hash, setupFileHash.result().toHex().constData());
2053 QFile::remove(setupFile);
2054 if(QMessageBox::critical(this, tr("Download Failed"), tr("The download seems to be corrupted. Please try again!"), tr("Try Again"), tr("Cancel")) == 0)
2056 continue;
2058 return;
2061 QApplication::setOverrideCursor(Qt::WaitCursor);
2062 process.start(binaryElevator, QStringList() << QString("/exec=%1").arg(setupFile));
2063 loop.exec(QEventLoop::ExcludeUserInputEvents);
2064 QFile::remove(setupFile);
2065 QApplication::restoreOverrideCursor();
2067 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)
2069 QApplication::quit();
2071 break;
2075 void MainWindow::showDropBoxWidgetActionTriggered(bool checked)
2077 m_settings->dropBoxWidgetEnabled(true);
2079 if(!m_dropBox->isVisible())
2081 m_dropBox->show();
2084 FLASH_WINDOW(m_dropBox);