Updated Ukrainian translation.
[LameXP.git] / src / Dialog_MainWindow.cpp
bloba1f611e4f59b7cff0e95dd2359fab9050b6ffe24
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
22 #include "Dialog_MainWindow.h"
24 //LameXP includes
25 #include "Global.h"
26 #include "Resource.h"
27 #include "Dialog_WorkingBanner.h"
28 #include "Dialog_MetaInfo.h"
29 #include "Dialog_About.h"
30 #include "Dialog_Update.h"
31 #include "Dialog_DropBox.h"
32 #include "Dialog_CueImport.h"
33 #include "Dialog_LogView.h"
34 #include "Thread_FileAnalyzer.h"
35 #include "Thread_FileAnalyzer_ST.h"
36 #include "Thread_MessageHandler.h"
37 #include "Model_MetaInfo.h"
38 #include "Model_Settings.h"
39 #include "Model_FileList.h"
40 #include "Model_FileSystem.h"
41 #include "WinSevenTaskbar.h"
42 #include "Registry_Decoder.h"
43 #include "ShellIntegration.h"
44 #include "CustomEventFilter.h"
46 //Qt includes
47 #include <QMessageBox>
48 #include <QTimer>
49 #include <QDesktopWidget>
50 #include <QDate>
51 #include <QFileDialog>
52 #include <QInputDialog>
53 #include <QFileSystemModel>
54 #include <QDesktopServices>
55 #include <QUrl>
56 #include <QPlastiqueStyle>
57 #include <QCleanlooksStyle>
58 #include <QWindowsVistaStyle>
59 #include <QWindowsStyle>
60 #include <QSysInfo>
61 #include <QDragEnterEvent>
62 #include <QMimeData>
63 #include <QProcess>
64 #include <QUuid>
65 #include <QProcessEnvironment>
66 #include <QCryptographicHash>
67 #include <QTranslator>
68 #include <QResource>
69 #include <QScrollBar>
71 //System includes
72 #include <MMSystem.h>
73 #include <ShellAPI.h>
75 ////////////////////////////////////////////////////////////
76 // Helper macros
77 ////////////////////////////////////////////////////////////
79 #define ABORT_IF_BUSY do \
80 { \
81 if(m_banner->isVisible() || m_delayedFileTimer->isActive()) \
82 { \
83 MessageBeep(MB_ICONEXCLAMATION); \
84 return; \
85 } \
86 } \
87 while(0)
89 #define SET_TEXT_COLOR(WIDGET, COLOR) do \
90 { \
91 QPalette _palette = WIDGET->palette(); \
92 _palette.setColor(QPalette::WindowText, (COLOR)); \
93 _palette.setColor(QPalette::Text, (COLOR)); \
94 WIDGET->setPalette(_palette); \
95 } \
96 while(0)
98 #define SET_FONT_BOLD(WIDGET,BOLD) do \
99 { \
100 QFont _font = WIDGET->font(); \
101 _font.setBold(BOLD); \
102 WIDGET->setFont(_font); \
104 while(0)
106 #define TEMP_HIDE_DROPBOX(CMD) do \
108 bool _dropBoxVisible = m_dropBox->isVisible(); \
109 if(_dropBoxVisible) m_dropBox->hide(); \
110 do { CMD } while(0); \
111 if(_dropBoxVisible) m_dropBox->show(); \
113 while(0)
115 #define SET_MODEL(VIEW, MODEL) do \
117 QItemSelectionModel *_tmp = (VIEW)->selectionModel(); \
118 (VIEW)->setModel(MODEL); \
119 LAMEXP_DELETE(_tmp); \
121 while(0)
123 #define SET_CHECKBOX_STATE(CHCKBX, STATE) do \
125 if((CHCKBX)->isChecked() != (STATE)) \
127 (CHCKBX)->click(); \
129 if((CHCKBX)->isChecked() != (STATE)) \
131 qWarning("Warning: Failed to set checkbox " #CHCKBX " state!"); \
134 while(0)
136 #define TRIM_STRING_RIGHT(STR) do \
138 while((STR.length() > 0) && STR[STR.length()-1].isSpace()) STR.chop(1); \
140 while(0)
142 #define LINK(URL) QString("<a href=\"%1\">%2</a>").arg(URL).arg(QString(URL).replace("-", "&minus;"))
143 #define FSLINK(PATH) QString("<a href=\"file:///%1\">%2</a>").arg(PATH).arg(QString(PATH).replace("-", "&minus;"))
144 #define USE_NATIVE_FILE_DIALOG (lamexp_themes_enabled() || ((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) < QSysInfo::WV_XP))
145 #define CENTER_CURRENT_OUTPUT_FOLDER_DELAYED QTimer::singleShot(125, this, SLOT(centerOutputFolderModel()))
147 ////////////////////////////////////////////////////////////
148 // Constructor
149 ////////////////////////////////////////////////////////////
151 MainWindow::MainWindow(FileListModel *fileListModel, AudioFileModel *metaInfo, SettingsModel *settingsModel, QWidget *parent)
153 QMainWindow(parent),
154 m_fileListModel(fileListModel),
155 m_metaData(metaInfo),
156 m_settings(settingsModel),
157 m_fileSystemModel(NULL),
158 m_neroEncoderAvailable(lamexp_check_tool("neroAacEnc.exe") && lamexp_check_tool("neroAacDec.exe") && lamexp_check_tool("neroAacTag.exe")),
159 m_fhgEncoderAvailable(lamexp_check_tool("fhgaacenc.exe") && lamexp_check_tool("enc_fhgaac.dll") && lamexp_check_tool("nsutil.dll") && lamexp_check_tool("libmp4v2.dll")),
160 m_qaacEncoderAvailable(lamexp_check_tool("qaac.exe") && lamexp_check_tool("libsoxrate.dll")),
161 m_accepted(false),
162 m_firstTimeShown(true),
163 m_outputFolderViewCentering(false),
164 m_outputFolderViewInitCounter(0)
166 //Init the dialog, from the .ui file
167 setupUi(this);
168 setWindowFlags(windowFlags() ^ Qt::WindowMaximizeButtonHint);
170 //Register meta types
171 qRegisterMetaType<AudioFileModel>("AudioFileModel");
173 //Enabled main buttons
174 connect(buttonAbout, SIGNAL(clicked()), this, SLOT(aboutButtonClicked()));
175 connect(buttonStart, SIGNAL(clicked()), this, SLOT(encodeButtonClicked()));
176 connect(buttonQuit, SIGNAL(clicked()), this, SLOT(closeButtonClicked()));
178 //Setup tab widget
179 tabWidget->setCurrentIndex(0);
180 connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabPageChanged(int)));
182 //--------------------------------
183 // Setup "Source" tab
184 //--------------------------------
186 sourceFileView->setModel(m_fileListModel);
187 sourceFileView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
188 sourceFileView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
189 sourceFileView->setContextMenuPolicy(Qt::CustomContextMenu);
190 sourceFileView->viewport()->installEventFilter(this);
191 m_dropNoteLabel = new QLabel(sourceFileView);
192 m_dropNoteLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
193 SET_FONT_BOLD(m_dropNoteLabel, true);
194 SET_TEXT_COLOR(m_dropNoteLabel, Qt::darkGray);
195 m_sourceFilesContextMenu = new QMenu();
196 m_showDetailsContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/zoom.png"), "N/A");
197 m_previewContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/sound.png"), "N/A");
198 m_findFileContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/folder_go.png"), "N/A");
199 m_sourceFilesContextMenu->addSeparator();
200 m_exportCsvContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/table_save.png"), "N/A");
201 m_importCsvContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/folder_table.png"), "N/A");
202 SET_FONT_BOLD(m_showDetailsContextAction, true);
203 connect(buttonAddFiles, SIGNAL(clicked()), this, SLOT(addFilesButtonClicked()));
204 connect(buttonRemoveFile, SIGNAL(clicked()), this, SLOT(removeFileButtonClicked()));
205 connect(buttonClearFiles, SIGNAL(clicked()), this, SLOT(clearFilesButtonClicked()));
206 connect(buttonFileUp, SIGNAL(clicked()), this, SLOT(fileUpButtonClicked()));
207 connect(buttonFileDown, SIGNAL(clicked()), this, SLOT(fileDownButtonClicked()));
208 connect(buttonShowDetails, SIGNAL(clicked()), this, SLOT(showDetailsButtonClicked()));
209 connect(m_fileListModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(sourceModelChanged()));
210 connect(m_fileListModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(sourceModelChanged()));
211 connect(m_fileListModel, SIGNAL(modelReset()), this, SLOT(sourceModelChanged()));
212 connect(sourceFileView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(sourceFilesContextMenu(QPoint)));
213 connect(sourceFileView->verticalScrollBar(), SIGNAL(sliderMoved(int)), this, SLOT(sourceFilesScrollbarMoved(int)));
214 connect(sourceFileView->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(sourceFilesScrollbarMoved(int)));
215 connect(m_showDetailsContextAction, SIGNAL(triggered(bool)), this, SLOT(showDetailsButtonClicked()));
216 connect(m_previewContextAction, SIGNAL(triggered(bool)), this, SLOT(previewContextActionTriggered()));
217 connect(m_findFileContextAction, SIGNAL(triggered(bool)), this, SLOT(findFileContextActionTriggered()));
218 connect(m_exportCsvContextAction, SIGNAL(triggered(bool)), this, SLOT(exportCsvContextActionTriggered()));
219 connect(m_importCsvContextAction, SIGNAL(triggered(bool)), this, SLOT(importCsvContextActionTriggered()));
221 //--------------------------------
222 // Setup "Output" tab
223 //--------------------------------
225 outputFolderView->setHeaderHidden(true);
226 outputFolderView->setAnimated(false);
227 outputFolderView->setMouseTracking(false);
228 outputFolderView->setContextMenuPolicy(Qt::CustomContextMenu);
229 outputFolderView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
231 m_evenFilterOutputFolderMouse = new CustomEventFilter;
232 outputFoldersEditorLabel->installEventFilter(m_evenFilterOutputFolderMouse);
233 outputFoldersFovoritesLabel->installEventFilter(m_evenFilterOutputFolderMouse);
234 outputFolderLabel->installEventFilter(m_evenFilterOutputFolderMouse);
236 m_evenFilterOutputFolderView = new CustomEventFilter;
237 outputFolderView->installEventFilter(m_evenFilterOutputFolderView);
239 SET_CHECKBOX_STATE(saveToSourceFolderCheckBox, m_settings->outputToSourceDir());
240 prependRelativePathCheckBox->setChecked(m_settings->prependRelativeSourcePath());
242 connect(outputFolderView, SIGNAL(clicked(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
243 connect(outputFolderView, SIGNAL(activated(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
244 connect(outputFolderView, SIGNAL(pressed(QModelIndex)), this, SLOT(outputFolderViewClicked(QModelIndex)));
245 connect(outputFolderView, SIGNAL(entered(QModelIndex)), this, SLOT(outputFolderViewMoved(QModelIndex)));
246 connect(outputFolderView, SIGNAL(expanded(QModelIndex)), this, SLOT(outputFolderItemExpanded(QModelIndex)));
247 connect(buttonMakeFolder, SIGNAL(clicked()), this, SLOT(makeFolderButtonClicked()));
248 connect(buttonGotoHome, SIGNAL(clicked()), SLOT(gotoHomeFolderButtonClicked()));
249 connect(buttonGotoDesktop, SIGNAL(clicked()), this, SLOT(gotoDesktopButtonClicked()));
250 connect(buttonGotoMusic, SIGNAL(clicked()), this, SLOT(gotoMusicFolderButtonClicked()));
251 connect(saveToSourceFolderCheckBox, SIGNAL(clicked()), this, SLOT(saveToSourceFolderChanged()));
252 connect(prependRelativePathCheckBox, SIGNAL(clicked()), this, SLOT(prependRelativePathChanged()));
253 connect(outputFolderEdit, SIGNAL(editingFinished()), this, SLOT(outputFolderEditFinished()));
254 connect(m_evenFilterOutputFolderMouse, SIGNAL(eventOccurred(QWidget*, QEvent*)), this, SLOT(outputFolderMouseEventOccurred(QWidget*, QEvent*)));
255 connect(m_evenFilterOutputFolderView, SIGNAL(eventOccurred(QWidget*, QEvent*)), this, SLOT(outputFolderViewEventOccurred(QWidget*, QEvent*)));
257 if(m_outputFolderContextMenu = new QMenu())
259 m_showFolderContextAction = m_outputFolderContextMenu->addAction(QIcon(":/icons/zoom.png"), "N/A");
260 m_refreshFolderContextAction = m_outputFolderContextMenu->addAction(QIcon(":/icons/arrow_refresh.png"), "N/A");
261 m_outputFolderContextMenu->setDefaultAction(m_showFolderContextAction);
262 connect(outputFolderView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(outputFolderContextMenu(QPoint)));
263 connect(m_showFolderContextAction, SIGNAL(triggered(bool)), this, SLOT(showFolderContextActionTriggered()));
264 connect(m_refreshFolderContextAction, SIGNAL(triggered(bool)), this, SLOT(refreshFolderContextActionTriggered()));
267 if(m_outputFolderFavoritesMenu = new QMenu())
269 m_addFavoriteFolderAction = m_outputFolderFavoritesMenu->addAction(QIcon(":/icons/add.png"), "N/A");
270 m_outputFolderFavoritesMenu->insertSeparator(m_addFavoriteFolderAction);
271 connect(m_addFavoriteFolderAction, SIGNAL(triggered(bool)), this, SLOT(addFavoriteFolderActionTriggered()));
274 outputFolderEdit->setVisible(false);
275 if(m_outputFolderNoteBox = new QLabel(outputFolderView))
277 m_outputFolderNoteBox->setAutoFillBackground(true);
278 m_outputFolderNoteBox->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
279 m_outputFolderNoteBox->setFrameShape(QFrame::StyledPanel);
280 SET_FONT_BOLD(m_outputFolderNoteBox, true);
281 m_outputFolderNoteBox->hide();
285 outputFolderViewClicked(QModelIndex());
286 refreshFavorites();
288 //--------------------------------
289 // Setup "Meta Data" tab
290 //--------------------------------
292 m_metaInfoModel = new MetaInfoModel(m_metaData, 6);
293 m_metaInfoModel->clearData();
294 m_metaInfoModel->setData(m_metaInfoModel->index(4, 1), m_settings->metaInfoPosition());
295 metaDataView->setModel(m_metaInfoModel);
296 metaDataView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
297 metaDataView->verticalHeader()->hide();
298 metaDataView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
299 SET_CHECKBOX_STATE(writeMetaDataCheckBox, m_settings->writeMetaTags());
300 generatePlaylistCheckBox->setChecked(m_settings->createPlaylist());
301 connect(buttonEditMeta, SIGNAL(clicked()), this, SLOT(editMetaButtonClicked()));
302 connect(buttonClearMeta, SIGNAL(clicked()), this, SLOT(clearMetaButtonClicked()));
303 connect(writeMetaDataCheckBox, SIGNAL(clicked()), this, SLOT(metaTagsEnabledChanged()));
304 connect(generatePlaylistCheckBox, SIGNAL(clicked()), this, SLOT(playlistEnabledChanged()));
306 //--------------------------------
307 //Setup "Compression" tab
308 //--------------------------------
310 m_encoderButtonGroup = new QButtonGroup(this);
311 m_encoderButtonGroup->addButton(radioButtonEncoderMP3, SettingsModel::MP3Encoder);
312 m_encoderButtonGroup->addButton(radioButtonEncoderVorbis, SettingsModel::VorbisEncoder);
313 m_encoderButtonGroup->addButton(radioButtonEncoderAAC, SettingsModel::AACEncoder);
314 m_encoderButtonGroup->addButton(radioButtonEncoderAC3, SettingsModel::AC3Encoder);
315 m_encoderButtonGroup->addButton(radioButtonEncoderFLAC, SettingsModel::FLACEncoder);
316 m_encoderButtonGroup->addButton(radioButtonEncoderOpus, SettingsModel::OpusEncoder);
317 m_encoderButtonGroup->addButton(radioButtonEncoderDCA, SettingsModel::DCAEncoder);
318 m_encoderButtonGroup->addButton(radioButtonEncoderPCM, SettingsModel::PCMEncoder);
320 m_modeButtonGroup = new QButtonGroup(this);
321 m_modeButtonGroup->addButton(radioButtonModeQuality, SettingsModel::VBRMode);
322 m_modeButtonGroup->addButton(radioButtonModeAverageBitrate, SettingsModel::ABRMode);
323 m_modeButtonGroup->addButton(radioButtonConstBitrate, SettingsModel::CBRMode);
325 radioButtonEncoderAAC->setEnabled(m_neroEncoderAvailable || m_fhgEncoderAvailable || m_qaacEncoderAvailable);
326 radioButtonEncoderMP3->setChecked(m_settings->compressionEncoder() == SettingsModel::MP3Encoder);
327 radioButtonEncoderVorbis->setChecked(m_settings->compressionEncoder() == SettingsModel::VorbisEncoder);
328 radioButtonEncoderAAC->setChecked((m_settings->compressionEncoder() == SettingsModel::AACEncoder) && (m_neroEncoderAvailable || m_fhgEncoderAvailable || m_qaacEncoderAvailable));
329 radioButtonEncoderAC3->setChecked(m_settings->compressionEncoder() == SettingsModel::AC3Encoder);
330 radioButtonEncoderFLAC->setChecked(m_settings->compressionEncoder() == SettingsModel::FLACEncoder);
331 radioButtonEncoderOpus->setChecked(m_settings->compressionEncoder() == SettingsModel::OpusEncoder);
332 radioButtonEncoderDCA->setChecked(m_settings->compressionEncoder() == SettingsModel::DCAEncoder);
333 radioButtonEncoderPCM->setChecked(m_settings->compressionEncoder() == SettingsModel::PCMEncoder);
334 radioButtonModeQuality->setChecked(m_settings->compressionRCMode() == SettingsModel::VBRMode);
335 radioButtonModeAverageBitrate->setChecked(m_settings->compressionRCMode() == SettingsModel::ABRMode);
336 radioButtonConstBitrate->setChecked(m_settings->compressionRCMode() == SettingsModel::CBRMode);
337 sliderBitrate->setValue(m_settings->compressionBitrate());
339 m_evenFilterCompressionTab = new CustomEventFilter();
340 labelCompressionHelp->installEventFilter(m_evenFilterCompressionTab);
342 connect(m_encoderButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateEncoder(int)));
343 connect(m_modeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateRCMode(int)));
344 connect(m_evenFilterCompressionTab, SIGNAL(eventOccurred(QWidget*, QEvent*)), this, SLOT(compressionTabEventOccurred(QWidget*, QEvent*)));
345 connect(sliderBitrate, SIGNAL(valueChanged(int)), this, SLOT(updateBitrate(int)));
347 updateEncoder(m_encoderButtonGroup->checkedId());
349 //--------------------------------
350 //Setup "Advanced Options" tab
351 //--------------------------------
353 sliderLameAlgoQuality->setValue(m_settings->lameAlgoQuality());
354 if(m_settings->maximumInstances() > 0) sliderMaxInstances->setValue(m_settings->maximumInstances());
356 spinBoxBitrateManagementMin->setValue(m_settings->bitrateManagementMinRate());
357 spinBoxBitrateManagementMax->setValue(m_settings->bitrateManagementMaxRate());
358 spinBoxNormalizationFilter->setValue(static_cast<double>(m_settings->normalizationFilterMaxVolume()) / 100.0);
359 spinBoxToneAdjustBass->setValue(static_cast<double>(m_settings->toneAdjustBass()) / 100.0);
360 spinBoxToneAdjustTreble->setValue(static_cast<double>(m_settings->toneAdjustTreble()) / 100.0);
361 spinBoxAftenSearchSize->setValue(m_settings->aftenExponentSearchSize());
362 spinBoxOpusComplexity->setValue(m_settings->opusComplexity());
364 comboBoxMP3ChannelMode->setCurrentIndex(m_settings->lameChannelMode());
365 comboBoxSamplingRate->setCurrentIndex(m_settings->samplingRate());
366 comboBoxAACProfile->setCurrentIndex(m_settings->aacEncProfile());
367 comboBoxAftenCodingMode->setCurrentIndex(m_settings->aftenAudioCodingMode());
368 comboBoxAftenDRCMode->setCurrentIndex(m_settings->aftenDynamicRangeCompression());
369 comboBoxNormalizationMode->setCurrentIndex(m_settings->normalizationFilterEqualizationMode());
370 comboBoxOpusOptimize->setCurrentIndex(m_settings->opusOptimizeFor());
371 comboBoxOpusFramesize->setCurrentIndex(m_settings->opusFramesize());
373 SET_CHECKBOX_STATE(checkBoxBitrateManagement, m_settings->bitrateManagementEnabled());
374 SET_CHECKBOX_STATE(checkBoxNeroAAC2PassMode, m_settings->neroAACEnable2Pass());
375 SET_CHECKBOX_STATE(checkBoxAftenFastAllocation, m_settings->aftenFastBitAllocation());
376 SET_CHECKBOX_STATE(checkBoxNormalizationFilter, m_settings->normalizationFilterEnabled());
377 SET_CHECKBOX_STATE(checkBoxAutoDetectInstances, (m_settings->maximumInstances() < 1));
378 SET_CHECKBOX_STATE(checkBoxUseSystemTempFolder, m_settings->customTempPathEnabled());
379 SET_CHECKBOX_STATE(checkBoxRenameOutput, m_settings->renameOutputFilesEnabled());
380 SET_CHECKBOX_STATE(checkBoxForceStereoDownmix, m_settings->forceStereoDownmix());
381 SET_CHECKBOX_STATE(checkBoxOpusExpAnalysis, m_settings->opusExpAnalysis());
382 checkBoxNeroAAC2PassMode->setEnabled(!(m_fhgEncoderAvailable || m_qaacEncoderAvailable));
384 lineEditCustomParamLAME->setText(m_settings->customParametersLAME());
385 lineEditCustomParamOggEnc->setText(m_settings->customParametersOggEnc());
386 lineEditCustomParamNeroAAC->setText(m_settings->customParametersAacEnc());
387 lineEditCustomParamFLAC->setText(m_settings->customParametersFLAC());
388 lineEditCustomParamAften->setText(m_settings->customParametersAften());
389 lineEditCustomParamOpus->setText(m_settings->customParametersOpus());
390 lineEditCustomTempFolder->setText(QDir::toNativeSeparators(m_settings->customTempPath()));
391 lineEditRenamePattern->setText(m_settings->renameOutputFilesPattern());
393 m_evenFilterCustumParamsHelp = new CustomEventFilter();
394 helpCustomParamLAME->installEventFilter(m_evenFilterCustumParamsHelp);
395 helpCustomParamOggEnc->installEventFilter(m_evenFilterCustumParamsHelp);
396 helpCustomParamNeroAAC->installEventFilter(m_evenFilterCustumParamsHelp);
397 helpCustomParamFLAC->installEventFilter(m_evenFilterCustumParamsHelp);
398 helpCustomParamAften->installEventFilter(m_evenFilterCustumParamsHelp);
399 helpCustomParamOpus->installEventFilter(m_evenFilterCustumParamsHelp);
401 connect(sliderLameAlgoQuality, SIGNAL(valueChanged(int)), this, SLOT(updateLameAlgoQuality(int)));
402 connect(checkBoxBitrateManagement, SIGNAL(clicked(bool)), this, SLOT(bitrateManagementEnabledChanged(bool)));
403 connect(spinBoxBitrateManagementMin, SIGNAL(valueChanged(int)), this, SLOT(bitrateManagementMinChanged(int)));
404 connect(spinBoxBitrateManagementMax, SIGNAL(valueChanged(int)), this, SLOT(bitrateManagementMaxChanged(int)));
405 connect(comboBoxMP3ChannelMode, SIGNAL(currentIndexChanged(int)), this, SLOT(channelModeChanged(int)));
406 connect(comboBoxSamplingRate, SIGNAL(currentIndexChanged(int)), this, SLOT(samplingRateChanged(int)));
407 connect(checkBoxNeroAAC2PassMode, SIGNAL(clicked(bool)), this, SLOT(neroAAC2PassChanged(bool)));
408 connect(comboBoxAACProfile, SIGNAL(currentIndexChanged(int)), this, SLOT(neroAACProfileChanged(int)));
409 connect(checkBoxNormalizationFilter, SIGNAL(clicked(bool)), this, SLOT(normalizationEnabledChanged(bool)));
410 connect(comboBoxAftenCodingMode, SIGNAL(currentIndexChanged(int)), this, SLOT(aftenCodingModeChanged(int)));
411 connect(comboBoxAftenDRCMode, SIGNAL(currentIndexChanged(int)), this, SLOT(aftenDRCModeChanged(int)));
412 connect(spinBoxAftenSearchSize, SIGNAL(valueChanged(int)), this, SLOT(aftenSearchSizeChanged(int)));
413 connect(checkBoxAftenFastAllocation, SIGNAL(clicked(bool)), this, SLOT(aftenFastAllocationChanged(bool)));
414 connect(spinBoxNormalizationFilter, SIGNAL(valueChanged(double)), this, SLOT(normalizationMaxVolumeChanged(double)));
415 connect(comboBoxNormalizationMode, SIGNAL(currentIndexChanged(int)), this, SLOT(normalizationModeChanged(int)));
416 connect(spinBoxToneAdjustBass, SIGNAL(valueChanged(double)), this, SLOT(toneAdjustBassChanged(double)));
417 connect(spinBoxToneAdjustTreble, SIGNAL(valueChanged(double)), this, SLOT(toneAdjustTrebleChanged(double)));
418 connect(buttonToneAdjustReset, SIGNAL(clicked()), this, SLOT(toneAdjustTrebleReset()));
419 connect(lineEditCustomParamLAME, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
420 connect(lineEditCustomParamOggEnc, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
421 connect(lineEditCustomParamNeroAAC, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
422 connect(lineEditCustomParamFLAC, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
423 connect(lineEditCustomParamAften, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
424 connect(lineEditCustomParamOpus, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
425 connect(sliderMaxInstances, SIGNAL(valueChanged(int)), this, SLOT(updateMaximumInstances(int)));
426 connect(checkBoxAutoDetectInstances, SIGNAL(clicked(bool)), this, SLOT(autoDetectInstancesChanged(bool)));
427 connect(buttonBrowseCustomTempFolder, SIGNAL(clicked()), this, SLOT(browseCustomTempFolderButtonClicked()));
428 connect(lineEditCustomTempFolder, SIGNAL(textChanged(QString)), this, SLOT(customTempFolderChanged(QString)));
429 connect(checkBoxUseSystemTempFolder, SIGNAL(clicked(bool)), this, SLOT(useCustomTempFolderChanged(bool)));
430 connect(buttonResetAdvancedOptions, SIGNAL(clicked()), this, SLOT(resetAdvancedOptionsButtonClicked()));
431 connect(checkBoxRenameOutput, SIGNAL(clicked(bool)), this, SLOT(renameOutputEnabledChanged(bool)));
432 connect(lineEditRenamePattern, SIGNAL(editingFinished()), this, SLOT(renameOutputPatternChanged()));
433 connect(lineEditRenamePattern, SIGNAL(textChanged(QString)), this, SLOT(renameOutputPatternChanged(QString)));
434 connect(labelShowRenameMacros, SIGNAL(linkActivated(QString)), this, SLOT(showRenameMacros(QString)));
435 connect(checkBoxForceStereoDownmix, SIGNAL(clicked(bool)), this, SLOT(forceStereoDownmixEnabledChanged(bool)));
436 connect(comboBoxOpusOptimize, SIGNAL(currentIndexChanged(int)), SLOT(opusSettingsChanged()));
437 connect(comboBoxOpusFramesize, SIGNAL(currentIndexChanged(int)), this, SLOT(opusSettingsChanged()));
438 connect(spinBoxOpusComplexity, SIGNAL(valueChanged(int)), this, SLOT(opusSettingsChanged()));
439 connect(checkBoxOpusExpAnalysis, SIGNAL(clicked(bool)), this, SLOT(opusSettingsChanged()));
440 connect(m_evenFilterCustumParamsHelp, SIGNAL(eventOccurred(QWidget*, QEvent*)), this, SLOT(customParamsHelpRequested(QWidget*, QEvent*)));
442 //--------------------------------
443 // Force initial GUI update
444 //--------------------------------
446 updateLameAlgoQuality(sliderLameAlgoQuality->value());
447 updateMaximumInstances(sliderMaxInstances->value());
448 toneAdjustTrebleChanged(spinBoxToneAdjustTreble->value());
449 toneAdjustBassChanged(spinBoxToneAdjustBass->value());
450 customParamsChanged();
452 //--------------------------------
453 // Initialize actions
454 //--------------------------------
456 //Activate file menu actions
457 actionOpenFolder->setData(QVariant::fromValue<bool>(false));
458 actionOpenFolderRecursively->setData(QVariant::fromValue<bool>(true));
459 connect(actionOpenFolder, SIGNAL(triggered()), this, SLOT(openFolderActionActivated()));
460 connect(actionOpenFolderRecursively, SIGNAL(triggered()), this, SLOT(openFolderActionActivated()));
462 //Activate view menu actions
463 m_tabActionGroup = new QActionGroup(this);
464 m_tabActionGroup->addAction(actionSourceFiles);
465 m_tabActionGroup->addAction(actionOutputDirectory);
466 m_tabActionGroup->addAction(actionCompression);
467 m_tabActionGroup->addAction(actionMetaData);
468 m_tabActionGroup->addAction(actionAdvancedOptions);
469 actionSourceFiles->setData(0);
470 actionOutputDirectory->setData(1);
471 actionMetaData->setData(2);
472 actionCompression->setData(3);
473 actionAdvancedOptions->setData(4);
474 actionSourceFiles->setChecked(true);
475 connect(m_tabActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(tabActionActivated(QAction*)));
477 //Activate style menu actions
478 m_styleActionGroup = new QActionGroup(this);
479 m_styleActionGroup->addAction(actionStylePlastique);
480 m_styleActionGroup->addAction(actionStyleCleanlooks);
481 m_styleActionGroup->addAction(actionStyleWindowsVista);
482 m_styleActionGroup->addAction(actionStyleWindowsXP);
483 m_styleActionGroup->addAction(actionStyleWindowsClassic);
484 actionStylePlastique->setData(0);
485 actionStyleCleanlooks->setData(1);
486 actionStyleWindowsVista->setData(2);
487 actionStyleWindowsXP->setData(3);
488 actionStyleWindowsClassic->setData(4);
489 actionStylePlastique->setChecked(true);
490 actionStyleWindowsXP->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_XP && lamexp_themes_enabled());
491 actionStyleWindowsVista->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_VISTA && lamexp_themes_enabled());
492 connect(m_styleActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(styleActionActivated(QAction*)));
493 styleActionActivated(NULL);
495 //Populate the language menu
496 m_languageActionGroup = new QActionGroup(this);
497 QStringList translations = lamexp_query_translations();
498 while(!translations.isEmpty())
500 QString langId = translations.takeFirst();
501 QAction *currentLanguage = new QAction(this);
502 currentLanguage->setData(langId);
503 currentLanguage->setText(lamexp_translation_name(langId));
504 currentLanguage->setIcon(QIcon(QString(":/flags/%1.png").arg(langId)));
505 currentLanguage->setCheckable(true);
506 m_languageActionGroup->addAction(currentLanguage);
507 menuLanguage->insertAction(actionLoadTranslationFromFile, currentLanguage);
509 menuLanguage->insertSeparator(actionLoadTranslationFromFile);
510 connect(actionLoadTranslationFromFile, SIGNAL(triggered(bool)), this, SLOT(languageFromFileActionActivated(bool)));
511 connect(m_languageActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(languageActionActivated(QAction*)));
513 //Activate tools menu actions
514 actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
515 actionDisableSounds->setChecked(!m_settings->soundsEnabled());
516 actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
517 actionDisableSlowStartupNotifications->setChecked(!m_settings->antivirNotificationsEnabled());
518 actionDisableShellIntegration->setChecked(!m_settings->shellIntegrationEnabled());
519 actionDisableShellIntegration->setDisabled(lamexp_portable_mode() && actionDisableShellIntegration->isChecked());
520 actionCheckForBetaUpdates->setChecked(m_settings->autoUpdateCheckBeta() || lamexp_version_demo());
521 actionCheckForBetaUpdates->setEnabled(!lamexp_version_demo());
522 actionHibernateComputer->setChecked(m_settings->hibernateComputer());
523 actionHibernateComputer->setEnabled(lamexp_is_hibernation_supported());
524 connect(actionDisableUpdateReminder, SIGNAL(triggered(bool)), this, SLOT(disableUpdateReminderActionTriggered(bool)));
525 connect(actionDisableSounds, SIGNAL(triggered(bool)), this, SLOT(disableSoundsActionTriggered(bool)));
526 connect(actionDisableNeroAacNotifications, SIGNAL(triggered(bool)), this, SLOT(disableNeroAacNotificationsActionTriggered(bool)));
527 connect(actionDisableSlowStartupNotifications, SIGNAL(triggered(bool)), this, SLOT(disableSlowStartupNotificationsActionTriggered(bool)));
528 connect(actionDisableShellIntegration, SIGNAL(triggered(bool)), this, SLOT(disableShellIntegrationActionTriggered(bool)));
529 connect(actionShowDropBoxWidget, SIGNAL(triggered(bool)), this, SLOT(showDropBoxWidgetActionTriggered(bool)));
530 connect(actionHibernateComputer, SIGNAL(triggered(bool)), this, SLOT(hibernateComputerActionTriggered(bool)));
531 connect(actionCheckForBetaUpdates, SIGNAL(triggered(bool)), this, SLOT(checkForBetaUpdatesActionTriggered(bool)));
532 connect(actionImportCueSheet, SIGNAL(triggered(bool)), this, SLOT(importCueSheetActionTriggered(bool)));
534 //Activate help menu actions
535 actionVisitHomepage->setData(QString::fromLatin1(lamexp_website_url()));
536 actionVisitSupport->setData(QString::fromLatin1(lamexp_support_url()));
537 actionDocumentFAQ->setData(QString("%1/FAQ.html").arg(QApplication::applicationDirPath()));
538 actionDocumentChangelog->setData(QString("%1/Changelog.html").arg(QApplication::applicationDirPath()));
539 actionDocumentTranslate->setData(QString("%1/Translate.html").arg(QApplication::applicationDirPath()));
540 connect(actionCheckUpdates, SIGNAL(triggered()), this, SLOT(checkUpdatesActionActivated()));
541 connect(actionVisitHomepage, SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
542 connect(actionVisitSupport, SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
543 connect(actionDocumentFAQ, SIGNAL(triggered()), this, SLOT(documentActionActivated()));
544 connect(actionDocumentChangelog, SIGNAL(triggered()), this, SLOT(documentActionActivated()));
545 connect(actionDocumentTranslate, SIGNAL(triggered()), this, SLOT(documentActionActivated()));
547 //--------------------------------
548 // Prepare to show window
549 //--------------------------------
551 //Center window in screen
552 QRect desktopRect = QApplication::desktop()->screenGeometry();
553 QRect thisRect = this->geometry();
554 move((desktopRect.width() - thisRect.width()) / 2, (desktopRect.height() - thisRect.height()) / 2);
555 setMinimumSize(thisRect.width(), thisRect.height());
557 //Create banner
558 m_banner = new WorkingBanner(this);
560 //Create DropBox widget
561 m_dropBox = new DropBox(this, m_fileListModel, m_settings);
562 connect(m_fileListModel, SIGNAL(modelReset()), m_dropBox, SLOT(modelChanged()));
563 connect(m_fileListModel, SIGNAL(rowsInserted(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
564 connect(m_fileListModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), m_dropBox, SLOT(modelChanged()));
565 connect(m_fileListModel, SIGNAL(rowAppended()), m_dropBox, SLOT(modelChanged()));
567 //Create message handler thread
568 m_messageHandler = new MessageHandlerThread();
569 m_delayedFileList = new QStringList();
570 m_delayedFileTimer = new QTimer();
571 m_delayedFileTimer->setSingleShot(true);
572 m_delayedFileTimer->setInterval(5000);
573 connect(m_messageHandler, SIGNAL(otherInstanceDetected()), this, SLOT(notifyOtherInstance()), Qt::QueuedConnection);
574 connect(m_messageHandler, SIGNAL(fileReceived(QString)), this, SLOT(addFileDelayed(QString)), Qt::QueuedConnection);
575 connect(m_messageHandler, SIGNAL(folderReceived(QString, bool)), this, SLOT(addFolderDelayed(QString, bool)), Qt::QueuedConnection);
576 connect(m_messageHandler, SIGNAL(killSignalReceived()), this, SLOT(close()), Qt::QueuedConnection);
577 connect(m_delayedFileTimer, SIGNAL(timeout()), this, SLOT(handleDelayedFiles()));
578 m_messageHandler->start();
580 //Load translation file
581 QList<QAction*> languageActions = m_languageActionGroup->actions();
582 while(!languageActions.isEmpty())
584 QAction *currentLanguage = languageActions.takeFirst();
585 if(currentLanguage->data().toString().compare(m_settings->currentLanguage(), Qt::CaseInsensitive) == 0)
587 currentLanguage->setChecked(true);
588 languageActionActivated(currentLanguage);
592 //Re-translate (make sure we translate once)
593 QEvent languageChangeEvent(QEvent::LanguageChange);
594 changeEvent(&languageChangeEvent);
596 //Enable Drag & Drop
597 this->setAcceptDrops(true);
600 ////////////////////////////////////////////////////////////
601 // Destructor
602 ////////////////////////////////////////////////////////////
604 MainWindow::~MainWindow(void)
606 //Stop message handler thread
607 if(m_messageHandler && m_messageHandler->isRunning())
609 m_messageHandler->stop();
610 if(!m_messageHandler->wait(2500))
612 m_messageHandler->terminate();
613 m_messageHandler->wait();
617 //Unset models
618 SET_MODEL(sourceFileView, NULL);
619 SET_MODEL(outputFolderView, NULL);
620 SET_MODEL(metaDataView, NULL);
622 //Free memory
623 LAMEXP_DELETE(m_tabActionGroup);
624 LAMEXP_DELETE(m_styleActionGroup);
625 LAMEXP_DELETE(m_languageActionGroup);
626 LAMEXP_DELETE(m_banner);
627 LAMEXP_DELETE(m_fileSystemModel);
628 LAMEXP_DELETE(m_messageHandler);
629 LAMEXP_DELETE(m_delayedFileList);
630 LAMEXP_DELETE(m_delayedFileTimer);
631 LAMEXP_DELETE(m_metaInfoModel);
632 LAMEXP_DELETE(m_encoderButtonGroup);
633 LAMEXP_DELETE(m_encoderButtonGroup);
634 LAMEXP_DELETE(m_sourceFilesContextMenu);
635 LAMEXP_DELETE(m_outputFolderFavoritesMenu);
636 LAMEXP_DELETE(m_outputFolderContextMenu);
637 LAMEXP_DELETE(m_dropBox);
638 LAMEXP_DELETE(m_evenFilterCustumParamsHelp);
639 LAMEXP_DELETE(m_evenFilterOutputFolderMouse);
640 LAMEXP_DELETE(m_evenFilterOutputFolderView);
641 LAMEXP_DELETE(m_evenFilterCompressionTab);
644 ////////////////////////////////////////////////////////////
645 // PRIVATE FUNCTIONS
646 ////////////////////////////////////////////////////////////
649 * Add file to source list
651 void MainWindow::addFiles(const QStringList &files)
653 if(files.isEmpty())
655 return;
658 tabWidget->setCurrentIndex(0);
660 //int timeMT = 0, timeST = 0;
662 //--Prepass--
664 //FileAnalyzer_ST *analyzerPre = new FileAnalyzer_ST(files);
665 //connect(analyzerPre, SIGNAL(fileSelected(QString)), m_banner, SLOT(setText(QString)), Qt::QueuedConnection);
666 //connect(analyzerPre, SIGNAL(progressValChanged(unsigned int)), m_banner, SLOT(setProgressVal(unsigned int)), Qt::QueuedConnection);
667 //connect(analyzerPre, SIGNAL(progressMaxChanged(unsigned int)), m_banner, SLOT(setProgressMax(unsigned int)), Qt::QueuedConnection);
668 //connect(analyzerPre, SIGNAL(fileAnalyzed(AudioFileModel)), m_fileListModel, SLOT(addFile(AudioFileModel)), Qt::QueuedConnection);
669 //connect(m_banner, SIGNAL(userAbort()), analyzerPre, SLOT(abortProcess()), Qt::DirectConnection);
671 //try
673 // m_fileListModel->setBlockUpdates(true);
674 // m_banner->show(tr("Adding file(s), please wait..."), analyzerPre);
676 //catch(...)
678 // /* ignore any exceptions that may occur */
681 //--MT--
683 FileAnalyzer *analyzer = new FileAnalyzer(files);
684 connect(analyzer, SIGNAL(fileSelected(QString)), m_banner, SLOT(setText(QString)), Qt::QueuedConnection);
685 connect(analyzer, SIGNAL(progressValChanged(unsigned int)), m_banner, SLOT(setProgressVal(unsigned int)), Qt::QueuedConnection);
686 connect(analyzer, SIGNAL(progressMaxChanged(unsigned int)), m_banner, SLOT(setProgressMax(unsigned int)), Qt::QueuedConnection);
687 connect(analyzer, SIGNAL(fileAnalyzed(AudioFileModel)), m_fileListModel, SLOT(addFile(AudioFileModel)), Qt::QueuedConnection);
688 connect(m_banner, SIGNAL(userAbort()), analyzer, SLOT(abortProcess()), Qt::DirectConnection);
692 m_fileListModel->setBlockUpdates(true);
693 QTime startTime = QTime::currentTime();
694 m_banner->show(tr("Adding file(s), please wait..."), analyzer);
695 //timeMT = startTime.secsTo(QTime::currentTime());
697 catch(...)
699 /* ignore any exceptions that may occur */
702 m_fileListModel->setBlockUpdates(false);
703 qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
704 sourceFileView->update();
705 qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
706 sourceFileView->scrollToBottom();
707 qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
709 if(analyzer->filesDenied())
711 QMessageBox::warning(this, tr("Access Denied"), QString("%1<br>%2").arg(NOBR(tr("%1 file(s) have been rejected, because read access was not granted!").arg(analyzer->filesDenied())), NOBR(tr("This usually means the file is locked by another process."))));
713 if(analyzer->filesDummyCDDA())
715 QMessageBox::warning(this, tr("CDDA Files"), QString("%1<br><br>%2<br>%3").arg(NOBR(tr("%1 file(s) have been rejected, because they are dummy CDDA files!").arg(analyzer->filesDummyCDDA())), NOBR(tr("Sorry, LameXP cannot extract audio tracks from an Audio-CD at present.")), NOBR(tr("We recommend using %1 for that purpose.").arg("<a href=\"http://www.exactaudiocopy.de/\">Exact Audio Copy</a>"))));
717 if(analyzer->filesCueSheet())
719 QMessageBox::warning(this, tr("Cue Sheet"), QString("%1<br>%2").arg(NOBR(tr("%1 file(s) have been rejected, because they appear to be Cue Sheet images!").arg(analyzer->filesCueSheet())), NOBR(tr("Please use LameXP's Cue Sheet wizard for importing Cue Sheet files."))));
721 if(analyzer->filesRejected())
723 QMessageBox::warning(this, tr("Files Rejected"), QString("%1<br>%2").arg(NOBR(tr("%1 file(s) have been rejected, because the file format could not be recognized!").arg(analyzer->filesRejected())), NOBR(tr("This usually means the file is damaged or the file format is not supported."))));
726 LAMEXP_DELETE(analyzer);
727 //LAMEXP_DELETE(analyzerST);
728 //LAMEXP_DELETE(analyzerPre);
730 m_banner->close();
734 * Add folder to source list
736 void MainWindow::addFolder(const QString &path, bool recursive, bool delayed)
738 QFileInfoList folderInfoList;
739 folderInfoList << QFileInfo(path);
740 QStringList fileList;
742 m_banner->show(tr("Scanning folder(s) for files, please wait..."));
744 QApplication::processEvents();
745 GetAsyncKeyState(VK_ESCAPE);
747 while(!folderInfoList.isEmpty())
749 if(GetAsyncKeyState(VK_ESCAPE) & 0x0001)
751 MessageBeep(MB_ICONERROR);
752 qWarning("Operation cancelled by user!");
753 fileList.clear();
754 break;
757 QDir currentDir(folderInfoList.takeFirst().canonicalFilePath());
758 QFileInfoList fileInfoList = currentDir.entryInfoList(QDir::Files | QDir::NoSymLinks);
760 while(!fileInfoList.isEmpty())
762 fileList << fileInfoList.takeFirst().canonicalFilePath();
765 QApplication::processEvents();
767 if(recursive)
769 folderInfoList.append(currentDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks));
770 QApplication::processEvents();
774 m_banner->close();
775 QApplication::processEvents();
777 if(!fileList.isEmpty())
779 if(delayed)
781 addFilesDelayed(fileList);
783 else
785 addFiles(fileList);
791 * Check for updates
793 bool MainWindow::checkForUpdates(void)
795 bool bReadyToInstall = false;
797 UpdateDialog *updateDialog = new UpdateDialog(m_settings, this);
798 updateDialog->exec();
800 if(updateDialog->getSuccess())
802 m_settings->autoUpdateLastCheck(QDate::currentDate().toString(Qt::ISODate));
803 bReadyToInstall = updateDialog->updateReadyToInstall();
806 LAMEXP_DELETE(updateDialog);
807 return bReadyToInstall;
810 void MainWindow::refreshFavorites(void)
812 QList<QAction*> folderList = m_outputFolderFavoritesMenu->actions();
813 QStringList favorites = m_settings->favoriteOutputFolders().split("|", QString::SkipEmptyParts);
814 while(favorites.count() > 6) favorites.removeFirst();
816 while(!folderList.isEmpty())
818 QAction *currentItem = folderList.takeFirst();
819 if(currentItem->isSeparator()) break;
820 m_outputFolderFavoritesMenu->removeAction(currentItem);
821 LAMEXP_DELETE(currentItem);
824 QAction *lastItem = m_outputFolderFavoritesMenu->actions().first();
826 while(!favorites.isEmpty())
828 QString path = favorites.takeLast();
829 if(QDir(path).exists())
831 QAction *action = new QAction(QIcon(":/icons/folder_go.png"), QDir::toNativeSeparators(path), this);
832 action->setData(path);
833 m_outputFolderFavoritesMenu->insertAction(lastItem, action);
834 connect(action, SIGNAL(triggered(bool)), this, SLOT(gotoFavoriteFolder()));
835 lastItem = action;
840 ////////////////////////////////////////////////////////////
841 // EVENTS
842 ////////////////////////////////////////////////////////////
845 * Window is about to be shown
847 void MainWindow::showEvent(QShowEvent *event)
849 m_accepted = false;
850 m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
851 sourceModelChanged();
853 if(!event->spontaneous())
855 tabWidget->setCurrentIndex(0);
858 if(m_firstTimeShown)
860 m_firstTimeShown = false;
861 QTimer::singleShot(0, this, SLOT(windowShown()));
863 else
865 if(m_settings->dropBoxWidgetEnabled())
867 m_dropBox->setVisible(true);
873 * Re-translate the UI
875 void MainWindow::changeEvent(QEvent *e)
877 if(e->type() == QEvent::LanguageChange)
879 int comboBoxIndex[8];
881 //Backup combobox indices, as retranslateUi() resets
882 comboBoxIndex[0] = comboBoxMP3ChannelMode->currentIndex();
883 comboBoxIndex[1] = comboBoxSamplingRate->currentIndex();
884 comboBoxIndex[2] = comboBoxAACProfile->currentIndex();
885 comboBoxIndex[3] = comboBoxAftenCodingMode->currentIndex();
886 comboBoxIndex[4] = comboBoxAftenDRCMode->currentIndex();
887 comboBoxIndex[5] = comboBoxNormalizationMode->currentIndex();
888 comboBoxIndex[6] = comboBoxOpusOptimize->currentIndex();
889 comboBoxIndex[7] = comboBoxOpusFramesize->currentIndex();
891 //Re-translate from UIC
892 Ui::MainWindow::retranslateUi(this);
894 //Restore combobox indices
895 comboBoxMP3ChannelMode->setCurrentIndex(comboBoxIndex[0]);
896 comboBoxSamplingRate->setCurrentIndex(comboBoxIndex[1]);
897 comboBoxAACProfile->setCurrentIndex(comboBoxIndex[2]);
898 comboBoxAftenCodingMode->setCurrentIndex(comboBoxIndex[3]);
899 comboBoxAftenDRCMode->setCurrentIndex(comboBoxIndex[4]);
900 comboBoxNormalizationMode->setCurrentIndex(comboBoxIndex[5]);
901 comboBoxOpusOptimize->setCurrentIndex(comboBoxIndex[6]);
902 comboBoxOpusFramesize->setCurrentIndex(comboBoxIndex[7]);
904 //Update the window title
905 if(LAMEXP_DEBUG)
907 setWindowTitle(QString("%1 [!!! DEBUG BUILD !!!]").arg(windowTitle()));
909 else if(lamexp_version_demo())
911 setWindowTitle(QString("%1 [%2]").arg(windowTitle(), tr("DEMO VERSION")));
914 //Manually re-translate widgets that UIC doesn't handle
915 m_dropNoteLabel->setText(QString("» %1 «").arg(tr("You can drop in audio files here!")));
916 m_outputFolderNoteBox->setText(tr("Initializing directory outline, please be patient..."));
917 m_showDetailsContextAction->setText(tr("Show Details"));
918 m_previewContextAction->setText(tr("Open File in External Application"));
919 m_findFileContextAction->setText(tr("Browse File Location"));
920 m_showFolderContextAction->setText(tr("Browse Selected Folder"));
921 m_refreshFolderContextAction->setText(tr("Refresh Directory Outline"));
922 m_addFavoriteFolderAction->setText(tr("Bookmark Current Output Folder"));
923 m_exportCsvContextAction->setText(tr("Export Meta Tags to CSV File"));
924 m_importCsvContextAction->setText(tr("Import Meta Tags from CSV File"));
926 //Force GUI update
927 m_metaInfoModel->clearData();
928 m_metaInfoModel->setData(m_metaInfoModel->index(4, 1), m_settings->metaInfoPosition());
929 updateEncoder(m_settings->compressionEncoder());
930 updateLameAlgoQuality(sliderLameAlgoQuality->value());
931 updateMaximumInstances(sliderMaxInstances->value());
932 renameOutputPatternChanged(lineEditRenamePattern->text());
934 //Re-install shell integration
935 if(m_settings->shellIntegrationEnabled())
937 ShellIntegration::install();
940 //Force resize, if needed
941 tabPageChanged(tabWidget->currentIndex());
946 * File dragged over window
948 void MainWindow::dragEnterEvent(QDragEnterEvent *event)
950 QStringList formats = event->mimeData()->formats();
952 if(formats.contains("application/x-qt-windows-mime;value=\"FileNameW\"", Qt::CaseInsensitive) && formats.contains("text/uri-list", Qt::CaseInsensitive))
954 event->acceptProposedAction();
959 * File dropped onto window
961 void MainWindow::dropEvent(QDropEvent *event)
963 ABORT_IF_BUSY;
965 QStringList droppedFiles;
966 QList<QUrl> urls = event->mimeData()->urls();
968 while(!urls.isEmpty())
970 QUrl currentUrl = urls.takeFirst();
971 QFileInfo file(currentUrl.toLocalFile());
972 if(!file.exists())
974 continue;
976 if(file.isFile())
978 qDebug("Dropped File: %s", file.canonicalFilePath().toUtf8().constData());
979 droppedFiles << file.canonicalFilePath();
980 continue;
982 if(file.isDir())
984 qDebug("Dropped Folder: %s", file.canonicalFilePath().toUtf8().constData());
985 QList<QFileInfo> list = QDir(file.canonicalFilePath()).entryInfoList(QDir::Files | QDir::NoSymLinks);
986 if(list.count() > 0)
988 for(int j = 0; j < list.count(); j++)
990 droppedFiles << list.at(j).canonicalFilePath();
993 else
995 list = QDir(file.canonicalFilePath()).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
996 for(int j = 0; j < list.count(); j++)
998 qDebug("Descending to Folder: %s", list.at(j).canonicalFilePath().toUtf8().constData());
999 urls.prepend(QUrl::fromLocalFile(list.at(j).canonicalFilePath()));
1005 if(!droppedFiles.isEmpty())
1007 addFilesDelayed(droppedFiles, true);
1012 * Window tries to close
1014 void MainWindow::closeEvent(QCloseEvent *event)
1016 if(m_banner->isVisible() || m_delayedFileTimer->isActive())
1018 MessageBeep(MB_ICONEXCLAMATION);
1019 event->ignore();
1022 if(m_dropBox)
1024 m_dropBox->hide();
1029 * Window was resized
1031 void MainWindow::resizeEvent(QResizeEvent *event)
1033 if(event) QMainWindow::resizeEvent(event);
1034 m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
1036 if(QWidget *port = outputFolderView->viewport())
1038 m_outputFolderNoteBox->setGeometry(16, (port->height() - 64) / 2, port->width() - 32, 64);
1043 * Key press event filter
1045 void MainWindow::keyPressEvent(QKeyEvent *e)
1047 if(e->key() == Qt::Key_F5)
1049 if(outputFolderView->isVisible())
1051 QTimer::singleShot(0, this, SLOT(refreshFolderContextActionTriggered()));
1052 return;
1056 if(e->key() == Qt::Key_Delete)
1058 if(sourceFileView->isVisible())
1060 QTimer::singleShot(0, this, SLOT(removeFileButtonClicked()));
1061 return;
1065 QMainWindow::keyPressEvent(e);
1069 * Event filter
1071 bool MainWindow::eventFilter(QObject *obj, QEvent *event)
1073 if(obj == m_fileSystemModel)
1075 if(QApplication::overrideCursor() == NULL)
1077 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1078 QTimer::singleShot(250, this, SLOT(restoreCursor()));
1082 return QMainWindow::eventFilter(obj, event);
1085 bool MainWindow::event(QEvent *e)
1087 switch(e->type())
1089 case lamexp_event_queryendsession:
1090 qWarning("System is shutting down, main window prepares to close...");
1091 if(m_banner->isVisible()) m_banner->close();
1092 if(m_delayedFileTimer->isActive()) m_delayedFileTimer->stop();
1093 return true;
1094 case lamexp_event_endsession:
1095 qWarning("System is shutting down, main window will close now...");
1096 if(isVisible())
1098 while(!close())
1100 QApplication::processEvents(QEventLoop::WaitForMoreEvents & QEventLoop::ExcludeUserInputEvents);
1103 m_fileListModel->clearFiles();
1104 return true;
1105 case QEvent::MouseButtonPress:
1106 if(outputFolderEdit->isVisible())
1108 QTimer::singleShot(0, this, SLOT(outputFolderEditFinished()));
1110 default:
1111 return QMainWindow::event(e);
1115 bool MainWindow::winEvent(MSG *message, long *result)
1117 return WinSevenTaskbar::handleWinEvent(message, result);
1120 ////////////////////////////////////////////////////////////
1121 // Slots
1122 ////////////////////////////////////////////////////////////
1124 // =========================================================
1125 // Show window slots
1126 // =========================================================
1129 * Window shown
1131 void MainWindow::windowShown(void)
1133 const QStringList &arguments = lamexp_arguments(); //QApplication::arguments();
1135 //First run?
1136 bool firstRun = false;
1137 for(int i = 0; i < arguments.count(); i++)
1139 /*QMessageBox::information(this, QString::number(i), arguments[i]);*/
1140 if(!arguments[i].compare("--first-run", Qt::CaseInsensitive)) firstRun = true;
1143 //Check license
1144 if((m_settings->licenseAccepted() <= 0) || firstRun)
1146 int iAccepted = -1;
1148 if((m_settings->licenseAccepted() == 0) || firstRun)
1150 AboutDialog *about = new AboutDialog(m_settings, this, true);
1151 iAccepted = about->exec();
1152 LAMEXP_DELETE(about);
1155 if(iAccepted <= 0)
1157 m_settings->licenseAccepted(-1);
1158 QApplication::processEvents();
1159 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
1160 QMessageBox::critical(this, tr("License Declined"), tr("You have declined the license. Consequently the application will exit now!"), tr("Goodbye!"));
1161 QFileInfo uninstallerInfo = QFileInfo(QString("%1/Uninstall.exe").arg(QApplication::applicationDirPath()));
1162 if(uninstallerInfo.exists())
1164 QString uninstallerDir = uninstallerInfo.canonicalPath();
1165 QString uninstallerPath = uninstallerInfo.canonicalFilePath();
1166 for(int i = 0; i < 3; i++)
1168 HINSTANCE res = ShellExecuteW(reinterpret_cast<HWND>(this->winId()), L"open", QWCHAR(QDir::toNativeSeparators(uninstallerPath)), L"/Force", QWCHAR(QDir::toNativeSeparators(uninstallerDir)), SW_SHOWNORMAL);
1169 if(reinterpret_cast<int>(res) > 32) break;
1172 else
1174 MoveFileEx(QWCHAR(QDir::toNativeSeparators(QFileInfo(QApplication::applicationFilePath()).canonicalFilePath())), NULL, MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_REPLACE_EXISTING);
1176 QApplication::quit();
1177 return;
1180 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WOOHOO), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
1181 m_settings->licenseAccepted(1);
1182 if(lamexp_version_demo()) showAnnounceBox();
1185 //Check for expiration
1186 if(lamexp_version_demo())
1188 if(QDate::currentDate() >= lamexp_version_expires())
1190 qWarning("Binary has expired !!!");
1191 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
1192 if(QMessageBox::warning(this, tr("LameXP - Expired"), QString("%1<br>%2").arg(NOBR(tr("This demo (pre-release) version of LameXP has expired at %1.").arg(lamexp_version_expires().toString(Qt::ISODate))), NOBR(tr("LameXP is free software and release versions won't expire."))), tr("Check for Updates"), tr("Exit Program")) == 0)
1194 checkForUpdates();
1196 QApplication::quit();
1197 return;
1201 //Slow startup indicator
1202 if(m_settings->slowStartup() && m_settings->antivirNotificationsEnabled())
1204 QString message;
1205 message += NOBR(tr("It seems that a bogus anti-virus software is slowing down the startup of LameXP.")).append("<br>");
1206 message += NOBR(tr("Please refer to the %1 document for details and solutions!")).arg("<a href=\"http://lamexp.sourceforge.net/doc/FAQ.html#df406578\">F.A.Q.</a>").append("<br>");
1207 if(QMessageBox::warning(this, tr("Slow Startup"), message, tr("Discard"), tr("Don't Show Again")) == 1)
1209 m_settings->antivirNotificationsEnabled(false);
1210 actionDisableSlowStartupNotifications->setChecked(!m_settings->antivirNotificationsEnabled());
1214 //Update reminder
1215 if(QDate::currentDate() >= lamexp_version_date().addYears(1))
1217 qWarning("Binary is more than a year old, time to update!");
1218 int ret = QMessageBox::warning(this, tr("Urgent Update"), NOBR(tr("Your version of LameXP is more than a year old. Time for an update!")), tr("Check for Updates"), tr("Exit Program"), tr("Ignore"));
1219 switch(ret)
1221 case 0:
1222 if(checkForUpdates())
1224 QApplication::quit();
1225 return;
1227 break;
1228 case 1:
1229 QApplication::quit();
1230 return;
1231 default:
1232 QEventLoop loop; QTimer::singleShot(7000, &loop, SLOT(quit()));
1233 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WAITING), GetModuleHandle(NULL), SND_RESOURCE | SND_ASYNC);
1234 m_banner->show(tr("Skipping update check this time, please be patient..."), &loop);
1235 break;
1238 else if(m_settings->autoUpdateEnabled())
1240 QDate lastUpdateCheck = QDate::fromString(m_settings->autoUpdateLastCheck(), Qt::ISODate);
1241 if(!firstRun && (!lastUpdateCheck.isValid() || QDate::currentDate() >= lastUpdateCheck.addDays(14)))
1243 if(QMessageBox::information(this, tr("Update Reminder"), NOBR(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)
1245 if(checkForUpdates())
1247 QApplication::quit();
1248 return;
1254 //Check for AAC support
1255 if(m_neroEncoderAvailable)
1257 if(m_settings->neroAacNotificationsEnabled())
1259 if(lamexp_tool_version("neroAacEnc.exe") < lamexp_toolver_neroaac())
1261 QString messageText;
1262 messageText += NOBR(tr("LameXP detected that your version of the Nero AAC encoder is outdated!")).append("<br>");
1263 messageText += NOBR(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")))).append("<br><br>");
1264 messageText += NOBR(tr("You can download the latest version of the Nero AAC encoder from the Nero website at:")).append("<br>");
1265 messageText += "<nobr><tt>" + LINK(AboutDialog::neroAacUrl) + "</tt></nobr><br><br>";
1266 messageText += NOBR(tr("(Hint: Please ignore the name of the downloaded ZIP file and check the included 'changelog.txt' instead!)")).append("<br>");
1267 QMessageBox::information(this, tr("AAC Encoder Outdated"), messageText);
1271 else
1273 if(m_settings->neroAacNotificationsEnabled() && (!(m_fhgEncoderAvailable || m_qaacEncoderAvailable)))
1275 QString appPath = QDir(QCoreApplication::applicationDirPath()).canonicalPath();
1276 if(appPath.isEmpty()) appPath = QCoreApplication::applicationDirPath();
1277 QString messageText;
1278 messageText += NOBR(tr("The Nero AAC encoder could not be found. AAC encoding support will be disabled.")).append("<br>");
1279 messageText += NOBR(tr("Please put 'neroAacEnc.exe', 'neroAacDec.exe' and 'neroAacTag.exe' into the LameXP directory!")).append("<br><br>");
1280 messageText += NOBR(tr("Your LameXP directory is located here:")).append("<br>");
1281 messageText += QString("<nobr><tt>%1</tt></nobr><br><br>").arg(FSLINK(QDir::toNativeSeparators(appPath)));
1282 messageText += NOBR(tr("You can download the Nero AAC encoder for free from the official Nero website at:")).append("<br>");
1283 messageText += "<nobr><tt>" + LINK(AboutDialog::neroAacUrl) + "</tt></nobr><br>";
1284 if(QMessageBox::information(this, tr("AAC Support Disabled"), messageText, tr("Discard"), tr("Don't Show Again")) == 1)
1286 m_settings->neroAacNotificationsEnabled(false);
1287 actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
1292 //Add files from the command-line
1293 for(int i = 0; i < arguments.count() - 1; i++)
1295 QStringList addedFiles;
1296 if(!arguments[i].compare("--add", Qt::CaseInsensitive))
1298 QFileInfo currentFile(arguments[++i].trimmed());
1299 qDebug("Adding file from CLI: %s", currentFile.absoluteFilePath().toUtf8().constData());
1300 addedFiles.append(currentFile.absoluteFilePath());
1302 if(!addedFiles.isEmpty())
1304 addFilesDelayed(addedFiles);
1308 //Add folders from the command-line
1309 for(int i = 0; i < arguments.count() - 1; i++)
1311 if(!arguments[i].compare("--add-folder", Qt::CaseInsensitive))
1313 QFileInfo currentFile(arguments[++i].trimmed());
1314 qDebug("Adding folder from CLI: %s", currentFile.absoluteFilePath().toUtf8().constData());
1315 addFolder(currentFile.absoluteFilePath(), false, true);
1317 if(!arguments[i].compare("--add-recursive", Qt::CaseInsensitive))
1319 QFileInfo currentFile(arguments[++i].trimmed());
1320 qDebug("Adding folder recursively from CLI: %s", currentFile.absoluteFilePath().toUtf8().constData());
1321 addFolder(currentFile.absoluteFilePath(), true, true);
1325 //Enable shell integration
1326 if(m_settings->shellIntegrationEnabled())
1328 ShellIntegration::install();
1331 //Make DropBox visible
1332 if(m_settings->dropBoxWidgetEnabled())
1334 m_dropBox->setVisible(true);
1339 * Show announce box
1341 void MainWindow::showAnnounceBox(void)
1343 const unsigned int timeout = 8U;
1345 const QString announceText = QString("%1<br><br>%2<br><nobr><tt>%3</tt></nobr><br>").arg
1347 NOBR("We are still looking for LameXP translators!"),
1348 NOBR("If you are willing to translate LameXP to your language or to complete an existing translation, please refer to:"),
1349 LINK("http://lamexp.sourceforge.net/doc/Translate.html")
1352 QMessageBox *announceBox = new QMessageBox(QMessageBox::Warning, "We want you!", announceText, QMessageBox::NoButton, this);
1353 announceBox->setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
1354 announceBox->setIconPixmap(QIcon(":/images/Announcement.png").pixmap(64,79));
1356 QTimer *timers[timeout+1];
1357 QPushButton *buttons[timeout+1];
1359 for(unsigned int i = 0; i <= timeout; i++)
1361 QString text = (i > 0) ? QString("%1 (%2)").arg(tr("Discard"), QString::number(i)) : tr("Discard");
1362 buttons[i] = announceBox->addButton(text, (i > 0) ? QMessageBox::NoRole : QMessageBox::AcceptRole);
1365 for(unsigned int i = 0; i <= timeout; i++)
1367 buttons[i]->setEnabled(i == 0);
1368 buttons[i]->setVisible(i == timeout);
1371 for(unsigned int i = 0; i < timeout; i++)
1373 timers[i] = new QTimer(this);
1374 timers[i]->setSingleShot(true);
1375 timers[i]->setInterval(1000);
1376 connect(timers[i], SIGNAL(timeout()), buttons[i+1], SLOT(hide()));
1377 connect(timers[i], SIGNAL(timeout()), buttons[i], SLOT(show()));
1378 if(i > 0)
1380 connect(timers[i], SIGNAL(timeout()), timers[i-1], SLOT(start()));
1384 timers[timeout-1]->start();
1385 announceBox->exec();
1387 for(unsigned int i = 0; i < timeout; i++)
1389 timers[i]->stop();
1390 LAMEXP_DELETE(timers[i]);
1393 LAMEXP_DELETE(announceBox);
1396 // =========================================================
1397 // Main button solots
1398 // =========================================================
1401 * Encode button
1403 void MainWindow::encodeButtonClicked(void)
1405 static const unsigned __int64 oneGigabyte = 1073741824ui64;
1406 static const unsigned __int64 minimumFreeDiskspaceMultiplier = 2ui64;
1407 static const char *writeTestBuffer = "LAMEXP_WRITE_TEST";
1409 ABORT_IF_BUSY;
1411 if(m_fileListModel->rowCount() < 1)
1413 QMessageBox::warning(this, tr("LameXP"), NOBR(tr("You must add at least one file to the list before proceeding!")));
1414 tabWidget->setCurrentIndex(0);
1415 return;
1418 QString tempFolder = m_settings->customTempPathEnabled() ? m_settings->customTempPath() : lamexp_temp_folder2();
1419 if(!QFileInfo(tempFolder).exists() || !QFileInfo(tempFolder).isDir())
1421 if(QMessageBox::warning(this, tr("Not Found"), QString("%1<br><tt>%2</tt>").arg(NOBR(tr("Your currently selected TEMP folder does not exist anymore:")), NOBR(QDir::toNativeSeparators(tempFolder))), tr("Restore Default"), tr("Cancel")) == 0)
1423 SET_CHECKBOX_STATE(checkBoxUseSystemTempFolder, m_settings->customTempPathEnabledDefault());
1425 return;
1428 bool ok = false;
1429 unsigned __int64 currentFreeDiskspace = lamexp_free_diskspace(tempFolder, &ok);
1431 if(ok && (currentFreeDiskspace < (oneGigabyte * minimumFreeDiskspaceMultiplier)))
1433 QStringList tempFolderParts = tempFolder.split("/", QString::SkipEmptyParts, Qt::CaseInsensitive);
1434 tempFolderParts.takeLast();
1435 if(m_settings->soundsEnabled()) PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY), GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
1436 QString lowDiskspaceMsg = QString("%1<br>%2<br><br>%3<br>%4<br>").arg
1438 NOBR(tr("There are less than %1 GB of free diskspace available on your system's TEMP folder.").arg(QString::number(minimumFreeDiskspaceMultiplier))),
1439 NOBR(tr("It is highly recommend to free up more diskspace before proceeding with the encode!")),
1440 NOBR(tr("Your TEMP folder is located at:")),
1441 QString("<nobr><tt>%1</tt></nobr>").arg(FSLINK(tempFolderParts.join("\\")))
1443 switch(QMessageBox::warning(this, tr("Low Diskspace Warning"), lowDiskspaceMsg, tr("Abort Encoding Process"), tr("Clean Disk Now"), tr("Ignore")))
1445 case 1:
1446 QProcess::startDetached(QString("%1/cleanmgr.exe").arg(lamexp_known_folder(lamexp_folder_systemfolder)), QStringList() << "/D" << tempFolderParts.first());
1447 case 0:
1448 return;
1449 break;
1450 default:
1451 QMessageBox::warning(this, tr("Low Diskspace"), NOBR(tr("You are proceeding with low diskspace. Problems might occur!")));
1452 break;
1456 switch(m_settings->compressionEncoder())
1458 case SettingsModel::MP3Encoder:
1459 case SettingsModel::VorbisEncoder:
1460 case SettingsModel::AACEncoder:
1461 case SettingsModel::AC3Encoder:
1462 case SettingsModel::FLACEncoder:
1463 case SettingsModel::OpusEncoder:
1464 case SettingsModel::DCAEncoder:
1465 case SettingsModel::PCMEncoder:
1466 break;
1467 default:
1468 QMessageBox::warning(this, tr("LameXP"), tr("Sorry, an unsupported encoder has been chosen!"));
1469 tabWidget->setCurrentIndex(3);
1470 return;
1473 if(!m_settings->outputToSourceDir())
1475 QFile writeTest(QString("%1/~%2.txt").arg(m_settings->outputDir(), lamexp_rand_str()));
1476 if(!(writeTest.open(QIODevice::ReadWrite) && (writeTest.write(writeTestBuffer) == strlen(writeTestBuffer))))
1478 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!")));
1479 tabWidget->setCurrentIndex(1);
1480 return;
1482 else
1484 writeTest.close();
1485 writeTest.remove();
1489 m_accepted = true;
1490 close();
1494 * About button
1496 void MainWindow::aboutButtonClicked(void)
1498 ABORT_IF_BUSY;
1500 TEMP_HIDE_DROPBOX
1502 AboutDialog *aboutBox = new AboutDialog(m_settings, this);
1503 aboutBox->exec();
1504 LAMEXP_DELETE(aboutBox);
1509 * Close button
1511 void MainWindow::closeButtonClicked(void)
1513 ABORT_IF_BUSY;
1514 close();
1517 // =========================================================
1518 // Tab widget slots
1519 // =========================================================
1522 * Tab page changed
1524 void MainWindow::tabPageChanged(int idx)
1526 resizeEvent(NULL);
1528 QList<QAction*> actions = m_tabActionGroup->actions();
1529 for(int i = 0; i < actions.count(); i++)
1531 bool ok = false;
1532 int actionIndex = actions.at(i)->data().toInt(&ok);
1533 if(ok && actionIndex == idx)
1535 actions.at(i)->setChecked(true);
1539 int initialWidth = this->width();
1540 int maximumWidth = QApplication::desktop()->width();
1542 if(this->isVisible())
1544 while(tabWidget->width() < tabWidget->sizeHint().width())
1546 int previousWidth = this->width();
1547 this->resize(this->width() + 1, this->height());
1548 if(this->frameGeometry().width() >= maximumWidth) break;
1549 if(this->width() <= previousWidth) break;
1553 if(idx == tabWidget->indexOf(tabOptions) && scrollArea->widget() && this->isVisible())
1555 for(int i = 0; i < 2; i++)
1557 QApplication::processEvents();
1558 while(scrollArea->viewport()->width() < scrollArea->widget()->width())
1560 int previousWidth = this->width();
1561 this->resize(this->width() + 1, this->height());
1562 if(this->frameGeometry().width() >= maximumWidth) break;
1563 if(this->width() <= previousWidth) break;
1567 else if(idx == tabWidget->indexOf(tabSourceFiles))
1569 m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
1571 else if(idx == tabWidget->indexOf(tabOutputDir))
1573 if(!m_fileSystemModel)
1575 QTimer::singleShot(125, this, SLOT(initOutputFolderModel()));
1577 else
1579 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
1583 if(initialWidth < this->width())
1585 QPoint prevPos = this->pos();
1586 int delta = (this->width() - initialWidth) >> 2;
1587 move(prevPos.x() - delta, prevPos.y());
1592 * Tab action triggered
1594 void MainWindow::tabActionActivated(QAction *action)
1596 if(action && action->data().isValid())
1598 bool ok = false;
1599 int index = action->data().toInt(&ok);
1600 if(ok)
1602 tabWidget->setCurrentIndex(index);
1607 // =========================================================
1608 // View menu slots
1609 // =========================================================
1612 * Style action triggered
1614 void MainWindow::styleActionActivated(QAction *action)
1616 //Change style setting
1617 if(action && action->data().isValid())
1619 bool ok = false;
1620 int actionIndex = action->data().toInt(&ok);
1621 if(ok)
1623 m_settings->interfaceStyle(actionIndex);
1627 //Set up the new style
1628 switch(m_settings->interfaceStyle())
1630 case 1:
1631 if(actionStyleCleanlooks->isEnabled())
1633 actionStyleCleanlooks->setChecked(true);
1634 QApplication::setStyle(new QCleanlooksStyle());
1635 break;
1637 case 2:
1638 if(actionStyleWindowsVista->isEnabled())
1640 actionStyleWindowsVista->setChecked(true);
1641 QApplication::setStyle(new QWindowsVistaStyle());
1642 break;
1644 case 3:
1645 if(actionStyleWindowsXP->isEnabled())
1647 actionStyleWindowsXP->setChecked(true);
1648 QApplication::setStyle(new QWindowsXPStyle());
1649 break;
1651 case 4:
1652 if(actionStyleWindowsClassic->isEnabled())
1654 actionStyleWindowsClassic->setChecked(true);
1655 QApplication::setStyle(new QWindowsStyle());
1656 break;
1658 default:
1659 actionStylePlastique->setChecked(true);
1660 QApplication::setStyle(new QPlastiqueStyle());
1661 break;
1664 //Force re-translate after style change
1665 if(QEvent *e = new QEvent(QEvent::LanguageChange))
1667 changeEvent(e);
1668 LAMEXP_DELETE(e);
1673 * Language action triggered
1675 void MainWindow::languageActionActivated(QAction *action)
1677 if(action->data().type() == QVariant::String)
1679 QString langId = action->data().toString();
1681 if(lamexp_install_translator(langId))
1683 action->setChecked(true);
1684 m_settings->currentLanguage(langId);
1690 * Load language from file action triggered
1692 void MainWindow::languageFromFileActionActivated(bool checked)
1694 QFileDialog dialog(this, tr("Load Translation"));
1695 dialog.setFileMode(QFileDialog::ExistingFile);
1696 dialog.setNameFilter(QString("%1 (*.qm)").arg(tr("Translation Files")));
1698 if(dialog.exec())
1700 QStringList selectedFiles = dialog.selectedFiles();
1701 if(lamexp_install_translator_from_file(selectedFiles.first()))
1703 QList<QAction*> actions = m_languageActionGroup->actions();
1704 while(!actions.isEmpty())
1706 actions.takeFirst()->setChecked(false);
1709 else
1711 languageActionActivated(m_languageActionGroup->actions().first());
1716 // =========================================================
1717 // Tools menu slots
1718 // =========================================================
1721 * Disable update reminder action
1723 void MainWindow::disableUpdateReminderActionTriggered(bool checked)
1725 if(checked)
1727 if(0 == QMessageBox::question(this, tr("Disable Update Reminder"), NOBR(tr("Do you really want to disable the update reminder?")), tr("Yes"), tr("No"), QString(), 1))
1729 QMessageBox::information(this, tr("Update Reminder"), QString("%1<br>%2").arg(NOBR(tr("The update reminder has been disabled.")), NOBR(tr("Please remember to check for updates at regular intervals!"))));
1730 m_settings->autoUpdateEnabled(false);
1732 else
1734 m_settings->autoUpdateEnabled(true);
1737 else
1739 QMessageBox::information(this, tr("Update Reminder"), NOBR(tr("The update reminder has been re-enabled.")));
1740 m_settings->autoUpdateEnabled(true);
1743 actionDisableUpdateReminder->setChecked(!m_settings->autoUpdateEnabled());
1747 * Disable sound effects action
1749 void MainWindow::disableSoundsActionTriggered(bool checked)
1751 if(checked)
1753 if(0 == QMessageBox::question(this, tr("Disable Sound Effects"), NOBR(tr("Do you really want to disable all sound effects?")), tr("Yes"), tr("No"), QString(), 1))
1755 QMessageBox::information(this, tr("Sound Effects"), NOBR(tr("All sound effects have been disabled.")));
1756 m_settings->soundsEnabled(false);
1758 else
1760 m_settings->soundsEnabled(true);
1763 else
1765 QMessageBox::information(this, tr("Sound Effects"), NOBR(tr("The sound effects have been re-enabled.")));
1766 m_settings->soundsEnabled(true);
1769 actionDisableSounds->setChecked(!m_settings->soundsEnabled());
1773 * Disable Nero AAC encoder action
1775 void MainWindow::disableNeroAacNotificationsActionTriggered(bool checked)
1777 if(checked)
1779 if(0 == QMessageBox::question(this, tr("Nero AAC Notifications"), NOBR(tr("Do you really want to disable all Nero AAC Encoder notifications?")), tr("Yes"), tr("No"), QString(), 1))
1781 QMessageBox::information(this, tr("Nero AAC Notifications"), NOBR(tr("All Nero AAC Encoder notifications have been disabled.")));
1782 m_settings->neroAacNotificationsEnabled(false);
1784 else
1786 m_settings->neroAacNotificationsEnabled(true);
1789 else
1791 QMessageBox::information(this, tr("Nero AAC Notifications"), NOBR(tr("The Nero AAC Encoder notifications have been re-enabled.")));
1792 m_settings->neroAacNotificationsEnabled(true);
1795 actionDisableNeroAacNotifications->setChecked(!m_settings->neroAacNotificationsEnabled());
1799 * Disable slow startup action
1801 void MainWindow::disableSlowStartupNotificationsActionTriggered(bool checked)
1803 if(checked)
1805 if(0 == QMessageBox::question(this, tr("Slow Startup Notifications"), NOBR(tr("Do you really want to disable the slow startup notifications?")), tr("Yes"), tr("No"), QString(), 1))
1807 QMessageBox::information(this, tr("Slow Startup Notifications"), NOBR(tr("The slow startup notifications have been disabled.")));
1808 m_settings->antivirNotificationsEnabled(false);
1810 else
1812 m_settings->antivirNotificationsEnabled(true);
1815 else
1817 QMessageBox::information(this, tr("Slow Startup Notifications"), NOBR(tr("The slow startup notifications have been re-enabled.")));
1818 m_settings->antivirNotificationsEnabled(true);
1821 actionDisableSlowStartupNotifications->setChecked(!m_settings->antivirNotificationsEnabled());
1825 * Import a Cue Sheet file
1827 void MainWindow::importCueSheetActionTriggered(bool checked)
1829 ABORT_IF_BUSY;
1831 TEMP_HIDE_DROPBOX
1833 while(true)
1835 int result = 0;
1836 QString selectedCueFile;
1838 if(USE_NATIVE_FILE_DIALOG)
1840 selectedCueFile = QFileDialog::getOpenFileName(this, tr("Open Cue Sheet"), m_settings->mostRecentInputPath(), QString("%1 (*.cue)").arg(tr("Cue Sheet File")));
1842 else
1844 QFileDialog dialog(this, tr("Open Cue Sheet"));
1845 dialog.setFileMode(QFileDialog::ExistingFile);
1846 dialog.setNameFilter(QString("%1 (*.cue)").arg(tr("Cue Sheet File")));
1847 dialog.setDirectory(m_settings->mostRecentInputPath());
1848 if(dialog.exec())
1850 selectedCueFile = dialog.selectedFiles().first();
1854 if(!selectedCueFile.isEmpty())
1856 m_settings->mostRecentInputPath(QFileInfo(selectedCueFile).canonicalPath());
1857 CueImportDialog *cueImporter = new CueImportDialog(this, m_fileListModel, selectedCueFile);
1858 result = cueImporter->exec();
1859 LAMEXP_DELETE(cueImporter);
1862 if(result != (-1)) break;
1868 * Show the "drop box" widget
1870 void MainWindow::showDropBoxWidgetActionTriggered(bool checked)
1872 m_settings->dropBoxWidgetEnabled(true);
1874 if(!m_dropBox->isVisible())
1876 m_dropBox->show();
1879 lamexp_blink_window(m_dropBox);
1883 * Check for beta (pre-release) updates
1885 void MainWindow::checkForBetaUpdatesActionTriggered(bool checked)
1887 bool checkUpdatesNow = false;
1889 if(checked)
1891 if(0 == QMessageBox::question(this, tr("Beta Updates"), NOBR(tr("Do you really want LameXP to check for Beta (pre-release) updates?")), tr("Yes"), tr("No"), QString(), 1))
1893 if(0 == QMessageBox::information(this, tr("Beta Updates"), NOBR(tr("LameXP will check for Beta (pre-release) updates from now on.")), tr("Check Now"), tr("Discard")))
1895 checkUpdatesNow = true;
1897 m_settings->autoUpdateCheckBeta(true);
1899 else
1901 m_settings->autoUpdateCheckBeta(false);
1904 else
1906 QMessageBox::information(this, tr("Beta Updates"), NOBR(tr("LameXP will <i>not</i> check for Beta (pre-release) updates from now on.")));
1907 m_settings->autoUpdateCheckBeta(false);
1910 actionCheckForBetaUpdates->setChecked(m_settings->autoUpdateCheckBeta());
1912 if(checkUpdatesNow)
1914 if(checkForUpdates())
1916 QApplication::quit();
1922 * Hibernate computer action
1924 void MainWindow::hibernateComputerActionTriggered(bool checked)
1926 if(checked)
1928 if(0 == QMessageBox::question(this, tr("Hibernate Computer"), NOBR(tr("Do you really want the computer to be hibernated on shutdown?")), tr("Yes"), tr("No"), QString(), 1))
1930 QMessageBox::information(this, tr("Hibernate Computer"), NOBR(tr("LameXP will hibernate the computer on shutdown from now on.")));
1931 m_settings->hibernateComputer(true);
1933 else
1935 m_settings->hibernateComputer(false);
1938 else
1940 QMessageBox::information(this, tr("Hibernate Computer"), NOBR(tr("LameXP will <i>not</i> hibernate the computer on shutdown from now on.")));
1941 m_settings->hibernateComputer(false);
1944 actionHibernateComputer->setChecked(m_settings->hibernateComputer());
1948 * Disable shell integration action
1950 void MainWindow::disableShellIntegrationActionTriggered(bool checked)
1952 if(checked)
1954 if(0 == QMessageBox::question(this, tr("Shell Integration"), NOBR(tr("Do you really want to disable the LameXP shell integration?")), tr("Yes"), tr("No"), QString(), 1))
1956 ShellIntegration::remove();
1957 QMessageBox::information(this, tr("Shell Integration"), NOBR(tr("The LameXP shell integration has been disabled.")));
1958 m_settings->shellIntegrationEnabled(false);
1960 else
1962 m_settings->shellIntegrationEnabled(true);
1965 else
1967 ShellIntegration::install();
1968 QMessageBox::information(this, tr("Shell Integration"), NOBR(tr("The LameXP shell integration has been re-enabled.")));
1969 m_settings->shellIntegrationEnabled(true);
1972 actionDisableShellIntegration->setChecked(!m_settings->shellIntegrationEnabled());
1974 if(lamexp_portable_mode() && actionDisableShellIntegration->isChecked())
1976 actionDisableShellIntegration->setEnabled(false);
1980 // =========================================================
1981 // Help menu slots
1982 // =========================================================
1985 * Visit homepage action
1987 void MainWindow::visitHomepageActionActivated(void)
1989 if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
1991 if(action->data().isValid() && (action->data().type() == QVariant::String))
1993 QDesktopServices::openUrl(QUrl(action->data().toString()));
1999 * Show document
2001 void MainWindow::documentActionActivated(void)
2003 if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
2005 if(action->data().isValid() && (action->data().type() == QVariant::String))
2007 QFileInfo document(action->data().toString());
2008 QFileInfo resource(QString(":/doc/%1.html").arg(document.baseName()));
2009 if(document.exists() && document.isFile() && (document.size() == resource.size()))
2011 QDesktopServices::openUrl(QUrl::fromLocalFile(document.canonicalFilePath()));
2013 else
2015 QFile source(resource.filePath());
2016 QFile output(QString("%1/%2.%3.html").arg(lamexp_temp_folder2(), document.baseName(), lamexp_rand_str().left(8)));
2017 if(source.open(QIODevice::ReadOnly) && output.open(QIODevice::ReadWrite))
2019 output.write(source.readAll());
2020 action->setData(output.fileName());
2021 source.close();
2022 output.close();
2023 QDesktopServices::openUrl(QUrl::fromLocalFile(output.fileName()));
2031 * Check for updates action
2033 void MainWindow::checkUpdatesActionActivated(void)
2035 ABORT_IF_BUSY;
2036 bool bFlag = false;
2038 TEMP_HIDE_DROPBOX
2040 bFlag = checkForUpdates();
2043 if(bFlag)
2045 QApplication::quit();
2049 // =========================================================
2050 // Source file slots
2051 // =========================================================
2054 * Add file(s) button
2056 void MainWindow::addFilesButtonClicked(void)
2058 ABORT_IF_BUSY;
2060 TEMP_HIDE_DROPBOX
2062 if(USE_NATIVE_FILE_DIALOG)
2064 QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
2065 QStringList selectedFiles = QFileDialog::getOpenFileNames(this, tr("Add file(s)"), m_settings->mostRecentInputPath(), fileTypeFilters.join(";;"));
2066 if(!selectedFiles.isEmpty())
2068 m_settings->mostRecentInputPath(QFileInfo(selectedFiles.first()).canonicalPath());
2069 addFiles(selectedFiles);
2072 else
2074 QFileDialog dialog(this, tr("Add file(s)"));
2075 QStringList fileTypeFilters = DecoderRegistry::getSupportedTypes();
2076 dialog.setFileMode(QFileDialog::ExistingFiles);
2077 dialog.setNameFilter(fileTypeFilters.join(";;"));
2078 dialog.setDirectory(m_settings->mostRecentInputPath());
2079 if(dialog.exec())
2081 QStringList selectedFiles = dialog.selectedFiles();
2082 if(!selectedFiles.isEmpty())
2084 m_settings->mostRecentInputPath(QFileInfo(selectedFiles.first()).canonicalPath());
2085 addFiles(selectedFiles);
2093 * Open folder action
2095 void MainWindow::openFolderActionActivated(void)
2097 ABORT_IF_BUSY;
2098 QString selectedFolder;
2100 if(QAction *action = dynamic_cast<QAction*>(QObject::sender()))
2102 TEMP_HIDE_DROPBOX
2104 if(USE_NATIVE_FILE_DIALOG)
2106 selectedFolder = QFileDialog::getExistingDirectory(this, tr("Add Folder"), m_settings->mostRecentInputPath());
2108 else
2110 QFileDialog dialog(this, tr("Add Folder"));
2111 dialog.setFileMode(QFileDialog::DirectoryOnly);
2112 dialog.setDirectory(m_settings->mostRecentInputPath());
2113 if(dialog.exec())
2115 selectedFolder = dialog.selectedFiles().first();
2119 if(!selectedFolder.isEmpty())
2121 m_settings->mostRecentInputPath(QDir(selectedFolder).canonicalPath());
2122 addFolder(selectedFolder, action->data().toBool());
2129 * Remove file button
2131 void MainWindow::removeFileButtonClicked(void)
2133 if(sourceFileView->currentIndex().isValid())
2135 int iRow = sourceFileView->currentIndex().row();
2136 m_fileListModel->removeFile(sourceFileView->currentIndex());
2137 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
2142 * Clear files button
2144 void MainWindow::clearFilesButtonClicked(void)
2146 m_fileListModel->clearFiles();
2150 * Move file up button
2152 void MainWindow::fileUpButtonClicked(void)
2154 if(sourceFileView->currentIndex().isValid())
2156 int iRow = sourceFileView->currentIndex().row() - 1;
2157 m_fileListModel->moveFile(sourceFileView->currentIndex(), -1);
2158 sourceFileView->selectRow(iRow >= 0 ? iRow : 0);
2163 * Move file down button
2165 void MainWindow::fileDownButtonClicked(void)
2167 if(sourceFileView->currentIndex().isValid())
2169 int iRow = sourceFileView->currentIndex().row() + 1;
2170 m_fileListModel->moveFile(sourceFileView->currentIndex(), 1);
2171 sourceFileView->selectRow(iRow < m_fileListModel->rowCount() ? iRow : m_fileListModel->rowCount()-1);
2176 * Show details button
2178 void MainWindow::showDetailsButtonClicked(void)
2180 ABORT_IF_BUSY;
2182 int iResult = 0;
2183 MetaInfoDialog *metaInfoDialog = new MetaInfoDialog(this);
2184 QModelIndex index = sourceFileView->currentIndex();
2186 while(index.isValid())
2188 if(iResult > 0)
2190 index = m_fileListModel->index(index.row() + 1, index.column());
2191 sourceFileView->selectRow(index.row());
2193 if(iResult < 0)
2195 index = m_fileListModel->index(index.row() - 1, index.column());
2196 sourceFileView->selectRow(index.row());
2199 AudioFileModel &file = (*m_fileListModel)[index];
2200 TEMP_HIDE_DROPBOX
2202 iResult = metaInfoDialog->exec(file, index.row() > 0, index.row() < m_fileListModel->rowCount() - 1);
2205 if(iResult == INT_MAX)
2207 m_metaInfoModel->assignInfoFrom(file);
2208 tabWidget->setCurrentIndex(tabWidget->indexOf(tabMetaData));
2209 break;
2212 if(!iResult) break;
2215 LAMEXP_DELETE(metaInfoDialog);
2216 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2217 sourceFilesScrollbarMoved(0);
2221 * Show context menu for source files
2223 void MainWindow::sourceFilesContextMenu(const QPoint &pos)
2225 QAbstractScrollArea *scrollArea = dynamic_cast<QAbstractScrollArea*>(QObject::sender());
2226 QWidget *sender = scrollArea ? scrollArea->viewport() : dynamic_cast<QWidget*>(QObject::sender());
2228 if(sender)
2230 if(pos.x() <= sender->width() && pos.y() <= sender->height() && pos.x() >= 0 && pos.y() >= 0)
2232 m_sourceFilesContextMenu->popup(sender->mapToGlobal(pos));
2238 * Scrollbar of source files moved
2240 void MainWindow::sourceFilesScrollbarMoved(int)
2242 sourceFileView->resizeColumnToContents(0);
2246 * Open selected file in external player
2248 void MainWindow::previewContextActionTriggered(void)
2250 const static char *appNames[3] = {"smplayer_portable.exe", "smplayer.exe", "mplayer.exe"};
2251 const static wchar_t *registryKey = L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}";
2253 QModelIndex index = sourceFileView->currentIndex();
2254 if(!index.isValid())
2256 return;
2259 QString mplayerPath;
2260 HKEY registryKeyHandle;
2262 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, registryKey, 0, KEY_READ, &registryKeyHandle) == ERROR_SUCCESS)
2264 wchar_t Buffer[4096];
2265 DWORD BuffSize = sizeof(wchar_t*) * 4096;
2266 if(RegQueryValueExW(registryKeyHandle, L"InstallLocation", 0, 0, reinterpret_cast<BYTE*>(Buffer), &BuffSize) == ERROR_SUCCESS)
2268 mplayerPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(Buffer));
2272 if(!mplayerPath.isEmpty())
2274 QDir mplayerDir(mplayerPath);
2275 if(mplayerDir.exists())
2277 for(int i = 0; i < 3; i++)
2279 if(mplayerDir.exists(appNames[i]))
2281 QProcess::startDetached(mplayerDir.absoluteFilePath(appNames[i]), QStringList() << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
2282 return;
2288 QDesktopServices::openUrl(QString("file:///").append(m_fileListModel->getFile(index).filePath()));
2292 * Find selected file in explorer
2294 void MainWindow::findFileContextActionTriggered(void)
2296 QModelIndex index = sourceFileView->currentIndex();
2297 if(index.isValid())
2299 QString systemRootPath;
2301 QDir systemRoot(lamexp_known_folder(lamexp_folder_systemfolder));
2302 if(systemRoot.exists() && systemRoot.cdUp())
2304 systemRootPath = systemRoot.canonicalPath();
2307 if(!systemRootPath.isEmpty())
2309 QFileInfo explorer(QString("%1/explorer.exe").arg(systemRootPath));
2310 if(explorer.exists() && explorer.isFile())
2312 QProcess::execute(explorer.canonicalFilePath(), QStringList() << "/select," << QDir::toNativeSeparators(m_fileListModel->getFile(index).filePath()));
2313 return;
2316 else
2318 qWarning("SystemRoot directory could not be detected!");
2324 * Add all pending files
2326 void MainWindow::handleDelayedFiles(void)
2328 m_delayedFileTimer->stop();
2330 if(m_delayedFileList->isEmpty())
2332 return;
2335 if(m_banner->isVisible())
2337 m_delayedFileTimer->start(5000);
2338 return;
2341 QStringList selectedFiles;
2342 tabWidget->setCurrentIndex(0);
2344 while(!m_delayedFileList->isEmpty())
2346 QFileInfo currentFile = QFileInfo(m_delayedFileList->takeFirst());
2347 if(!currentFile.exists() || !currentFile.isFile())
2349 continue;
2351 selectedFiles << currentFile.canonicalFilePath();
2354 addFiles(selectedFiles);
2358 * Export Meta tags to CSV file
2360 void MainWindow::exportCsvContextActionTriggered(void)
2362 TEMP_HIDE_DROPBOX
2364 QString selectedCsvFile;
2366 if(USE_NATIVE_FILE_DIALOG)
2368 selectedCsvFile = QFileDialog::getSaveFileName(this, tr("Save CSV file"), m_settings->mostRecentInputPath(), QString("%1 (*.csv)").arg(tr("CSV File")));
2370 else
2372 QFileDialog dialog(this, tr("Save CSV file"));
2373 dialog.setFileMode(QFileDialog::AnyFile);
2374 dialog.setAcceptMode(QFileDialog::AcceptSave);
2375 dialog.setNameFilter(QString("%1 (*.csv)").arg(tr("CSV File")));
2376 dialog.setDirectory(m_settings->mostRecentInputPath());
2377 if(dialog.exec())
2379 selectedCsvFile = dialog.selectedFiles().first();
2383 if(!selectedCsvFile.isEmpty())
2385 m_settings->mostRecentInputPath(QFileInfo(selectedCsvFile).canonicalPath());
2386 switch(m_fileListModel->exportToCsv(selectedCsvFile))
2388 case FileListModel::CsvError_NoTags:
2389 QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, there are no meta tags that can be exported!")));
2390 break;
2391 case FileListModel::CsvError_FileOpen:
2392 QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, failed to open CSV file for writing!")));
2393 break;
2394 case FileListModel::CsvError_FileWrite:
2395 QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, failed to write to the CSV file!")));
2396 break;
2397 case FileListModel::CsvError_OK:
2398 QMessageBox::information(this, tr("CSV Export"), NOBR(tr("The CSV files was created successfully!")));
2399 break;
2400 default:
2401 qWarning("exportToCsv: Unknown return code!");
2409 * Import Meta tags from CSV file
2411 void MainWindow::importCsvContextActionTriggered(void)
2413 TEMP_HIDE_DROPBOX
2415 QString selectedCsvFile;
2417 if(USE_NATIVE_FILE_DIALOG)
2419 selectedCsvFile = QFileDialog::getOpenFileName(this, tr("Open CSV file"), m_settings->mostRecentInputPath(), QString("%1 (*.csv)").arg(tr("CSV File")));
2421 else
2423 QFileDialog dialog(this, tr("Open CSV file"));
2424 dialog.setFileMode(QFileDialog::ExistingFile);
2425 dialog.setNameFilter(QString("%1 (*.csv)").arg(tr("CSV File")));
2426 dialog.setDirectory(m_settings->mostRecentInputPath());
2427 if(dialog.exec())
2429 selectedCsvFile = dialog.selectedFiles().first();
2433 if(!selectedCsvFile.isEmpty())
2435 m_settings->mostRecentInputPath(QFileInfo(selectedCsvFile).canonicalPath());
2436 switch(m_fileListModel->importFromCsv(this, selectedCsvFile))
2438 case FileListModel::CsvError_FileOpen:
2439 QMessageBox::critical(this, tr("CSV Import"), NOBR(tr("Sorry, failed to open CSV file for reading!")));
2440 break;
2441 case FileListModel::CsvError_FileRead:
2442 QMessageBox::critical(this, tr("CSV Import"), NOBR(tr("Sorry, failed to read from the CSV file!")));
2443 break;
2444 case FileListModel::CsvError_NoTags:
2445 QMessageBox::critical(this, tr("CSV Import"), NOBR(tr("Sorry, the CSV file does not contain any known fields!")));
2446 break;
2447 case FileListModel::CsvError_Incomplete:
2448 QMessageBox::warning(this, tr("CSV Import"), NOBR(tr("CSV file is incomplete. Not all files were updated!")));
2449 break;
2450 case FileListModel::CsvError_OK:
2451 QMessageBox::information(this, tr("CSV Import"), NOBR(tr("The CSV files was imported successfully!")));
2452 break;
2453 case FileListModel::CsvError_Aborted:
2454 /* User aborted, ignore! */
2455 break;
2456 default:
2457 qWarning("exportToCsv: Unknown return code!");
2464 * Show or hide Drag'n'Drop notice after model reset
2466 void MainWindow::sourceModelChanged(void)
2468 m_dropNoteLabel->setVisible(m_fileListModel->rowCount() <= 0);
2471 // =========================================================
2472 // Output folder slots
2473 // =========================================================
2476 * Output folder changed (mouse clicked)
2478 void MainWindow::outputFolderViewClicked(const QModelIndex &index)
2480 if(index.isValid() && (outputFolderView->currentIndex() != index))
2482 outputFolderView->setCurrentIndex(index);
2485 if(m_fileSystemModel && index.isValid())
2487 QString selectedDir = m_fileSystemModel->filePath(index);
2488 if(selectedDir.length() < 3) selectedDir.append(QDir::separator());
2489 outputFolderLabel->setText(QDir::toNativeSeparators(selectedDir));
2490 m_settings->outputDir(selectedDir);
2492 else
2494 outputFolderLabel->setText(QDir::toNativeSeparators(m_settings->outputDir()));
2499 * Output folder changed (mouse moved)
2501 void MainWindow::outputFolderViewMoved(const QModelIndex &index)
2503 if(QApplication::mouseButtons() & Qt::LeftButton)
2505 outputFolderViewClicked(index);
2510 * Goto desktop button
2512 void MainWindow::gotoDesktopButtonClicked(void)
2514 if(!m_fileSystemModel)
2516 qWarning("File system model not initialized yet!");
2517 return;
2520 QString desktopPath = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
2522 if(!desktopPath.isEmpty() && QDir(desktopPath).exists())
2524 outputFolderView->setCurrentIndex(m_fileSystemModel->index(desktopPath));
2525 outputFolderViewClicked(outputFolderView->currentIndex());
2526 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2528 else
2530 buttonGotoDesktop->setEnabled(false);
2535 * Goto home folder button
2537 void MainWindow::gotoHomeFolderButtonClicked(void)
2539 if(!m_fileSystemModel)
2541 qWarning("File system model not initialized yet!");
2542 return;
2545 QString homePath = QDesktopServices::storageLocation(QDesktopServices::HomeLocation);
2547 if(!homePath.isEmpty() && QDir(homePath).exists())
2549 outputFolderView->setCurrentIndex(m_fileSystemModel->index(homePath));
2550 outputFolderViewClicked(outputFolderView->currentIndex());
2551 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2553 else
2555 buttonGotoHome->setEnabled(false);
2560 * Goto music folder button
2562 void MainWindow::gotoMusicFolderButtonClicked(void)
2564 if(!m_fileSystemModel)
2566 qWarning("File system model not initialized yet!");
2567 return;
2570 QString musicPath = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
2572 if(!musicPath.isEmpty() && QDir(musicPath).exists())
2574 outputFolderView->setCurrentIndex(m_fileSystemModel->index(musicPath));
2575 outputFolderViewClicked(outputFolderView->currentIndex());
2576 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2578 else
2580 buttonGotoMusic->setEnabled(false);
2585 * Goto music favorite output folder
2587 void MainWindow::gotoFavoriteFolder(void)
2589 if(!m_fileSystemModel)
2591 qWarning("File system model not initialized yet!");
2592 return;
2595 QAction *item = dynamic_cast<QAction*>(QObject::sender());
2597 if(item)
2599 QDir path(item->data().toString());
2600 if(path.exists())
2602 outputFolderView->setCurrentIndex(m_fileSystemModel->index(path.canonicalPath()));
2603 outputFolderViewClicked(outputFolderView->currentIndex());
2604 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2606 else
2608 MessageBeep(MB_ICONERROR);
2609 m_outputFolderFavoritesMenu->removeAction(item);
2610 item->deleteLater();
2616 * Make folder button
2618 void MainWindow::makeFolderButtonClicked(void)
2620 ABORT_IF_BUSY;
2622 if(!m_fileSystemModel)
2624 qWarning("File system model not initialized yet!");
2625 return;
2628 QDir basePath(m_fileSystemModel->fileInfo(outputFolderView->currentIndex()).absoluteFilePath());
2629 QString suggestedName = tr("New Folder");
2631 if(!m_metaData->fileArtist().isEmpty() && !m_metaData->fileAlbum().isEmpty())
2633 suggestedName = QString("%1 - %2").arg(m_metaData->fileArtist(), m_metaData->fileAlbum());
2635 else if(!m_metaData->fileArtist().isEmpty())
2637 suggestedName = m_metaData->fileArtist();
2639 else if(!m_metaData->fileAlbum().isEmpty())
2641 suggestedName = m_metaData->fileAlbum();
2643 else
2645 for(int i = 0; i < m_fileListModel->rowCount(); i++)
2647 AudioFileModel audioFile = m_fileListModel->getFile(m_fileListModel->index(i, 0));
2648 if(!audioFile.fileAlbum().isEmpty() || !audioFile.fileArtist().isEmpty())
2650 if(!audioFile.fileArtist().isEmpty() && !audioFile.fileAlbum().isEmpty())
2652 suggestedName = QString("%1 - %2").arg(audioFile.fileArtist(), audioFile.fileAlbum());
2654 else if(!audioFile.fileArtist().isEmpty())
2656 suggestedName = audioFile.fileArtist();
2658 else if(!audioFile.fileAlbum().isEmpty())
2660 suggestedName = audioFile.fileAlbum();
2662 break;
2667 suggestedName = lamexp_clean_filename(suggestedName);
2669 while(true)
2671 bool bApplied = false;
2672 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();
2674 if(bApplied)
2676 folderName = lamexp_clean_filepath(folderName.simplified());
2678 if(folderName.isEmpty())
2680 MessageBeep(MB_ICONERROR);
2681 continue;
2684 int i = 1;
2685 QString newFolder = folderName;
2687 while(basePath.exists(newFolder))
2689 newFolder = QString(folderName).append(QString().sprintf(" (%d)", ++i));
2692 if(basePath.mkpath(newFolder))
2694 QDir createdDir = basePath;
2695 if(createdDir.cd(newFolder))
2697 QModelIndex newIndex = m_fileSystemModel->index(createdDir.canonicalPath());
2698 outputFolderView->setCurrentIndex(newIndex);
2699 outputFolderViewClicked(newIndex);
2700 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2703 else
2705 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!")));
2708 break;
2713 * Output to source dir changed
2715 void MainWindow::saveToSourceFolderChanged(void)
2717 m_settings->outputToSourceDir(saveToSourceFolderCheckBox->isChecked());
2721 * Prepend relative source file path to output file name changed
2723 void MainWindow::prependRelativePathChanged(void)
2725 m_settings->prependRelativeSourcePath(prependRelativePathCheckBox->isChecked());
2729 * Show context menu for output folder
2731 void MainWindow::outputFolderContextMenu(const QPoint &pos)
2733 QAbstractScrollArea *scrollArea = dynamic_cast<QAbstractScrollArea*>(QObject::sender());
2734 QWidget *sender = scrollArea ? scrollArea->viewport() : dynamic_cast<QWidget*>(QObject::sender());
2736 if(pos.x() <= sender->width() && pos.y() <= sender->height() && pos.x() >= 0 && pos.y() >= 0)
2738 m_outputFolderContextMenu->popup(sender->mapToGlobal(pos));
2743 * Show selected folder in explorer
2745 void MainWindow::showFolderContextActionTriggered(void)
2747 if(!m_fileSystemModel)
2749 qWarning("File system model not initialized yet!");
2750 return;
2753 QString path = QDir::toNativeSeparators(m_fileSystemModel->filePath(outputFolderView->currentIndex()));
2754 if(!path.endsWith(QDir::separator())) path.append(QDir::separator());
2755 ShellExecuteW(reinterpret_cast<HWND>(this->winId()), L"explore", QWCHAR(path), NULL, NULL, SW_SHOW);
2759 * Refresh the directory outline
2761 void MainWindow::refreshFolderContextActionTriggered(void)
2763 //force re-initialization
2764 QTimer::singleShot(0, this, SLOT(initOutputFolderModel()));
2768 * Add current folder to favorites
2770 void MainWindow::addFavoriteFolderActionTriggered(void)
2772 QString path = m_fileSystemModel->filePath(outputFolderView->currentIndex());
2773 QStringList favorites = m_settings->favoriteOutputFolders().split("|", QString::SkipEmptyParts);
2775 if(!favorites.contains(path, Qt::CaseInsensitive))
2777 favorites.append(path);
2778 while(favorites.count() > 6) favorites.removeFirst();
2780 else
2782 MessageBeep(MB_ICONWARNING);
2785 m_settings->favoriteOutputFolders(favorites.join("|"));
2786 refreshFavorites();
2790 * Output folder edit finished
2792 void MainWindow::outputFolderEditFinished(void)
2794 if(outputFolderEdit->isHidden())
2796 return; //Not currently in edit mode!
2799 bool ok = false;
2801 QString text = QDir::fromNativeSeparators(outputFolderEdit->text().trimmed());
2802 while(text.startsWith('"') || text.startsWith('/')) text = text.right(text.length() - 1).trimmed();
2803 while(text.endsWith('"') || text.endsWith('/')) text = text.left(text.length() - 1).trimmed();
2805 static const char *str = "?*<>|\"";
2806 for(size_t i = 0; str[i]; i++) text.replace(str[i], "_");
2808 if(!((text.length() >= 2) && text.at(0).isLetter() && text.at(1) == QChar(':')))
2810 text = QString("%1/%2").arg(QDir::fromNativeSeparators(outputFolderLabel->text()), text);
2813 if(text.length() == 2) text += "/"; /* "X:" => "X:/" */
2815 while(text.length() > 2)
2817 QFileInfo info(text);
2818 if(info.exists() && info.isDir())
2820 QModelIndex index = m_fileSystemModel->index(QFileInfo(info.canonicalFilePath()).absoluteFilePath());
2821 if(index.isValid())
2823 ok = true;
2824 outputFolderView->setCurrentIndex(index);
2825 outputFolderViewClicked(index);
2826 break;
2829 else if(info.exists() && info.isFile())
2831 QModelIndex index = m_fileSystemModel->index(QFileInfo(info.canonicalPath()).absoluteFilePath());
2832 if(index.isValid())
2834 ok = true;
2835 outputFolderView->setCurrentIndex(index);
2836 outputFolderViewClicked(index);
2837 break;
2841 text = text.left(text.length() - 1).trimmed();
2844 outputFolderEdit->setVisible(false);
2845 outputFolderLabel->setVisible(true);
2846 outputFolderView->setEnabled(true);
2848 if(!ok) MessageBeep(MB_ICONERROR);
2849 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2853 * Initialize file system model
2855 void MainWindow::initOutputFolderModel(void)
2857 if(m_outputFolderNoteBox->isHidden())
2859 m_outputFolderNoteBox->show();
2860 m_outputFolderNoteBox->repaint();
2861 m_outputFolderViewInitCounter = 4;
2863 if(m_fileSystemModel)
2865 SET_MODEL(outputFolderView, NULL);
2866 LAMEXP_DELETE(m_fileSystemModel);
2867 outputFolderView->repaint();
2870 if(m_fileSystemModel = new QFileSystemModelEx())
2872 m_fileSystemModel->installEventFilter(this);
2873 connect(m_fileSystemModel, SIGNAL(directoryLoaded(QString)), this, SLOT(outputFolderDirectoryLoaded(QString)));
2874 connect(m_fileSystemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(outputFolderRowsInserted(QModelIndex,int,int)));
2876 SET_MODEL(outputFolderView, m_fileSystemModel);
2877 outputFolderView->header()->setStretchLastSection(true);
2878 outputFolderView->header()->hideSection(1);
2879 outputFolderView->header()->hideSection(2);
2880 outputFolderView->header()->hideSection(3);
2882 m_fileSystemModel->setRootPath("");
2883 QModelIndex index = m_fileSystemModel->index(m_settings->outputDir());
2884 if(index.isValid()) outputFolderView->setCurrentIndex(index);
2885 outputFolderViewClicked(outputFolderView->currentIndex());
2888 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2889 QTimer::singleShot(125, this, SLOT(initOutputFolderModel_doAsync()));
2894 * Initialize file system model (do NOT call this one directly!)
2896 void MainWindow::initOutputFolderModel_doAsync(void)
2898 if(m_outputFolderViewInitCounter > 0)
2900 m_outputFolderViewInitCounter--;
2901 QTimer::singleShot(125, this, SLOT(initOutputFolderModel_doAsync()));
2903 else
2905 QTimer::singleShot(125, m_outputFolderNoteBox, SLOT(hide()));
2906 outputFolderView->setFocus();
2911 * Center current folder in view
2913 void MainWindow::centerOutputFolderModel(void)
2915 if(outputFolderView->isVisible())
2917 centerOutputFolderModel_doAsync();
2918 QTimer::singleShot(125, this, SLOT(centerOutputFolderModel_doAsync()));
2923 * Center current folder in view (do NOT call this one directly!)
2925 void MainWindow::centerOutputFolderModel_doAsync(void)
2927 if(outputFolderView->isVisible())
2929 m_outputFolderViewCentering = true;
2930 const QModelIndex index = outputFolderView->currentIndex();
2931 outputFolderView->scrollTo(index, QAbstractItemView::PositionAtCenter);
2932 outputFolderView->setFocus();
2937 * File system model asynchronously loaded a dir
2939 void MainWindow::outputFolderDirectoryLoaded(const QString &path)
2941 if(m_outputFolderViewCentering)
2943 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2948 * File system model inserted new items
2950 void MainWindow::outputFolderRowsInserted(const QModelIndex &parent, int start, int end)
2952 if(m_outputFolderViewCentering)
2954 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2959 * Directory view item was expanded by user
2961 void MainWindow::outputFolderItemExpanded(const QModelIndex &item)
2963 //We need to stop centering as soon as the user has expanded an item manually!
2964 m_outputFolderViewCentering = false;
2968 * View event for output folder control occurred
2970 void MainWindow::outputFolderViewEventOccurred(QWidget *sender, QEvent *event)
2972 switch(event->type())
2974 case QEvent::Enter:
2975 case QEvent::Leave:
2976 case QEvent::KeyPress:
2977 case QEvent::KeyRelease:
2978 case QEvent::FocusIn:
2979 case QEvent::FocusOut:
2980 case QEvent::TouchEnd:
2981 outputFolderViewClicked(outputFolderView->currentIndex());
2982 break;
2987 * Mouse event for output folder control occurred
2989 void MainWindow::outputFolderMouseEventOccurred(QWidget *sender, QEvent *event)
2991 QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(event);
2992 QPoint pos = (mouseEvent) ? mouseEvent->pos() : QPoint();
2994 if(sender == outputFolderLabel)
2996 switch(event->type())
2998 case QEvent::MouseButtonPress:
2999 if(mouseEvent && (mouseEvent->button() == Qt::LeftButton))
3001 QString path = outputFolderLabel->text();
3002 if(!path.endsWith(QDir::separator())) path.append(QDir::separator());
3003 ShellExecuteW(reinterpret_cast<HWND>(this->winId()), L"explore", QWCHAR(path), NULL, NULL, SW_SHOW);
3005 break;
3006 case QEvent::Enter:
3007 outputFolderLabel->setForegroundRole(QPalette::Link);
3008 break;
3009 case QEvent::Leave:
3010 outputFolderLabel->setForegroundRole(QPalette::WindowText);
3011 break;
3014 else if(sender == outputFoldersFovoritesLabel)
3016 switch(event->type())
3018 case QEvent::Enter:
3019 outputFoldersFovoritesLabel->setFrameShadow(QFrame::Raised);
3020 break;
3021 case QEvent::MouseButtonPress:
3022 outputFoldersFovoritesLabel->setFrameShadow(QFrame::Sunken);
3023 break;
3024 case QEvent::MouseButtonRelease:
3025 outputFoldersFovoritesLabel->setFrameShadow(QFrame::Raised);
3026 if(mouseEvent)
3028 if(pos.x() <= sender->width() && pos.y() <= sender->height() && pos.x() >= 0 && pos.y() >= 0 && mouseEvent->button() != Qt::MidButton)
3030 if(outputFolderView->isEnabled())
3032 m_outputFolderFavoritesMenu->popup(sender->mapToGlobal(pos));
3036 break;
3037 case QEvent::Leave:
3038 outputFoldersFovoritesLabel->setFrameShadow(QFrame::Plain);
3039 break;
3042 else if(sender == outputFoldersEditorLabel)
3044 switch(event->type())
3046 case QEvent::Enter:
3047 outputFoldersEditorLabel->setFrameShadow(QFrame::Raised);
3048 break;
3049 case QEvent::MouseButtonPress:
3050 outputFoldersEditorLabel->setFrameShadow(QFrame::Sunken);
3051 break;
3052 case QEvent::MouseButtonRelease:
3053 outputFoldersEditorLabel->setFrameShadow(QFrame::Raised);
3054 if(mouseEvent)
3056 if(pos.x() <= sender->width() && pos.y() <= sender->height() && pos.x() >= 0 && pos.y() >= 0 && mouseEvent->button() != Qt::MidButton)
3058 if(outputFolderView->isEnabled())
3060 outputFolderView->setEnabled(false);
3061 outputFolderLabel->setVisible(false);
3062 outputFolderEdit->setVisible(true);
3063 outputFolderEdit->setText(outputFolderLabel->text());
3064 outputFolderEdit->selectAll();
3065 outputFolderEdit->setFocus();
3069 break;
3070 case QEvent::Leave:
3071 outputFoldersEditorLabel->setFrameShadow(QFrame::Plain);
3072 break;
3077 // =========================================================
3078 // Metadata tab slots
3079 // =========================================================
3082 * Edit meta button clicked
3084 void MainWindow::editMetaButtonClicked(void)
3086 ABORT_IF_BUSY;
3088 const QModelIndex index = metaDataView->currentIndex();
3090 if(index.isValid())
3092 m_metaInfoModel->editItem(index, this);
3094 if(index.row() == 4)
3096 m_settings->metaInfoPosition(m_metaData->filePosition());
3102 * Reset meta button clicked
3104 void MainWindow::clearMetaButtonClicked(void)
3106 ABORT_IF_BUSY;
3107 m_metaInfoModel->clearData();
3111 * Meta tags enabled changed
3113 void MainWindow::metaTagsEnabledChanged(void)
3115 m_settings->writeMetaTags(writeMetaDataCheckBox->isChecked());
3119 * Playlist enabled changed
3121 void MainWindow::playlistEnabledChanged(void)
3123 m_settings->createPlaylist(generatePlaylistCheckBox->isChecked());
3126 // =========================================================
3127 // Compression tab slots
3128 // =========================================================
3131 * Update encoder
3133 void MainWindow::updateEncoder(int id)
3135 m_settings->compressionEncoder(id);
3137 switch(m_settings->compressionEncoder())
3139 case SettingsModel::VorbisEncoder:
3140 radioButtonModeQuality->setEnabled(true);
3141 radioButtonModeAverageBitrate->setEnabled(true);
3142 radioButtonConstBitrate->setEnabled(false);
3143 if(radioButtonConstBitrate->isChecked()) radioButtonModeQuality->setChecked(true);
3144 sliderBitrate->setEnabled(true);
3145 break;
3146 case SettingsModel::AC3Encoder:
3147 radioButtonModeQuality->setEnabled(true);
3148 radioButtonModeQuality->setChecked(true);
3149 radioButtonModeAverageBitrate->setEnabled(false);
3150 radioButtonConstBitrate->setEnabled(true);
3151 sliderBitrate->setEnabled(true);
3152 break;
3153 case SettingsModel::FLACEncoder:
3154 radioButtonModeQuality->setEnabled(false);
3155 radioButtonModeQuality->setChecked(true);
3156 radioButtonModeAverageBitrate->setEnabled(false);
3157 radioButtonConstBitrate->setEnabled(false);
3158 sliderBitrate->setEnabled(true);
3159 break;
3160 case SettingsModel::PCMEncoder:
3161 radioButtonModeQuality->setEnabled(false);
3162 radioButtonModeQuality->setChecked(true);
3163 radioButtonModeAverageBitrate->setEnabled(false);
3164 radioButtonConstBitrate->setEnabled(false);
3165 sliderBitrate->setEnabled(false);
3166 break;
3167 case SettingsModel::AACEncoder:
3168 radioButtonModeQuality->setEnabled(true);
3169 radioButtonModeAverageBitrate->setEnabled(!m_fhgEncoderAvailable);
3170 if(m_fhgEncoderAvailable && radioButtonModeAverageBitrate->isChecked()) radioButtonConstBitrate->setChecked(true);
3171 radioButtonConstBitrate->setEnabled(true);
3172 sliderBitrate->setEnabled(true);
3173 break;
3174 case SettingsModel::DCAEncoder:
3175 radioButtonModeQuality->setEnabled(false);
3176 radioButtonModeAverageBitrate->setEnabled(false);
3177 radioButtonConstBitrate->setEnabled(true);
3178 radioButtonConstBitrate->setChecked(true);
3179 sliderBitrate->setEnabled(true);
3180 break;
3181 default:
3182 radioButtonModeQuality->setEnabled(true);
3183 radioButtonModeAverageBitrate->setEnabled(true);
3184 radioButtonConstBitrate->setEnabled(true);
3185 sliderBitrate->setEnabled(true);
3186 break;
3189 if(m_settings->compressionEncoder() == SettingsModel::AACEncoder)
3191 const QString encoderName = m_qaacEncoderAvailable ? tr("QAAC (Apple)") : (m_fhgEncoderAvailable ? tr("FHG AAC (Winamp)") : (m_neroEncoderAvailable ? tr("Nero AAC") : tr("Not available!")));
3192 labelEncoderInfo->setVisible(true);
3193 labelEncoderInfo->setText(tr("Current AAC Encoder: %1").arg(encoderName));
3195 else
3197 labelEncoderInfo->setVisible(false);
3200 updateRCMode(m_modeButtonGroup->checkedId());
3204 * Update rate-control mode
3206 void MainWindow::updateRCMode(int id)
3208 m_settings->compressionRCMode(id);
3210 switch(m_settings->compressionEncoder())
3212 case SettingsModel::MP3Encoder:
3213 switch(m_settings->compressionRCMode())
3215 case SettingsModel::VBRMode:
3216 sliderBitrate->setMinimum(0);
3217 sliderBitrate->setMaximum(9);
3218 break;
3219 default:
3220 sliderBitrate->setMinimum(0);
3221 sliderBitrate->setMaximum(13);
3222 break;
3224 break;
3225 case SettingsModel::VorbisEncoder:
3226 switch(m_settings->compressionRCMode())
3228 case SettingsModel::VBRMode:
3229 sliderBitrate->setMinimum(-2);
3230 sliderBitrate->setMaximum(10);
3231 break;
3232 default:
3233 sliderBitrate->setMinimum(4);
3234 sliderBitrate->setMaximum(63);
3235 break;
3237 break;
3238 case SettingsModel::AC3Encoder:
3239 switch(m_settings->compressionRCMode())
3241 case SettingsModel::VBRMode:
3242 sliderBitrate->setMinimum(0);
3243 sliderBitrate->setMaximum(16);
3244 break;
3245 default:
3246 sliderBitrate->setMinimum(0);
3247 sliderBitrate->setMaximum(18);
3248 break;
3250 break;
3251 case SettingsModel::AACEncoder:
3252 switch(m_settings->compressionRCMode())
3254 case SettingsModel::VBRMode:
3255 sliderBitrate->setMinimum(0);
3256 sliderBitrate->setMaximum(20);
3257 break;
3258 default:
3259 sliderBitrate->setMinimum(4);
3260 sliderBitrate->setMaximum(63);
3261 break;
3263 break;
3264 case SettingsModel::FLACEncoder:
3265 sliderBitrate->setMinimum(0);
3266 sliderBitrate->setMaximum(8);
3267 break;
3268 case SettingsModel::OpusEncoder:
3269 sliderBitrate->setMinimum(1);
3270 sliderBitrate->setMaximum(32);
3271 break;
3272 case SettingsModel::DCAEncoder:
3273 sliderBitrate->setMinimum(1);
3274 sliderBitrate->setMaximum(128);
3275 break;
3276 case SettingsModel::PCMEncoder:
3277 sliderBitrate->setMinimum(0);
3278 sliderBitrate->setMaximum(2);
3279 sliderBitrate->setValue(1);
3280 break;
3281 default:
3282 sliderBitrate->setMinimum(0);
3283 sliderBitrate->setMaximum(0);
3284 break;
3287 updateBitrate(sliderBitrate->value());
3291 * Update bitrate
3293 void MainWindow::updateBitrate(int value)
3295 m_settings->compressionBitrate(value);
3297 switch(m_settings->compressionRCMode())
3299 case SettingsModel::VBRMode:
3300 switch(m_settings->compressionEncoder())
3302 case SettingsModel::MP3Encoder:
3303 labelBitrate->setText(tr("Quality Level %1").arg(9 - value));
3304 break;
3305 case SettingsModel::VorbisEncoder:
3306 labelBitrate->setText(tr("Quality Level %1").arg(value));
3307 break;
3308 case SettingsModel::AACEncoder:
3309 labelBitrate->setText(tr("Quality Level %1").arg(QString().sprintf("%.2f", static_cast<double>(value * 5) / 100.0)));
3310 break;
3311 case SettingsModel::FLACEncoder:
3312 labelBitrate->setText(tr("Compression %1").arg(value));
3313 break;
3314 case SettingsModel::OpusEncoder:
3315 labelBitrate->setText(QString("&asymp; %1 kbps").arg(qMin(500, value * 8)));
3316 break;
3317 case SettingsModel::AC3Encoder:
3318 labelBitrate->setText(tr("Quality Level %1").arg(qMin(1024, qMax(0, value * 64))));
3319 break;
3320 case SettingsModel::PCMEncoder:
3321 labelBitrate->setText(tr("Uncompressed"));
3322 break;
3323 default:
3324 labelBitrate->setText(QString::number(value));
3325 break;
3327 break;
3328 case SettingsModel::ABRMode:
3329 switch(m_settings->compressionEncoder())
3331 case SettingsModel::MP3Encoder:
3332 labelBitrate->setText(QString("&asymp; %1 kbps").arg(SettingsModel::mp3Bitrates[value]));
3333 break;
3334 case SettingsModel::FLACEncoder:
3335 labelBitrate->setText(tr("Compression %1").arg(value));
3336 break;
3337 case SettingsModel::AC3Encoder:
3338 labelBitrate->setText(QString("&asymp; %1 kbps").arg(SettingsModel::ac3Bitrates[value]));
3339 break;
3340 case SettingsModel::PCMEncoder:
3341 labelBitrate->setText(tr("Uncompressed"));
3342 break;
3343 default:
3344 labelBitrate->setText(QString("&asymp; %1 kbps").arg(qMin(500, value * 8)));
3345 break;
3347 break;
3348 default:
3349 switch(m_settings->compressionEncoder())
3351 case SettingsModel::MP3Encoder:
3352 labelBitrate->setText(QString("%1 kbps").arg(SettingsModel::mp3Bitrates[value]));
3353 break;
3354 case SettingsModel::FLACEncoder:
3355 labelBitrate->setText(tr("Compression %1").arg(value));
3356 break;
3357 case SettingsModel::AC3Encoder:
3358 labelBitrate->setText(QString("%1 kbps").arg(SettingsModel::ac3Bitrates[value]));
3359 break;
3360 case SettingsModel::DCAEncoder:
3361 labelBitrate->setText(QString("%1 kbps").arg(value * 32));
3362 break;
3363 case SettingsModel::PCMEncoder:
3364 labelBitrate->setText(tr("Uncompressed"));
3365 break;
3366 default:
3367 labelBitrate->setText(QString("%1 kbps").arg(qMin(500, value * 8)));
3368 break;
3370 break;
3375 * Event for compression tab occurred
3377 void MainWindow::compressionTabEventOccurred(QWidget *sender, QEvent *event)
3379 static const QUrl helpUrl("http://lamexp.sourceforge.net/doc/FAQ.html#054010d9");
3381 if((sender == labelCompressionHelp) && (event->type() == QEvent::MouseButtonPress))
3383 QDesktopServices::openUrl(helpUrl);
3387 // =========================================================
3388 // Advanced option slots
3389 // =========================================================
3392 * Lame algorithm quality changed
3394 void MainWindow::updateLameAlgoQuality(int value)
3396 QString text;
3398 switch(value)
3400 case 4:
3401 text = tr("Best Quality (Very Slow)");
3402 break;
3403 case 3:
3404 text = tr("High Quality (Recommended)");
3405 break;
3406 case 2:
3407 text = tr("Average Quality (Default)");
3408 break;
3409 case 1:
3410 text = tr("Low Quality (Fast)");
3411 break;
3412 case 0:
3413 text = tr("Poor Quality (Very Fast)");
3414 break;
3417 if(!text.isEmpty())
3419 m_settings->lameAlgoQuality(value);
3420 labelLameAlgoQuality->setText(text);
3423 bool warning = (value == 0), notice = (value == 4);
3424 labelLameAlgoQualityWarning->setVisible(warning);
3425 labelLameAlgoQualityWarningIcon->setVisible(warning);
3426 labelLameAlgoQualityNotice->setVisible(notice);
3427 labelLameAlgoQualityNoticeIcon->setVisible(notice);
3428 labelLameAlgoQualitySpacer->setVisible(warning || notice);
3432 * Bitrate management endabled/disabled
3434 void MainWindow::bitrateManagementEnabledChanged(bool checked)
3436 m_settings->bitrateManagementEnabled(checked);
3440 * Minimum bitrate has changed
3442 void MainWindow::bitrateManagementMinChanged(int value)
3444 if(value > spinBoxBitrateManagementMax->value())
3446 spinBoxBitrateManagementMin->setValue(spinBoxBitrateManagementMax->value());
3447 m_settings->bitrateManagementMinRate(spinBoxBitrateManagementMax->value());
3449 else
3451 m_settings->bitrateManagementMinRate(value);
3456 * Maximum bitrate has changed
3458 void MainWindow::bitrateManagementMaxChanged(int value)
3460 if(value < spinBoxBitrateManagementMin->value())
3462 spinBoxBitrateManagementMax->setValue(spinBoxBitrateManagementMin->value());
3463 m_settings->bitrateManagementMaxRate(spinBoxBitrateManagementMin->value());
3465 else
3467 m_settings->bitrateManagementMaxRate(value);
3472 * Channel mode has changed
3474 void MainWindow::channelModeChanged(int value)
3476 if(value >= 0) m_settings->lameChannelMode(value);
3480 * Sampling rate has changed
3482 void MainWindow::samplingRateChanged(int value)
3484 if(value >= 0) m_settings->samplingRate(value);
3488 * Nero AAC 2-Pass mode changed
3490 void MainWindow::neroAAC2PassChanged(bool checked)
3492 m_settings->neroAACEnable2Pass(checked);
3496 * Nero AAC profile mode changed
3498 void MainWindow::neroAACProfileChanged(int value)
3500 if(value >= 0) m_settings->aacEncProfile(value);
3504 * Aften audio coding mode changed
3506 void MainWindow::aftenCodingModeChanged(int value)
3508 if(value >= 0) m_settings->aftenAudioCodingMode(value);
3512 * Aften DRC mode changed
3514 void MainWindow::aftenDRCModeChanged(int value)
3516 if(value >= 0) m_settings->aftenDynamicRangeCompression(value);
3520 * Aften exponent search size changed
3522 void MainWindow::aftenSearchSizeChanged(int value)
3524 if(value >= 0) m_settings->aftenExponentSearchSize(value);
3528 * Aften fast bit allocation changed
3530 void MainWindow::aftenFastAllocationChanged(bool checked)
3532 m_settings->aftenFastBitAllocation(checked);
3537 * Opus encoder settings changed
3539 void MainWindow::opusSettingsChanged(void)
3541 m_settings->opusOptimizeFor(comboBoxOpusOptimize->currentIndex());
3542 m_settings->opusFramesize(comboBoxOpusFramesize->currentIndex());
3543 m_settings->opusComplexity(spinBoxOpusComplexity->value());
3544 m_settings->opusExpAnalysis(checkBoxOpusExpAnalysis->isChecked());
3548 * Normalization filter enabled changed
3550 void MainWindow::normalizationEnabledChanged(bool checked)
3552 m_settings->normalizationFilterEnabled(checked);
3556 * Normalization max. volume changed
3558 void MainWindow::normalizationMaxVolumeChanged(double value)
3560 m_settings->normalizationFilterMaxVolume(static_cast<int>(value * 100.0));
3564 * Normalization equalization mode changed
3566 void MainWindow::normalizationModeChanged(int mode)
3568 m_settings->normalizationFilterEqualizationMode(mode);
3572 * Tone adjustment has changed (Bass)
3574 void MainWindow::toneAdjustBassChanged(double value)
3576 m_settings->toneAdjustBass(static_cast<int>(value * 100.0));
3577 spinBoxToneAdjustBass->setPrefix((value > 0) ? "+" : QString());
3581 * Tone adjustment has changed (Treble)
3583 void MainWindow::toneAdjustTrebleChanged(double value)
3585 m_settings->toneAdjustTreble(static_cast<int>(value * 100.0));
3586 spinBoxToneAdjustTreble->setPrefix((value > 0) ? "+" : QString());
3590 * Tone adjustment has been reset
3592 void MainWindow::toneAdjustTrebleReset(void)
3594 spinBoxToneAdjustBass->setValue(m_settings->toneAdjustBassDefault());
3595 spinBoxToneAdjustTreble->setValue(m_settings->toneAdjustTrebleDefault());
3596 toneAdjustBassChanged(spinBoxToneAdjustBass->value());
3597 toneAdjustTrebleChanged(spinBoxToneAdjustTreble->value());
3601 * Custom encoder parameters changed
3603 void MainWindow::customParamsChanged(void)
3605 lineEditCustomParamLAME->setText(lineEditCustomParamLAME->text().simplified());
3606 lineEditCustomParamOggEnc->setText(lineEditCustomParamOggEnc->text().simplified());
3607 lineEditCustomParamNeroAAC->setText(lineEditCustomParamNeroAAC->text().simplified());
3608 lineEditCustomParamFLAC->setText(lineEditCustomParamFLAC->text().simplified());
3609 lineEditCustomParamAften->setText(lineEditCustomParamAften->text().simplified());
3610 lineEditCustomParamOpus->setText(lineEditCustomParamOpus->text().simplified());
3612 bool customParamsUsed = false;
3613 if(!lineEditCustomParamLAME->text().isEmpty()) customParamsUsed = true;
3614 if(!lineEditCustomParamOggEnc->text().isEmpty()) customParamsUsed = true;
3615 if(!lineEditCustomParamNeroAAC->text().isEmpty()) customParamsUsed = true;
3616 if(!lineEditCustomParamFLAC->text().isEmpty()) customParamsUsed = true;
3617 if(!lineEditCustomParamAften->text().isEmpty()) customParamsUsed = true;
3618 if(!lineEditCustomParamOpus->text().isEmpty()) customParamsUsed = true;
3620 labelCustomParamsIcon->setVisible(customParamsUsed);
3621 labelCustomParamsText->setVisible(customParamsUsed);
3622 labelCustomParamsSpacer->setVisible(customParamsUsed);
3624 m_settings->customParametersLAME(lineEditCustomParamLAME->text());
3625 m_settings->customParametersOggEnc(lineEditCustomParamOggEnc->text());
3626 m_settings->customParametersAacEnc(lineEditCustomParamNeroAAC->text());
3627 m_settings->customParametersFLAC(lineEditCustomParamFLAC->text());
3628 m_settings->customParametersAften(lineEditCustomParamAften->text());
3629 m_settings->customParametersOpus(lineEditCustomParamOpus->text());
3633 * Rename output files enabled changed
3635 void MainWindow::renameOutputEnabledChanged(bool checked)
3637 m_settings->renameOutputFilesEnabled(checked);
3641 * Rename output files patterm changed
3643 void MainWindow::renameOutputPatternChanged(void)
3645 QString temp = lineEditRenamePattern->text().simplified();
3646 lineEditRenamePattern->setText(temp.isEmpty() ? m_settings->renameOutputFilesPatternDefault() : temp);
3647 m_settings->renameOutputFilesPattern(lineEditRenamePattern->text());
3651 * Rename output files patterm changed
3653 void MainWindow::renameOutputPatternChanged(const QString &text)
3655 QString pattern(text.simplified());
3657 pattern.replace("<BaseName>", "The_White_Stripes_-_Fell_In_Love_With_A_Girl", Qt::CaseInsensitive);
3658 pattern.replace("<TrackNo>", "04", Qt::CaseInsensitive);
3659 pattern.replace("<Title>", "Fell In Love With A Girl", Qt::CaseInsensitive);
3660 pattern.replace("<Artist>", "The White Stripes", Qt::CaseInsensitive);
3661 pattern.replace("<Album>", "White Blood Cells", Qt::CaseInsensitive);
3662 pattern.replace("<Year>", "2001", Qt::CaseInsensitive);
3663 pattern.replace("<Comment>", "Encoded by LameXP", Qt::CaseInsensitive);
3665 if(pattern.compare(lamexp_clean_filename(pattern)))
3667 if(lineEditRenamePattern->palette().color(QPalette::Text) != Qt::red)
3669 MessageBeep(MB_ICONERROR);
3670 SET_TEXT_COLOR(lineEditRenamePattern, Qt::red);
3673 else
3675 if(lineEditRenamePattern->palette().color(QPalette::Text) != Qt::black)
3677 MessageBeep(MB_ICONINFORMATION);
3678 SET_TEXT_COLOR(lineEditRenamePattern, Qt::black);
3682 labelRanameExample->setText(lamexp_clean_filename(pattern));
3686 * Show list of rename macros
3688 void MainWindow::showRenameMacros(const QString &text)
3690 if(text.compare("reset", Qt::CaseInsensitive) == 0)
3692 lineEditRenamePattern->setText(m_settings->renameOutputFilesPatternDefault());
3693 return;
3696 const QString format = QString("<tr><td><tt>&lt;%1&gt;</tt></td><td>&nbsp;&nbsp;</td><td>%2</td></tr>");
3698 QString message = QString("<table>");
3699 message += QString(format).arg("BaseName", tr("File name without extension"));
3700 message += QString(format).arg("TrackNo", tr("Track number with leading zero"));
3701 message += QString(format).arg("Title", tr("Track title"));
3702 message += QString(format).arg("Artist", tr("Artist name"));
3703 message += QString(format).arg("Album", tr("Album name"));
3704 message += QString(format).arg("Year", tr("Year with (at least) four digits"));
3705 message += QString(format).arg("Comment", tr("Comment"));
3706 message += "</table><br><br>";
3707 message += QString("%1<br>").arg(tr("Characters forbidden in file names:"));
3708 message += "<b><tt>\\ / : * ? &lt; &gt; |<br>";
3710 QMessageBox::information(this, tr("Rename Macros"), message, tr("Discard"));
3713 void MainWindow::forceStereoDownmixEnabledChanged(bool checked)
3715 m_settings->forceStereoDownmix(checked);
3719 * Maximum number of instances changed
3721 void MainWindow::updateMaximumInstances(int value)
3723 labelMaxInstances->setText(tr("%1 Instance(s)").arg(QString::number(value)));
3724 m_settings->maximumInstances(checkBoxAutoDetectInstances->isChecked() ? NULL : value);
3728 * Auto-detect number of instances
3730 void MainWindow::autoDetectInstancesChanged(bool checked)
3732 m_settings->maximumInstances(checked ? NULL : sliderMaxInstances->value());
3736 * Browse for custom TEMP folder button clicked
3738 void MainWindow::browseCustomTempFolderButtonClicked(void)
3740 QString newTempFolder;
3742 if(USE_NATIVE_FILE_DIALOG)
3744 newTempFolder = QFileDialog::getExistingDirectory(this, QString(), m_settings->customTempPath());
3746 else
3748 QFileDialog dialog(this);
3749 dialog.setFileMode(QFileDialog::DirectoryOnly);
3750 dialog.setDirectory(m_settings->customTempPath());
3751 if(dialog.exec())
3753 newTempFolder = dialog.selectedFiles().first();
3757 if(!newTempFolder.isEmpty())
3759 QFile writeTest(QString("%1/~%2.tmp").arg(newTempFolder, lamexp_rand_str()));
3760 if(writeTest.open(QIODevice::ReadWrite))
3762 writeTest.remove();
3763 lineEditCustomTempFolder->setText(QDir::toNativeSeparators(newTempFolder));
3765 else
3767 QMessageBox::warning(this, tr("Access Denied"), tr("Cannot write to the selected directory. Please choose another directory!"));
3773 * Custom TEMP folder changed
3775 void MainWindow::customTempFolderChanged(const QString &text)
3777 m_settings->customTempPath(QDir::fromNativeSeparators(text));
3781 * Use custom TEMP folder option changed
3783 void MainWindow::useCustomTempFolderChanged(bool checked)
3785 m_settings->customTempPathEnabled(!checked);
3789 * Help for custom parameters was requested
3791 void MainWindow::customParamsHelpRequested(QWidget *obj, QEvent *event)
3793 if(event->type() != QEvent::MouseButtonRelease)
3795 return;
3798 if(QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(event))
3800 QPoint pos = mouseEvent->pos();
3801 if(!(pos.x() <= obj->width() && pos.y() <= obj->height() && pos.x() >= 0 && pos.y() >= 0 && mouseEvent->button() != Qt::MidButton))
3803 return;
3807 if(obj == helpCustomParamLAME) showCustomParamsHelpScreen("lame.exe", "--longhelp");
3808 else if(obj == helpCustomParamOggEnc) showCustomParamsHelpScreen("oggenc2.exe", "--help");
3809 else if(obj == helpCustomParamNeroAAC)
3811 if(m_qaacEncoderAvailable) showCustomParamsHelpScreen("qaac.exe", "--help");
3812 else if(m_fhgEncoderAvailable) showCustomParamsHelpScreen("fhgaacenc.exe", "");
3813 else if(m_neroEncoderAvailable) showCustomParamsHelpScreen("neroAacEnc.exe", "-help");
3814 else MessageBeep(MB_ICONERROR);
3816 else if(obj == helpCustomParamFLAC) showCustomParamsHelpScreen("flac.exe", "--help");
3817 else if(obj == helpCustomParamAften) showCustomParamsHelpScreen("aften.exe", "-h");
3818 else if(obj == helpCustomParamOpus) showCustomParamsHelpScreen("opusenc_std.exe", "--help");
3819 else MessageBeep(MB_ICONERROR);
3823 * Show help for custom parameters
3825 void MainWindow::showCustomParamsHelpScreen(const QString &toolName, const QString &command)
3827 const QString binary = lamexp_lookup_tool(toolName);
3828 if(binary.isEmpty())
3830 MessageBeep(MB_ICONERROR);
3831 qWarning("customParamsHelpRequested: Binary could not be found!");
3832 return;
3835 QProcess *process = new QProcess();
3836 process->setProcessChannelMode(QProcess::MergedChannels);
3837 process->setReadChannel(QProcess::StandardOutput);
3838 process->start(binary, command.isEmpty() ? QStringList() : QStringList() << command);
3839 qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
3841 if(process->waitForStarted(15000))
3843 qApp->processEvents();
3844 process->waitForFinished(15000);
3847 if(process->state() != QProcess::NotRunning)
3849 process->kill();
3850 process->waitForFinished(-1);
3853 qApp->restoreOverrideCursor();
3854 QStringList output; bool spaceFlag = true;
3856 while(process->canReadLine())
3858 QString temp = QString::fromUtf8(process->readLine());
3859 TRIM_STRING_RIGHT(temp);
3860 if(temp.isEmpty())
3862 if(!spaceFlag) { output << temp; spaceFlag = true; }
3864 else
3866 output << temp; spaceFlag = false;
3870 LAMEXP_DELETE(process);
3872 if(output.count() < 1)
3874 qWarning("Empty output, cannot show help screen!");
3875 MessageBeep(MB_ICONERROR);
3878 LogViewDialog *dialog = new LogViewDialog(this);
3879 TEMP_HIDE_DROPBOX( dialog->exec(output); );
3880 LAMEXP_DELETE(dialog);
3884 * Reset all advanced options to their defaults
3886 void MainWindow::resetAdvancedOptionsButtonClicked(void)
3888 sliderLameAlgoQuality->setValue(m_settings->lameAlgoQualityDefault());
3889 spinBoxBitrateManagementMin->setValue(m_settings->bitrateManagementMinRateDefault());
3890 spinBoxBitrateManagementMax->setValue(m_settings->bitrateManagementMaxRateDefault());
3891 spinBoxNormalizationFilter->setValue(static_cast<double>(m_settings->normalizationFilterMaxVolumeDefault()) / 100.0);
3892 spinBoxToneAdjustBass->setValue(static_cast<double>(m_settings->toneAdjustBassDefault()) / 100.0);
3893 spinBoxToneAdjustTreble->setValue(static_cast<double>(m_settings->toneAdjustTrebleDefault()) / 100.0);
3894 spinBoxAftenSearchSize->setValue(m_settings->aftenExponentSearchSizeDefault());
3895 spinBoxOpusComplexity->setValue(m_settings->opusComplexityDefault());
3896 comboBoxMP3ChannelMode->setCurrentIndex(m_settings->lameChannelModeDefault());
3897 comboBoxSamplingRate->setCurrentIndex(m_settings->samplingRateDefault());
3898 comboBoxAACProfile->setCurrentIndex(m_settings->aacEncProfileDefault());
3899 comboBoxAftenCodingMode->setCurrentIndex(m_settings->aftenAudioCodingModeDefault());
3900 comboBoxAftenDRCMode->setCurrentIndex(m_settings->aftenDynamicRangeCompressionDefault());
3901 comboBoxNormalizationMode->setCurrentIndex(m_settings->normalizationFilterEqualizationModeDefault());
3902 comboBoxOpusOptimize->setCurrentIndex(m_settings->opusOptimizeForDefault());
3903 comboBoxOpusFramesize->setCurrentIndex(m_settings->opusFramesizeDefault());
3904 SET_CHECKBOX_STATE(checkBoxBitrateManagement, m_settings->bitrateManagementEnabledDefault());
3905 SET_CHECKBOX_STATE(checkBoxNeroAAC2PassMode, m_settings->neroAACEnable2PassDefault());
3906 SET_CHECKBOX_STATE(checkBoxNormalizationFilter, m_settings->normalizationFilterEnabledDefault());
3907 SET_CHECKBOX_STATE(checkBoxAutoDetectInstances, (m_settings->maximumInstancesDefault() < 1));
3908 SET_CHECKBOX_STATE(checkBoxUseSystemTempFolder, m_settings->customTempPathEnabledDefault());
3909 SET_CHECKBOX_STATE(checkBoxAftenFastAllocation, m_settings->aftenFastBitAllocationDefault());
3910 SET_CHECKBOX_STATE(checkBoxRenameOutput, m_settings->renameOutputFilesEnabledDefault());
3911 SET_CHECKBOX_STATE(checkBoxForceStereoDownmix, m_settings->forceStereoDownmixDefault());
3912 SET_CHECKBOX_STATE(checkBoxOpusExpAnalysis, m_settings->opusExpAnalysisDefault());
3913 lineEditCustomParamLAME->setText(m_settings->customParametersLAMEDefault());
3914 lineEditCustomParamOggEnc->setText(m_settings->customParametersOggEncDefault());
3915 lineEditCustomParamNeroAAC->setText(m_settings->customParametersAacEncDefault());
3916 lineEditCustomParamFLAC->setText(m_settings->customParametersFLACDefault());
3917 lineEditCustomParamOpus->setText(m_settings->customParametersFLACDefault());
3918 lineEditCustomTempFolder->setText(QDir::toNativeSeparators(m_settings->customTempPathDefault()));
3919 lineEditRenamePattern->setText(m_settings->renameOutputFilesPatternDefault());
3920 customParamsChanged();
3921 scrollArea->verticalScrollBar()->setValue(0);
3924 // =========================================================
3925 // Multi-instance handling slots
3926 // =========================================================
3929 * Other instance detected
3931 void MainWindow::notifyOtherInstance(void)
3933 if(!m_banner->isVisible())
3935 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);
3936 msgBox.exec();
3941 * Add file from another instance
3943 void MainWindow::addFileDelayed(const QString &filePath, bool tryASAP)
3945 if(tryASAP && !m_delayedFileTimer->isActive())
3947 qDebug("Received file: %s", filePath.toUtf8().constData());
3948 m_delayedFileList->append(filePath);
3949 QTimer::singleShot(0, this, SLOT(handleDelayedFiles()));
3952 m_delayedFileTimer->stop();
3953 qDebug("Received file: %s", filePath.toUtf8().constData());
3954 m_delayedFileList->append(filePath);
3955 m_delayedFileTimer->start(5000);
3959 * Add files from another instance
3961 void MainWindow::addFilesDelayed(const QStringList &filePaths, bool tryASAP)
3963 if(tryASAP && !m_delayedFileTimer->isActive())
3965 qDebug("Received %d file(s).", filePaths.count());
3966 m_delayedFileList->append(filePaths);
3967 QTimer::singleShot(0, this, SLOT(handleDelayedFiles()));
3969 else
3971 m_delayedFileTimer->stop();
3972 qDebug("Received %d file(s).", filePaths.count());
3973 m_delayedFileList->append(filePaths);
3974 m_delayedFileTimer->start(5000);
3979 * Add folder from another instance
3981 void MainWindow::addFolderDelayed(const QString &folderPath, bool recursive)
3983 if(!m_banner->isVisible())
3985 addFolder(folderPath, recursive, true);
3989 // =========================================================
3990 // Misc slots
3991 // =========================================================
3994 * Restore the override cursor
3996 void MainWindow::restoreCursor(void)
3998 QApplication::restoreOverrideCursor();