1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2011 LoRd_MuldeR <MuldeR2@GMX.de>
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.
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"
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"
43 #include <QMessageBox>
45 #include <QDesktopWidget>
47 #include <QFileDialog>
48 #include <QInputDialog>
49 #include <QFileSystemModel>
50 #include <QDesktopServices>
52 #include <QPlastiqueStyle>
53 #include <QCleanlooksStyle>
54 #include <QWindowsVistaStyle>
55 #include <QWindowsStyle>
57 #include <QDragEnterEvent>
58 #include <QWindowsMime>
61 #include <QProcessEnvironment>
62 #include <QCryptographicHash>
63 #include <QTranslator>
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 ////////////////////////////////////////////////////////////
80 ////////////////////////////////////////////////////////////
82 MainWindow::MainWindow(FileListModel *fileListModel, AudioFileModel *metaInfo, SettingsModel *settingsModel, QWidget *parent)
85 m_fileListModel(fileListModel),
87 m_settings(settingsModel),
89 m_firstTimeShown(true)
91 //Init the dialog, from the .ui file
93 setWindowFlags(windowFlags() ^ Qt::WindowMaximizeButtonHint);
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()));
104 tabWidget->setCurrentIndex(0);
105 connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabPageChanged(int)));
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()));
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 m_metaInfoModel->setData(m_metaInfoModel->index(4, 1), m_settings->metaInfoPosition());
172 metaDataView->setModel(m_metaInfoModel);
173 metaDataView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
174 metaDataView->verticalHeader()->hide();
175 metaDataView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
176 while(writeMetaDataCheckBox->isChecked() != m_settings->writeMetaTags()) writeMetaDataCheckBox->click();
177 generatePlaylistCheckBox->setChecked(m_settings->createPlaylist());
178 connect(buttonEditMeta, SIGNAL(clicked()), this, SLOT(editMetaButtonClicked()));
179 connect(buttonClearMeta, SIGNAL(clicked()), this, SLOT(clearMetaButtonClicked()));
180 connect(writeMetaDataCheckBox, SIGNAL(clicked()), this, SLOT(metaTagsEnabledChanged()));
181 connect(generatePlaylistCheckBox, SIGNAL(clicked()), this, SLOT(playlistEnabledChanged()));
183 //Setup "Compression" tab
184 m_encoderButtonGroup = new QButtonGroup(this);
185 m_encoderButtonGroup->addButton(radioButtonEncoderMP3, SettingsModel::MP3Encoder);
186 m_encoderButtonGroup->addButton(radioButtonEncoderVorbis, SettingsModel::VorbisEncoder);
187 m_encoderButtonGroup->addButton(radioButtonEncoderAAC, SettingsModel::AACEncoder);
188 m_encoderButtonGroup->addButton(radioButtonEncoderFLAC, SettingsModel::FLACEncoder);
189 m_encoderButtonGroup->addButton(radioButtonEncoderPCM, SettingsModel::PCMEncoder);
190 m_modeButtonGroup = new QButtonGroup(this);
191 m_modeButtonGroup->addButton(radioButtonModeQuality, SettingsModel::VBRMode);
192 m_modeButtonGroup->addButton(radioButtonModeAverageBitrate, SettingsModel::ABRMode);
193 m_modeButtonGroup->addButton(radioButtonConstBitrate, SettingsModel::CBRMode);
194 radioButtonEncoderMP3->setChecked(m_settings->compressionEncoder() == SettingsModel::MP3Encoder);
195 radioButtonEncoderVorbis->setChecked(m_settings->compressionEncoder() == SettingsModel::VorbisEncoder);
196 radioButtonEncoderAAC->setChecked(m_settings->compressionEncoder() == SettingsModel::AACEncoder);
197 radioButtonEncoderFLAC->setChecked(m_settings->compressionEncoder() == SettingsModel::FLACEncoder);
198 radioButtonEncoderPCM->setChecked(m_settings->compressionEncoder() == SettingsModel::PCMEncoder);
199 radioButtonModeQuality->setChecked(m_settings->compressionRCMode() == SettingsModel::VBRMode);
200 radioButtonModeAverageBitrate->setChecked(m_settings->compressionRCMode() == SettingsModel::ABRMode);
201 radioButtonConstBitrate->setChecked(m_settings->compressionRCMode() == SettingsModel::CBRMode);
202 sliderBitrate->setValue(m_settings->compressionBitrate());
203 connect(m_encoderButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateEncoder(int)));
204 connect(m_modeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateRCMode(int)));
205 connect(sliderBitrate, SIGNAL(valueChanged(int)), this, SLOT(updateBitrate(int)));
206 updateEncoder(m_encoderButtonGroup->checkedId());
208 //Setup "Advanced Options" tab
209 sliderLameAlgoQuality->setValue(m_settings->lameAlgoQuality());
210 spinBoxBitrateManagementMin->setValue(m_settings->bitrateManagementMinRate());
211 spinBoxBitrateManagementMax->setValue(m_settings->bitrateManagementMaxRate());
212 spinBoxNormalizationFilter->setValue(static_cast<double>(m_settings->normalizationFilterMaxVolume()) / 100.0);
213 spinBoxToneAdjustBass->setValue(static_cast<double>(m_settings->toneAdjustBass()) / 100.0);
214 spinBoxToneAdjustTreble->setValue(static_cast<double>(m_settings->toneAdjustTreble()) / 100.0);
215 comboBoxMP3ChannelMode->setCurrentIndex(m_settings->lameChannelMode());
216 comboBoxSamplingRate->setCurrentIndex(m_settings->samplingRate());
217 comboBoxNeroAACProfile->setCurrentIndex(m_settings->neroAACProfile());
218 while(checkBoxBitrateManagement->isChecked() != m_settings->bitrateManagementEnabled()) checkBoxBitrateManagement->click();
219 while(checkBoxNeroAAC2PassMode->isChecked() != m_settings->neroAACEnable2Pass()) checkBoxNeroAAC2PassMode->click();
220 while(checkBoxNormalizationFilter->isChecked() != m_settings->normalizationFilterEnabled()) checkBoxNormalizationFilter->click();
221 lineEditCustomParamLAME->setText(m_settings->customParametersLAME());
222 lineEditCustomParamOggEnc->setText(m_settings->customParametersOggEnc());
223 lineEditCustomParamNeroAAC->setText(m_settings->customParametersNeroAAC());
224 lineEditCustomParamFLAC->setText(m_settings->customParametersFLAC());
225 connect(sliderLameAlgoQuality, SIGNAL(valueChanged(int)), this, SLOT(updateLameAlgoQuality(int)));
226 connect(checkBoxBitrateManagement, SIGNAL(clicked(bool)), this, SLOT(bitrateManagementEnabledChanged(bool)));
227 connect(spinBoxBitrateManagementMin, SIGNAL(valueChanged(int)), this, SLOT(bitrateManagementMinChanged(int)));
228 connect(spinBoxBitrateManagementMax, SIGNAL(valueChanged(int)), this, SLOT(bitrateManagementMaxChanged(int)));
229 connect(comboBoxMP3ChannelMode, SIGNAL(currentIndexChanged(int)), this, SLOT(channelModeChanged(int)));
230 connect(comboBoxSamplingRate, SIGNAL(currentIndexChanged(int)), this, SLOT(samplingRateChanged(int)));
231 connect(checkBoxNeroAAC2PassMode, SIGNAL(clicked(bool)), this, SLOT(neroAAC2PassChanged(bool)));
232 connect(comboBoxNeroAACProfile, SIGNAL(currentIndexChanged(int)), this, SLOT(neroAACProfileChanged(int)));
233 connect(checkBoxNormalizationFilter, SIGNAL(clicked(bool)), this, SLOT(normalizationEnabledChanged(bool)));
234 connect(spinBoxNormalizationFilter, SIGNAL(valueChanged(double)), this, SLOT(normalizationMaxVolumeChanged(double)));
235 connect(spinBoxToneAdjustBass, SIGNAL(valueChanged(double)), this, SLOT(toneAdjustBassChanged(double)));
236 connect(spinBoxToneAdjustTreble, SIGNAL(valueChanged(double)), this, SLOT(toneAdjustTrebleChanged(double)));
237 connect(buttonToneAdjustReset, SIGNAL(clicked()), this, SLOT(toneAdjustTrebleReset()));
238 connect(lineEditCustomParamLAME, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
239 connect(lineEditCustomParamOggEnc, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
240 connect(lineEditCustomParamNeroAAC, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
241 connect(lineEditCustomParamFLAC, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
242 connect(buttonResetAdvancedOptions, SIGNAL(clicked()), this, SLOT(resetAdvancedOptionsButtonClicked()));
243 updateLameAlgoQuality(sliderLameAlgoQuality->value());
244 toneAdjustTrebleChanged(spinBoxToneAdjustTreble->value());
245 toneAdjustBassChanged(spinBoxToneAdjustBass->value());
246 customParamsChanged();
248 //Activate file menu actions
249 connect(actionOpenFolder, SIGNAL(triggered()), this, SLOT(openFolderActionActivated()));
251 //Activate view menu actions
252 m_tabActionGroup = new QActionGroup(this);
253 m_tabActionGroup->addAction(actionSourceFiles);
254 m_tabActionGroup->addAction(actionOutputDirectory);
255 m_tabActionGroup->addAction(actionCompression);
256 m_tabActionGroup->addAction(actionMetaData);
257 m_tabActionGroup->addAction(actionAdvancedOptions);
258 actionSourceFiles->setData(0);
259 actionOutputDirectory->setData(1);
260 actionMetaData->setData(2);
261 actionCompression->setData(3);
262 actionAdvancedOptions->setData(4);
263 actionSourceFiles->setChecked(true);
264 connect(m_tabActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(tabActionActivated(QAction*)));
266 //Activate style menu actions
267 m_styleActionGroup = new QActionGroup(this);
268 m_styleActionGroup->addAction(actionStylePlastique);
269 m_styleActionGroup->addAction(actionStyleCleanlooks);
270 m_styleActionGroup->addAction(actionStyleWindowsVista);
271 m_styleActionGroup->addAction(actionStyleWindowsXP);
272 m_styleActionGroup->addAction(actionStyleWindowsClassic);
273 actionStylePlastique->setData(0);
274 actionStyleCleanlooks->setData(1);
275 actionStyleWindowsVista->setData(2);
276 actionStyleWindowsXP->setData(3);
277 actionStyleWindowsClassic->setData(4);
278 actionStylePlastique->setChecked(true);
279 actionStyleWindowsXP->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_XP && lamexp_themes_enabled());
280 actionStyleWindowsVista->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_VISTA && lamexp_themes_enabled());
281 connect(m_styleActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(styleActionActivated(QAction*)));
282 styleActionActivated(NULL);
284 //Populate the language menu
285 m_languageActionGroup = new QActionGroup(this);
286 QStringList translations = lamexp_query_translations();
287 while(!translations.isEmpty())
289 QString langId = translations.takeFirst();
290 QAction *currentLanguage = new QAction(this);
291 currentLanguage->setData(langId);
292 currentLanguage->setText(lamexp_translation_name(langId));
293 currentLanguage->setIcon(QIcon(QString(":/flags/%1.png").arg(langId)));
294 currentLanguage->setCheckable(true);
295 m_languageActionGroup->addAction(currentLanguage);
296 menuLanguage->insertAction(actionLoadTranslationFromFile, currentLanguage);
298 menuLanguage->insertSeparator(actionLoadTranslationFromFile);
299 connect(actionLoadTranslationFromFile, SIGNAL(triggered(bool)), this, SLOT(languageFromFileActionActivated(bool)));
300 connect(m_languageActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(languageActionActivated(QAction*)));
302 //Activate tools menu actions
303 actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
304 actionDisableSounds->setChecked(!m_settings->soundsEnabled());
305 actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
306 actionDisableWmaDecoderNotifications->setChecked(!m_settings->wmaDecoderNotificationsEnabled());
307 actionDisableShellIntegration->setChecked(!m_settings->shellIntegrationEnabled());
308 actionDisableShellIntegration->setDisabled(lamexp_portable_mode() && actionDisableShellIntegration->isChecked());
309 connect(actionDisableUpdateReminder, SIGNAL(triggered(bool)), this, SLOT(disableUpdateReminderActionTriggered(bool)));
310 connect(actionDisableSounds, SIGNAL(triggered(bool)), this, SLOT(disableSoundsActionTriggered(bool)));
311 connect(actionInstallWMADecoder, SIGNAL(triggered(bool)), this, SLOT(installWMADecoderActionTriggered(bool)));
312 connect(actionDisableNeroAacNotifications, SIGNAL(triggered(bool)), this, SLOT(disableNeroAacNotificationsActionTriggered(bool)));
313 connect(actionDisableWmaDecoderNotifications, SIGNAL(triggered(bool)), this, SLOT(disableWmaDecoderNotificationsActionTriggered(bool)));
314 connect(actionDisableShellIntegration, SIGNAL(triggered(bool)), this, SLOT(disableShellIntegrationActionTriggered(bool)));
315 connect(actionShowDropBoxWidget, SIGNAL(triggered(bool)), this, SLOT(showDropBoxWidgetActionTriggered(bool)));
317 //Activate help menu actions
318 connect(actionCheckUpdates, SIGNAL(triggered()), this, SLOT(checkUpdatesActionActivated()));
319 connect(actionVisitHomepage, SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
321 //Center window in screen
322 QRect desktopRect = QApplication::desktop()->screenGeometry();
323 QRect thisRect = this->geometry();
324 move((desktopRect.width() - thisRect.width()) / 2, (desktopRect.height() - thisRect.height()) / 2);
325 setMinimumSize(thisRect.width(), thisRect.height());
328 m_banner = new WorkingBanner(this);
330 //Create DropBox widget
331 m_dropBox = new DropBox(this, m_fileListModel, m_settings);
332 connect(m_fileListModel, SIGNAL(modelReset()), m_dropBox, SLOT(modelChanged()));
333 connect(m_fileListModel, SIGNAL(rowsInserted(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
334 connect(m_fileListModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
336 //Create message handler thread
337 m_messageHandler = new MessageHandlerThread();
338 m_delayedFileList = new QStringList();
339 m_delayedFileTimer = new QTimer();
340 connect(m_messageHandler, SIGNAL(otherInstanceDetected()), this, SLOT(notifyOtherInstance()), Qt::QueuedConnection);
341 connect(m_messageHandler, SIGNAL(fileReceived(QString)), this, SLOT(addFileDelayed(QString)), Qt::QueuedConnection);
342 connect(m_messageHandler, SIGNAL(killSignalReceived()), this, SLOT(close()), Qt::QueuedConnection);
343 connect(m_delayedFileTimer, SIGNAL(timeout()), this, SLOT(handleDelayedFiles()));
344 m_messageHandler->start();
346 //Load translation file
347 QList<QAction*> languageActions = m_languageActionGroup->actions();
348 while(!languageActions.isEmpty())
350 QAction *currentLanguage = languageActions.takeFirst();
351 if(currentLanguage->data().toString().compare(m_settings->currentLanguage(), Qt::CaseInsensitive) == 0)
353 currentLanguage->setChecked(true);
354 languageActionActivated(currentLanguage);
358 //Re-translate (make sure we translate once)
359 QEvent languageChangeEvent(QEvent::LanguageChange);
360 changeEvent(&languageChangeEvent);
363 this->setAcceptDrops(true);
366 ////////////////////////////////////////////////////////////
368 ////////////////////////////////////////////////////////////
370 MainWindow::~MainWindow(void)
372 //Stop message handler thread
373 if(m_messageHandler && m_messageHandler->isRunning())
375 m_messageHandler->stop();
376 if(!m_messageHandler->wait(10000))
378 m_messageHandler->terminate();
379 m_messageHandler->wait();
384 sourceFileView->setModel(NULL);
385 metaDataView->setModel(NULL);
388 LAMEXP_DELETE(m_tabActionGroup);
389 LAMEXP_DELETE(m_styleActionGroup);
390 LAMEXP_DELETE(m_languageActionGroup);
391 LAMEXP_DELETE(m_banner);
392 LAMEXP_DELETE(m_fileSystemModel);
393 LAMEXP_DELETE(m_messageHandler);
394 LAMEXP_DELETE(m_delayedFileList);
395 LAMEXP_DELETE(m_delayedFileTimer);
396 LAMEXP_DELETE(m_metaInfoModel);
397 LAMEXP_DELETE(m_encoderButtonGroup);
398 LAMEXP_DELETE(m_encoderButtonGroup);
399 LAMEXP_DELETE(m_sourceFilesContextMenu);
400 LAMEXP_DELETE(m_dropBox);
403 ////////////////////////////////////////////////////////////
405 ////////////////////////////////////////////////////////////
408 * Add file to source list
410 void MainWindow::addFiles(const QStringList &files)
417 tabWidget->setCurrentIndex(0);
419 FileAnalyzer *analyzer = new FileAnalyzer(files);
420 connect(analyzer, SIGNAL(fileSelected(QString)), m_banner, SLOT(setText(QString)), Qt::QueuedConnection);
421 connect(analyzer, SIGNAL(fileAnalyzed(AudioFileModel)), m_fileListModel, SLOT(addFile(AudioFileModel)), Qt::QueuedConnection);
423 m_banner->show(tr("Adding file(s), please wait..."), analyzer);
425 if(analyzer->filesDenied())
427 QMessageBox::warning(this, tr("Access Denied"), QString("<nobr>%1<br>%2</nobr>").arg(tr("%1 file(s) have been rejected, because read access was not granted!").arg(analyzer->filesDenied()), tr("This usually means the file is locked by another process.")));
429 if(analyzer->filesRejected())
431 QMessageBox::warning(this, tr("Files Rejected"), QString("<nobr>%1<br>%2</nobr>").arg(tr("%1 file(s) have been rejected, because the file format could not be recognized!").arg(analyzer->filesRejected()), tr("This usually means the file is damaged or the file format is not supported.")));
434 LAMEXP_DELETE(analyzer);
435 sourceFileView->scrollToBottom();
440 * Download and install WMA Decoder component
442 bool MainWindow::installWMADecoder(void)
444 static const char *download_url = "http://www.nch.com.au/components/wmawav.exe";
445 static const char *download_hash = "52a3b0e6690faf3f830c336d3c0eadfb7a4e9bc6";
447 bool bResult = false;
449 QString binaryWGet = lamexp_lookup_tool("wget.exe");
450 QString binaryElevator = lamexp_lookup_tool("elevator.exe");
452 if(binaryWGet.isEmpty() || binaryElevator.isEmpty())
454 throw "Required binary is not available!";
459 QString setupFile = QString("%1/%2.exe").arg(lamexp_temp_folder(), lamexp_rand_str());
462 process.setWorkingDirectory(QFileInfo(setupFile).absolutePath());
465 connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
466 connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), &loop, SLOT(quit()));
468 process.start(binaryWGet, QStringList() << "-O" << QFileInfo(setupFile).fileName() << download_url);
469 m_banner->show(tr("Downloading WMA Decoder Setup, please wait..."), &loop);
471 if(process.exitCode() != 0 || QFileInfo(setupFile).size() < 10240)
473 QFile::remove(setupFile);
474 if(QMessageBox::critical(this, tr("Download Failed"), tr("Failed to download the WMA Decoder setup. Check your internet connection!"), tr("Try Again"), tr("Cancel")) == 0)
481 QFile setupFileContent(setupFile);
482 QCryptographicHash setupFileHash(QCryptographicHash::Sha1);
484 setupFileContent.open(QIODevice::ReadOnly);
485 if(setupFileContent.isOpen() && setupFileContent.isReadable())
487 setupFileHash.addData(setupFileContent.readAll());
488 setupFileContent.close();
491 if(_stricmp(setupFileHash.result().toHex().constData(), download_hash))
493 qWarning("Hash miscompare:\n Expected %s\n Detected %s\n", download_hash, setupFileHash.result().toHex().constData());
494 QFile::remove(setupFile);
495 if(QMessageBox::critical(this, tr("Download Failed"), tr("The download seems to be corrupted. Please try again!"), tr("Try Again"), tr("Cancel")) == 0)
502 QApplication::setOverrideCursor(Qt::WaitCursor);
503 process.start(binaryElevator, QStringList() << QString("/exec=%1").arg(setupFile));
504 loop.exec(QEventLoop::ExcludeUserInputEvents);
505 QFile::remove(setupFile);
506 QApplication::restoreOverrideCursor();
508 if(QMessageBox::information(this, tr("WMA Decoder"), tr("The WMA File Decoder has been installed. Please restart LameXP now!"), tr("Quit LameXP"), tr("Postpone")) == 0)
521 bool MainWindow::checkForUpdates(void)
523 bool bReadyToInstall = false;
525 UpdateDialog *updateDialog = new UpdateDialog(m_settings, this);
526 updateDialog->exec();
528 if(updateDialog->getSuccess())
530 m_settings->autoUpdateLastCheck(QDate::currentDate().toString(Qt::ISODate));
531 bReadyToInstall = updateDialog->updateReadyToInstall();
534 LAMEXP_DELETE(updateDialog);
535 return bReadyToInstall;
538 ////////////////////////////////////////////////////////////
540 ////////////////////////////////////////////////////////////
543 * Window is about to be shown
545 void MainWindow::showEvent(QShowEvent *event)
548 m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
549 sourceModelChanged();
550 tabWidget->setCurrentIndex(0);
554 m_firstTimeShown = false;
555 QTimer::singleShot(0, this, SLOT(windowShown()));
559 if(m_settings->dropBoxWidgetEnabled())
561 m_dropBox->setVisible(true);
567 * Re-translate the UI
569 void MainWindow::changeEvent(QEvent *e)
571 if(e->type() == QEvent::LanguageChange)
573 int comboBoxIndex[3];
575 //Backup combobox indices, as retranslateUi() resets
576 comboBoxIndex[0] = comboBoxMP3ChannelMode->currentIndex();
577 comboBoxIndex[1] = comboBoxSamplingRate->currentIndex();
578 comboBoxIndex[2] = comboBoxNeroAACProfile->currentIndex();
580 //Re-translate from UIC
581 Ui::MainWindow::retranslateUi(this);
583 //Restore combobox indices
584 comboBoxMP3ChannelMode->setCurrentIndex(comboBoxIndex[0]);
585 comboBoxSamplingRate->setCurrentIndex(comboBoxIndex[1]);
586 comboBoxNeroAACProfile->setCurrentIndex(comboBoxIndex[2]);
588 if(lamexp_version_demo())
590 setWindowTitle(QString("%1 [%2]").arg(windowTitle(), tr("DEMO VERSION")));
593 //Manually re-translate widgets that UIC doesn't handle
594 m_dropNoteLabel->setText(QString("» %1 «").arg(tr("You can drop in audio files here!")));
595 m_showDetailsContextAction->setText(tr("Show Details"));
596 m_previewContextAction->setText(tr("Open File in External Application"));
597 m_findFileContextAction->setText(tr("Browse File Location"));
598 m_showFolderContextAction->setText(tr("Browse Selected Folder"));
601 m_metaInfoModel->clearData();
602 m_metaInfoModel->setData(m_metaInfoModel->index(4, 1), m_settings->metaInfoPosition());
603 updateEncoder(m_settings->compressionEncoder());
604 updateLameAlgoQuality(sliderLameAlgoQuality->value());
606 //Re-install shell integration
607 if(m_settings->shellIntegrationEnabled())
609 ShellIntegration::install();
615 * File dragged over window
617 void MainWindow::dragEnterEvent(QDragEnterEvent *event)
619 QStringList formats = event->mimeData()->formats();
621 if(formats.contains("application/x-qt-windows-mime;value=\"FileNameW\"", Qt::CaseInsensitive) && formats.contains("text/uri-list", Qt::CaseInsensitive))
623 event->acceptProposedAction();
628 * File dropped onto window
630 void MainWindow::dropEvent(QDropEvent *event)
634 QStringList droppedFiles;
635 const QList<QUrl> urls = event->mimeData()->urls();
637 for(int i = 0; i < urls.count(); i++)
639 QFileInfo file(urls.at(i).toLocalFile());
646 droppedFiles << file.canonicalFilePath();
651 QList<QFileInfo> list = QDir(file.canonicalFilePath()).entryInfoList(QDir::Files);
652 for(int j = 0; j < list.count(); j++)
654 droppedFiles << list.at(j).canonicalFilePath();
659 addFiles(droppedFiles);
663 * Window tries to close
665 void MainWindow::closeEvent(QCloseEvent *event)
667 if(m_banner->isVisible() || m_delayedFileTimer->isActive())
669 MessageBeep(MB_ICONEXCLAMATION);
682 void MainWindow::resizeEvent(QResizeEvent *event)
684 QMainWindow::resizeEvent(event);
685 m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
691 bool MainWindow::eventFilter(QObject *obj, QEvent *event)
693 if(obj == m_fileSystemModel && QApplication::overrideCursor() == NULL)
695 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
696 QTimer::singleShot(250, this, SLOT(restoreCursor()));
698 else if(obj == outputFolderLabel)
700 switch(event->type())
702 case QEvent::MouseButtonPress:
703 if(dynamic_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)
705 QDesktopServices::openUrl(QString("file:///%1").arg(outputFolderLabel->text()));
709 outputFolderLabel->setForegroundRole(QPalette::Link);
712 outputFolderLabel->setForegroundRole(QPalette::WindowText);
719 ////////////////////////////////////////////////////////////
721 ////////////////////////////////////////////////////////////
726 void MainWindow::windowShown(void)
728 QStringList arguments = QApplication::arguments();
731 if(m_settings->licenseAccepted() <= 0)
735 if(m_settings->licenseAccepted() == 0)
737 AboutDialog *about = new AboutDialog(m_settings, this, true);
738 iAccepted = about->exec();
739 LAMEXP_DELETE(about);
744 m_settings->licenseAccepted(-1);
745 QApplication::processEvents();
746 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
747 QMessageBox::critical(this, tr("License Declined"), tr("You have declined the license. Consequently the application will exit now!"), tr("Goodbye!"));
748 QProcess::startDetached(QString("%1/Uninstall.exe").arg(QApplication::applicationDirPath()), QStringList());
749 QApplication::quit();
753 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WOOHOO), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
754 m_settings->licenseAccepted(1);
757 //Check for expiration
758 if(lamexp_version_demo())
760 if(QDate::currentDate() >= lamexp_version_expires())
762 qWarning("Binary has expired !!!");
763 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
764 if(QMessageBox::warning(this, tr("LameXP - Expired"), QString("<nobr>%1<br>%2</nobr>").arg(tr("This demo (pre-release) version of LameXP has expired at %1.").arg(lamexp_version_expires().toString(Qt::ISODate)), tr("LameXP is free software and release versions won't expire.")), tr("Check for Updates"), tr("Exit Program")) == 0)
768 QApplication::quit();
774 if(QDate::currentDate() >= lamexp_version_date().addYears(1))
776 qWarning("Binary is more than a year old, time to update!");
777 if(QMessageBox::warning(this, tr("Urgent Update"), QString("<nobr>%1</nobr>").arg(tr("Your version of LameXP is more than a year old. Time for an update!")), tr("Check for Updates"), tr("Exit Program")) == 0)
779 if(checkForUpdates())
781 QApplication::quit();
787 QApplication::quit();
791 else if(m_settings->autoUpdateEnabled())
793 QDate lastUpdateCheck = QDate::fromString(m_settings->autoUpdateLastCheck(), Qt::ISODate);
794 if(!lastUpdateCheck.isValid() || QDate::currentDate() >= lastUpdateCheck.addDays(14))
796 if(QMessageBox::information(this, tr("Update Reminder"), QString("<nobr>%1</nobr>").arg(lastUpdateCheck.isValid() ? tr("Your last update check was more than 14 days ago. Check for updates now?") : tr("Your did not check for LameXP updates yet. Check for updates now?")), tr("Check for Updates"), tr("Postpone")) == 0)
798 if(checkForUpdates())
800 QApplication::quit();
807 //Check for AAC support
808 if(m_settings->neroAacNotificationsEnabled())
810 if(lamexp_check_tool("neroAacEnc.exe") && lamexp_check_tool("neroAacDec.exe") && lamexp_check_tool("neroAacTag.exe"))
812 if(lamexp_tool_version("neroAacEnc.exe") < lamexp_toolver_neroaac())
815 messageText += QString("<nobr>%1<br>").arg(tr("LameXP detected that your version of the Nero AAC encoder is outdated!"));
816 messageText += QString("%1<br><br>").arg(tr("The current version available is %1 (or later), but you still have version %2 installed.").arg(lamexp_version2string("?.?.?.?", lamexp_toolver_neroaac(), tr("n/a")), lamexp_version2string("?.?.?.?", lamexp_tool_version("neroAacEnc.exe"), tr("n/a"))));
817 messageText += QString("%1<br>").arg(tr("You can download the latest version of the Nero AAC encoder from the Nero website at:"));
818 messageText += "<tt>" + LINK(AboutDialog::neroAacUrl) + "</tt><br></nobr>";
819 QMessageBox::information(this, tr("AAC Encoder Outdated"), messageText);
824 radioButtonEncoderAAC->setEnabled(false);
825 QString appPath = QDir(QCoreApplication::applicationDirPath()).canonicalPath();
826 if(appPath.isEmpty()) appPath = QCoreApplication::applicationDirPath();
828 messageText += QString("<nobr>%1<br>").arg(tr("The Nero AAC encoder could not be found. AAC encoding support will be disabled."));
829 messageText += QString("%1<br><br>").arg(tr("Please put 'neroAacEnc.exe', 'neroAacDec.exe' and 'neroAacTag.exe' into the LameXP directory!"));
830 messageText += QString("%1<br>").arg(tr("Your LameXP directory is located here:"));
831 messageText += QString("<i><nobr><a href=\"file:///%1\">%1</a></nobr></i><br><br>").arg(QDir::toNativeSeparators(appPath));
832 messageText += QString("%1<br>").arg(tr("You can download the Nero AAC encoder for free from the official Nero website at:"));
833 messageText += "<tt>" + LINK(AboutDialog::neroAacUrl) + "</tt><br></nobr>";
834 QMessageBox::information(this, tr("AAC Support Disabled"), messageText);
838 //Check for WMA support
839 if(m_settings->wmaDecoderNotificationsEnabled())
841 if(!lamexp_check_tool("wmawav.exe"))
844 messageText += QString("<nobr>%1<br>").arg(tr("LameXP has detected that the WMA File Decoder component is not currently installed on your system."));
845 messageText += QString("%1<br><br>").arg(tr("You won't be able to process WMA files as input unless the WMA File Decoder component is installed!"));
846 messageText += QString("%1</nobr>").arg(tr("Do you want to download and install the WMA File Decoder component now?"));
847 if(QMessageBox::information(this, tr("WMA Decoder Missing"), messageText, tr("Download && Install"), tr("Postpone")) == 0)
849 if(installWMADecoder())
851 QApplication::quit();
858 //Add files from the command-line
859 for(int i = 0; i < arguments.count() - 1; i++)
861 if(!arguments[i].compare("--add", Qt::CaseInsensitive))
863 QFileInfo currentFile(arguments[++i].trimmed());
864 qDebug("Adding file from CLI: %s", currentFile.canonicalFilePath().toUtf8().constData());
865 m_delayedFileList->append(currentFile.canonicalFilePath());
869 //Start delayed files timer
870 if(!m_delayedFileList->isEmpty() && !m_delayedFileTimer->isActive())
872 m_delayedFileTimer->start(5000);
875 //Enable shell integration
876 if(m_settings->shellIntegrationEnabled())
878 ShellIntegration::install();
881 //Make DropBox visible
882 if(m_settings->dropBoxWidgetEnabled())
884 m_dropBox->setVisible(true);
891 void MainWindow::aboutButtonClicked(void)
897 AboutDialog *aboutBox = new AboutDialog(m_settings, this);
899 LAMEXP_DELETE(aboutBox);
906 void MainWindow::encodeButtonClicked(void)
908 static const __int64 oneGigabyte = 1073741824;
909 static const __int64 minimumFreeDiskspaceMultiplier = 2;
913 if(m_fileListModel->rowCount() < 1)
915 QMessageBox::warning(this, tr("LameXP"), QString("<nobr>%1</nobr>").arg(tr("You must add at least one file to the list before proceeding!")));
916 tabWidget->setCurrentIndex(0);
920 __int64 currentFreeDiskspace = lamexp_free_diskspace(lamexp_temp_folder());
922 if(currentFreeDiskspace < (oneGigabyte * minimumFreeDiskspaceMultiplier))
924 QStringList tempFolderParts = lamexp_temp_folder().split("/", QString::SkipEmptyParts, Qt::CaseInsensitive);
925 tempFolderParts.takeLast();
926 if(m_settings->soundsEnabled()) PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
927 switch(QMessageBox::warning(this, tr("Low Diskspace Warning"), QString("<nobr>%1</nobr><br><nobr>%2</nobr><br><br>%3").arg(tr("There are less than %1 GB of free diskspace available on your system's TEMP folder.").arg(QString::number(minimumFreeDiskspaceMultiplier)), tr("It is highly recommend to free up more diskspace before proceeding with the encode!"), tr("Your TEMP folder is located at:")).append("<br><nobr><i><a href=\"file:///%3\">%3</a></i></nobr><br>").arg(tempFolderParts.join("\\")), tr("Abort Encoding Process"), tr("Clean Disk Now"), tr("Ignore")))
930 QProcess::startDetached(QString("%1/cleanmgr.exe").arg(lamexp_known_folder(lamexp_folder_systemfolder)), QStringList() << "/D" << tempFolderParts.first());
935 QMessageBox::warning(this, tr("Low Diskspace"), tr("You are proceeding with low diskspace. Problems might occur!"));
940 switch(m_settings->compressionEncoder())
942 case SettingsModel::MP3Encoder:
943 case SettingsModel::VorbisEncoder:
944 case SettingsModel::AACEncoder:
945 case SettingsModel::FLACEncoder:
946 case SettingsModel::PCMEncoder:
949 QMessageBox::warning(this, tr("LameXP"), tr("Sorry, an unsupported encoder has been chosen!"));
950 tabWidget->setCurrentIndex(3);
954 if(!m_settings->outputToSourceDir())
956 QFile writeTest(QString("%1/~%2.txt").arg(m_settings->outputDir(), QUuid::createUuid().toString()));
957 if(!writeTest.open(QIODevice::ReadWrite))
959 QMessageBox::warning(this, tr("LameXP"), QString("%1<br><nobr>%2</nobr><br><br>%3").arg(tr("Cannot write to the selected output directory."), m_settings->outputDir(), tr("Please choose a different directory!")));
960 tabWidget->setCurrentIndex(1);
977 void MainWindow::closeButtonClicked(void)
986 void MainWindow::addFilesButtonClicked(void)
992 if(lamexp_themes_enabled())
994 QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
995 QStringList selectedFiles = QFileDialog::getOpenFileNames(this, tr("Add file(s)"), QString(), fileTypeFilters.join(";;"));
996 if(!selectedFiles.isEmpty())
998 addFiles(selectedFiles);
1003 QFileDialog dialog(this, tr("Add file(s)"));
1004 QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
1005 dialog.setFileMode(QFileDialog::ExistingFiles);
1006 dialog.setNameFilter(fileTypeFilters.join(";;"));
1009 QStringList selectedFiles = dialog.selectedFiles();
1010 addFiles(selectedFiles);
1017 * Open folder action
1019 void MainWindow::openFolderActionActivated(void)
1022 QString selectedFolder;
1026 if(lamexp_themes_enabled())
1028 selectedFolder = QFileDialog::getExistingDirectory(this, tr("Add folder"), QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
1032 QFileDialog dialog(this, tr("Add folder"));
1033 dialog.setFileMode(QFileDialog::DirectoryOnly);
1034 dialog.setDirectory(QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
1037 selectedFolder = dialog.selectedFiles().first();
1041 if(!selectedFolder.isEmpty())
1043 QDir sourceDir(selectedFolder);
1044 QFileInfoList fileInfoList = sourceDir.entryInfoList(QDir::Files);
1045 QStringList fileList;
1047 while(!fileInfoList.isEmpty())
1049 fileList << fileInfoList.takeFirst().canonicalFilePath();
1058 * Remove file button
1060 void MainWindow::removeFileButtonClicked(void)
1062 if(sourceFileView->currentIndex().isValid())
1064 int iRow = sourceFileView->currentIndex().row();
1065 m_fileListModel->removeFile(sourceFileView->currentIndex());
1066 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
1071 * Clear files button
1073 void MainWindow::clearFilesButtonClicked(void)
1075 m_fileListModel->clearFiles();
1079 * Move file up button
1081 void MainWindow::fileUpButtonClicked(void)
1083 if(sourceFileView->currentIndex().isValid())
1085 int iRow = sourceFileView->currentIndex().row() - 1;
1086 m_fileListModel->moveFile(sourceFileView->currentIndex(), -1);
1087 sourceFileView->selectRow(iRow >= 0 ? iRow : 0);
1092 * Move file down button
1094 void MainWindow::fileDownButtonClicked(void)
1096 if(sourceFileView->currentIndex().isValid())
1098 int iRow = sourceFileView->currentIndex().row() + 1;
1099 m_fileListModel->moveFile(sourceFileView->currentIndex(), 1);
1100 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
1105 * Show details button
1107 void MainWindow::showDetailsButtonClicked(void)
1112 MetaInfoDialog *metaInfoDialog = new MetaInfoDialog(this);
1113 QModelIndex index = sourceFileView->currentIndex();
1115 while(index.isValid())
1119 index = m_fileListModel->index(index.row() + 1, index.column());
1120 sourceFileView->selectRow(index.row());
1124 index = m_fileListModel->index(index.row() - 1, index.column());
1125 sourceFileView->selectRow(index.row());
1128 AudioFileModel &file = (*m_fileListModel)[index];
1129 iResult = metaInfoDialog->exec(file, index.row() > 0, index.row() < m_fileListModel->rowCount() - 1);
1134 LAMEXP_DELETE(metaInfoDialog);
1140 void MainWindow::tabPageChanged(int idx)
1142 QList<QAction*> actions = m_tabActionGroup->actions();
1143 for(int i = 0; i < actions.count(); i++)
1146 int actionIndex = actions.at(i)->data().toInt(&ok);
1147 if(ok && actionIndex == idx)
1149 actions.at(i)->setChecked(true);
1155 * Tab action triggered
1157 void MainWindow::tabActionActivated(QAction *action)
1159 if(action && action->data().isValid())
1162 int index = action->data().toInt(&ok);
1165 tabWidget->setCurrentIndex(index);
1171 * Style action triggered
1173 void MainWindow::styleActionActivated(QAction *action)
1175 //Change style setting
1176 if(action && action->data().isValid())
1179 int actionIndex = action->data().toInt(&ok);
1182 m_settings->interfaceStyle(actionIndex);
1186 //Set up the new style
1187 switch(m_settings->interfaceStyle())
1190 if(actionStyleCleanlooks->isEnabled())
1192 actionStyleCleanlooks->setChecked(true);
1193 QApplication::setStyle(new QCleanlooksStyle());
1197 if(actionStyleWindowsVista->isEnabled())
1199 actionStyleWindowsVista->setChecked(true);
1200 QApplication::setStyle(new QWindowsVistaStyle());
1204 if(actionStyleWindowsXP->isEnabled())
1206 actionStyleWindowsXP->setChecked(true);
1207 QApplication::setStyle(new QWindowsXPStyle());
1211 if(actionStyleWindowsClassic->isEnabled())
1213 actionStyleWindowsClassic->setChecked(true);
1214 QApplication::setStyle(new QWindowsStyle());
1218 actionStylePlastique->setChecked(true);
1219 QApplication::setStyle(new QPlastiqueStyle());
1223 //Force re-translate after style change
1224 changeEvent(new QEvent(QEvent::LanguageChange));
1228 * Language action triggered
1230 void MainWindow::languageActionActivated(QAction *action)
1232 if(action->data().type() == QVariant::String)
1234 QString langId = action->data().toString();
1236 if(lamexp_install_translator(langId))
1238 action->setChecked(true);
1239 m_settings->currentLanguage(langId);
1245 * Load language from file action triggered
1247 void MainWindow::languageFromFileActionActivated(bool checked)
1249 QFileDialog dialog(this, tr("Load Translation"));
1250 dialog.setFileMode(QFileDialog::ExistingFile);
1251 dialog.setNameFilter(QString("%1 (*.qm)").arg(tr("Translation Files")));
1255 QStringList selectedFiles = dialog.selectedFiles();
1256 if(lamexp_install_translator_from_file(selectedFiles.first()))
1258 QList<QAction*> actions = m_languageActionGroup->actions();
1259 while(!actions.isEmpty())
1261 actions.takeFirst()->setChecked(false);
1266 languageActionActivated(m_languageActionGroup->actions().first());
1272 * Output folder changed (mouse clicked)
1274 void MainWindow::outputFolderViewClicked(const QModelIndex &index)
1276 if(outputFolderView->currentIndex() != index)
1278 outputFolderView->setCurrentIndex(index);
1280 QString selectedDir = m_fileSystemModel->filePath(index);
1281 if(selectedDir.length() < 3) selectedDir.append(QDir::separator());
1282 outputFolderLabel->setText(QDir::toNativeSeparators(selectedDir));
1283 m_settings->outputDir(selectedDir);
1287 * Output folder changed (mouse moved)
1289 void MainWindow::outputFolderViewMoved(const QModelIndex &index)
1291 if(QApplication::mouseButtons() & Qt::LeftButton)
1293 outputFolderViewClicked(index);
1298 * Goto desktop button
1300 void MainWindow::gotoDesktopButtonClicked(void)
1302 QString desktopPath = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
1304 if(!desktopPath.isEmpty() && QDir(desktopPath).exists())
1306 outputFolderView->setCurrentIndex(m_fileSystemModel->index(desktopPath));
1307 outputFolderViewClicked(outputFolderView->currentIndex());
1308 outputFolderView->setFocus();
1312 buttonGotoDesktop->setEnabled(false);
1317 * Goto home folder button
1319 void MainWindow::gotoHomeFolderButtonClicked(void)
1321 QString homePath = QDesktopServices::storageLocation(QDesktopServices::HomeLocation);
1323 if(!homePath.isEmpty() && QDir(homePath).exists())
1325 outputFolderView->setCurrentIndex(m_fileSystemModel->index(homePath));
1326 outputFolderViewClicked(outputFolderView->currentIndex());
1327 outputFolderView->setFocus();
1331 buttonGotoHome->setEnabled(false);
1336 * Goto music folder button
1338 void MainWindow::gotoMusicFolderButtonClicked(void)
1340 QString musicPath = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
1342 if(!musicPath.isEmpty() && QDir(musicPath).exists())
1344 outputFolderView->setCurrentIndex(m_fileSystemModel->index(musicPath));
1345 outputFolderViewClicked(outputFolderView->currentIndex());
1346 outputFolderView->setFocus();
1350 buttonGotoMusic->setEnabled(false);
1355 * Make folder button
1357 void MainWindow::makeFolderButtonClicked(void)
1361 QDir basePath(m_fileSystemModel->fileInfo(outputFolderView->currentIndex()).absoluteFilePath());
1362 QString suggestedName = tr("New Folder");
1364 if(!m_metaData->fileArtist().isEmpty() && !m_metaData->fileAlbum().isEmpty())
1366 suggestedName = QString("%1 - %2").arg(m_metaData->fileArtist(), m_metaData->fileAlbum());
1368 else if(!m_metaData->fileArtist().isEmpty())
1370 suggestedName = m_metaData->fileArtist();
1372 else if(!m_metaData->fileAlbum().isEmpty())
1374 suggestedName = m_metaData->fileAlbum();
1378 for(int i = 0; i < m_fileListModel->rowCount(); i++)
1380 AudioFileModel audioFile = m_fileListModel->getFile(m_fileListModel->index(i, 0));
1381 if(!audioFile.fileAlbum().isEmpty() || !audioFile.fileArtist().isEmpty())
1383 if(!audioFile.fileArtist().isEmpty() && !audioFile.fileAlbum().isEmpty())
1385 suggestedName = QString("%1 - %2").arg(audioFile.fileArtist(), audioFile.fileAlbum());
1387 else if(!audioFile.fileArtist().isEmpty())
1389 suggestedName = audioFile.fileArtist();
1391 else if(!audioFile.fileAlbum().isEmpty())
1393 suggestedName = audioFile.fileAlbum();
1402 bool bApplied = false;
1403 QString folderName = QInputDialog::getText(this, tr("New Folder"), tr("Enter the name of the new folder:").leftJustified(96, ' '), QLineEdit::Normal, suggestedName, &bApplied, Qt::WindowStaysOnTopHint).simplified();
1407 folderName.remove(":", Qt::CaseInsensitive);
1408 folderName.remove("/", Qt::CaseInsensitive);
1409 folderName.remove("\\", Qt::CaseInsensitive);
1410 folderName.remove("?", Qt::CaseInsensitive);
1411 folderName.remove("*", Qt::CaseInsensitive);
1412 folderName.remove("<", Qt::CaseInsensitive);
1413 folderName.remove(">", Qt::CaseInsensitive);
1415 folderName = folderName.simplified();
1417 if(folderName.isEmpty())
1419 MessageBeep(MB_ICONERROR);
1424 QString newFolder = folderName;
1426 while(basePath.exists(newFolder))
1428 newFolder = QString(folderName).append(QString().sprintf(" (%d)", ++i));
1431 if(basePath.mkdir(newFolder))
1433 QDir createdDir = basePath;
1434 if(createdDir.cd(newFolder))
1436 outputFolderView->setCurrentIndex(m_fileSystemModel->index(createdDir.canonicalPath()));
1437 outputFolderViewClicked(outputFolderView->currentIndex());
1438 outputFolderView->setFocus();
1443 QMessageBox::warning(this, tr("Failed to create folder"), QString("%1<br><nobr>%2</nobr><br><br>%3").arg(tr("The new folder could not be created:"), basePath.absoluteFilePath(newFolder), tr("Drive is read-only or insufficient access rights!")));
1451 * Edit meta button clicked
1453 void MainWindow::editMetaButtonClicked(void)
1457 const QModelIndex index = metaDataView->currentIndex();
1458 m_metaInfoModel->editItem(index, this);
1460 if(index.row() == 4)
1462 m_settings->metaInfoPosition(m_metaData->filePosition());
1467 * Reset meta button clicked
1469 void MainWindow::clearMetaButtonClicked(void)
1472 m_metaInfoModel->clearData();
1476 * Visit homepage action
1478 void MainWindow::visitHomepageActionActivated(void)
1480 QDesktopServices::openUrl(QUrl("http://mulder.dummwiedeutsch.de/"));
1484 * Check for updates action
1486 void MainWindow::checkUpdatesActionActivated(void)
1493 bFlag = checkForUpdates();
1498 QApplication::quit();
1503 * Other instance detected
1505 void MainWindow::notifyOtherInstance(void)
1507 if(!m_banner->isVisible())
1509 QMessageBox msgBox(QMessageBox::Warning, tr("Already Running"), tr("LameXP is already running, please use the running instance!"), QMessageBox::NoButton, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowStaysOnTopHint);
1515 * Add file from another instance
1517 void MainWindow::addFileDelayed(const QString &filePath)
1519 m_delayedFileTimer->stop();
1520 qDebug("Received file: %s", filePath.toUtf8().constData());
1521 m_delayedFileList->append(filePath);
1522 m_delayedFileTimer->start(5000);
1526 * Add all pending files
1528 void MainWindow::handleDelayedFiles(void)
1530 if(m_banner->isVisible())
1535 m_delayedFileTimer->stop();
1536 if(m_delayedFileList->isEmpty())
1541 QStringList selectedFiles;
1542 tabWidget->setCurrentIndex(0);
1544 while(!m_delayedFileList->isEmpty())
1546 QFileInfo currentFile = QFileInfo(m_delayedFileList->takeFirst());
1547 if(!currentFile.exists())
1551 if(currentFile.isFile())
1553 selectedFiles << currentFile.canonicalFilePath();
1556 if(currentFile.isDir())
1558 QList<QFileInfo> list = QDir(currentFile.canonicalFilePath()).entryInfoList(QDir::Files);
1559 for(int j = 0; j < list.count(); j++)
1561 selectedFiles << list.at(j).canonicalFilePath();
1566 addFiles(selectedFiles);
1572 void MainWindow::updateEncoder(int id)
1574 m_settings->compressionEncoder(id);
1576 switch(m_settings->compressionEncoder())
1578 case SettingsModel::VorbisEncoder:
1579 radioButtonModeQuality->setEnabled(true);
1580 radioButtonModeAverageBitrate->setEnabled(true);
1581 radioButtonConstBitrate->setEnabled(false);
1582 if(radioButtonConstBitrate->isChecked()) radioButtonModeQuality->setChecked(true);
1583 sliderBitrate->setEnabled(true);
1585 case SettingsModel::FLACEncoder:
1586 radioButtonModeQuality->setEnabled(false);
1587 radioButtonModeQuality->setChecked(true);
1588 radioButtonModeAverageBitrate->setEnabled(false);
1589 radioButtonConstBitrate->setEnabled(false);
1590 sliderBitrate->setEnabled(true);
1592 case SettingsModel::PCMEncoder:
1593 radioButtonModeQuality->setEnabled(false);
1594 radioButtonModeQuality->setChecked(true);
1595 radioButtonModeAverageBitrate->setEnabled(false);
1596 radioButtonConstBitrate->setEnabled(false);
1597 sliderBitrate->setEnabled(false);
1600 radioButtonModeQuality->setEnabled(true);
1601 radioButtonModeAverageBitrate->setEnabled(true);
1602 radioButtonConstBitrate->setEnabled(true);
1603 sliderBitrate->setEnabled(true);
1607 updateRCMode(m_modeButtonGroup->checkedId());
1611 * Update rate-control mode
1613 void MainWindow::updateRCMode(int id)
1615 m_settings->compressionRCMode(id);
1617 switch(m_settings->compressionEncoder())
1619 case SettingsModel::MP3Encoder:
1620 switch(m_settings->compressionRCMode())
1622 case SettingsModel::VBRMode:
1623 sliderBitrate->setMinimum(0);
1624 sliderBitrate->setMaximum(9);
1627 sliderBitrate->setMinimum(0);
1628 sliderBitrate->setMaximum(13);
1632 case SettingsModel::VorbisEncoder:
1633 switch(m_settings->compressionRCMode())
1635 case SettingsModel::VBRMode:
1636 sliderBitrate->setMinimum(-2);
1637 sliderBitrate->setMaximum(10);
1640 sliderBitrate->setMinimum(4);
1641 sliderBitrate->setMaximum(63);
1645 case SettingsModel::AACEncoder:
1646 switch(m_settings->compressionRCMode())
1648 case SettingsModel::VBRMode:
1649 sliderBitrate->setMinimum(0);
1650 sliderBitrate->setMaximum(20);
1653 sliderBitrate->setMinimum(4);
1654 sliderBitrate->setMaximum(63);
1658 case SettingsModel::FLACEncoder:
1659 sliderBitrate->setMinimum(0);
1660 sliderBitrate->setMaximum(8);
1662 case SettingsModel::PCMEncoder:
1663 sliderBitrate->setMinimum(0);
1664 sliderBitrate->setMaximum(2);
1665 sliderBitrate->setValue(1);
1668 sliderBitrate->setMinimum(0);
1669 sliderBitrate->setMaximum(0);
1673 updateBitrate(sliderBitrate->value());
1679 void MainWindow::updateBitrate(int value)
1681 m_settings->compressionBitrate(value);
1683 switch(m_settings->compressionRCMode())
1685 case SettingsModel::VBRMode:
1686 switch(m_settings->compressionEncoder())
1688 case SettingsModel::MP3Encoder:
1689 labelBitrate->setText(tr("Quality Level %1").arg(9 - value));
1691 case SettingsModel::VorbisEncoder:
1692 labelBitrate->setText(tr("Quality Level %1").arg(value));
1694 case SettingsModel::AACEncoder:
1695 labelBitrate->setText(tr("Quality Level %1").arg(QString().sprintf("%.2f", static_cast<double>(value * 5) / 100.0)));
1697 case SettingsModel::FLACEncoder:
1698 labelBitrate->setText(tr("Compression %1").arg(value));
1700 case SettingsModel::PCMEncoder:
1701 labelBitrate->setText(tr("Uncompressed"));
1704 labelBitrate->setText(QString::number(value));
1708 case SettingsModel::ABRMode:
1709 switch(m_settings->compressionEncoder())
1711 case SettingsModel::MP3Encoder:
1712 labelBitrate->setText(QString("≈ %1 kbps").arg(SettingsModel::mp3Bitrates[value]));
1714 case SettingsModel::FLACEncoder:
1715 labelBitrate->setText(tr("Compression %1").arg(value));
1717 case SettingsModel::PCMEncoder:
1718 labelBitrate->setText(tr("Uncompressed"));
1721 labelBitrate->setText(QString("≈ %1 kbps").arg(min(500, value * 8)));
1726 switch(m_settings->compressionEncoder())
1728 case SettingsModel::MP3Encoder:
1729 labelBitrate->setText(QString("%1 kbps").arg(SettingsModel::mp3Bitrates[value]));
1731 case SettingsModel::FLACEncoder:
1732 labelBitrate->setText(tr("Compression %1").arg(value));
1734 case SettingsModel::PCMEncoder:
1735 labelBitrate->setText(tr("Uncompressed"));
1738 labelBitrate->setText(QString("%1 kbps").arg(min(500, value * 8)));
1747 * Lame algorithm quality changed
1749 void MainWindow::updateLameAlgoQuality(int value)
1756 text = tr("Best Quality (Very Slow)");
1759 text = tr("High Quality (Recommended)");
1762 text = tr("Average Quality (Default)");
1765 text = tr("Low Quality (Fast)");
1768 text = tr("Poor Quality (Very Fast)");
1774 m_settings->lameAlgoQuality(value);
1775 labelLameAlgoQuality->setText(text);
1780 * Bitrate management endabled/disabled
1782 void MainWindow::bitrateManagementEnabledChanged(bool checked)
1784 m_settings->bitrateManagementEnabled(checked);
1788 * Minimum bitrate has changed
1790 void MainWindow::bitrateManagementMinChanged(int value)
1792 if(value > spinBoxBitrateManagementMax->value())
1794 spinBoxBitrateManagementMin->setValue(spinBoxBitrateManagementMax->value());
1795 m_settings->bitrateManagementMinRate(spinBoxBitrateManagementMax->value());
1799 m_settings->bitrateManagementMinRate(value);
1804 * Maximum bitrate has changed
1806 void MainWindow::bitrateManagementMaxChanged(int value)
1808 if(value < spinBoxBitrateManagementMin->value())
1810 spinBoxBitrateManagementMax->setValue(spinBoxBitrateManagementMin->value());
1811 m_settings->bitrateManagementMaxRate(spinBoxBitrateManagementMin->value());
1815 m_settings->bitrateManagementMaxRate(value);
1820 * Channel mode has changed
1822 void MainWindow::channelModeChanged(int value)
1824 if(value >= 0) m_settings->lameChannelMode(value);
1828 * Sampling rate has changed
1830 void MainWindow::samplingRateChanged(int value)
1832 if(value >= 0) m_settings->samplingRate(value);
1836 * Nero AAC 2-Pass mode changed
1838 void MainWindow::neroAAC2PassChanged(bool checked)
1840 m_settings->neroAACEnable2Pass(checked);
1844 * Nero AAC profile mode changed
1846 void MainWindow::neroAACProfileChanged(int value)
1848 if(value >= 0) m_settings->neroAACProfile(value);
1852 * Normalization filter enabled changed
1854 void MainWindow::normalizationEnabledChanged(bool checked)
1856 m_settings->normalizationFilterEnabled(checked);
1860 * Normalization max. volume changed
1862 void MainWindow::normalizationMaxVolumeChanged(double value)
1864 m_settings->normalizationFilterMaxVolume(static_cast<int>(value * 100.0));
1868 * Tone adjustment has changed (Bass)
1870 void MainWindow::toneAdjustBassChanged(double value)
1872 m_settings->toneAdjustBass(static_cast<int>(value * 100.0));
1873 spinBoxToneAdjustBass->setPrefix((value > 0) ? "+" : QString());
1877 * Tone adjustment has changed (Treble)
1879 void MainWindow::toneAdjustTrebleChanged(double value)
1881 m_settings->toneAdjustTreble(static_cast<int>(value * 100.0));
1882 spinBoxToneAdjustTreble->setPrefix((value > 0) ? "+" : QString());
1886 * Tone adjustment has been reset
1888 void MainWindow::toneAdjustTrebleReset(void)
1890 spinBoxToneAdjustBass->setValue(m_settings->toneAdjustBassDefault());
1891 spinBoxToneAdjustTreble->setValue(m_settings->toneAdjustTrebleDefault());
1892 toneAdjustBassChanged(spinBoxToneAdjustBass->value());
1893 toneAdjustTrebleChanged(spinBoxToneAdjustTreble->value());
1897 * Custom encoder parameters changed
1899 void MainWindow::customParamsChanged(void)
1901 lineEditCustomParamLAME->setText(lineEditCustomParamLAME->text().simplified());
1902 lineEditCustomParamOggEnc->setText(lineEditCustomParamOggEnc->text().simplified());
1903 lineEditCustomParamNeroAAC->setText(lineEditCustomParamNeroAAC->text().simplified());
1904 lineEditCustomParamFLAC->setText(lineEditCustomParamFLAC->text().simplified());
1906 bool customParamsUsed = false;
1907 if(!lineEditCustomParamLAME->text().isEmpty()) customParamsUsed = true;
1908 if(!lineEditCustomParamOggEnc->text().isEmpty()) customParamsUsed = true;
1909 if(!lineEditCustomParamNeroAAC->text().isEmpty()) customParamsUsed = true;
1910 if(!lineEditCustomParamFLAC->text().isEmpty()) customParamsUsed = true;
1912 labelCustomParamsIcon->setVisible(customParamsUsed);
1913 labelCustomParamsText->setVisible(customParamsUsed);
1914 labelCustomParamsSpacer->setVisible(customParamsUsed);
1916 m_settings->customParametersLAME(lineEditCustomParamLAME->text());
1917 m_settings->customParametersOggEnc(lineEditCustomParamOggEnc->text());
1918 m_settings->customParametersNeroAAC(lineEditCustomParamNeroAAC->text());
1919 m_settings->customParametersFLAC(lineEditCustomParamFLAC->text());
1923 * Reset all advanced options to their defaults
1925 void MainWindow::resetAdvancedOptionsButtonClicked(void)
1927 sliderLameAlgoQuality->setValue(m_settings->lameAlgoQualityDefault());
1928 spinBoxBitrateManagementMin->setValue(m_settings->bitrateManagementMinRateDefault());
1929 spinBoxBitrateManagementMax->setValue(m_settings->bitrateManagementMaxRateDefault());
1930 spinBoxNormalizationFilter->setValue(static_cast<double>(m_settings->normalizationFilterMaxVolumeDefault()) / 100.0);
1931 spinBoxToneAdjustBass->setValue(static_cast<double>(m_settings->toneAdjustBassDefault()) / 100.0);
1932 spinBoxToneAdjustTreble->setValue(static_cast<double>(m_settings->toneAdjustTrebleDefault()) / 100.0);
1933 comboBoxMP3ChannelMode->setCurrentIndex(m_settings->lameChannelModeDefault());
1934 comboBoxSamplingRate->setCurrentIndex(m_settings->samplingRateDefault());
1935 comboBoxNeroAACProfile->setCurrentIndex(m_settings->neroAACProfileDefault());
1936 while(checkBoxBitrateManagement->isChecked() != m_settings->bitrateManagementEnabledDefault()) checkBoxBitrateManagement->click();
1937 while(checkBoxNeroAAC2PassMode->isChecked() != m_settings->neroAACEnable2PassDefault()) checkBoxNeroAAC2PassMode->click();
1938 while(checkBoxNormalizationFilter->isChecked() != m_settings->normalizationFilterEnabledDefault()) checkBoxNormalizationFilter->click();
1939 lineEditCustomParamLAME->setText(m_settings->customParametersLAMEDefault());
1940 lineEditCustomParamOggEnc->setText(m_settings->customParametersOggEncDefault());
1941 lineEditCustomParamNeroAAC->setText(m_settings->customParametersNeroAACDefault());
1942 lineEditCustomParamFLAC->setText(m_settings->customParametersFLACDefault());
1943 customParamsChanged();
1944 scrollArea->verticalScrollBar()->setValue(0);
1950 void MainWindow::sourceModelChanged(void)
1952 m_dropNoteLabel->setVisible(m_fileListModel->rowCount() <= 0);
1956 * Meta tags enabled changed
1958 void MainWindow::metaTagsEnabledChanged(void)
1960 m_settings->writeMetaTags(writeMetaDataCheckBox->isChecked());
1964 * Playlist enabled changed
1966 void MainWindow::playlistEnabledChanged(void)
1968 m_settings->createPlaylist(generatePlaylistCheckBox->isChecked());
1972 * Output to source dir changed
1974 void MainWindow::saveToSourceFolderChanged(void)
1976 m_settings->outputToSourceDir(saveToSourceFolderCheckBox->isChecked());
1980 * Prepend relative source file path to output file name changed
1982 void MainWindow::prependRelativePathChanged(void)
1984 m_settings->prependRelativeSourcePath(prependRelativePathCheckBox->isChecked());
1989 * Restore the override cursor
1991 void MainWindow::restoreCursor(void)
1993 QApplication::restoreOverrideCursor();
1997 * Show context menu for source files
1999 void MainWindow::sourceFilesContextMenu(const QPoint &pos)
2001 QAbstractScrollArea *scrollArea = dynamic_cast<QAbstractScrollArea*>(QObject::sender());
2002 QWidget *sender = scrollArea ? scrollArea->viewport() : dynamic_cast<QWidget*>(QObject::sender());
2006 if(pos.x() <= sender->width() && pos.y() <= sender->height() && pos.x() >= 0 && pos.y() >= 0)
2008 m_sourceFilesContextMenu->popup(sender->mapToGlobal(pos));
2014 * Open selected file in external player
2016 void MainWindow::previewContextActionTriggered(void)
2018 const static char *appNames[3] = {"smplayer_portable.exe", "smplayer.exe", "mplayer.exe"};
2019 const static wchar_t *registryKey = L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}";
2021 QModelIndex index = sourceFileView->currentIndex();
2022 if(!index.isValid())
2027 QString mplayerPath;
2028 HKEY registryKeyHandle;
2030 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, registryKey, 0, KEY_READ, ®istryKeyHandle) == ERROR_SUCCESS)
2032 wchar_t Buffer[4096];
2033 DWORD BuffSize = sizeof(wchar_t*) * 4096;
2034 if(RegQueryValueExW(registryKeyHandle, L"InstallLocation", 0, 0, reinterpret_cast<BYTE*>(Buffer), &BuffSize) == ERROR_SUCCESS)
2036 mplayerPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(Buffer));
2040 if(!mplayerPath.isEmpty())
2042 QDir mplayerDir(mplayerPath);
2043 if(mplayerDir.exists())
2045 for(int i = 0; i < 3; i++)
2047 if(mplayerDir.exists(appNames[i]))
2049 QProcess::startDetached(mplayerDir.absoluteFilePath(appNames[i]), QStringList() << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
2056 QDesktopServices::openUrl(QString("file:///").append(m_fileListModel->getFile(index).filePath()));
2060 * Find selected file in explorer
2062 void MainWindow::findFileContextActionTriggered(void)
2064 QModelIndex index = sourceFileView->currentIndex();
2067 QString systemRootPath;
2069 QDir systemRoot(lamexp_known_folder(lamexp_folder_systemfolder));
2070 if(systemRoot.exists() && systemRoot.cdUp())
2072 systemRootPath = systemRoot.canonicalPath();
2075 if(!systemRootPath.isEmpty())
2077 QFileInfo explorer(QString("%1/explorer.exe").arg(systemRootPath));
2078 if(explorer.exists() && explorer.isFile())
2080 QProcess::execute(explorer.canonicalFilePath(), QStringList() << "/select," << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
2086 qWarning("SystemRoot directory could not be detected!");
2092 * Show context menu for output folder
2094 void MainWindow::outputFolderContextMenu(const QPoint &pos)
2096 QAbstractScrollArea *scrollArea = dynamic_cast<QAbstractScrollArea*>(QObject::sender());
2097 QWidget *sender = scrollArea ? scrollArea->viewport() : dynamic_cast<QWidget*>(QObject::sender());
2099 if(pos.x() <= sender->width() && pos.y() <= sender->height() && pos.x() >= 0 && pos.y() >= 0)
2101 m_outputFolderContextMenu->popup(sender->mapToGlobal(pos));
2106 * Show selected folder in explorer
2108 void MainWindow::showFolderContextActionTriggered(void)
2110 QDesktopServices::openUrl(QUrl::fromLocalFile(m_fileSystemModel->filePath(outputFolderView->currentIndex())));
2114 * Disable update reminder action
2116 void MainWindow::disableUpdateReminderActionTriggered(bool checked)
2120 if(0 == QMessageBox::question(this, tr("Disable Update Reminder"), tr("Do you really want to disable the update reminder?"), tr("Yes"), tr("No"), QString(), 1))
2122 QMessageBox::information(this, tr("Update Reminder"), QString("%1<br>%2").arg(tr("The update reminder has been disabled."), tr("Please remember to check for updates at regular intervals!")));
2123 m_settings->autoUpdateEnabled(false);
2127 m_settings->autoUpdateEnabled(true);
2132 QMessageBox::information(this, tr("Update Reminder"), tr("The update reminder has been re-enabled."));
2133 m_settings->autoUpdateEnabled(true);
2136 actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
2140 * Disable sound effects action
2142 void MainWindow::disableSoundsActionTriggered(bool checked)
2146 if(0 == QMessageBox::question(this, tr("Disable Sound Effects"), tr("Do you really want to disable all sound effects?"), tr("Yes"), tr("No"), QString(), 1))
2148 QMessageBox::information(this, tr("Sound Effects"), tr("All sound effects have been disabled."));
2149 m_settings->soundsEnabled(false);
2153 m_settings->soundsEnabled(true);
2158 QMessageBox::information(this, tr("Sound Effects"), tr("The sound effects have been re-enabled."));
2159 m_settings->soundsEnabled(true);
2162 actionDisableSounds->setChecked(!m_settings->soundsEnabled());
2166 * Disable Nero AAC encoder action
2168 void MainWindow::disableNeroAacNotificationsActionTriggered(bool checked)
2172 if(0 == QMessageBox::question(this, tr("Nero AAC Notifications"), tr("Do you really want to disable all Nero AAC Encoder notifications?"), tr("Yes"), tr("No"), QString(), 1))
2174 QMessageBox::information(this, tr("Nero AAC Notifications"), tr("All Nero AAC Encoder notifications have been disabled."));
2175 m_settings->neroAacNotificationsEnabled(false);
2179 m_settings->neroAacNotificationsEnabled(true);
2184 QMessageBox::information(this, tr("Nero AAC Notifications"), tr("The Nero AAC Encoder notifications have been re-enabled."));
2185 m_settings->neroAacNotificationsEnabled(true);
2188 actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
2192 * Disable WMA Decoder component action
2194 void MainWindow::disableWmaDecoderNotificationsActionTriggered(bool checked)
2198 if(0 == QMessageBox::question(this, tr("WMA Decoder Notifications"), tr("Do you really want to disable all WMA Decoder notifications?"), tr("Yes"), tr("No"), QString(), 1))
2200 QMessageBox::information(this, tr("WMA Decoder Notifications"), tr("All WMA Decoder notifications have been disabled."));
2201 m_settings->wmaDecoderNotificationsEnabled(false);
2205 m_settings->wmaDecoderNotificationsEnabled(true);
2210 QMessageBox::information(this, tr("WMA Decoder Notifications"), tr("The WMA Decoder notifications have been re-enabled."));
2211 m_settings->wmaDecoderNotificationsEnabled(true);
2214 actionDisableWmaDecoderNotifications->setChecked(!m_settings->wmaDecoderNotificationsEnabled());
2218 * Download and install WMA Decoder component
2220 void MainWindow::installWMADecoderActionTriggered(bool checked)
2222 if(QMessageBox::question(this, tr("Install WMA Decoder"), tr("Do you want to download and install the WMA File Decoder component now?"), tr("Download && Install"), tr("Cancel")) == 0)
2224 if(installWMADecoder())
2226 QApplication::quit();
2233 * Show the "drop box" widget
2235 void MainWindow::showDropBoxWidgetActionTriggered(bool checked)
2237 m_settings->dropBoxWidgetEnabled(true);
2239 if(!m_dropBox->isVisible())
2244 FLASH_WINDOW(m_dropBox);
2248 * Disable shell integration action
2250 void MainWindow::disableShellIntegrationActionTriggered(bool checked)
2254 if(0 == QMessageBox::question(this, tr("Shell Integration"), tr("Do you really want to disable the LameXP shell integration?"), tr("Yes"), tr("No"), QString(), 1))
2256 ShellIntegration::remove();
2257 QMessageBox::information(this, tr("Shell Integration"), tr("The LameXP shell integration has been disabled."));
2258 m_settings->shellIntegrationEnabled(false);
2262 m_settings->shellIntegrationEnabled(true);
2267 ShellIntegration::install();
2268 QMessageBox::information(this, tr("Shell Integration"), tr("The LameXP shell integration has been re-enabled."));
2269 m_settings->shellIntegrationEnabled(true);
2272 actionDisableShellIntegration->setChecked(!m_settings->shellIntegrationEnabled());
2274 if(lamexp_portable_mode() && actionDisableShellIntegration->isChecked())
2276 actionDisableShellIntegration->setEnabled(false);