Added support for Speex input.
[LameXP.git] / src / Dialog_MainWindow.cpp
blob0bbc7446d9cec5fb34e6f82ef4d82622ce2ac100
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"
40 #include "ShellIntegration.h"
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>
67 //Win32 includes
68 #include <Windows.h>
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(); }
78 ////////////////////////////////////////////////////////////
79 // Constructor
80 ////////////////////////////////////////////////////////////
82 MainWindow::MainWindow(FileListModel *fileListModel, AudioFileModel *metaInfo, SettingsModel *settingsModel, QWidget *parent)
84 QMainWindow(parent),
85 m_fileListModel(fileListModel),
86 m_metaData(metaInfo),
87 m_settings(settingsModel),
88 m_accepted(false),
89 m_firstTimeShown(true)
91 //Init the dialog, from the .ui file
92 setupUi(this);
93 setWindowFlags(windowFlags() ^ Qt::WindowMaximizeButtonHint);
95 //Register meta types
96 qRegisterMetaType<AudioFileModel>("AudioFileModel");
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()));
103 //Setup tab widget
104 tabWidget->setCurrentIndex(0);
105 connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabPageChanged(int)));
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()));
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);
168 //Setup "Meta Data" tab
169 m_metaInfoModel = new MetaInfoModel(m_metaData, 6);
170 m_metaInfoModel->clearData();
171 metaDataView->setModel(m_metaInfoModel);
172 metaDataView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
173 metaDataView->verticalHeader()->hide();
174 metaDataView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
175 while(writeMetaDataCheckBox->isChecked() != m_settings->writeMetaTags()) writeMetaDataCheckBox->click();
176 generatePlaylistCheckBox->setChecked(m_settings->createPlaylist());
177 connect(buttonEditMeta, SIGNAL(clicked()), this, SLOT(editMetaButtonClicked()));
178 connect(buttonClearMeta, SIGNAL(clicked()), this, SLOT(clearMetaButtonClicked()));
179 connect(writeMetaDataCheckBox, SIGNAL(clicked()), this, SLOT(metaTagsEnabledChanged()));
180 connect(generatePlaylistCheckBox, SIGNAL(clicked()), this, SLOT(playlistEnabledChanged()));
182 //Setup "Compression" tab
183 m_encoderButtonGroup = new QButtonGroup(this);
184 m_encoderButtonGroup->addButton(radioButtonEncoderMP3, SettingsModel::MP3Encoder);
185 m_encoderButtonGroup->addButton(radioButtonEncoderVorbis, SettingsModel::VorbisEncoder);
186 m_encoderButtonGroup->addButton(radioButtonEncoderAAC, SettingsModel::AACEncoder);
187 m_encoderButtonGroup->addButton(radioButtonEncoderFLAC, SettingsModel::FLACEncoder);
188 m_encoderButtonGroup->addButton(radioButtonEncoderPCM, SettingsModel::PCMEncoder);
189 m_modeButtonGroup = new QButtonGroup(this);
190 m_modeButtonGroup->addButton(radioButtonModeQuality, SettingsModel::VBRMode);
191 m_modeButtonGroup->addButton(radioButtonModeAverageBitrate, SettingsModel::ABRMode);
192 m_modeButtonGroup->addButton(radioButtonConstBitrate, SettingsModel::CBRMode);
193 radioButtonEncoderMP3->setChecked(m_settings->compressionEncoder() == SettingsModel::MP3Encoder);
194 radioButtonEncoderVorbis->setChecked(m_settings->compressionEncoder() == SettingsModel::VorbisEncoder);
195 radioButtonEncoderAAC->setChecked(m_settings->compressionEncoder() == SettingsModel::AACEncoder);
196 radioButtonEncoderFLAC->setChecked(m_settings->compressionEncoder() == SettingsModel::FLACEncoder);
197 radioButtonEncoderPCM->setChecked(m_settings->compressionEncoder() == SettingsModel::PCMEncoder);
198 radioButtonModeQuality->setChecked(m_settings->compressionRCMode() == SettingsModel::VBRMode);
199 radioButtonModeAverageBitrate->setChecked(m_settings->compressionRCMode() == SettingsModel::ABRMode);
200 radioButtonConstBitrate->setChecked(m_settings->compressionRCMode() == SettingsModel::CBRMode);
201 sliderBitrate->setValue(m_settings->compressionBitrate());
202 connect(m_encoderButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateEncoder(int)));
203 connect(m_modeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateRCMode(int)));
204 connect(sliderBitrate, SIGNAL(valueChanged(int)), this, SLOT(updateBitrate(int)));
205 updateEncoder(m_encoderButtonGroup->checkedId());
207 //Setup "Advanced Options" tab
208 sliderLameAlgoQuality->setValue(m_settings->lameAlgoQuality());
209 spinBoxBitrateManagementMin->setValue(m_settings->bitrateManagementMinRate());
210 spinBoxBitrateManagementMax->setValue(m_settings->bitrateManagementMaxRate());
211 spinBoxNormalizationFilter->setValue(static_cast<double>(m_settings->normalizationFilterMaxVolume()) / 100.0);
212 spinBoxToneAdjustBass->setValue(static_cast<double>(m_settings->toneAdjustBass()) / 100.0);
213 spinBoxToneAdjustTreble->setValue(static_cast<double>(m_settings->toneAdjustTreble()) / 100.0);
214 comboBoxMP3ChannelMode->setCurrentIndex(m_settings->lameChannelMode());
215 comboBoxSamplingRate->setCurrentIndex(m_settings->samplingRate());
216 comboBoxNeroAACProfile->setCurrentIndex(m_settings->neroAACProfile());
217 while(checkBoxBitrateManagement->isChecked() != m_settings->bitrateManagementEnabled()) checkBoxBitrateManagement->click();
218 while(checkBoxNeroAAC2PassMode->isChecked() != m_settings->neroAACEnable2Pass()) checkBoxNeroAAC2PassMode->click();
219 while(checkBoxNormalizationFilter->isChecked() != m_settings->normalizationFilterEnabled()) checkBoxNormalizationFilter->click();
220 connect(sliderLameAlgoQuality, SIGNAL(valueChanged(int)), this, SLOT(updateLameAlgoQuality(int)));
221 connect(checkBoxBitrateManagement, SIGNAL(clicked(bool)), this, SLOT(bitrateManagementEnabledChanged(bool)));
222 connect(spinBoxBitrateManagementMin, SIGNAL(valueChanged(int)), this, SLOT(bitrateManagementMinChanged(int)));
223 connect(spinBoxBitrateManagementMax, SIGNAL(valueChanged(int)), this, SLOT(bitrateManagementMaxChanged(int)));
224 connect(comboBoxMP3ChannelMode, SIGNAL(currentIndexChanged(int)), this, SLOT(channelModeChanged(int)));
225 connect(comboBoxSamplingRate, SIGNAL(currentIndexChanged(int)), this, SLOT(samplingRateChanged(int)));
226 connect(checkBoxNeroAAC2PassMode, SIGNAL(clicked(bool)), this, SLOT(neroAAC2PassChanged(bool)));
227 connect(comboBoxNeroAACProfile, SIGNAL(currentIndexChanged(int)), this, SLOT(neroAACProfileChanged(int)));
228 connect(checkBoxNormalizationFilter, SIGNAL(clicked(bool)), this, SLOT(normalizationEnabledChanged(bool)));
229 connect(spinBoxNormalizationFilter, SIGNAL(valueChanged(double)), this, SLOT(normalizationMaxVolumeChanged(double)));
230 connect(spinBoxToneAdjustBass, SIGNAL(valueChanged(double)), this, SLOT(toneAdjustBassChanged(double)));
231 connect(spinBoxToneAdjustTreble, SIGNAL(valueChanged(double)), this, SLOT(toneAdjustTrebleChanged(double)));
232 connect(buttonToneAdjustReset, SIGNAL(clicked()), this, SLOT(toneAdjustTrebleReset()));
233 connect(buttonResetAdvancedOptions, SIGNAL(clicked()), this, SLOT(resetAdvancedOptionsButtonClicked()));
234 updateLameAlgoQuality(sliderLameAlgoQuality->value());
235 toneAdjustTrebleChanged(spinBoxToneAdjustTreble->value());
236 toneAdjustBassChanged(spinBoxToneAdjustBass->value());
238 //Activate file menu actions
239 connect(actionOpenFolder, SIGNAL(triggered()), this, SLOT(openFolderActionActivated()));
241 //Activate view menu actions
242 m_tabActionGroup = new QActionGroup(this);
243 m_tabActionGroup->addAction(actionSourceFiles);
244 m_tabActionGroup->addAction(actionOutputDirectory);
245 m_tabActionGroup->addAction(actionCompression);
246 m_tabActionGroup->addAction(actionMetaData);
247 m_tabActionGroup->addAction(actionAdvancedOptions);
248 actionSourceFiles->setData(0);
249 actionOutputDirectory->setData(1);
250 actionMetaData->setData(2);
251 actionCompression->setData(3);
252 actionAdvancedOptions->setData(4);
253 actionSourceFiles->setChecked(true);
254 connect(m_tabActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(tabActionActivated(QAction*)));
256 //Activate style menu actions
257 m_styleActionGroup = new QActionGroup(this);
258 m_styleActionGroup->addAction(actionStylePlastique);
259 m_styleActionGroup->addAction(actionStyleCleanlooks);
260 m_styleActionGroup->addAction(actionStyleWindowsVista);
261 m_styleActionGroup->addAction(actionStyleWindowsXP);
262 m_styleActionGroup->addAction(actionStyleWindowsClassic);
263 actionStylePlastique->setData(0);
264 actionStyleCleanlooks->setData(1);
265 actionStyleWindowsVista->setData(2);
266 actionStyleWindowsXP->setData(3);
267 actionStyleWindowsClassic->setData(4);
268 actionStylePlastique->setChecked(true);
269 actionStyleWindowsXP->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_XP && lamexp_themes_enabled());
270 actionStyleWindowsVista->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_VISTA && lamexp_themes_enabled());
271 connect(m_styleActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(styleActionActivated(QAction*)));
272 styleActionActivated(NULL);
274 //Populate the language menu
275 m_languageActionGroup = new QActionGroup(this);
276 QStringList translations = lamexp_query_translations();
277 while(!translations.isEmpty())
279 QString langId = translations.takeFirst();
280 QAction *currentLanguage = new QAction(this);
281 currentLanguage->setData(langId);
282 currentLanguage->setText(lamexp_translation_name(langId));
283 currentLanguage->setIcon(QIcon(QString(":/flags/%1.png").arg(langId)));
284 currentLanguage->setCheckable(true);
285 m_languageActionGroup->addAction(currentLanguage);
286 menuLanguage->insertAction(actionLoadTranslationFromFile, currentLanguage);
288 menuLanguage->insertSeparator(actionLoadTranslationFromFile);
289 connect(actionLoadTranslationFromFile, SIGNAL(triggered(bool)), this, SLOT(languageFromFileActionActivated(bool)));
290 connect(m_languageActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(languageActionActivated(QAction*)));
292 //Activate tools menu actions
293 actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
294 actionDisableSounds->setChecked(!m_settings->soundsEnabled());
295 actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
296 actionDisableWmaDecoderNotifications->setChecked(!m_settings->wmaDecoderNotificationsEnabled());
297 actionDisableShellIntegration->setChecked(!m_settings->shellIntegrationEnabled());
298 actionDisableShellIntegration->setDisabled(lamexp_portable_mode() && actionDisableShellIntegration->isChecked());
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(actionDisableShellIntegration, SIGNAL(triggered(bool)), this, SLOT(disableShellIntegrationActionTriggered(bool)));
305 connect(actionShowDropBoxWidget, SIGNAL(triggered(bool)), this, SLOT(showDropBoxWidgetActionTriggered(bool)));
307 //Activate help menu actions
308 connect(actionCheckUpdates, SIGNAL(triggered()), this, SLOT(checkUpdatesActionActivated()));
309 connect(actionVisitHomepage, SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
311 //Center window in screen
312 QRect desktopRect = QApplication::desktop()->screenGeometry();
313 QRect thisRect = this->geometry();
314 move((desktopRect.width() - thisRect.width()) / 2, (desktopRect.height() - thisRect.height()) / 2);
315 setMinimumSize(thisRect.width(), thisRect.height());
317 //Create banner
318 m_banner = new WorkingBanner(this);
320 //Create DropBox widget
321 m_dropBox = new DropBox(this, m_fileListModel, m_settings);
322 connect(m_fileListModel, SIGNAL(modelReset()), m_dropBox, SLOT(modelChanged()));
323 connect(m_fileListModel, SIGNAL(rowsInserted(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
324 connect(m_fileListModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
326 //Create message handler thread
327 m_messageHandler = new MessageHandlerThread();
328 m_delayedFileList = new QStringList();
329 m_delayedFileTimer = new QTimer();
330 connect(m_messageHandler, SIGNAL(otherInstanceDetected()), this, SLOT(notifyOtherInstance()), Qt::QueuedConnection);
331 connect(m_messageHandler, SIGNAL(fileReceived(QString)), this, SLOT(addFileDelayed(QString)), Qt::QueuedConnection);
332 connect(m_messageHandler, SIGNAL(killSignalReceived()), this, SLOT(close()), Qt::QueuedConnection);
333 connect(m_delayedFileTimer, SIGNAL(timeout()), this, SLOT(handleDelayedFiles()));
334 m_messageHandler->start();
336 //Load translation file
337 QList<QAction*> languageActions = m_languageActionGroup->actions();
338 while(!languageActions.isEmpty())
340 QAction *currentLanguage = languageActions.takeFirst();
341 if(currentLanguage->data().toString().compare(m_settings->currentLanguage(), Qt::CaseInsensitive) == 0)
343 currentLanguage->setChecked(true);
344 languageActionActivated(currentLanguage);
348 //Re-translate (make sure we translate once)
349 QEvent languageChangeEvent(QEvent::LanguageChange);
350 changeEvent(&languageChangeEvent);
352 //Enable Drag & Drop
353 this->setAcceptDrops(true);
356 ////////////////////////////////////////////////////////////
357 // Destructor
358 ////////////////////////////////////////////////////////////
360 MainWindow::~MainWindow(void)
362 //Stop message handler thread
363 if(m_messageHandler && m_messageHandler->isRunning())
365 m_messageHandler->stop();
366 if(!m_messageHandler->wait(10000))
368 m_messageHandler->terminate();
369 m_messageHandler->wait();
373 //Unset models
374 sourceFileView->setModel(NULL);
375 metaDataView->setModel(NULL);
377 //Free memory
378 LAMEXP_DELETE(m_tabActionGroup);
379 LAMEXP_DELETE(m_styleActionGroup);
380 LAMEXP_DELETE(m_languageActionGroup);
381 LAMEXP_DELETE(m_banner);
382 LAMEXP_DELETE(m_fileSystemModel);
383 LAMEXP_DELETE(m_messageHandler);
384 LAMEXP_DELETE(m_delayedFileList);
385 LAMEXP_DELETE(m_delayedFileTimer);
386 LAMEXP_DELETE(m_metaInfoModel);
387 LAMEXP_DELETE(m_encoderButtonGroup);
388 LAMEXP_DELETE(m_encoderButtonGroup);
389 LAMEXP_DELETE(m_sourceFilesContextMenu);
390 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();
430 * Download and install WMA Decoder component
432 void MainWindow::installWMADecoder(void)
434 static const char *download_url = "http://www.nch.com.au/components/wmawav.exe";
435 static const char *download_hash = "52a3b0e6690faf3f830c336d3c0eadfb7a4e9bc6";
437 QString binaryWGet = lamexp_lookup_tool("wget.exe");
438 QString binaryElevator = lamexp_lookup_tool("elevator.exe");
440 if(binaryWGet.isEmpty() || binaryElevator.isEmpty())
442 throw "Required binary is not available!";
445 while(true)
447 QString setupFile = QString("%1/%2.exe").arg(lamexp_temp_folder(), lamexp_rand_str());
449 QProcess process;
450 process.setWorkingDirectory(QFileInfo(setupFile).absolutePath());
452 QEventLoop loop;
453 connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
454 connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), &loop, SLOT(quit()));
456 process.start(binaryWGet, QStringList() << "-O" << QFileInfo(setupFile).fileName() << download_url);
457 m_banner->show(tr("Downloading WMA Decoder Setup, please wait..."), &loop);
459 if(process.exitCode() != 0 || QFileInfo(setupFile).size() < 10240)
461 QFile::remove(setupFile);
462 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)
464 continue;
466 return;
469 QFile setupFileContent(setupFile);
470 QCryptographicHash setupFileHash(QCryptographicHash::Sha1);
472 setupFileContent.open(QIODevice::ReadOnly);
473 if(setupFileContent.isOpen() && setupFileContent.isReadable())
475 setupFileHash.addData(setupFileContent.readAll());
476 setupFileContent.close();
479 if(_stricmp(setupFileHash.result().toHex().constData(), download_hash))
481 qWarning("Hash miscompare:\n Expected %s\n Detected %s\n", download_hash, setupFileHash.result().toHex().constData());
482 QFile::remove(setupFile);
483 if(QMessageBox::critical(this, tr("Download Failed"), tr("The download seems to be corrupted. Please try again!"), tr("Try Again"), tr("Cancel")) == 0)
485 continue;
487 return;
490 QApplication::setOverrideCursor(Qt::WaitCursor);
491 process.start(binaryElevator, QStringList() << QString("/exec=%1").arg(setupFile));
492 loop.exec(QEventLoop::ExcludeUserInputEvents);
493 QFile::remove(setupFile);
494 QApplication::restoreOverrideCursor();
496 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)
498 QApplication::quit();
500 break;
504 ////////////////////////////////////////////////////////////
505 // EVENTS
506 ////////////////////////////////////////////////////////////
509 * Window is about to be shown
511 void MainWindow::showEvent(QShowEvent *event)
513 m_accepted = false;
514 m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
515 sourceModelChanged();
516 tabWidget->setCurrentIndex(0);
518 if(m_firstTimeShown)
520 m_firstTimeShown = false;
521 QTimer::singleShot(0, this, SLOT(windowShown()));
523 else
525 if(m_settings->dropBoxWidgetEnabled())
527 m_dropBox->setVisible(true);
533 * Re-translate the UI
535 void MainWindow::changeEvent(QEvent *e)
537 if(e->type() == QEvent::LanguageChange)
539 int comboBoxIndex[3];
541 //Backup combobox indices
542 comboBoxIndex[0] = comboBoxMP3ChannelMode->currentIndex();
543 comboBoxIndex[1] = comboBoxSamplingRate->currentIndex();
544 comboBoxIndex[2] = comboBoxNeroAACProfile->currentIndex();
546 //Re.translate from UIC
547 Ui::MainWindow::retranslateUi(this);
549 //Restore combobox indices
550 comboBoxMP3ChannelMode->setCurrentIndex(comboBoxIndex[0]);
551 comboBoxSamplingRate->setCurrentIndex(comboBoxIndex[1]);
552 comboBoxNeroAACProfile->setCurrentIndex(comboBoxIndex[2]);
554 if(lamexp_version_demo())
556 setWindowTitle(QString("%1 [%2]").arg(windowTitle(), tr("DEMO VERSION")));
559 //Manual re-translate
560 m_dropNoteLabel->setText(QString("» %1 «").arg(tr("You can drop in audio files here!")));
561 m_showDetailsContextAction->setText(tr("Show Details"));
562 m_previewContextAction->setText(tr("Open File in External Application"));
563 m_findFileContextAction->setText(tr("Browse File Location"));
564 m_showFolderContextAction->setText(tr("Browse Selected Folder"));
566 //Force GUI update
567 m_metaInfoModel->clearData();
568 updateEncoder(m_settings->compressionEncoder());
569 updateLameAlgoQuality(sliderLameAlgoQuality->value());
571 if(m_settings->shellIntegrationEnabled())
573 ShellIntegration::install();
579 * File dragged over window
581 void MainWindow::dragEnterEvent(QDragEnterEvent *event)
583 QStringList formats = event->mimeData()->formats();
585 if(formats.contains("application/x-qt-windows-mime;value=\"FileNameW\"", Qt::CaseInsensitive) && formats.contains("text/uri-list", Qt::CaseInsensitive))
587 event->acceptProposedAction();
592 * File dropped onto window
594 void MainWindow::dropEvent(QDropEvent *event)
596 ABORT_IF_BUSY;
598 QStringList droppedFiles;
599 const QList<QUrl> urls = event->mimeData()->urls();
601 for(int i = 0; i < urls.count(); i++)
603 QFileInfo file(urls.at(i).toLocalFile());
604 if(!file.exists())
606 continue;
608 if(file.isFile())
610 droppedFiles << file.canonicalFilePath();
611 continue;
613 if(file.isDir())
615 QList<QFileInfo> list = QDir(file.canonicalFilePath()).entryInfoList(QDir::Files);
616 for(int j = 0; j < list.count(); j++)
618 droppedFiles << list.at(j).canonicalFilePath();
623 addFiles(droppedFiles);
627 * Window tries to close
629 void MainWindow::closeEvent(QCloseEvent *event)
631 if(m_banner->isVisible() || m_delayedFileTimer->isActive())
633 MessageBeep(MB_ICONEXCLAMATION);
634 event->ignore();
637 if(m_dropBox)
639 m_dropBox->hide();
644 * Window was resized
646 void MainWindow::resizeEvent(QResizeEvent *event)
648 QMainWindow::resizeEvent(event);
649 m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
653 * Event filter
655 bool MainWindow::eventFilter(QObject *obj, QEvent *event)
657 if(obj == m_fileSystemModel && QApplication::overrideCursor() == NULL)
659 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
660 QTimer::singleShot(250, this, SLOT(restoreCursor()));
662 else if(obj == outputFolderLabel)
664 switch(event->type())
666 case QEvent::MouseButtonPress:
667 if(dynamic_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)
669 QDesktopServices::openUrl(QString("file:///%1").arg(outputFolderLabel->text()));
671 break;
672 case QEvent::Enter:
673 outputFolderLabel->setForegroundRole(QPalette::Link);
674 break;
675 case QEvent::Leave:
676 outputFolderLabel->setForegroundRole(QPalette::WindowText);
677 break;
680 return false;
683 ////////////////////////////////////////////////////////////
684 // Slots
685 ////////////////////////////////////////////////////////////
688 * Window shown
690 void MainWindow::windowShown(void)
692 QStringList arguments = QApplication::arguments();
694 //Check license
695 if(m_settings->licenseAccepted() <= 0)
697 int iAccepted = -1;
699 if(m_settings->licenseAccepted() == 0)
701 AboutDialog *about = new AboutDialog(m_settings, this, true);
702 iAccepted = about->exec();
703 LAMEXP_DELETE(about);
706 if(iAccepted <= 0)
708 m_settings->licenseAccepted(-1);
709 QApplication::processEvents();
710 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
711 QMessageBox::critical(this, tr("License Declined"), tr("You have declined the license. Consequently the application will exit now!"), tr("Goodbye!"));
712 QProcess::startDetached(QString("%1/Uninstall.exe").arg(QApplication::applicationDirPath()), QStringList());
713 QApplication::quit();
714 return;
717 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WOOHOO), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
718 m_settings->licenseAccepted(1);
721 //Check for expiration
722 if(lamexp_version_demo())
724 if(QDate::currentDate() >= lamexp_version_expires())
726 qWarning("Binary has expired !!!");
727 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
728 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)
730 checkUpdatesActionActivated();
732 QApplication::quit();
733 return;
737 //Update reminder
738 if(QDate::currentDate() >= lamexp_version_date().addYears(1))
740 qWarning("Binary is more than a year old, time to update!");
741 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)
743 checkUpdatesActionActivated();
745 else
747 QApplication::quit();
748 return;
751 else if(m_settings->autoUpdateEnabled())
753 QDate lastUpdateCheck = QDate::fromString(m_settings->autoUpdateLastCheck(), Qt::ISODate);
754 if(!lastUpdateCheck.isValid() || QDate::currentDate() >= lastUpdateCheck.addDays(14))
756 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)
758 checkUpdatesActionActivated();
763 //Check for AAC support
764 if(m_settings->neroAacNotificationsEnabled())
766 if(lamexp_check_tool("neroAacEnc.exe") && lamexp_check_tool("neroAacDec.exe") && lamexp_check_tool("neroAacTag.exe"))
768 if(lamexp_tool_version("neroAacEnc.exe") < lamexp_toolver_neroaac())
770 QString messageText;
771 messageText += QString("<nobr>%1<br>").arg(tr("LameXP detected that your version of the Nero AAC encoder is outdated!"));
772 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"))));
773 messageText += QString("%1<br>").arg(tr("You can download the latest version of the Nero AAC encoder from the Nero website at:"));
774 messageText += "<tt>" + LINK(AboutDialog::neroAacUrl) + "</tt><br></nobr>";
775 QMessageBox::information(this, tr("AAC Encoder Outdated"), messageText);
778 else
780 radioButtonEncoderAAC->setEnabled(false);
781 QString appPath = QDir(QCoreApplication::applicationDirPath()).canonicalPath();
782 if(appPath.isEmpty()) appPath = QCoreApplication::applicationDirPath();
783 QString messageText;
784 messageText += QString("<nobr>%1<br>").arg(tr("The Nero AAC encoder could not be found. AAC encoding support will be disabled."));
785 messageText += QString("%1<br><br>").arg(tr("Please put 'neroAacEnc.exe', 'neroAacDec.exe' and 'neroAacTag.exe' into the LameXP directory!"));
786 messageText += QString("%1<br>").arg(tr("Your LameXP directory is located here:"));
787 messageText += QString("<i><nobr><a href=\"file:///%1\">%1</a></nobr></i><br><br>").arg(QDir::toNativeSeparators(appPath));
788 messageText += QString("%1<br>").arg(tr("You can download the Nero AAC encoder for free from the official Nero website at:"));
789 messageText += "<tt>" + LINK(AboutDialog::neroAacUrl) + "</tt><br></nobr>";
790 QMessageBox::information(this, tr("AAC Support Disabled"), messageText);
794 //Check for WMA support
795 if(m_settings->wmaDecoderNotificationsEnabled())
797 if(!lamexp_check_tool("wmawav.exe"))
799 QString messageText;
800 messageText += QString("<nobr>%1<br>").arg(tr("LameXP has detected that the WMA File Decoder component is not currently installed on your system."));
801 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!"));
802 messageText += QString("%1</nobr>").arg(tr("Do you want to download and install the WMA File Decoder component now?"));
803 if(QMessageBox::information(this, tr("WMA Decoder Missing"), messageText, tr("Download && Install"), tr("Postpone")) == 0)
805 installWMADecoder();
810 //Add files from the command-line
811 for(int i = 0; i < arguments.count() - 1; i++)
813 if(!arguments[i].compare("--add", Qt::CaseInsensitive))
815 QFileInfo currentFile(arguments[++i].trimmed());
816 qDebug("Adding file from CLI: %s", currentFile.canonicalFilePath().toUtf8().constData());
817 m_delayedFileList->append(currentFile.canonicalFilePath());
821 //Start delayed files timer
822 if(!m_delayedFileList->isEmpty() && !m_delayedFileTimer->isActive())
824 m_delayedFileTimer->start(5000);
827 //Enable shell integration
828 if(m_settings->shellIntegrationEnabled())
830 ShellIntegration::install();
833 //Make DropBox visible
834 if(m_settings->dropBoxWidgetEnabled())
836 m_dropBox->setVisible(true);
841 * About button
843 void MainWindow::aboutButtonClicked(void)
845 ABORT_IF_BUSY;
847 TEMP_HIDE_DROPBOX
849 AboutDialog *aboutBox = new AboutDialog(m_settings, this);
850 aboutBox->exec();
851 LAMEXP_DELETE(aboutBox);
856 * Encode button
858 void MainWindow::encodeButtonClicked(void)
860 static const __int64 oneGigabyte = 1073741824;
861 static const __int64 minimumFreeDiskspaceMultiplier = 2;
863 ABORT_IF_BUSY;
865 if(m_fileListModel->rowCount() < 1)
867 QMessageBox::warning(this, tr("LameXP"), QString("<nobr>%1</nobr>").arg(tr("You must add at least one file to the list before proceeding!")));
868 tabWidget->setCurrentIndex(0);
869 return;
872 __int64 currentFreeDiskspace = lamexp_free_diskspace(lamexp_temp_folder());
874 if(currentFreeDiskspace < (oneGigabyte * minimumFreeDiskspaceMultiplier))
876 QStringList tempFolderParts = lamexp_temp_folder().split("/", QString::SkipEmptyParts, Qt::CaseInsensitive);
877 tempFolderParts.takeLast();
878 if(m_settings->soundsEnabled()) PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
879 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")))
881 case 1:
882 QProcess::startDetached(QString("%1/cleanmgr.exe").arg(lamexp_known_folder(lamexp_folder_systemfolder)), QStringList() << "/D" << tempFolderParts.first());
883 case 0:
884 return;
885 break;
886 default:
887 QMessageBox::warning(this, tr("Low Diskspace"), tr("You are proceeding with low diskspace. Problems might occur!"));
888 break;
892 switch(m_settings->compressionEncoder())
894 case SettingsModel::MP3Encoder:
895 case SettingsModel::VorbisEncoder:
896 case SettingsModel::AACEncoder:
897 case SettingsModel::FLACEncoder:
898 case SettingsModel::PCMEncoder:
899 break;
900 default:
901 QMessageBox::warning(this, tr("LameXP"), tr("Sorry, an unsupported encoder has been chosen!"));
902 tabWidget->setCurrentIndex(3);
903 return;
906 if(!m_settings->outputToSourceDir())
908 QFile writeTest(QString("%1/~%2.txt").arg(m_settings->outputDir(), QUuid::createUuid().toString()));
909 if(!writeTest.open(QIODevice::ReadWrite))
911 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!")));
912 tabWidget->setCurrentIndex(1);
913 return;
915 else
917 writeTest.close();
918 writeTest.remove();
922 m_accepted = true;
923 close();
927 * Close button
929 void MainWindow::closeButtonClicked(void)
931 ABORT_IF_BUSY;
932 close();
936 * Add file(s) button
938 void MainWindow::addFilesButtonClicked(void)
940 ABORT_IF_BUSY;
942 TEMP_HIDE_DROPBOX
944 if(lamexp_themes_enabled())
946 QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
947 QStringList selectedFiles = QFileDialog::getOpenFileNames(this, tr("Add file(s)"), QString(), fileTypeFilters.join(";;"));
948 if(!selectedFiles.isEmpty())
950 addFiles(selectedFiles);
953 else
955 QFileDialog dialog(this, tr("Add file(s)"));
956 QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
957 dialog.setFileMode(QFileDialog::ExistingFiles);
958 dialog.setNameFilter(fileTypeFilters.join(";;"));
959 if(dialog.exec())
961 QStringList selectedFiles = dialog.selectedFiles();
962 addFiles(selectedFiles);
969 * Open folder action
971 void MainWindow::openFolderActionActivated(void)
973 ABORT_IF_BUSY;
974 QString selectedFolder;
976 TEMP_HIDE_DROPBOX
978 if(lamexp_themes_enabled())
980 selectedFolder = QFileDialog::getExistingDirectory(this, tr("Add folder"), QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
982 else
984 QFileDialog dialog(this, tr("Add folder"));
985 dialog.setFileMode(QFileDialog::DirectoryOnly);
986 dialog.setDirectory(QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
987 if(dialog.exec())
989 selectedFolder = dialog.selectedFiles().first();
993 if(!selectedFolder.isEmpty())
995 QDir sourceDir(selectedFolder);
996 QFileInfoList fileInfoList = sourceDir.entryInfoList(QDir::Files);
997 QStringList fileList;
999 while(!fileInfoList.isEmpty())
1001 fileList << fileInfoList.takeFirst().canonicalFilePath();
1004 addFiles(fileList);
1010 * Remove file button
1012 void MainWindow::removeFileButtonClicked(void)
1014 if(sourceFileView->currentIndex().isValid())
1016 int iRow = sourceFileView->currentIndex().row();
1017 m_fileListModel->removeFile(sourceFileView->currentIndex());
1018 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
1023 * Clear files button
1025 void MainWindow::clearFilesButtonClicked(void)
1027 m_fileListModel->clearFiles();
1031 * Move file up button
1033 void MainWindow::fileUpButtonClicked(void)
1035 if(sourceFileView->currentIndex().isValid())
1037 int iRow = sourceFileView->currentIndex().row() - 1;
1038 m_fileListModel->moveFile(sourceFileView->currentIndex(), -1);
1039 sourceFileView->selectRow(iRow >= 0 ? iRow : 0);
1044 * Move file down button
1046 void MainWindow::fileDownButtonClicked(void)
1048 if(sourceFileView->currentIndex().isValid())
1050 int iRow = sourceFileView->currentIndex().row() + 1;
1051 m_fileListModel->moveFile(sourceFileView->currentIndex(), 1);
1052 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
1057 * Show details button
1059 void MainWindow::showDetailsButtonClicked(void)
1061 ABORT_IF_BUSY;
1063 int iResult = 0;
1064 MetaInfoDialog *metaInfoDialog = new MetaInfoDialog(this);
1065 QModelIndex index = sourceFileView->currentIndex();
1067 while(index.isValid())
1069 if(iResult > 0)
1071 index = m_fileListModel->index(index.row() + 1, index.column());
1072 sourceFileView->selectRow(index.row());
1074 if(iResult < 0)
1076 index = m_fileListModel->index(index.row() - 1, index.column());
1077 sourceFileView->selectRow(index.row());
1080 AudioFileModel &file = (*m_fileListModel)[index];
1081 iResult = metaInfoDialog->exec(file, index.row() > 0, index.row() < m_fileListModel->rowCount() - 1);
1083 if(!iResult) break;
1086 LAMEXP_DELETE(metaInfoDialog);
1090 * Tab page changed
1092 void MainWindow::tabPageChanged(int idx)
1094 QList<QAction*> actions = m_tabActionGroup->actions();
1095 for(int i = 0; i < actions.count(); i++)
1097 bool ok = false;
1098 int actionIndex = actions.at(i)->data().toInt(&ok);
1099 if(ok && actionIndex == idx)
1101 actions.at(i)->setChecked(true);
1107 * Tab action triggered
1109 void MainWindow::tabActionActivated(QAction *action)
1111 if(action && action->data().isValid())
1113 bool ok = false;
1114 int index = action->data().toInt(&ok);
1115 if(ok)
1117 tabWidget->setCurrentIndex(index);
1123 * Style action triggered
1125 void MainWindow::styleActionActivated(QAction *action)
1127 if(action && action->data().isValid())
1129 bool ok = false;
1130 int actionIndex = action->data().toInt(&ok);
1131 m_settings->interfaceStyle(actionIndex);
1134 switch(m_settings->interfaceStyle())
1136 case 1:
1137 if(actionStyleCleanlooks->isEnabled())
1139 actionStyleCleanlooks->setChecked(true);
1140 QApplication::setStyle(new QCleanlooksStyle());
1141 break;
1143 case 2:
1144 if(actionStyleWindowsVista->isEnabled())
1146 actionStyleWindowsVista->setChecked(true);
1147 QApplication::setStyle(new QWindowsVistaStyle());
1148 break;
1150 case 3:
1151 if(actionStyleWindowsXP->isEnabled())
1153 actionStyleWindowsXP->setChecked(true);
1154 QApplication::setStyle(new QWindowsXPStyle());
1155 break;
1157 case 4:
1158 if(actionStyleWindowsClassic->isEnabled())
1160 actionStyleWindowsClassic->setChecked(true);
1161 QApplication::setStyle(new QWindowsStyle());
1162 break;
1164 default:
1165 actionStylePlastique->setChecked(true);
1166 QApplication::setStyle(new QPlastiqueStyle());
1167 break;
1172 * Language action triggered
1174 void MainWindow::languageActionActivated(QAction *action)
1176 if(action->data().type() == QVariant::String)
1178 QString langId = action->data().toString();
1180 if(lamexp_install_translator(langId))
1182 action->setChecked(true);
1183 m_settings->currentLanguage(langId);
1189 * Load language from file action triggered
1191 void MainWindow::languageFromFileActionActivated(bool checked)
1193 QFileDialog dialog(this, tr("Load Translation"));
1194 dialog.setFileMode(QFileDialog::ExistingFile);
1195 dialog.setNameFilter(QString("%1 (*.qm)").arg(tr("Translation Files")));
1197 if(dialog.exec())
1199 QStringList selectedFiles = dialog.selectedFiles();
1200 if(lamexp_install_translator_from_file(selectedFiles.first()))
1202 QList<QAction*> actions = m_languageActionGroup->actions();
1203 while(!actions.isEmpty())
1205 actions.takeFirst()->setChecked(false);
1208 else
1210 languageActionActivated(m_languageActionGroup->actions().first());
1216 * Output folder changed (mouse clicked)
1218 void MainWindow::outputFolderViewClicked(const QModelIndex &index)
1220 if(outputFolderView->currentIndex() != index)
1222 outputFolderView->setCurrentIndex(index);
1224 QString selectedDir = m_fileSystemModel->filePath(index);
1225 if(selectedDir.length() < 3) selectedDir.append(QDir::separator());
1226 outputFolderLabel->setText(QDir::toNativeSeparators(selectedDir));
1227 m_settings->outputDir(selectedDir);
1231 * Output folder changed (mouse moved)
1233 void MainWindow::outputFolderViewMoved(const QModelIndex &index)
1235 if(QApplication::mouseButtons() & Qt::LeftButton)
1237 outputFolderViewClicked(index);
1242 * Goto desktop button
1244 void MainWindow::gotoDesktopButtonClicked(void)
1246 QString desktopPath = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
1248 if(!desktopPath.isEmpty() && QDir(desktopPath).exists())
1250 outputFolderView->setCurrentIndex(m_fileSystemModel->index(desktopPath));
1251 outputFolderViewClicked(outputFolderView->currentIndex());
1252 outputFolderView->setFocus();
1254 else
1256 buttonGotoDesktop->setEnabled(false);
1261 * Goto home folder button
1263 void MainWindow::gotoHomeFolderButtonClicked(void)
1265 QString homePath = QDesktopServices::storageLocation(QDesktopServices::HomeLocation);
1267 if(!homePath.isEmpty() && QDir(homePath).exists())
1269 outputFolderView->setCurrentIndex(m_fileSystemModel->index(homePath));
1270 outputFolderViewClicked(outputFolderView->currentIndex());
1271 outputFolderView->setFocus();
1273 else
1275 buttonGotoHome->setEnabled(false);
1280 * Goto music folder button
1282 void MainWindow::gotoMusicFolderButtonClicked(void)
1284 QString musicPath = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
1286 if(!musicPath.isEmpty() && QDir(musicPath).exists())
1288 outputFolderView->setCurrentIndex(m_fileSystemModel->index(musicPath));
1289 outputFolderViewClicked(outputFolderView->currentIndex());
1290 outputFolderView->setFocus();
1292 else
1294 buttonGotoMusic->setEnabled(false);
1299 * Make folder button
1301 void MainWindow::makeFolderButtonClicked(void)
1303 ABORT_IF_BUSY;
1305 QDir basePath(m_fileSystemModel->fileInfo(outputFolderView->currentIndex()).absoluteFilePath());
1306 QString suggestedName = tr("New Folder");
1308 if(!m_metaData->fileArtist().isEmpty() && !m_metaData->fileAlbum().isEmpty())
1310 suggestedName = QString("%1 - %2").arg(m_metaData->fileArtist(), m_metaData->fileAlbum());
1312 else if(!m_metaData->fileArtist().isEmpty())
1314 suggestedName = m_metaData->fileArtist();
1316 else if(!m_metaData->fileAlbum().isEmpty())
1318 suggestedName = m_metaData->fileAlbum();
1320 else
1322 for(int i = 0; i < m_fileListModel->rowCount(); i++)
1324 AudioFileModel audioFile = m_fileListModel->getFile(m_fileListModel->index(i, 0));
1325 if(!audioFile.fileAlbum().isEmpty() || !audioFile.fileArtist().isEmpty())
1327 if(!audioFile.fileArtist().isEmpty() && !audioFile.fileAlbum().isEmpty())
1329 suggestedName = QString("%1 - %2").arg(audioFile.fileArtist(), audioFile.fileAlbum());
1331 else if(!audioFile.fileArtist().isEmpty())
1333 suggestedName = audioFile.fileArtist();
1335 else if(!audioFile.fileAlbum().isEmpty())
1337 suggestedName = audioFile.fileAlbum();
1339 break;
1344 while(true)
1346 bool bApplied = false;
1347 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();
1349 if(bApplied)
1351 folderName.remove(":", Qt::CaseInsensitive);
1352 folderName.remove("/", Qt::CaseInsensitive);
1353 folderName.remove("\\", Qt::CaseInsensitive);
1354 folderName.remove("?", Qt::CaseInsensitive);
1355 folderName.remove("*", Qt::CaseInsensitive);
1356 folderName.remove("<", Qt::CaseInsensitive);
1357 folderName.remove(">", Qt::CaseInsensitive);
1359 folderName = folderName.simplified();
1361 if(folderName.isEmpty())
1363 MessageBeep(MB_ICONERROR);
1364 continue;
1367 int i = 1;
1368 QString newFolder = folderName;
1370 while(basePath.exists(newFolder))
1372 newFolder = QString(folderName).append(QString().sprintf(" (%d)", ++i));
1375 if(basePath.mkdir(newFolder))
1377 QDir createdDir = basePath;
1378 if(createdDir.cd(newFolder))
1380 outputFolderView->setCurrentIndex(m_fileSystemModel->index(createdDir.canonicalPath()));
1381 outputFolderViewClicked(outputFolderView->currentIndex());
1382 outputFolderView->setFocus();
1385 else
1387 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!")));
1390 break;
1395 * Edit meta button clicked
1397 void MainWindow::editMetaButtonClicked(void)
1399 ABORT_IF_BUSY;
1400 m_metaInfoModel->editItem(metaDataView->currentIndex(), this);
1404 * Reset meta button clicked
1406 void MainWindow::clearMetaButtonClicked(void)
1408 ABORT_IF_BUSY;
1409 m_metaInfoModel->clearData();
1413 * Visit homepage action
1415 void MainWindow::visitHomepageActionActivated(void)
1417 QDesktopServices::openUrl(QUrl("http://mulder.dummwiedeutsch.de/"));
1421 * Check for updates action
1423 void MainWindow::checkUpdatesActionActivated(void)
1425 ABORT_IF_BUSY;
1427 TEMP_HIDE_DROPBOX
1429 UpdateDialog *updateDialog = new UpdateDialog(m_settings, this);
1430 updateDialog->exec();
1431 if(updateDialog->getSuccess())
1433 m_settings->autoUpdateLastCheck(QDate::currentDate().toString(Qt::ISODate));
1435 LAMEXP_DELETE(updateDialog);
1440 * Other instance detected
1442 void MainWindow::notifyOtherInstance(void)
1444 if(!m_banner->isVisible())
1446 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);
1447 msgBox.exec();
1452 * Add file from another instance
1454 void MainWindow::addFileDelayed(const QString &filePath)
1456 m_delayedFileTimer->stop();
1457 qDebug("Received file: %s", filePath.toUtf8().constData());
1458 m_delayedFileList->append(filePath);
1459 m_delayedFileTimer->start(5000);
1463 * Add all pending files
1465 void MainWindow::handleDelayedFiles(void)
1467 if(m_banner->isVisible())
1469 return;
1472 m_delayedFileTimer->stop();
1473 if(m_delayedFileList->isEmpty())
1475 return;
1478 QStringList selectedFiles;
1479 tabWidget->setCurrentIndex(0);
1481 while(!m_delayedFileList->isEmpty())
1483 QFileInfo currentFile = QFileInfo(m_delayedFileList->takeFirst());
1484 if(!currentFile.exists())
1486 continue;
1488 if(currentFile.isFile())
1490 selectedFiles << currentFile.canonicalFilePath();
1491 continue;
1493 if(currentFile.isDir())
1495 QList<QFileInfo> list = QDir(currentFile.canonicalFilePath()).entryInfoList(QDir::Files);
1496 for(int j = 0; j < list.count(); j++)
1498 selectedFiles << list.at(j).canonicalFilePath();
1503 addFiles(selectedFiles);
1507 * Update encoder
1509 void MainWindow::updateEncoder(int id)
1511 m_settings->compressionEncoder(id);
1513 switch(m_settings->compressionEncoder())
1515 case SettingsModel::VorbisEncoder:
1516 radioButtonModeQuality->setEnabled(true);
1517 radioButtonModeAverageBitrate->setEnabled(true);
1518 radioButtonConstBitrate->setEnabled(false);
1519 if(radioButtonConstBitrate->isChecked()) radioButtonModeQuality->setChecked(true);
1520 sliderBitrate->setEnabled(true);
1521 break;
1522 case SettingsModel::FLACEncoder:
1523 radioButtonModeQuality->setEnabled(false);
1524 radioButtonModeQuality->setChecked(true);
1525 radioButtonModeAverageBitrate->setEnabled(false);
1526 radioButtonConstBitrate->setEnabled(false);
1527 sliderBitrate->setEnabled(true);
1528 break;
1529 case SettingsModel::PCMEncoder:
1530 radioButtonModeQuality->setEnabled(false);
1531 radioButtonModeQuality->setChecked(true);
1532 radioButtonModeAverageBitrate->setEnabled(false);
1533 radioButtonConstBitrate->setEnabled(false);
1534 sliderBitrate->setEnabled(false);
1535 break;
1536 default:
1537 radioButtonModeQuality->setEnabled(true);
1538 radioButtonModeAverageBitrate->setEnabled(true);
1539 radioButtonConstBitrate->setEnabled(true);
1540 sliderBitrate->setEnabled(true);
1541 break;
1544 updateRCMode(m_modeButtonGroup->checkedId());
1548 * Update rate-control mode
1550 void MainWindow::updateRCMode(int id)
1552 m_settings->compressionRCMode(id);
1554 switch(m_settings->compressionEncoder())
1556 case SettingsModel::MP3Encoder:
1557 switch(m_settings->compressionRCMode())
1559 case SettingsModel::VBRMode:
1560 sliderBitrate->setMinimum(0);
1561 sliderBitrate->setMaximum(9);
1562 break;
1563 default:
1564 sliderBitrate->setMinimum(0);
1565 sliderBitrate->setMaximum(13);
1566 break;
1568 break;
1569 case SettingsModel::VorbisEncoder:
1570 switch(m_settings->compressionRCMode())
1572 case SettingsModel::VBRMode:
1573 sliderBitrate->setMinimum(-2);
1574 sliderBitrate->setMaximum(10);
1575 break;
1576 default:
1577 sliderBitrate->setMinimum(4);
1578 sliderBitrate->setMaximum(63);
1579 break;
1581 break;
1582 case SettingsModel::AACEncoder:
1583 switch(m_settings->compressionRCMode())
1585 case SettingsModel::VBRMode:
1586 sliderBitrate->setMinimum(0);
1587 sliderBitrate->setMaximum(20);
1588 break;
1589 default:
1590 sliderBitrate->setMinimum(4);
1591 sliderBitrate->setMaximum(63);
1592 break;
1594 break;
1595 case SettingsModel::FLACEncoder:
1596 sliderBitrate->setMinimum(0);
1597 sliderBitrate->setMaximum(8);
1598 break;
1599 case SettingsModel::PCMEncoder:
1600 sliderBitrate->setMinimum(0);
1601 sliderBitrate->setMaximum(2);
1602 sliderBitrate->setValue(1);
1603 break;
1604 default:
1605 sliderBitrate->setMinimum(0);
1606 sliderBitrate->setMaximum(0);
1607 break;
1610 updateBitrate(sliderBitrate->value());
1614 * Update bitrate
1616 void MainWindow::updateBitrate(int value)
1618 m_settings->compressionBitrate(value);
1620 switch(m_settings->compressionRCMode())
1622 case SettingsModel::VBRMode:
1623 switch(m_settings->compressionEncoder())
1625 case SettingsModel::MP3Encoder:
1626 labelBitrate->setText(tr("Quality Level %1").arg(9 - value));
1627 break;
1628 case SettingsModel::VorbisEncoder:
1629 labelBitrate->setText(tr("Quality Level %1").arg(value));
1630 break;
1631 case SettingsModel::AACEncoder:
1632 labelBitrate->setText(tr("Quality Level %1").arg(QString().sprintf("%.2f", static_cast<double>(value * 5) / 100.0)));
1633 break;
1634 case SettingsModel::FLACEncoder:
1635 labelBitrate->setText(tr("Compression %1").arg(value));
1636 break;
1637 case SettingsModel::PCMEncoder:
1638 labelBitrate->setText(tr("Uncompressed"));
1639 break;
1640 default:
1641 labelBitrate->setText(QString::number(value));
1642 break;
1644 break;
1645 case SettingsModel::ABRMode:
1646 switch(m_settings->compressionEncoder())
1648 case SettingsModel::MP3Encoder:
1649 labelBitrate->setText(QString("&asymp; %1 kbps").arg(SettingsModel::mp3Bitrates[value]));
1650 break;
1651 case SettingsModel::FLACEncoder:
1652 labelBitrate->setText(tr("Compression %1").arg(value));
1653 break;
1654 case SettingsModel::PCMEncoder:
1655 labelBitrate->setText(tr("Uncompressed"));
1656 break;
1657 default:
1658 labelBitrate->setText(QString("&asymp; %1 kbps").arg(min(500, value * 8)));
1659 break;
1661 break;
1662 default:
1663 switch(m_settings->compressionEncoder())
1665 case SettingsModel::MP3Encoder:
1666 labelBitrate->setText(QString("%1 kbps").arg(SettingsModel::mp3Bitrates[value]));
1667 break;
1668 case SettingsModel::FLACEncoder:
1669 labelBitrate->setText(tr("Compression %1").arg(value));
1670 break;
1671 case SettingsModel::PCMEncoder:
1672 labelBitrate->setText(tr("Uncompressed"));
1673 break;
1674 default:
1675 labelBitrate->setText(QString("%1 kbps").arg(min(500, value * 8)));
1676 break;
1678 break;
1684 * Lame algorithm quality changed
1686 void MainWindow::updateLameAlgoQuality(int value)
1688 QString text;
1690 switch(value)
1692 case 4:
1693 text = tr("Best Quality (Very Slow)");
1694 break;
1695 case 3:
1696 text = tr("High Quality (Recommended)");
1697 break;
1698 case 2:
1699 text = tr("Average Quality (Default)");
1700 break;
1701 case 1:
1702 text = tr("Low Quality (Fast)");
1703 break;
1704 case 0:
1705 text = tr("Poor Quality (Very Fast)");
1706 break;
1709 if(!text.isEmpty())
1711 m_settings->lameAlgoQuality(value);
1712 labelLameAlgoQuality->setText(text);
1717 * Bitrate management endabled/disabled
1719 void MainWindow::bitrateManagementEnabledChanged(bool checked)
1721 m_settings->bitrateManagementEnabled(checked);
1725 * Minimum bitrate has changed
1727 void MainWindow::bitrateManagementMinChanged(int value)
1729 if(value > spinBoxBitrateManagementMax->value())
1731 spinBoxBitrateManagementMin->setValue(spinBoxBitrateManagementMax->value());
1732 m_settings->bitrateManagementMinRate(spinBoxBitrateManagementMax->value());
1734 else
1736 m_settings->bitrateManagementMinRate(value);
1741 * Maximum bitrate has changed
1743 void MainWindow::bitrateManagementMaxChanged(int value)
1745 if(value < spinBoxBitrateManagementMin->value())
1747 spinBoxBitrateManagementMax->setValue(spinBoxBitrateManagementMin->value());
1748 m_settings->bitrateManagementMaxRate(spinBoxBitrateManagementMin->value());
1750 else
1752 m_settings->bitrateManagementMaxRate(value);
1757 * Channel mode has changed
1759 void MainWindow::channelModeChanged(int value)
1761 if(value >= 0) m_settings->lameChannelMode(value);
1765 * Sampling rate has changed
1767 void MainWindow::samplingRateChanged(int value)
1769 if(value >= 0) m_settings->samplingRate(value);
1773 * Nero AAC 2-Pass mode changed
1775 void MainWindow::neroAAC2PassChanged(bool checked)
1777 m_settings->neroAACEnable2Pass(checked);
1781 * Nero AAC profile mode changed
1783 void MainWindow::neroAACProfileChanged(int value)
1785 if(value >= 0) m_settings->neroAACProfile(value);
1789 * Normalization filter enabled changed
1791 void MainWindow::normalizationEnabledChanged(bool checked)
1793 m_settings->normalizationFilterEnabled(checked);
1797 * Normalization max. volume changed
1799 void MainWindow::normalizationMaxVolumeChanged(double value)
1801 m_settings->normalizationFilterMaxVolume(static_cast<int>(value * 100.0));
1805 * Tone adjustment has changed (Bass)
1807 void MainWindow::toneAdjustBassChanged(double value)
1809 m_settings->toneAdjustBass(static_cast<int>(value * 100.0));
1810 spinBoxToneAdjustBass->setPrefix((value > 0) ? "+" : QString());
1814 * Tone adjustment has changed (Treble)
1816 void MainWindow::toneAdjustTrebleChanged(double value)
1818 m_settings->toneAdjustTreble(static_cast<int>(value * 100.0));
1819 spinBoxToneAdjustTreble->setPrefix((value > 0) ? "+" : QString());
1823 * Tone adjustment has been reset
1825 void MainWindow::toneAdjustTrebleReset()
1827 spinBoxToneAdjustBass->setValue(m_settings->toneAdjustBassDefault());
1828 spinBoxToneAdjustTreble->setValue(m_settings->toneAdjustTrebleDefault());
1829 toneAdjustBassChanged(spinBoxToneAdjustBass->value());
1830 toneAdjustTrebleChanged(spinBoxToneAdjustTreble->value());
1834 * Reset all advanced options to their defaults
1836 void MainWindow::resetAdvancedOptionsButtonClicked()
1838 sliderLameAlgoQuality->setValue(m_settings->lameAlgoQualityDefault());
1839 spinBoxBitrateManagementMin->setValue(m_settings->bitrateManagementMinRateDefault());
1840 spinBoxBitrateManagementMax->setValue(m_settings->bitrateManagementMaxRateDefault());
1841 spinBoxNormalizationFilter->setValue(static_cast<double>(m_settings->normalizationFilterMaxVolumeDefault()) / 100.0);
1842 spinBoxToneAdjustBass->setValue(static_cast<double>(m_settings->toneAdjustBassDefault()) / 100.0);
1843 spinBoxToneAdjustTreble->setValue(static_cast<double>(m_settings->toneAdjustTrebleDefault()) / 100.0);
1844 comboBoxMP3ChannelMode->setCurrentIndex(m_settings->lameChannelModeDefault());
1845 comboBoxSamplingRate->setCurrentIndex(m_settings->samplingRateDefault());
1846 comboBoxNeroAACProfile->setCurrentIndex(m_settings->neroAACProfileDefault());
1847 while(checkBoxBitrateManagement->isChecked() != m_settings->bitrateManagementEnabledDefault()) checkBoxBitrateManagement->click();
1848 while(checkBoxNeroAAC2PassMode->isChecked() != m_settings->neroAACEnable2PassDefault()) checkBoxNeroAAC2PassMode->click();
1849 while(checkBoxNormalizationFilter->isChecked() != m_settings->normalizationFilterEnabledDefault()) checkBoxNormalizationFilter->click();
1850 scrollArea->verticalScrollBar()->setValue(0);
1854 * Model reset
1856 void MainWindow::sourceModelChanged(void)
1858 m_dropNoteLabel->setVisible(m_fileListModel->rowCount() <= 0);
1862 * Meta tags enabled changed
1864 void MainWindow::metaTagsEnabledChanged(void)
1866 m_settings->writeMetaTags(writeMetaDataCheckBox->isChecked());
1870 * Playlist enabled changed
1872 void MainWindow::playlistEnabledChanged(void)
1874 m_settings->createPlaylist(generatePlaylistCheckBox->isChecked());
1878 * Output to source dir changed
1880 void MainWindow::saveToSourceFolderChanged(void)
1882 m_settings->outputToSourceDir(saveToSourceFolderCheckBox->isChecked());
1886 * Prepend relative source file path to output file name changed
1888 void MainWindow::prependRelativePathChanged(void)
1890 m_settings->prependRelativeSourcePath(prependRelativePathCheckBox->isChecked());
1895 * Restore the override cursor
1897 void MainWindow::restoreCursor(void)
1899 QApplication::restoreOverrideCursor();
1903 * Show context menu for source files
1905 void MainWindow::sourceFilesContextMenu(const QPoint &pos)
1907 if(pos.x() <= sourceFileView->width() && pos.y() <= sourceFileView->height() && pos.x() >= 0 && pos.y() >= 0)
1909 m_sourceFilesContextMenu->popup(sourceFileView->mapToGlobal(pos));
1914 * Open selected file in external player
1916 void MainWindow::previewContextActionTriggered(void)
1918 const static char *appNames[3] = {"smplayer_portable.exe", "smplayer.exe", "mplayer.exe"};
1919 const static wchar_t *registryKey = L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}";
1921 QModelIndex index = sourceFileView->currentIndex();
1922 if(!index.isValid())
1924 return;
1927 QString mplayerPath;
1928 HKEY registryKeyHandle;
1930 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, registryKey, 0, KEY_READ, &registryKeyHandle) == ERROR_SUCCESS)
1932 wchar_t Buffer[4096];
1933 DWORD BuffSize = sizeof(wchar_t*) * 4096;
1934 if(RegQueryValueExW(registryKeyHandle, L"InstallLocation", 0, 0, reinterpret_cast<BYTE*>(Buffer), &BuffSize) == ERROR_SUCCESS)
1936 mplayerPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(Buffer));
1940 if(!mplayerPath.isEmpty())
1942 QDir mplayerDir(mplayerPath);
1943 if(mplayerDir.exists())
1945 for(int i = 0; i < 3; i++)
1947 if(mplayerDir.exists(appNames[i]))
1949 QProcess::startDetached(mplayerDir.absoluteFilePath(appNames[i]), QStringList() << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
1950 return;
1956 QDesktopServices::openUrl(QString("file:///").append(m_fileListModel->getFile(index).filePath()));
1960 * Find selected file in explorer
1962 void MainWindow::findFileContextActionTriggered(void)
1964 QModelIndex index = sourceFileView->currentIndex();
1965 if(index.isValid())
1967 QString systemRootPath;
1969 QDir systemRoot(lamexp_known_folder(lamexp_folder_systemfolder));
1970 if(systemRoot.exists() && systemRoot.cdUp())
1972 systemRootPath = systemRoot.canonicalPath();
1975 if(!systemRootPath.isEmpty())
1977 QFileInfo explorer(QString("%1/explorer.exe").arg(systemRootPath));
1978 if(explorer.exists() && explorer.isFile())
1980 QProcess::execute(explorer.canonicalFilePath(), QStringList() << "/select," << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
1981 return;
1984 else
1986 qWarning("SystemRoot directory could not be detected!");
1992 * Show context menu for output folder
1994 void MainWindow::outputFolderContextMenu(const QPoint &pos)
1997 if(pos.x() <= outputFolderView->width() && pos.y() <= outputFolderView->height() && pos.x() >= 0 && pos.y() >= 0)
1999 m_outputFolderContextMenu->popup(outputFolderView->mapToGlobal(pos));
2004 * Show selected folder in explorer
2006 void MainWindow::showFolderContextActionTriggered(void)
2008 QDesktopServices::openUrl(QUrl::fromLocalFile(m_fileSystemModel->filePath(outputFolderView->currentIndex())));
2012 * Disable update reminder action
2014 void MainWindow::disableUpdateReminderActionTriggered(bool checked)
2016 if(checked)
2018 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))
2020 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!")));
2021 m_settings->autoUpdateEnabled(false);
2023 else
2025 m_settings->autoUpdateEnabled(true);
2028 else
2030 QMessageBox::information(this, tr("Update Reminder"), tr("The update reminder has been re-enabled."));
2031 m_settings->autoUpdateEnabled(true);
2034 actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
2038 * Disable sound effects action
2040 void MainWindow::disableSoundsActionTriggered(bool checked)
2042 if(checked)
2044 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))
2046 QMessageBox::information(this, tr("Sound Effects"), tr("All sound effects have been disabled."));
2047 m_settings->soundsEnabled(false);
2049 else
2051 m_settings->soundsEnabled(true);
2054 else
2056 QMessageBox::information(this, tr("Sound Effects"), tr("The sound effects have been re-enabled."));
2057 m_settings->soundsEnabled(true);
2060 actionDisableSounds->setChecked(!m_settings->soundsEnabled());
2064 * Disable Nero AAC encoder action
2066 void MainWindow::disableNeroAacNotificationsActionTriggered(bool checked)
2068 if(checked)
2070 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))
2072 QMessageBox::information(this, tr("Nero AAC Notifications"), tr("All Nero AAC Encoder notifications have been disabled."));
2073 m_settings->neroAacNotificationsEnabled(false);
2075 else
2077 m_settings->neroAacNotificationsEnabled(true);
2080 else
2082 QMessageBox::information(this, tr("Nero AAC Notifications"), tr("The Nero AAC Encoder notifications have been re-enabled."));
2083 m_settings->neroAacNotificationsEnabled(true);
2086 actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
2090 * Disable WMA Decoder component action
2092 void MainWindow::disableWmaDecoderNotificationsActionTriggered(bool checked)
2094 if(checked)
2096 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))
2098 QMessageBox::information(this, tr("WMA Decoder Notifications"), tr("All WMA Decoder notifications have been disabled."));
2099 m_settings->wmaDecoderNotificationsEnabled(false);
2101 else
2103 m_settings->wmaDecoderNotificationsEnabled(true);
2106 else
2108 QMessageBox::information(this, tr("WMA Decoder Notifications"), tr("The WMA Decoder notifications have been re-enabled."));
2109 m_settings->wmaDecoderNotificationsEnabled(true);
2112 actionDisableWmaDecoderNotifications->setChecked(!m_settings->wmaDecoderNotificationsEnabled());
2116 * Download and install WMA Decoder component
2118 void MainWindow::installWMADecoderActionTriggered(bool checked)
2120 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)
2122 installWMADecoder();
2127 * Show the "drop box" widget
2129 void MainWindow::showDropBoxWidgetActionTriggered(bool checked)
2131 m_settings->dropBoxWidgetEnabled(true);
2133 if(!m_dropBox->isVisible())
2135 m_dropBox->show();
2138 FLASH_WINDOW(m_dropBox);
2142 * Disable shell integration action
2144 void MainWindow::disableShellIntegrationActionTriggered(bool checked)
2146 if(checked)
2148 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))
2150 ShellIntegration::remove();
2151 QMessageBox::information(this, tr("Shell Integration"), tr("The LameXP shell integration has been disabled."));
2152 m_settings->shellIntegrationEnabled(false);
2154 else
2156 m_settings->shellIntegrationEnabled(true);
2159 else
2161 ShellIntegration::install();
2162 QMessageBox::information(this, tr("Shell Integration"), tr("The LameXP shell integration has been re-enabled."));
2163 m_settings->shellIntegrationEnabled(true);
2166 actionDisableShellIntegration->setChecked(!m_settings->shellIntegrationEnabled());
2168 if(lamexp_portable_mode() && actionDisableShellIntegration->isChecked())
2170 actionDisableShellIntegration->setEnabled(false);