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"
42 #include <QMessageBox>
44 #include <QDesktopWidget>
46 #include <QFileDialog>
47 #include <QInputDialog>
48 #include <QFileSystemModel>
49 #include <QDesktopServices>
51 #include <QPlastiqueStyle>
52 #include <QCleanlooksStyle>
53 #include <QWindowsVistaStyle>
54 #include <QWindowsStyle>
56 #include <QDragEnterEvent>
57 #include <QWindowsMime>
60 #include <QProcessEnvironment>
61 #include <QCryptographicHash>
62 #include <QTranslator>
69 #define ABORT_IF_BUSY if(m_banner->isVisible() || m_delayedFileTimer->isActive()) { MessageBeep(MB_ICONEXCLAMATION); return; }
70 #define SET_TEXT_COLOR(WIDGET,COLOR) { QPalette _palette = WIDGET->palette(); _palette.setColor(QPalette::WindowText, COLOR); WIDGET->setPalette(_palette); }
71 #define SET_FONT_BOLD(WIDGET,BOLD) { QFont _font = WIDGET->font(); _font.setBold(BOLD); WIDGET->setFont(_font); }
72 #define FLASH_WINDOW(WND) { FLASHWINFO flashInfo; memset(&flashInfo, 0, sizeof(FLASHWINFO)); flashInfo.cbSize = sizeof(FLASHWINFO); flashInfo.dwFlags = FLASHW_ALL; flashInfo.uCount = 12; flashInfo.dwTimeout = 125; flashInfo.hwnd = WND->winId(); FlashWindowEx(&flashInfo); }
73 #define LINK(URL) QString("<a href=\"%1\">%2</a>").arg(URL).arg(URL)
74 #define TEMP_HIDE_DROPBOX(CMD) { bool __dropBoxVisible = m_dropBox->isVisible(); if(__dropBoxVisible) m_dropBox->hide(); CMD; if(__dropBoxVisible) m_dropBox->show(); }
77 class Index: public QObjectUserData
80 Index(int index) { m_index = index; }
81 int value(void) { return m_index; }
86 ////////////////////////////////////////////////////////////
88 ////////////////////////////////////////////////////////////
90 MainWindow::MainWindow(FileListModel *fileListModel, AudioFileModel *metaInfo, SettingsModel *settingsModel, QWidget *parent)
93 m_fileListModel(fileListModel),
95 m_settings(settingsModel),
97 m_firstTimeShown(true)
99 //Init the dialog, from the .ui file
101 setWindowFlags(windowFlags() ^ Qt::WindowMaximizeButtonHint);
103 //Register meta types
104 qRegisterMetaType<AudioFileModel>("AudioFileModel");
106 //Enabled main buttons
107 connect(buttonAbout, SIGNAL(clicked()), this, SLOT(aboutButtonClicked()));
108 connect(buttonStart, SIGNAL(clicked()), this, SLOT(encodeButtonClicked()));
109 connect(buttonQuit, SIGNAL(clicked()), this, SLOT(closeButtonClicked()));
112 tabWidget->setCurrentIndex(0);
113 connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabPageChanged(int)));
116 sourceFileView->setModel(m_fileListModel);
117 sourceFileView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
118 sourceFileView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
119 sourceFileView->setContextMenuPolicy(Qt::CustomContextMenu);
120 m_dropNoteLabel = new QLabel(sourceFileView);
121 m_dropNoteLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
122 SET_FONT_BOLD(m_dropNoteLabel, true);
123 SET_TEXT_COLOR(m_dropNoteLabel, Qt::darkGray);
124 m_sourceFilesContextMenu = new QMenu();
125 m_showDetailsContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/zoom.png"), "N/A");
126 m_previewContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/sound.png"), "N/A");
127 m_findFileContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/folder_go.png"), "N/A");
128 SET_FONT_BOLD(m_showDetailsContextAction, true);
129 connect(buttonAddFiles, SIGNAL(clicked()), this, SLOT(addFilesButtonClicked()));
130 connect(buttonRemoveFile, SIGNAL(clicked()), this, SLOT(removeFileButtonClicked()));
131 connect(buttonClearFiles, SIGNAL(clicked()), this, SLOT(clearFilesButtonClicked()));
132 connect(buttonFileUp, SIGNAL(clicked()), this, SLOT(fileUpButtonClicked()));
133 connect(buttonFileDown, SIGNAL(clicked()), this, SLOT(fileDownButtonClicked()));
134 connect(buttonShowDetails, SIGNAL(clicked()), this, SLOT(showDetailsButtonClicked()));
135 connect(m_fileListModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(sourceModelChanged()));
136 connect(m_fileListModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(sourceModelChanged()));
137 connect(m_fileListModel, SIGNAL(modelReset()), this, SLOT(sourceModelChanged()));
138 connect(sourceFileView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(sourceFilesContextMenu(QPoint)));
139 connect(m_showDetailsContextAction, SIGNAL(triggered(bool)), this, SLOT(showDetailsButtonClicked()));
140 connect(m_previewContextAction, SIGNAL(triggered(bool)), this, SLOT(previewContextActionTriggered()));
141 connect(m_findFileContextAction, SIGNAL(triggered(bool)), this, SLOT(findFileContextActionTriggered()));
144 m_fileSystemModel = new QFileSystemModelEx();
145 m_fileSystemModel->setRootPath(m_fileSystemModel->rootPath());
146 m_fileSystemModel->installEventFilter(this);
147 outputFolderView->setModel(m_fileSystemModel);
148 outputFolderView->header()->setStretchLastSection(true);
149 outputFolderView->header()->hideSection(1);
150 outputFolderView->header()->hideSection(2);
151 outputFolderView->header()->hideSection(3);
152 outputFolderView->setHeaderHidden(true);
153 outputFolderView->setAnimated(true);
154 outputFolderView->setMouseTracking(false);
155 outputFolderView->setContextMenuPolicy(Qt::CustomContextMenu);
156 while(saveToSourceFolderCheckBox->isChecked() != m_settings->outputToSourceDir()) saveToSourceFolderCheckBox->click();
157 prependRelativePathCheckBox->setChecked(m_settings->prependRelativeSourcePath());
158 connect(outputFolderView, SIGNAL(clicked(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
159 connect(outputFolderView, SIGNAL(activated(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
160 connect(outputFolderView, SIGNAL(pressed(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
161 connect(outputFolderView, SIGNAL(entered(QModelIndex)), this, SLOT(outputFolderViewMoved(QModelIndex)));
162 outputFolderView->setCurrentIndex(m_fileSystemModel->index(m_settings->outputDir()));
163 outputFolderViewClicked(outputFolderView->currentIndex());
164 connect(buttonMakeFolder, SIGNAL(clicked()), this, SLOT(makeFolderButtonClicked()));
165 connect(buttonGotoHome, SIGNAL(clicked()), SLOT(gotoHomeFolderButtonClicked()));
166 connect(buttonGotoDesktop, SIGNAL(clicked()), this, SLOT(gotoDesktopButtonClicked()));
167 connect(buttonGotoMusic, SIGNAL(clicked()), this, SLOT(gotoMusicFolderButtonClicked()));
168 connect(saveToSourceFolderCheckBox, SIGNAL(clicked()), this, SLOT(saveToSourceFolderChanged()));
169 connect(prependRelativePathCheckBox, SIGNAL(clicked()), this, SLOT(prependRelativePathChanged()));
170 m_outputFolderContextMenu = new QMenu();
171 m_showFolderContextAction = m_outputFolderContextMenu->addAction(QIcon(":/icons/zoom.png"), "N/A");
172 connect(outputFolderView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(outputFolderContextMenu(QPoint)));
173 connect(m_showFolderContextAction, SIGNAL(triggered(bool)), this, SLOT(showFolderContextActionTriggered()));
174 outputFolderLabel->installEventFilter(this);
176 //Setup "Meta Data" tab
177 m_metaInfoModel = new MetaInfoModel(m_metaData, 6);
178 m_metaInfoModel->clearData();
179 metaDataView->setModel(m_metaInfoModel);
180 metaDataView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
181 metaDataView->verticalHeader()->hide();
182 metaDataView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
183 while(writeMetaDataCheckBox->isChecked() != m_settings->writeMetaTags()) writeMetaDataCheckBox->click();
184 generatePlaylistCheckBox->setChecked(m_settings->createPlaylist());
185 connect(buttonEditMeta, SIGNAL(clicked()), this, SLOT(editMetaButtonClicked()));
186 connect(buttonClearMeta, SIGNAL(clicked()), this, SLOT(clearMetaButtonClicked()));
187 connect(writeMetaDataCheckBox, SIGNAL(clicked()), this, SLOT(metaTagsEnabledChanged()));
188 connect(generatePlaylistCheckBox, SIGNAL(clicked()), this, SLOT(playlistEnabledChanged()));
190 //Setup "Compression" tab
191 m_encoderButtonGroup = new QButtonGroup(this);
192 m_encoderButtonGroup->addButton(radioButtonEncoderMP3, SettingsModel::MP3Encoder);
193 m_encoderButtonGroup->addButton(radioButtonEncoderVorbis, SettingsModel::VorbisEncoder);
194 m_encoderButtonGroup->addButton(radioButtonEncoderAAC, SettingsModel::AACEncoder);
195 m_encoderButtonGroup->addButton(radioButtonEncoderFLAC, SettingsModel::FLACEncoder);
196 m_encoderButtonGroup->addButton(radioButtonEncoderPCM, SettingsModel::PCMEncoder);
197 m_modeButtonGroup = new QButtonGroup(this);
198 m_modeButtonGroup->addButton(radioButtonModeQuality, SettingsModel::VBRMode);
199 m_modeButtonGroup->addButton(radioButtonModeAverageBitrate, SettingsModel::ABRMode);
200 m_modeButtonGroup->addButton(radioButtonConstBitrate, SettingsModel::CBRMode);
201 radioButtonEncoderMP3->setChecked(m_settings->compressionEncoder() == SettingsModel::MP3Encoder);
202 radioButtonEncoderVorbis->setChecked(m_settings->compressionEncoder() == SettingsModel::VorbisEncoder);
203 radioButtonEncoderAAC->setChecked(m_settings->compressionEncoder() == SettingsModel::AACEncoder);
204 radioButtonEncoderFLAC->setChecked(m_settings->compressionEncoder() == SettingsModel::FLACEncoder);
205 radioButtonEncoderPCM->setChecked(m_settings->compressionEncoder() == SettingsModel::PCMEncoder);
206 radioButtonModeQuality->setChecked(m_settings->compressionRCMode() == SettingsModel::VBRMode);
207 radioButtonModeAverageBitrate->setChecked(m_settings->compressionRCMode() == SettingsModel::ABRMode);
208 radioButtonConstBitrate->setChecked(m_settings->compressionRCMode() == SettingsModel::CBRMode);
209 sliderBitrate->setValue(m_settings->compressionBitrate());
210 connect(m_encoderButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateEncoder(int)));
211 connect(m_modeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateRCMode(int)));
212 connect(sliderBitrate, SIGNAL(valueChanged(int)), this, SLOT(updateBitrate(int)));
213 updateEncoder(m_encoderButtonGroup->checkedId());
215 //Activate file menu actions
216 connect(actionOpenFolder, SIGNAL(triggered()), this, SLOT(openFolderActionActivated()));
218 //Activate view menu actions
219 m_tabActionGroup = new QActionGroup(this);
220 m_tabActionGroup->addAction(actionSourceFiles);
221 m_tabActionGroup->addAction(actionOutputDirectory);
222 m_tabActionGroup->addAction(actionCompression);
223 m_tabActionGroup->addAction(actionMetaData);
224 m_tabActionGroup->addAction(actionAdvancedOptions);
225 actionSourceFiles->setUserData(0, new Index(0));
226 actionOutputDirectory->setUserData(0, new Index(1));
227 actionMetaData->setUserData(0, new Index(2));
228 actionCompression->setUserData(0, new Index(3));
229 actionAdvancedOptions->setUserData(0, new Index(4));
230 actionSourceFiles->setChecked(true);
231 connect(m_tabActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(tabActionActivated(QAction*)));
233 //Activate style menu actions
234 m_styleActionGroup = new QActionGroup(this);
235 m_styleActionGroup->addAction(actionStylePlastique);
236 m_styleActionGroup->addAction(actionStyleCleanlooks);
237 m_styleActionGroup->addAction(actionStyleWindowsVista);
238 m_styleActionGroup->addAction(actionStyleWindowsXP);
239 m_styleActionGroup->addAction(actionStyleWindowsClassic);
240 actionStylePlastique->setUserData(0, new Index(0));
241 actionStyleCleanlooks->setUserData(0, new Index(1));
242 actionStyleWindowsVista->setUserData(0, new Index(2));
243 actionStyleWindowsXP->setUserData(0, new Index(3));
244 actionStyleWindowsClassic->setUserData(0, new Index(4));
245 actionStylePlastique->setChecked(true);
246 actionStyleWindowsXP->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_XP && lamexp_themes_enabled());
247 actionStyleWindowsVista->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_VISTA && lamexp_themes_enabled());
248 connect(m_styleActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(styleActionActivated(QAction*)));
249 styleActionActivated(NULL);
251 //Populate the language menu
252 m_languageActionGroup = new QActionGroup(this);
253 connect(m_languageActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(languageActionActivated(QAction*)));
254 QStringList translations = lamexp_query_translations();
255 while(!translations.isEmpty())
257 QString langId = translations.takeFirst();
258 QAction *currentLanguage = new QAction(this);
259 currentLanguage->setData(langId);
260 currentLanguage->setText(lamexp_translation_name(langId));
261 currentLanguage->setIcon(QIcon(QString(":/flags/%1.png").arg(langId)));
262 currentLanguage->setCheckable(true);
263 m_languageActionGroup->addAction(currentLanguage);
264 menuLanguage->addAction(currentLanguage);
267 //Activate tools menu actions
268 actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
269 actionDisableSounds->setChecked(!m_settings->soundsEnabled());
270 actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
271 actionDisableWmaDecoderNotifications->setChecked(!m_settings->wmaDecoderNotificationsEnabled());
272 connect(actionDisableUpdateReminder, SIGNAL(triggered(bool)), this, SLOT(disableUpdateReminderActionTriggered(bool)));
273 connect(actionDisableSounds, SIGNAL(triggered(bool)), this, SLOT(disableSoundsActionTriggered(bool)));
274 connect(actionInstallWMADecoder, SIGNAL(triggered(bool)), this, SLOT(installWMADecoderActionTriggered(bool)));
275 connect(actionDisableNeroAacNotifications, SIGNAL(triggered(bool)), this, SLOT(disableNeroAacNotificationsActionTriggered(bool)));
276 connect(actionDisableWmaDecoderNotifications, SIGNAL(triggered(bool)), this, SLOT(disableWmaDecoderNotificationsActionTriggered(bool)));
277 connect(actionShowDropBoxWidget, SIGNAL(triggered(bool)), this, SLOT(showDropBoxWidgetActionTriggered(bool)));
279 //Activate help menu actions
280 connect(actionCheckUpdates, SIGNAL(triggered()), this, SLOT(checkUpdatesActionActivated()));
281 connect(actionVisitHomepage, SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
283 //Center window in screen
284 QRect desktopRect = QApplication::desktop()->screenGeometry();
285 QRect thisRect = this->geometry();
286 move((desktopRect.width() - thisRect.width()) / 2, (desktopRect.height() - thisRect.height()) / 2);
287 setMinimumSize(thisRect.width(), thisRect.height());
290 m_banner = new WorkingBanner(this);
292 //Create DropBox widget
293 m_dropBox = new DropBox(this, m_fileListModel, m_settings);
294 connect(m_fileListModel, SIGNAL(modelReset()), m_dropBox, SLOT(modelChanged()));
295 connect(m_fileListModel, SIGNAL(rowsInserted(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
296 connect(m_fileListModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
298 //Create message handler thread
299 m_messageHandler = new MessageHandlerThread();
300 m_delayedFileList = new QStringList();
301 m_delayedFileTimer = new QTimer();
302 connect(m_messageHandler, SIGNAL(otherInstanceDetected()), this, SLOT(notifyOtherInstance()), Qt::QueuedConnection);
303 connect(m_messageHandler, SIGNAL(fileReceived(QString)), this, SLOT(addFileDelayed(QString)), Qt::QueuedConnection);
304 connect(m_messageHandler, SIGNAL(killSignalReceived()), this, SLOT(close()), Qt::QueuedConnection);
305 connect(m_delayedFileTimer, SIGNAL(timeout()), this, SLOT(handleDelayedFiles()));
306 m_messageHandler->start();
308 //Load translation file
309 QList<QAction*> languageActions = m_languageActionGroup->actions();
310 while(!languageActions.isEmpty())
312 QAction *currentLanguage = languageActions.takeFirst();
313 if(currentLanguage->data().toString().compare(m_settings->currentLanguage(), Qt::CaseInsensitive) == 0)
315 currentLanguage->setChecked(true);
316 languageActionActivated(currentLanguage);
320 //Re-translate (make sure we translate once)
321 QEvent languageChangeEvent(QEvent::LanguageChange);
322 changeEvent(&languageChangeEvent);
325 this->setAcceptDrops(true);
328 ////////////////////////////////////////////////////////////
330 ////////////////////////////////////////////////////////////
332 MainWindow::~MainWindow(void)
334 //Stop message handler thread
335 if(m_messageHandler && m_messageHandler->isRunning())
337 m_messageHandler->stop();
338 if(!m_messageHandler->wait(10000))
340 m_messageHandler->terminate();
341 m_messageHandler->wait();
346 sourceFileView->setModel(NULL);
347 metaDataView->setModel(NULL);
350 LAMEXP_DELETE(m_tabActionGroup);
351 LAMEXP_DELETE(m_styleActionGroup);
352 LAMEXP_DELETE(m_languageActionGroup);
353 LAMEXP_DELETE(m_banner);
354 LAMEXP_DELETE(m_fileSystemModel);
355 LAMEXP_DELETE(m_messageHandler);
356 LAMEXP_DELETE(m_delayedFileList);
357 LAMEXP_DELETE(m_delayedFileTimer);
358 LAMEXP_DELETE(m_metaInfoModel);
359 LAMEXP_DELETE(m_encoderButtonGroup);
360 LAMEXP_DELETE(m_encoderButtonGroup);
361 LAMEXP_DELETE(m_sourceFilesContextMenu);
362 LAMEXP_DELETE(m_dropBox);
366 ////////////////////////////////////////////////////////////
368 ////////////////////////////////////////////////////////////
371 * Add file to source list
373 void MainWindow::addFiles(const QStringList &files)
380 tabWidget->setCurrentIndex(0);
382 FileAnalyzer *analyzer = new FileAnalyzer(files);
383 connect(analyzer, SIGNAL(fileSelected(QString)), m_banner, SLOT(setText(QString)), Qt::QueuedConnection);
384 connect(analyzer, SIGNAL(fileAnalyzed(AudioFileModel)), m_fileListModel, SLOT(addFile(AudioFileModel)), Qt::QueuedConnection);
386 m_banner->show(tr("Adding file(s), please wait..."), analyzer);
388 if(analyzer->filesDenied())
390 QMessageBox::warning(this, tr("Access Denied"), QString("<nobr>%1<br>%2</nobr>").arg(tr("%1 file(s) have been rejected, because read access was not granted!").arg(analyzer->filesDenied()), tr("This usually means the file is locked by another process.")));
392 if(analyzer->filesRejected())
394 QMessageBox::warning(this, tr("Files Rejected"), QString("<nobr>%1<br>%2</nobr>").arg(tr("%1 file(s) have been rejected, because the file format could not be recognized!").arg(analyzer->filesRejected()), tr("This usually means the file is damaged or the file format is not supported.")));
397 LAMEXP_DELETE(analyzer);
398 sourceFileView->scrollToBottom();
402 ////////////////////////////////////////////////////////////
404 ////////////////////////////////////////////////////////////
407 * Window is about to be shown
409 void MainWindow::showEvent(QShowEvent *event)
412 m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
413 sourceModelChanged();
414 tabWidget->setCurrentIndex(0);
418 m_firstTimeShown = false;
419 QTimer::singleShot(0, this, SLOT(windowShown()));
423 if(m_settings->dropBoxWidgetEnabled())
425 m_dropBox->setVisible(true);
431 * Re-translate the UI
433 void MainWindow::changeEvent(QEvent *e)
435 if(e->type() == QEvent::LanguageChange)
437 Ui::MainWindow::retranslateUi(this);
439 if(lamexp_version_demo())
441 setWindowTitle(QString("%1 [%2]").arg(windowTitle(), tr("DEMO VERSION")));
444 m_dropNoteLabel->setText(QString("» %1 «").arg(tr("You can drop in audio files here!")));
445 m_showDetailsContextAction->setText(tr("Show Details"));
446 m_previewContextAction->setText(tr("Open File in External Application"));
447 m_findFileContextAction->setText(tr("Browse File Location"));
448 m_showFolderContextAction->setText(tr("Browse Selected Folder"));
453 * File dragged over window
455 void MainWindow::dragEnterEvent(QDragEnterEvent *event)
457 QStringList formats = event->mimeData()->formats();
459 if(formats.contains("application/x-qt-windows-mime;value=\"FileNameW\"", Qt::CaseInsensitive) && formats.contains("text/uri-list", Qt::CaseInsensitive))
461 event->acceptProposedAction();
466 * File dropped onto window
468 void MainWindow::dropEvent(QDropEvent *event)
472 QStringList droppedFiles;
473 const QList<QUrl> urls = event->mimeData()->urls();
475 for(int i = 0; i < urls.count(); i++)
477 QFileInfo file(urls.at(i).toLocalFile());
484 droppedFiles << file.canonicalFilePath();
489 QList<QFileInfo> list = QDir(file.canonicalFilePath()).entryInfoList(QDir::Files);
490 for(int j = 0; j < list.count(); j++)
492 droppedFiles << list.at(j).canonicalFilePath();
497 addFiles(droppedFiles);
501 * Window tries to close
503 void MainWindow::closeEvent(QCloseEvent *event)
505 if(m_banner->isVisible() || m_delayedFileTimer->isActive())
507 MessageBeep(MB_ICONEXCLAMATION);
520 void MainWindow::resizeEvent(QResizeEvent *event)
522 QMainWindow::resizeEvent(event);
523 m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
529 bool MainWindow::eventFilter(QObject *obj, QEvent *event)
531 if(obj == m_fileSystemModel && QApplication::overrideCursor() == NULL)
533 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
534 QTimer::singleShot(250, this, SLOT(restoreCursor()));
536 else if(obj == outputFolderLabel)
538 switch(event->type())
540 case QEvent::MouseButtonPress:
541 if(dynamic_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)
543 QDesktopServices::openUrl(QString("file:///%1").arg(outputFolderLabel->text()));
547 outputFolderLabel->setForegroundRole(QPalette::Link);
550 outputFolderLabel->setForegroundRole(QPalette::WindowText);
557 ////////////////////////////////////////////////////////////
559 ////////////////////////////////////////////////////////////
564 void MainWindow::windowShown(void)
566 QStringList arguments = QApplication::arguments();
569 if(m_settings->licenseAccepted() <= 0)
573 if(m_settings->licenseAccepted() == 0)
575 AboutDialog *about = new AboutDialog(m_settings, this, true);
576 iAccepted = about->exec();
577 LAMEXP_DELETE(about);
582 m_settings->licenseAccepted(-1);
583 QApplication::processEvents();
584 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
585 QMessageBox::critical(this, tr("License Declined"), tr("You have declined the license. Consequently the application will exit now!"), tr("Goodbye!"));
586 QProcess::startDetached(QString("%1/Uninstall.exe").arg(QApplication::applicationDirPath()), QStringList());
587 QApplication::quit();
591 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WOOHOO), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
592 m_settings->licenseAccepted(1);
595 //Check for expiration
596 if(lamexp_version_demo())
598 QDate expireDate = lamexp_version_date().addDays(14);
599 if(QDate::currentDate() >= expireDate)
601 qWarning("Binary has expired !!!");
602 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
603 if(QMessageBox::warning(this, tr("LameXP - Expired"), QString("<nobr>%1<br>%2</nobr>").arg(tr("This demo (pre-release) version of LameXP has expired at %1.").arg(expireDate.toString(Qt::ISODate)), tr("LameXP is free software and release versions won't expire.")), tr("Check for Updates"), tr("Exit Program")) == 0)
605 checkUpdatesActionActivated();
607 QApplication::quit();
613 if(QDate::currentDate() >= lamexp_version_date().addYears(1))
615 qWarning("Binary is more than a year old, time to update!");
616 if(QMessageBox::warning(this, tr("Urgent Update"), tr("Your version of LameXP is more than a year old. Time for an update!"), tr("Check for Updates"), tr("Exit Program")) == 0)
618 checkUpdatesActionActivated();
622 QApplication::quit();
626 else if(m_settings->autoUpdateEnabled())
628 QDate lastUpdateCheck = QDate::fromString(m_settings->autoUpdateLastCheck(), Qt::ISODate);
629 if(!lastUpdateCheck.isValid() || QDate::currentDate() >= lastUpdateCheck.addDays(14))
631 if(QMessageBox::information(this, tr("Update Reminder"), (lastUpdateCheck.isValid() ? tr("Your last update check was more than 14 days ago. Check for updates now?") : tr("Your did not check for LameXP updates yet. Check for updates now?")), tr("Check for Updates"), tr("Postpone")) == 0)
633 checkUpdatesActionActivated();
638 //Check for AAC support
639 if(m_settings->neroAacNotificationsEnabled())
641 if(lamexp_check_tool("neroAacEnc.exe") && lamexp_check_tool("neroAacDec.exe") && lamexp_check_tool("neroAacTag.exe"))
643 if(lamexp_tool_version("neroAacEnc.exe") < lamexp_toolver_neroaac())
646 messageText += QString("<nobr>%1<br>").arg(tr("LameXP detected that your version of the Nero AAC encoder is outdated!"));
647 messageText += QString("%1<br><br>").arg(tr("The current version available is %1 (or later), but you still have version %2 installed.").arg(lamexp_version2string("?.?.?.?", lamexp_toolver_neroaac()), lamexp_version2string("?.?.?.?", lamexp_tool_version("neroAacEnc.exe"))));
648 messageText += QString("%1<br>").arg(tr("You can download the latest version of the Nero AAC encoder from the Nero website at:"));
649 messageText += "<b>" + LINK(AboutDialog::neroAacUrl) + "</b><br></nobr>";
650 QMessageBox::information(this, tr("AAC Encoder Outdated"), messageText);
655 radioButtonEncoderAAC->setEnabled(false);
657 messageText += QString("<nobr>%1<br>").arg(tr("The Nero AAC encoder could not be found. AAC encoding support will be disabled."));
658 messageText += QString("%1<br><br>").arg(tr("Please put 'neroAacEnc.exe', 'neroAacDec.exe' and 'neroAacTag.exe' into the LameXP directory!"));
659 messageText += QString("%1<br>").arg(tr("Your LameXP directory is located here:"));
660 messageText += QString("<i><nobr><a href=\"file:///%1\">%1</a></nobr></i><br><br>").arg(QDir::toNativeSeparators(QCoreApplication::applicationDirPath()));
661 messageText += QString("%1<br>").arg(tr("You can download the Nero AAC encoder for free from the official Nero website at:"));
662 messageText += "<b>" + LINK(AboutDialog::neroAacUrl) + "</b><br></nobr>";
663 QMessageBox::information(this, tr("AAC Support Disabled"), messageText);
667 //Check for WMA support
668 if(m_settings->wmaDecoderNotificationsEnabled())
670 if(!lamexp_check_tool("wmawav.exe"))
673 messageText += QString("<nobr>%1<br>").arg(tr("LameXP has detected that the WMA File Decoder component is not currently installed on your system."));
674 messageText += QString("%1</nobr>").arg(tr("You won't be able to process WMA files as input unless the WMA File Decoder component is installed!"));
675 QMessageBox::information(this, tr("WMA Decoder Missing"), messageText);
676 installWMADecoderActionTriggered(rand() % 2);
680 //Add files from the command-line
681 for(int i = 0; i < arguments.count() - 1; i++)
683 if(!arguments[i].compare("--add", Qt::CaseInsensitive))
685 QFileInfo currentFile(arguments[++i].trimmed());
686 qDebug("Adding file from CLI: %s", currentFile.canonicalFilePath().toUtf8().constData());
687 m_delayedFileList->append(currentFile.canonicalFilePath());
691 //Start delayed files timer
692 if(!m_delayedFileList->isEmpty() && !m_delayedFileTimer->isActive())
694 m_delayedFileTimer->start(5000);
697 //Make DropBox visible
698 if(m_settings->dropBoxWidgetEnabled())
700 m_dropBox->setVisible(true);
707 void MainWindow::aboutButtonClicked(void)
713 AboutDialog *aboutBox = new AboutDialog(m_settings, this);
715 LAMEXP_DELETE(aboutBox);
722 void MainWindow::encodeButtonClicked(void)
724 static const __int64 oneGigabyte = 1073741824;
725 static const __int64 minimumFreeDiskspaceMultiplier = 2;
729 if(m_fileListModel->rowCount() < 1)
731 QMessageBox::warning(this, tr("LameXP"), tr("You must add at least one file to the list before proceeding!"));
732 tabWidget->setCurrentIndex(0);
736 __int64 currentFreeDiskspace = lamexp_free_diskspace(lamexp_temp_folder());
738 if(currentFreeDiskspace < (oneGigabyte * minimumFreeDiskspaceMultiplier))
740 QStringList tempFolderParts = lamexp_temp_folder().split("/", QString::SkipEmptyParts, Qt::CaseInsensitive);
741 tempFolderParts.takeLast();
742 if(m_settings->soundsEnabled()) PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
743 switch(QMessageBox::warning(this, tr("Low Diskspace Warning"), QString("<nobr>%1</nobr><br><nobr>%2</nobr><br><br>%3").arg(tr("There are less than %1 GB of free diskspace available on your system's TEMP folder.").arg(QString::number(minimumFreeDiskspaceMultiplier)), tr("It is highly recommend to free up more diskspace before proceeding with the encode!"), tr("Your TEMP folder is located at:")).append("<br><nobr><i><a href=\"file:///%3\">%3</a></i></nobr><br>").arg(tempFolderParts.join("\\")), tr("Abort Encoding Process"), tr("Clean Disk Now"), tr("Ignore")))
746 QProcess::startDetached(QString("%1/cleanmgr.exe").arg(lamexp_known_folder(lamexp_folder_systemfolder)), QStringList() << "/D" << tempFolderParts.first());
751 QMessageBox::warning(this, tr("Low Diskspace"), tr("You are proceeding with low diskspace. Problems might occur!"));
756 switch(m_settings->compressionEncoder())
758 case SettingsModel::MP3Encoder:
759 case SettingsModel::VorbisEncoder:
760 case SettingsModel::AACEncoder:
761 case SettingsModel::FLACEncoder:
762 case SettingsModel::PCMEncoder:
765 QMessageBox::warning(this, tr("LameXP"), tr("Sorry, an unsupported encoder has been chosen!"));
766 tabWidget->setCurrentIndex(3);
770 if(!m_settings->outputToSourceDir())
772 QFile writeTest(QString("%1/~%2.txt").arg(m_settings->outputDir(), QUuid::createUuid().toString()));
773 if(!writeTest.open(QIODevice::ReadWrite))
775 QMessageBox::warning(this, tr("LameXP"), QString("%1<br><nobr>%2</nobr><br><br>%3").arg(tr("Cannot write to the selected output directory."), m_settings->outputDir(), tr("Please choose a different directory!")));
776 tabWidget->setCurrentIndex(1);
793 void MainWindow::closeButtonClicked(void)
802 void MainWindow::addFilesButtonClicked(void)
808 if(lamexp_themes_enabled())
810 QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
811 QStringList selectedFiles = QFileDialog::getOpenFileNames(this, tr("Add file(s)"), QString(), fileTypeFilters.join(";;"));
812 if(!selectedFiles.isEmpty())
814 addFiles(selectedFiles);
819 QFileDialog dialog(this, tr("Add file(s)"));
820 QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
821 dialog.setFileMode(QFileDialog::ExistingFiles);
822 dialog.setNameFilter(fileTypeFilters.join(";;"));
825 QStringList selectedFiles = dialog.selectedFiles();
826 addFiles(selectedFiles);
835 void MainWindow::openFolderActionActivated(void)
838 QString selectedFolder;
842 if(lamexp_themes_enabled())
844 selectedFolder = QFileDialog::getExistingDirectory(this, tr("Add folder"), QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
848 QFileDialog dialog(this, tr("Add folder"));
849 dialog.setFileMode(QFileDialog::DirectoryOnly);
850 dialog.setDirectory(QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
853 selectedFolder = dialog.selectedFiles().first();
857 if(!selectedFolder.isEmpty())
859 QDir sourceDir(selectedFolder);
860 QFileInfoList fileInfoList = sourceDir.entryInfoList(QDir::Files);
861 QStringList fileList;
863 while(!fileInfoList.isEmpty())
865 fileList << fileInfoList.takeFirst().canonicalFilePath();
876 void MainWindow::removeFileButtonClicked(void)
878 if(sourceFileView->currentIndex().isValid())
880 int iRow = sourceFileView->currentIndex().row();
881 m_fileListModel->removeFile(sourceFileView->currentIndex());
882 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
889 void MainWindow::clearFilesButtonClicked(void)
891 m_fileListModel->clearFiles();
895 * Move file up button
897 void MainWindow::fileUpButtonClicked(void)
899 if(sourceFileView->currentIndex().isValid())
901 int iRow = sourceFileView->currentIndex().row() - 1;
902 m_fileListModel->moveFile(sourceFileView->currentIndex(), -1);
903 sourceFileView->selectRow(iRow >= 0 ? iRow : 0);
908 * Move file down button
910 void MainWindow::fileDownButtonClicked(void)
912 if(sourceFileView->currentIndex().isValid())
914 int iRow = sourceFileView->currentIndex().row() + 1;
915 m_fileListModel->moveFile(sourceFileView->currentIndex(), 1);
916 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
921 * Show details button
923 void MainWindow::showDetailsButtonClicked(void)
928 MetaInfoDialog *metaInfoDialog = new MetaInfoDialog(this);
929 QModelIndex index = sourceFileView->currentIndex();
931 while(index.isValid())
935 index = m_fileListModel->index(index.row() + 1, index.column());
936 sourceFileView->selectRow(index.row());
940 index = m_fileListModel->index(index.row() - 1, index.column());
941 sourceFileView->selectRow(index.row());
944 AudioFileModel &file = (*m_fileListModel)[index];
945 iResult = metaInfoDialog->exec(file, index.row() > 0, index.row() < m_fileListModel->rowCount() - 1);
950 LAMEXP_DELETE(metaInfoDialog);
956 void MainWindow::tabPageChanged(int idx)
958 QList<QAction*> actions = m_tabActionGroup->actions();
959 for(int i = 0; i < actions.count(); i++)
961 if(actions.at(i)->userData(0) && dynamic_cast<Index*>(actions.at(i)->userData(0))->value() == idx)
963 actions.at(i)->setChecked(true);
969 * Tab action triggered
971 void MainWindow::tabActionActivated(QAction *action)
973 if(action && action->userData(0))
975 int index = dynamic_cast<Index*>(action->userData(0))->value();
976 tabWidget->setCurrentIndex(index);
981 * Style action triggered
983 void MainWindow::styleActionActivated(QAction *action)
985 if(action && action->userData(0))
987 m_settings->interfaceStyle(dynamic_cast<Index*>(action->userData(0))->value());
990 switch(m_settings->interfaceStyle())
993 if(actionStyleCleanlooks->isEnabled())
995 actionStyleCleanlooks->setChecked(true);
996 QApplication::setStyle(new QCleanlooksStyle());
1000 if(actionStyleWindowsVista->isEnabled())
1002 actionStyleWindowsVista->setChecked(true);
1003 QApplication::setStyle(new QWindowsVistaStyle());
1007 if(actionStyleWindowsXP->isEnabled())
1009 actionStyleWindowsXP->setChecked(true);
1010 QApplication::setStyle(new QWindowsXPStyle());
1014 if(actionStyleWindowsClassic->isEnabled())
1016 actionStyleWindowsClassic->setChecked(true);
1017 QApplication::setStyle(new QWindowsStyle());
1021 actionStylePlastique->setChecked(true);
1022 QApplication::setStyle(new QPlastiqueStyle());
1028 * Language action triggered
1030 void MainWindow::languageActionActivated(QAction *action)
1032 QString langId = action->data().toString();
1034 if(lamexp_install_translator(langId))
1036 m_settings->currentLanguage(langId);
1041 * Output folder changed (mouse clicked)
1043 void MainWindow::outputFolderViewClicked(const QModelIndex &index)
1045 if(outputFolderView->currentIndex() != index)
1047 outputFolderView->setCurrentIndex(index);
1049 QString selectedDir = m_fileSystemModel->filePath(index);
1050 if(selectedDir.length() < 3) selectedDir.append(QDir::separator());
1051 outputFolderLabel->setText(QDir::toNativeSeparators(selectedDir));
1052 m_settings->outputDir(selectedDir);
1056 * Output folder changed (mouse moved)
1058 void MainWindow::outputFolderViewMoved(const QModelIndex &index)
1060 if(QApplication::mouseButtons() & Qt::LeftButton)
1062 outputFolderViewClicked(index);
1067 * Goto desktop button
1069 void MainWindow::gotoDesktopButtonClicked(void)
1071 QString desktopPath = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
1073 if(!desktopPath.isEmpty() && QDir(desktopPath).exists())
1075 outputFolderView->setCurrentIndex(m_fileSystemModel->index(desktopPath));
1076 outputFolderViewClicked(outputFolderView->currentIndex());
1077 outputFolderView->setFocus();
1081 buttonGotoDesktop->setEnabled(false);
1086 * Goto home folder button
1088 void MainWindow::gotoHomeFolderButtonClicked(void)
1090 QString homePath = QDesktopServices::storageLocation(QDesktopServices::HomeLocation);
1092 if(!homePath.isEmpty() && QDir(homePath).exists())
1094 outputFolderView->setCurrentIndex(m_fileSystemModel->index(homePath));
1095 outputFolderViewClicked(outputFolderView->currentIndex());
1096 outputFolderView->setFocus();
1100 buttonGotoHome->setEnabled(false);
1105 * Goto music folder button
1107 void MainWindow::gotoMusicFolderButtonClicked(void)
1109 QString musicPath = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
1111 if(!musicPath.isEmpty() && QDir(musicPath).exists())
1113 outputFolderView->setCurrentIndex(m_fileSystemModel->index(musicPath));
1114 outputFolderViewClicked(outputFolderView->currentIndex());
1115 outputFolderView->setFocus();
1119 buttonGotoMusic->setEnabled(false);
1124 * Make folder button
1126 void MainWindow::makeFolderButtonClicked(void)
1130 QDir basePath(m_fileSystemModel->fileInfo(outputFolderView->currentIndex()).absoluteFilePath());
1131 QString suggestedName = tr("New Folder");
1133 if(!m_metaData->fileArtist().isEmpty() && !m_metaData->fileAlbum().isEmpty())
1135 suggestedName = QString("%1 - %2").arg(m_metaData->fileArtist(), m_metaData->fileAlbum());
1137 else if(!m_metaData->fileArtist().isEmpty())
1139 suggestedName = m_metaData->fileArtist();
1141 else if(!m_metaData->fileAlbum().isEmpty())
1143 suggestedName = m_metaData->fileAlbum();
1147 for(int i = 0; i < m_fileListModel->rowCount(); i++)
1149 AudioFileModel audioFile = m_fileListModel->getFile(m_fileListModel->index(i, 0));
1150 if(!audioFile.fileAlbum().isEmpty() || !audioFile.fileArtist().isEmpty())
1152 if(!audioFile.fileArtist().isEmpty() && !audioFile.fileAlbum().isEmpty())
1154 suggestedName = QString("%1 - %2").arg(audioFile.fileArtist(), audioFile.fileAlbum());
1156 else if(!audioFile.fileArtist().isEmpty())
1158 suggestedName = audioFile.fileArtist();
1160 else if(!audioFile.fileAlbum().isEmpty())
1162 suggestedName = audioFile.fileAlbum();
1171 bool bApplied = false;
1172 QString folderName = QInputDialog::getText(this, tr("New Folder"), tr("Enter the name of the new folder:").leftJustified(96, ' '), QLineEdit::Normal, suggestedName, &bApplied, Qt::WindowStaysOnTopHint).simplified();
1176 folderName.remove(":", Qt::CaseInsensitive);
1177 folderName.remove("/", Qt::CaseInsensitive);
1178 folderName.remove("\\", Qt::CaseInsensitive);
1179 folderName.remove("?", Qt::CaseInsensitive);
1180 folderName.remove("*", Qt::CaseInsensitive);
1181 folderName.remove("<", Qt::CaseInsensitive);
1182 folderName.remove(">", Qt::CaseInsensitive);
1184 folderName = folderName.simplified();
1186 if(folderName.isEmpty())
1188 MessageBeep(MB_ICONERROR);
1193 QString newFolder = folderName;
1195 while(basePath.exists(newFolder))
1197 newFolder = QString(folderName).append(QString().sprintf(" (%d)", ++i));
1200 if(basePath.mkdir(newFolder))
1202 QDir createdDir = basePath;
1203 if(createdDir.cd(newFolder))
1205 outputFolderView->setCurrentIndex(m_fileSystemModel->index(createdDir.canonicalPath()));
1206 outputFolderViewClicked(outputFolderView->currentIndex());
1207 outputFolderView->setFocus();
1212 QMessageBox::warning(this, tr("Failed to create folder"), QString("%1<br><nobr>%2</nobr><br><br>%3").arg(tr("The new folder could not be created:"), basePath.absoluteFilePath(newFolder), tr("Drive is read-only or insufficient access rights!")));
1220 * Edit meta button clicked
1222 void MainWindow::editMetaButtonClicked(void)
1225 m_metaInfoModel->editItem(metaDataView->currentIndex(), this);
1229 * Reset meta button clicked
1231 void MainWindow::clearMetaButtonClicked(void)
1234 m_metaInfoModel->clearData();
1238 * Visit homepage action
1240 void MainWindow::visitHomepageActionActivated(void)
1242 QDesktopServices::openUrl(QUrl("http://mulder.dummwiedeutsch.de/"));
1246 * Check for updates action
1248 void MainWindow::checkUpdatesActionActivated(void)
1254 UpdateDialog *updateDialog = new UpdateDialog(m_settings, this);
1255 updateDialog->exec();
1256 if(updateDialog->getSuccess())
1258 m_settings->autoUpdateLastCheck(QDate::currentDate().toString(Qt::ISODate));
1260 LAMEXP_DELETE(updateDialog);
1265 * Other instance detected
1267 void MainWindow::notifyOtherInstance(void)
1269 if(!m_banner->isVisible())
1271 QMessageBox msgBox(QMessageBox::Warning, tr("Already Running"), tr("LameXP is already running, please use the running instance!"), QMessageBox::NoButton, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowStaysOnTopHint);
1277 * Add file from another instance
1279 void MainWindow::addFileDelayed(const QString &filePath)
1281 m_delayedFileTimer->stop();
1282 qDebug("Received file: %s", filePath.toUtf8().constData());
1283 m_delayedFileList->append(filePath);
1284 m_delayedFileTimer->start(5000);
1288 * Add all pending files
1290 void MainWindow::handleDelayedFiles(void)
1292 if(m_banner->isVisible())
1297 m_delayedFileTimer->stop();
1298 if(m_delayedFileList->isEmpty())
1303 QStringList selectedFiles;
1304 tabWidget->setCurrentIndex(0);
1306 while(!m_delayedFileList->isEmpty())
1308 QFileInfo currentFile = QFileInfo(m_delayedFileList->takeFirst());
1309 if(!currentFile.exists())
1313 if(currentFile.isFile())
1315 selectedFiles << currentFile.canonicalFilePath();
1318 if(currentFile.isDir())
1320 QList<QFileInfo> list = QDir(currentFile.canonicalFilePath()).entryInfoList(QDir::Files);
1321 for(int j = 0; j < list.count(); j++)
1323 selectedFiles << list.at(j).canonicalFilePath();
1328 addFiles(selectedFiles);
1334 void MainWindow::updateEncoder(int id)
1336 m_settings->compressionEncoder(id);
1338 switch(m_settings->compressionEncoder())
1340 case SettingsModel::VorbisEncoder:
1341 radioButtonModeQuality->setEnabled(true);
1342 radioButtonModeAverageBitrate->setEnabled(true);
1343 radioButtonConstBitrate->setEnabled(false);
1344 if(radioButtonConstBitrate->isChecked()) radioButtonModeQuality->setChecked(true);
1345 sliderBitrate->setEnabled(true);
1347 case SettingsModel::FLACEncoder:
1348 radioButtonModeQuality->setEnabled(false);
1349 radioButtonModeQuality->setChecked(true);
1350 radioButtonModeAverageBitrate->setEnabled(false);
1351 radioButtonConstBitrate->setEnabled(false);
1352 sliderBitrate->setEnabled(true);
1354 case SettingsModel::PCMEncoder:
1355 radioButtonModeQuality->setEnabled(false);
1356 radioButtonModeQuality->setChecked(true);
1357 radioButtonModeAverageBitrate->setEnabled(false);
1358 radioButtonConstBitrate->setEnabled(false);
1359 sliderBitrate->setEnabled(false);
1362 radioButtonModeQuality->setEnabled(true);
1363 radioButtonModeAverageBitrate->setEnabled(true);
1364 radioButtonConstBitrate->setEnabled(true);
1365 sliderBitrate->setEnabled(true);
1369 updateRCMode(m_modeButtonGroup->checkedId());
1373 * Update rate-control mode
1375 void MainWindow::updateRCMode(int id)
1377 m_settings->compressionRCMode(id);
1379 switch(m_settings->compressionEncoder())
1381 case SettingsModel::MP3Encoder:
1382 switch(m_settings->compressionRCMode())
1384 case SettingsModel::VBRMode:
1385 sliderBitrate->setMinimum(0);
1386 sliderBitrate->setMaximum(9);
1389 sliderBitrate->setMinimum(0);
1390 sliderBitrate->setMaximum(13);
1394 case SettingsModel::VorbisEncoder:
1395 switch(m_settings->compressionRCMode())
1397 case SettingsModel::VBRMode:
1398 sliderBitrate->setMinimum(-2);
1399 sliderBitrate->setMaximum(10);
1402 sliderBitrate->setMinimum(4);
1403 sliderBitrate->setMaximum(63);
1407 case SettingsModel::AACEncoder:
1408 switch(m_settings->compressionRCMode())
1410 case SettingsModel::VBRMode:
1411 sliderBitrate->setMinimum(0);
1412 sliderBitrate->setMaximum(20);
1415 sliderBitrate->setMinimum(4);
1416 sliderBitrate->setMaximum(63);
1420 case SettingsModel::FLACEncoder:
1421 sliderBitrate->setMinimum(0);
1422 sliderBitrate->setMaximum(8);
1424 case SettingsModel::PCMEncoder:
1425 sliderBitrate->setMinimum(0);
1426 sliderBitrate->setMaximum(2);
1427 sliderBitrate->setValue(1);
1430 sliderBitrate->setMinimum(0);
1431 sliderBitrate->setMaximum(0);
1435 updateBitrate(sliderBitrate->value());
1441 void MainWindow::updateBitrate(int value)
1443 m_settings->compressionBitrate(value);
1445 switch(m_settings->compressionRCMode())
1447 case SettingsModel::VBRMode:
1448 switch(m_settings->compressionEncoder())
1450 case SettingsModel::MP3Encoder:
1451 labelBitrate->setText(tr("Quality Level %1").arg(9 - value));
1453 case SettingsModel::VorbisEncoder:
1454 labelBitrate->setText(tr("Quality Level %1").arg(value));
1456 case SettingsModel::AACEncoder:
1457 labelBitrate->setText(tr("Quality Level %1").arg(QString().sprintf("%.2f", static_cast<double>(value * 5) / 100.0)));
1459 case SettingsModel::FLACEncoder:
1460 labelBitrate->setText(tr("Compression %1").arg(value));
1462 case SettingsModel::PCMEncoder:
1463 labelBitrate->setText(tr("Uncompressed"));
1466 labelBitrate->setText(QString::number(value));
1470 case SettingsModel::ABRMode:
1471 switch(m_settings->compressionEncoder())
1473 case SettingsModel::MP3Encoder:
1474 labelBitrate->setText(QString("≈ %1 kbps").arg(SettingsModel::mp3Bitrates[value]));
1476 case SettingsModel::FLACEncoder:
1477 labelBitrate->setText(tr("Compression %1").arg(value));
1479 case SettingsModel::PCMEncoder:
1480 labelBitrate->setText(tr("Uncompressed"));
1483 labelBitrate->setText(QString("≈ %1 kbps").arg(min(500, value * 8)));
1488 switch(m_settings->compressionEncoder())
1490 case SettingsModel::MP3Encoder:
1491 labelBitrate->setText(QString("%1 kbps").arg(SettingsModel::mp3Bitrates[value]));
1493 case SettingsModel::FLACEncoder:
1494 labelBitrate->setText(tr("Compression %1").arg(value));
1496 case SettingsModel::PCMEncoder:
1497 labelBitrate->setText(tr("Uncompressed"));
1500 labelBitrate->setText(QString("%1 kbps").arg(min(500, value * 8)));
1510 void MainWindow::sourceModelChanged(void)
1512 m_dropNoteLabel->setVisible(m_fileListModel->rowCount() <= 0);
1516 * Meta tags enabled changed
1518 void MainWindow::metaTagsEnabledChanged(void)
1520 m_settings->writeMetaTags(writeMetaDataCheckBox->isChecked());
1524 * Playlist enabled changed
1526 void MainWindow::playlistEnabledChanged(void)
1528 m_settings->createPlaylist(generatePlaylistCheckBox->isChecked());
1532 * Output to source dir changed
1534 void MainWindow::saveToSourceFolderChanged(void)
1536 m_settings->outputToSourceDir(saveToSourceFolderCheckBox->isChecked());
1540 * Prepend relative source file path to output file name changed
1542 void MainWindow::prependRelativePathChanged(void)
1544 m_settings->prependRelativeSourcePath(prependRelativePathCheckBox->isChecked());
1549 * Restore the override cursor
1551 void MainWindow::restoreCursor(void)
1553 QApplication::restoreOverrideCursor();
1557 * Show context menu for source files
1559 void MainWindow::sourceFilesContextMenu(const QPoint &pos)
1561 if(pos.x() <= sourceFileView->width() && pos.y() <= sourceFileView->height() && pos.x() >= 0 && pos.y() >= 0)
1563 m_sourceFilesContextMenu->popup(sourceFileView->mapToGlobal(pos));
1568 * Open selected file in external player
1570 void MainWindow::previewContextActionTriggered(void)
1572 const static char *appNames[3] = {"smplayer_portable.exe", "smplayer.exe", "mplayer.exe"};
1573 const static wchar_t *registryKey = L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}";
1575 QModelIndex index = sourceFileView->currentIndex();
1576 if(!index.isValid())
1581 QString mplayerPath;
1582 HKEY registryKeyHandle;
1584 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, registryKey, 0, KEY_READ, ®istryKeyHandle) == ERROR_SUCCESS)
1586 wchar_t Buffer[4096];
1587 DWORD BuffSize = sizeof(wchar_t*) * 4096;
1588 if(RegQueryValueExW(registryKeyHandle, L"InstallLocation", 0, 0, reinterpret_cast<BYTE*>(Buffer), &BuffSize) == ERROR_SUCCESS)
1590 mplayerPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(Buffer));
1594 if(!mplayerPath.isEmpty())
1596 QDir mplayerDir(mplayerPath);
1597 if(mplayerDir.exists())
1599 for(int i = 0; i < 3; i++)
1601 if(mplayerDir.exists(appNames[i]))
1603 QProcess::startDetached(mplayerDir.absoluteFilePath(appNames[i]), QStringList() << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
1610 QDesktopServices::openUrl(QString("file:///").append(m_fileListModel->getFile(index).filePath()));
1614 * Find selected file in explorer
1616 void MainWindow::findFileContextActionTriggered(void)
1618 QModelIndex index = sourceFileView->currentIndex();
1621 QString systemRootPath;
1623 QDir systemRoot(lamexp_known_folder(lamexp_folder_systemfolder));
1624 if(systemRoot.exists() && systemRoot.cdUp())
1626 systemRootPath = systemRoot.canonicalPath();
1629 if(!systemRootPath.isEmpty())
1631 QFileInfo explorer(QString("%1/explorer.exe").arg(systemRootPath));
1632 if(explorer.exists() && explorer.isFile())
1634 QProcess::execute(explorer.canonicalFilePath(), QStringList() << "/select," << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
1640 qWarning("SystemRoot directory could not be detected!");
1646 * Show context menu for output folder
1648 void MainWindow::outputFolderContextMenu(const QPoint &pos)
1651 if(pos.x() <= outputFolderView->width() && pos.y() <= outputFolderView->height() && pos.x() >= 0 && pos.y() >= 0)
1653 m_outputFolderContextMenu->popup(outputFolderView->mapToGlobal(pos));
1658 * Show selected folder in explorer
1660 void MainWindow::showFolderContextActionTriggered(void)
1662 QDesktopServices::openUrl(QUrl::fromLocalFile(m_fileSystemModel->filePath(outputFolderView->currentIndex())));
1666 * Disable update reminder action
1668 void MainWindow::disableUpdateReminderActionTriggered(bool checked)
1672 if(0 == QMessageBox::question(this, tr("Disable Update Reminder"), tr("Do you really want to disable the update reminder?"), tr("Yes"), tr("No"), QString(), 1))
1674 QMessageBox::information(this, tr("Update Reminder"), QString("%1<br>%2").arg(tr("The update reminder has been disabled."), tr("Please remember to check for updates at regular intervals!")));
1675 m_settings->autoUpdateEnabled(false);
1679 m_settings->autoUpdateEnabled(true);
1684 QMessageBox::information(this, tr("Update Reminder"), tr("The update reminder has been re-enabled."));
1685 m_settings->autoUpdateEnabled(true);
1688 actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
1692 * Disable sound effects action
1694 void MainWindow::disableSoundsActionTriggered(bool checked)
1698 if(0 == QMessageBox::question(this, tr("Disable Sound Effects"), tr("Do you really want to disable all sound effects?"), tr("Yes"), tr("No"), QString(), 1))
1700 QMessageBox::information(this, tr("Sound Effects"), tr("All sound effects have been disabled."));
1701 m_settings->soundsEnabled(false);
1705 m_settings->soundsEnabled(true);
1710 QMessageBox::information(this, tr("Sound Effects"), tr("The sound effects have been re-enabled."));
1711 m_settings->soundsEnabled(true);
1714 actionDisableSounds->setChecked(!m_settings->soundsEnabled());
1718 * Disable Nero AAC encoder action
1720 void MainWindow::disableNeroAacNotificationsActionTriggered(bool checked)
1724 if(0 == QMessageBox::question(this, tr("Nero AAC Notifications"), tr("Do you really want to disable all Nero AAC Encoder notifications?"), tr("Yes"), tr("No"), QString(), 1))
1726 QMessageBox::information(this, tr("Nero AAC Notifications"), tr("All Nero AAC Encoder notifications have been disabled."));
1727 m_settings->neroAacNotificationsEnabled(false);
1731 m_settings->neroAacNotificationsEnabled(true);
1736 QMessageBox::information(this, tr("Nero AAC Notifications"), tr("The Nero AAC Encoder notifications have been re-enabled."));
1737 m_settings->neroAacNotificationsEnabled(true);
1740 actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
1744 * Disable WMA Decoder component action
1746 void MainWindow::disableWmaDecoderNotificationsActionTriggered(bool checked)
1750 if(0 == QMessageBox::question(this, tr("WMA Decoder Notifications"), tr("Do you really want to disable all WMA Decoder notifications?"), tr("Yes"), tr("No"), QString(), 1))
1752 QMessageBox::information(this, tr("WMA Decoder Notifications"), tr("All WMA Decoder notifications have been disabled."));
1753 m_settings->wmaDecoderNotificationsEnabled(false);
1757 m_settings->wmaDecoderNotificationsEnabled(true);
1762 QMessageBox::information(this, tr("WMA Decoder Notifications"), tr("The WMA Decoder notifications have been re-enabled."));
1763 m_settings->wmaDecoderNotificationsEnabled(true);
1766 actionDisableWmaDecoderNotifications->setChecked(!m_settings->wmaDecoderNotificationsEnabled());
1770 * Download and install WMA Decoder component
1772 void MainWindow::installWMADecoderActionTriggered(bool checked)
1774 static const char *download_url = "http://www.nch.com.au/components/wmawav.exe";
1775 static const char *download_hash = "52a3b0e6690faf3f830c336d3c0eadfb7a4e9bc6";
1777 if(QMessageBox::question(this, tr("Install WMA Decoder"), tr("Do you want to download and install the WMA File Decoder component now?"), tr("Download && Install"), tr("Cancel")) != 0)
1782 QString binaryWGet = lamexp_lookup_tool("wget.exe");
1783 QString binaryElevator = lamexp_lookup_tool("elevator.exe");
1785 if(binaryWGet.isEmpty() || binaryElevator.isEmpty())
1787 throw "Required binary is not available!";
1792 QString setupFile = QString("%1/%2.exe").arg(lamexp_temp_folder(), lamexp_rand_str());
1795 process.setWorkingDirectory(QFileInfo(setupFile).absolutePath());
1798 connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
1799 connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), &loop, SLOT(quit()));
1801 process.start(binaryWGet, QStringList() << "-O" << QFileInfo(setupFile).fileName() << download_url);
1802 m_banner->show(tr("Downloading WMA Decoder Setup, please wait..."), &loop);
1804 if(process.exitCode() != 0 || QFileInfo(setupFile).size() < 10240)
1806 QFile::remove(setupFile);
1807 if(QMessageBox::critical(this, tr("Download Failed"), tr("Failed to download the WMA Decoder setup. Check your internet connection!"), tr("Try Again"), tr("Cancel")) == 0)
1814 QFile setupFileContent(setupFile);
1815 QCryptographicHash setupFileHash(QCryptographicHash::Sha1);
1817 setupFileContent.open(QIODevice::ReadOnly);
1818 if(setupFileContent.isOpen() && setupFileContent.isReadable())
1820 setupFileHash.addData(setupFileContent.readAll());
1821 setupFileContent.close();
1824 if(_stricmp(setupFileHash.result().toHex().constData(), download_hash))
1826 qWarning("Hash miscompare:\n Expected %s\n Detected %s\n", download_hash, setupFileHash.result().toHex().constData());
1827 QFile::remove(setupFile);
1828 if(QMessageBox::critical(this, tr("Download Failed"), tr("The download seems to be corrupted. Please try again!"), tr("Try Again"), tr("Cancel")) == 0)
1835 QApplication::setOverrideCursor(Qt::WaitCursor);
1836 process.start(binaryElevator, QStringList() << QString("/exec=%1").arg(setupFile));
1837 loop.exec(QEventLoop::ExcludeUserInputEvents);
1838 QFile::remove(setupFile);
1839 QApplication::restoreOverrideCursor();
1841 if(QMessageBox::information(this, tr("WMA Decoder"), tr("The WMA File Decoder has been installed. Please restart LameXP now!"), tr("Quit LameXP"), tr("Postpone")) == 0)
1843 QApplication::quit();
1849 void MainWindow::showDropBoxWidgetActionTriggered(bool checked)
1851 m_settings->dropBoxWidgetEnabled(true);
1853 if(!m_dropBox->isVisible())
1858 FLASH_WINDOW(m_dropBox);