1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
22 #include "Dialog_MainWindow.h"
27 #include "Dialog_WorkingBanner.h"
28 #include "Dialog_MetaInfo.h"
29 #include "Dialog_About.h"
30 #include "Dialog_Update.h"
31 #include "Dialog_DropBox.h"
32 #include "Dialog_CueImport.h"
33 #include "Thread_FileAnalyzer.h"
34 #include "Thread_MessageHandler.h"
35 #include "Model_MetaInfo.h"
36 #include "Model_Settings.h"
37 #include "Model_FileList.h"
38 #include "Model_FileSystem.h"
39 #include "WinSevenTaskbar.h"
40 #include "Registry_Decoder.h"
41 #include "ShellIntegration.h"
44 #include <QMessageBox>
46 #include <QDesktopWidget>
48 #include <QFileDialog>
49 #include <QInputDialog>
50 #include <QFileSystemModel>
51 #include <QDesktopServices>
53 #include <QPlastiqueStyle>
54 #include <QCleanlooksStyle>
55 #include <QWindowsVistaStyle>
56 #include <QWindowsStyle>
58 #include <QDragEnterEvent>
59 #include <QWindowsMime>
62 #include <QProcessEnvironment>
63 #include <QCryptographicHash>
64 #include <QTranslator>
73 #define ABORT_IF_BUSY if(m_banner->isVisible() || m_delayedFileTimer->isActive()) { MessageBeep(MB_ICONEXCLAMATION); return; }
74 #define SET_TEXT_COLOR(WIDGET,COLOR) { QPalette _palette = WIDGET->palette(); _palette.setColor(QPalette::WindowText, (COLOR)); _palette.setColor(QPalette::Text, (COLOR)); WIDGET->setPalette(_palette); }
75 #define SET_FONT_BOLD(WIDGET,BOLD) { QFont _font = WIDGET->font(); _font.setBold(BOLD); WIDGET->setFont(_font); }
76 #define LINK(URL) QString("<a href=\"%1\">%2</a>").arg(URL).arg(QString(URL).replace("-", "−"))
77 #define FSLINK(PATH) QString("<a href=\"file:///%1\">%2</a>").arg(PATH).arg(QString(PATH).replace("-", "−"))
78 #define TEMP_HIDE_DROPBOX(CMD) { bool __dropBoxVisible = m_dropBox->isVisible(); if(__dropBoxVisible) m_dropBox->hide(); {CMD}; if(__dropBoxVisible) m_dropBox->show(); }
79 #define USE_NATIVE_FILE_DIALOG (lamexp_themes_enabled() || ((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) < QSysInfo::WV_XP))
80 #define CENTER_CURRENT_OUTPUT_FOLDER_DELAYED QTimer::singleShot(125, this, SLOT(centerOutputFolderModel()))
82 ////////////////////////////////////////////////////////////
84 ////////////////////////////////////////////////////////////
86 MainWindow::MainWindow(FileListModel
*fileListModel
, AudioFileModel
*metaInfo
, SettingsModel
*settingsModel
, QWidget
*parent
)
89 m_fileListModel(fileListModel
),
91 m_settings(settingsModel
),
92 m_fileSystemModel(NULL
),
93 m_neroEncoderAvailable(lamexp_check_tool("neroAacEnc.exe") && lamexp_check_tool("neroAacDec.exe") && lamexp_check_tool("neroAacTag.exe")),
94 m_fhgEncoderAvailable(lamexp_check_tool("fhgaacenc.exe") && lamexp_check_tool("enc_fhgaac.dll") && lamexp_check_tool("nsutil.dll") && lamexp_check_tool("libmp4v2.dll")),
95 m_qaacEncoderAvailable(lamexp_check_tool("qaac.exe") && lamexp_check_tool("libsoxrate.dll")),
97 m_firstTimeShown(true),
98 m_outputFolderViewCentering(false),
99 m_outputFolderViewInitCounter(0)
101 //Init the dialog, from the .ui file
103 setWindowFlags(windowFlags() ^ Qt::WindowMaximizeButtonHint
);
105 //Register meta types
106 qRegisterMetaType
<AudioFileModel
>("AudioFileModel");
108 //Enabled main buttons
109 connect(buttonAbout
, SIGNAL(clicked()), this, SLOT(aboutButtonClicked()));
110 connect(buttonStart
, SIGNAL(clicked()), this, SLOT(encodeButtonClicked()));
111 connect(buttonQuit
, SIGNAL(clicked()), this, SLOT(closeButtonClicked()));
114 tabWidget
->setCurrentIndex(0);
115 connect(tabWidget
, SIGNAL(currentChanged(int)), this, SLOT(tabPageChanged(int)));
118 sourceFileView
->setModel(m_fileListModel
);
119 sourceFileView
->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents
);
120 sourceFileView
->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents
);
121 sourceFileView
->setContextMenuPolicy(Qt::CustomContextMenu
);
122 sourceFileView
->viewport()->installEventFilter(this);
123 m_dropNoteLabel
= new QLabel(sourceFileView
);
124 m_dropNoteLabel
->setAlignment(Qt::AlignHCenter
| Qt::AlignVCenter
);
125 SET_FONT_BOLD(m_dropNoteLabel
, true);
126 SET_TEXT_COLOR(m_dropNoteLabel
, Qt::darkGray
);
127 m_sourceFilesContextMenu
= new QMenu();
128 m_showDetailsContextAction
= m_sourceFilesContextMenu
->addAction(QIcon(":/icons/zoom.png"), "N/A");
129 m_previewContextAction
= m_sourceFilesContextMenu
->addAction(QIcon(":/icons/sound.png"), "N/A");
130 m_findFileContextAction
= m_sourceFilesContextMenu
->addAction(QIcon(":/icons/folder_go.png"), "N/A");
131 m_sourceFilesContextMenu
->addSeparator();
132 m_exportCsvContextAction
= m_sourceFilesContextMenu
->addAction(QIcon(":/icons/table_save.png"), "N/A");
133 m_importCsvContextAction
= m_sourceFilesContextMenu
->addAction(QIcon(":/icons/folder_table.png"), "N/A");
134 SET_FONT_BOLD(m_showDetailsContextAction
, true);
135 connect(buttonAddFiles
, SIGNAL(clicked()), this, SLOT(addFilesButtonClicked()));
136 connect(buttonRemoveFile
, SIGNAL(clicked()), this, SLOT(removeFileButtonClicked()));
137 connect(buttonClearFiles
, SIGNAL(clicked()), this, SLOT(clearFilesButtonClicked()));
138 connect(buttonFileUp
, SIGNAL(clicked()), this, SLOT(fileUpButtonClicked()));
139 connect(buttonFileDown
, SIGNAL(clicked()), this, SLOT(fileDownButtonClicked()));
140 connect(buttonShowDetails
, SIGNAL(clicked()), this, SLOT(showDetailsButtonClicked()));
141 connect(m_fileListModel
, SIGNAL(rowsInserted(QModelIndex
,int,int)), this, SLOT(sourceModelChanged()));
142 connect(m_fileListModel
, SIGNAL(rowsRemoved(QModelIndex
,int,int)), this, SLOT(sourceModelChanged()));
143 connect(m_fileListModel
, SIGNAL(modelReset()), this, SLOT(sourceModelChanged()));
144 connect(sourceFileView
, SIGNAL(customContextMenuRequested(QPoint
)), this, SLOT(sourceFilesContextMenu(QPoint
)));
145 connect(sourceFileView
->verticalScrollBar(), SIGNAL(sliderMoved(int)), this, SLOT(sourceFilesScrollbarMoved(int)));
146 connect(sourceFileView
->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(sourceFilesScrollbarMoved(int)));
147 connect(m_showDetailsContextAction
, SIGNAL(triggered(bool)), this, SLOT(showDetailsButtonClicked()));
148 connect(m_previewContextAction
, SIGNAL(triggered(bool)), this, SLOT(previewContextActionTriggered()));
149 connect(m_findFileContextAction
, SIGNAL(triggered(bool)), this, SLOT(findFileContextActionTriggered()));
150 connect(m_exportCsvContextAction
, SIGNAL(triggered(bool)), this, SLOT(exportCsvContextActionTriggered()));
151 connect(m_importCsvContextAction
, SIGNAL(triggered(bool)), this, SLOT(importCsvContextActionTriggered()));
154 outputFolderView
->setHeaderHidden(true);
155 outputFolderView
->setAnimated(false);
156 outputFolderView
->setMouseTracking(false);
157 outputFolderView
->setContextMenuPolicy(Qt::CustomContextMenu
);
158 outputFolderView
->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn
);
159 outputFolderView
->installEventFilter(this);
160 outputFoldersEditorLabel
->installEventFilter(this);
161 outputFoldersFovoritesLabel
->installEventFilter(this);
162 while(saveToSourceFolderCheckBox
->isChecked() != m_settings
->outputToSourceDir()) saveToSourceFolderCheckBox
->click();
163 prependRelativePathCheckBox
->setChecked(m_settings
->prependRelativeSourcePath());
164 connect(outputFolderView
, SIGNAL(clicked(QModelIndex
)), this, SLOT(outputFolderViewClicked(QModelIndex
)));
165 connect(outputFolderView
, SIGNAL(activated(QModelIndex
)), this, SLOT(outputFolderViewClicked(QModelIndex
)));
166 connect(outputFolderView
, SIGNAL(pressed(QModelIndex
)), this, SLOT(outputFolderViewClicked(QModelIndex
)));
167 connect(outputFolderView
, SIGNAL(entered(QModelIndex
)), this, SLOT(outputFolderViewMoved(QModelIndex
)));
168 connect(outputFolderView
, SIGNAL(expanded(QModelIndex
)), this, SLOT(outputFolderItemExpanded(QModelIndex
)));
169 connect(buttonMakeFolder
, SIGNAL(clicked()), this, SLOT(makeFolderButtonClicked()));
170 connect(buttonGotoHome
, SIGNAL(clicked()), SLOT(gotoHomeFolderButtonClicked()));
171 connect(buttonGotoDesktop
, SIGNAL(clicked()), this, SLOT(gotoDesktopButtonClicked()));
172 connect(buttonGotoMusic
, SIGNAL(clicked()), this, SLOT(gotoMusicFolderButtonClicked()));
173 connect(saveToSourceFolderCheckBox
, SIGNAL(clicked()), this, SLOT(saveToSourceFolderChanged()));
174 connect(prependRelativePathCheckBox
, SIGNAL(clicked()), this, SLOT(prependRelativePathChanged()));
175 connect(outputFolderEdit
, SIGNAL(editingFinished()), this, SLOT(outputFolderEditFinished()));
176 if(m_outputFolderContextMenu
= new QMenu())
178 m_showFolderContextAction
= m_outputFolderContextMenu
->addAction(QIcon(":/icons/zoom.png"), "N/A");
179 m_refreshFolderContextAction
= m_outputFolderContextMenu
->addAction(QIcon(":/icons/arrow_refresh.png"), "N/A");
180 m_outputFolderContextMenu
->setDefaultAction(m_showFolderContextAction
);
181 connect(outputFolderView
, SIGNAL(customContextMenuRequested(QPoint
)), this, SLOT(outputFolderContextMenu(QPoint
)));
182 connect(m_showFolderContextAction
, SIGNAL(triggered(bool)), this, SLOT(showFolderContextActionTriggered()));
183 connect(m_refreshFolderContextAction
, SIGNAL(triggered(bool)), this, SLOT(refreshFolderContextActionTriggered()));
185 if(m_outputFolderFavoritesMenu
= new QMenu())
187 m_addFavoriteFolderAction
= m_outputFolderFavoritesMenu
->addAction(QIcon(":/icons/add.png"), "N/A");
188 m_outputFolderFavoritesMenu
->insertSeparator(m_addFavoriteFolderAction
);
189 connect(m_addFavoriteFolderAction
, SIGNAL(triggered(bool)), this, SLOT(addFavoriteFolderActionTriggered()));
191 outputFolderEdit
->setVisible(false);
192 outputFolderLabel
->installEventFilter(this);
193 if(m_outputFolderNoteBox
= new QLabel(outputFolderView
))
195 m_outputFolderNoteBox
->setAutoFillBackground(true);
196 m_outputFolderNoteBox
->setAlignment(Qt::AlignHCenter
| Qt::AlignVCenter
);
197 m_outputFolderNoteBox
->setFrameShape(QFrame::StyledPanel
);
198 SET_FONT_BOLD(m_outputFolderNoteBox
, true);
199 m_outputFolderNoteBox
->hide();
202 outputFolderViewClicked(QModelIndex());
205 //Setup "Meta Data" tab
206 m_metaInfoModel
= new MetaInfoModel(m_metaData
, 6);
207 m_metaInfoModel
->clearData();
208 m_metaInfoModel
->setData(m_metaInfoModel
->index(4, 1), m_settings
->metaInfoPosition());
209 metaDataView
->setModel(m_metaInfoModel
);
210 metaDataView
->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents
);
211 metaDataView
->verticalHeader()->hide();
212 metaDataView
->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents
);
213 while(writeMetaDataCheckBox
->isChecked() != m_settings
->writeMetaTags()) writeMetaDataCheckBox
->click();
214 generatePlaylistCheckBox
->setChecked(m_settings
->createPlaylist());
215 connect(buttonEditMeta
, SIGNAL(clicked()), this, SLOT(editMetaButtonClicked()));
216 connect(buttonClearMeta
, SIGNAL(clicked()), this, SLOT(clearMetaButtonClicked()));
217 connect(writeMetaDataCheckBox
, SIGNAL(clicked()), this, SLOT(metaTagsEnabledChanged()));
218 connect(generatePlaylistCheckBox
, SIGNAL(clicked()), this, SLOT(playlistEnabledChanged()));
220 //Setup "Compression" tab
221 m_encoderButtonGroup
= new QButtonGroup(this);
222 m_encoderButtonGroup
->addButton(radioButtonEncoderMP3
, SettingsModel::MP3Encoder
);
223 m_encoderButtonGroup
->addButton(radioButtonEncoderVorbis
, SettingsModel::VorbisEncoder
);
224 m_encoderButtonGroup
->addButton(radioButtonEncoderAAC
, SettingsModel::AACEncoder
);
225 m_encoderButtonGroup
->addButton(radioButtonEncoderAC3
, SettingsModel::AC3Encoder
);
226 m_encoderButtonGroup
->addButton(radioButtonEncoderFLAC
, SettingsModel::FLACEncoder
);
227 m_encoderButtonGroup
->addButton(radioButtonEncoderDCA
, SettingsModel::DCAEncoder
);
228 m_encoderButtonGroup
->addButton(radioButtonEncoderPCM
, SettingsModel::PCMEncoder
);
229 m_modeButtonGroup
= new QButtonGroup(this);
230 m_modeButtonGroup
->addButton(radioButtonModeQuality
, SettingsModel::VBRMode
);
231 m_modeButtonGroup
->addButton(radioButtonModeAverageBitrate
, SettingsModel::ABRMode
);
232 m_modeButtonGroup
->addButton(radioButtonConstBitrate
, SettingsModel::CBRMode
);
233 radioButtonEncoderAAC
->setEnabled(m_neroEncoderAvailable
|| m_fhgEncoderAvailable
|| m_qaacEncoderAvailable
);
234 radioButtonEncoderMP3
->setChecked(m_settings
->compressionEncoder() == SettingsModel::MP3Encoder
);
235 radioButtonEncoderVorbis
->setChecked(m_settings
->compressionEncoder() == SettingsModel::VorbisEncoder
);
236 radioButtonEncoderAAC
->setChecked((m_settings
->compressionEncoder() == SettingsModel::AACEncoder
) && (m_neroEncoderAvailable
|| m_fhgEncoderAvailable
|| m_qaacEncoderAvailable
));
237 radioButtonEncoderAC3
->setChecked(m_settings
->compressionEncoder() == SettingsModel::AC3Encoder
);
238 radioButtonEncoderFLAC
->setChecked(m_settings
->compressionEncoder() == SettingsModel::FLACEncoder
);
239 radioButtonEncoderDCA
->setChecked(m_settings
->compressionEncoder() == SettingsModel::DCAEncoder
);
240 radioButtonEncoderPCM
->setChecked(m_settings
->compressionEncoder() == SettingsModel::PCMEncoder
);
241 radioButtonModeQuality
->setChecked(m_settings
->compressionRCMode() == SettingsModel::VBRMode
);
242 radioButtonModeAverageBitrate
->setChecked(m_settings
->compressionRCMode() == SettingsModel::ABRMode
);
243 radioButtonConstBitrate
->setChecked(m_settings
->compressionRCMode() == SettingsModel::CBRMode
);
244 sliderBitrate
->setValue(m_settings
->compressionBitrate());
245 connect(m_encoderButtonGroup
, SIGNAL(buttonClicked(int)), this, SLOT(updateEncoder(int)));
246 connect(m_modeButtonGroup
, SIGNAL(buttonClicked(int)), this, SLOT(updateRCMode(int)));
247 connect(sliderBitrate
, SIGNAL(valueChanged(int)), this, SLOT(updateBitrate(int)));
248 updateEncoder(m_encoderButtonGroup
->checkedId());
250 //Setup "Advanced Options" tab
251 sliderLameAlgoQuality
->setValue(m_settings
->lameAlgoQuality());
252 if(m_settings
->maximumInstances() > 0) sliderMaxInstances
->setValue(m_settings
->maximumInstances());
253 spinBoxBitrateManagementMin
->setValue(m_settings
->bitrateManagementMinRate());
254 spinBoxBitrateManagementMax
->setValue(m_settings
->bitrateManagementMaxRate());
255 spinBoxNormalizationFilter
->setValue(static_cast<double>(m_settings
->normalizationFilterMaxVolume()) / 100.0);
256 spinBoxToneAdjustBass
->setValue(static_cast<double>(m_settings
->toneAdjustBass()) / 100.0);
257 spinBoxToneAdjustTreble
->setValue(static_cast<double>(m_settings
->toneAdjustTreble()) / 100.0);
258 spinBoxAftenSearchSize
->setValue(m_settings
->aftenExponentSearchSize());
259 comboBoxMP3ChannelMode
->setCurrentIndex(m_settings
->lameChannelMode());
260 comboBoxSamplingRate
->setCurrentIndex(m_settings
->samplingRate());
261 comboBoxAACProfile
->setCurrentIndex(m_settings
->aacEncProfile());
262 comboBoxAftenCodingMode
->setCurrentIndex(m_settings
->aftenAudioCodingMode());
263 comboBoxAftenDRCMode
->setCurrentIndex(m_settings
->aftenDynamicRangeCompression());
264 comboBoxNormalizationMode
->setCurrentIndex(m_settings
->normalizationFilterEqualizationMode());
265 while(checkBoxBitrateManagement
->isChecked() != m_settings
->bitrateManagementEnabled()) checkBoxBitrateManagement
->click();
266 while(checkBoxNeroAAC2PassMode
->isChecked() != m_settings
->neroAACEnable2Pass()) checkBoxNeroAAC2PassMode
->click();
267 while(checkBoxAftenFastAllocation
->isChecked() != m_settings
->aftenFastBitAllocation()) checkBoxAftenFastAllocation
->click();
268 while(checkBoxNormalizationFilter
->isChecked() != m_settings
->normalizationFilterEnabled()) checkBoxNormalizationFilter
->click();
269 while(checkBoxAutoDetectInstances
->isChecked() != (m_settings
->maximumInstances() < 1)) checkBoxAutoDetectInstances
->click();
270 while(checkBoxUseSystemTempFolder
->isChecked() == m_settings
->customTempPathEnabled()) checkBoxUseSystemTempFolder
->click();
271 while(checkBoxRenameOutput
->isChecked() != m_settings
->renameOutputFilesEnabled()) checkBoxRenameOutput
->click();
272 while(checkBoxForceStereoDownmix
->isChecked() != m_settings
->forceStereoDownmix()) checkBoxForceStereoDownmix
->click();
273 checkBoxNeroAAC2PassMode
->setEnabled(!(m_fhgEncoderAvailable
|| m_qaacEncoderAvailable
));
274 lineEditCustomParamLAME
->setText(m_settings
->customParametersLAME());
275 lineEditCustomParamOggEnc
->setText(m_settings
->customParametersOggEnc());
276 lineEditCustomParamNeroAAC
->setText(m_settings
->customParametersAacEnc());
277 lineEditCustomParamFLAC
->setText(m_settings
->customParametersFLAC());
278 lineEditCustomParamAften
->setText(m_settings
->customParametersAften());
279 lineEditCustomTempFolder
->setText(QDir::toNativeSeparators(m_settings
->customTempPath()));
280 lineEditRenamePattern
->setText(m_settings
->renameOutputFilesPattern());
281 connect(sliderLameAlgoQuality
, SIGNAL(valueChanged(int)), this, SLOT(updateLameAlgoQuality(int)));
282 connect(checkBoxBitrateManagement
, SIGNAL(clicked(bool)), this, SLOT(bitrateManagementEnabledChanged(bool)));
283 connect(spinBoxBitrateManagementMin
, SIGNAL(valueChanged(int)), this, SLOT(bitrateManagementMinChanged(int)));
284 connect(spinBoxBitrateManagementMax
, SIGNAL(valueChanged(int)), this, SLOT(bitrateManagementMaxChanged(int)));
285 connect(comboBoxMP3ChannelMode
, SIGNAL(currentIndexChanged(int)), this, SLOT(channelModeChanged(int)));
286 connect(comboBoxSamplingRate
, SIGNAL(currentIndexChanged(int)), this, SLOT(samplingRateChanged(int)));
287 connect(checkBoxNeroAAC2PassMode
, SIGNAL(clicked(bool)), this, SLOT(neroAAC2PassChanged(bool)));
288 connect(comboBoxAACProfile
, SIGNAL(currentIndexChanged(int)), this, SLOT(neroAACProfileChanged(int)));
289 connect(checkBoxNormalizationFilter
, SIGNAL(clicked(bool)), this, SLOT(normalizationEnabledChanged(bool)));
290 connect(comboBoxAftenCodingMode
, SIGNAL(currentIndexChanged(int)), this, SLOT(aftenCodingModeChanged(int)));
291 connect(comboBoxAftenDRCMode
, SIGNAL(currentIndexChanged(int)), this, SLOT(aftenDRCModeChanged(int)));
292 connect(spinBoxAftenSearchSize
, SIGNAL(valueChanged(int)), this, SLOT(aftenSearchSizeChanged(int)));
293 connect(checkBoxAftenFastAllocation
, SIGNAL(clicked(bool)), this, SLOT(aftenFastAllocationChanged(bool)));
294 connect(spinBoxNormalizationFilter
, SIGNAL(valueChanged(double)), this, SLOT(normalizationMaxVolumeChanged(double)));
295 connect(comboBoxNormalizationMode
, SIGNAL(currentIndexChanged(int)), this, SLOT(normalizationModeChanged(int)));
296 connect(spinBoxToneAdjustBass
, SIGNAL(valueChanged(double)), this, SLOT(toneAdjustBassChanged(double)));
297 connect(spinBoxToneAdjustTreble
, SIGNAL(valueChanged(double)), this, SLOT(toneAdjustTrebleChanged(double)));
298 connect(buttonToneAdjustReset
, SIGNAL(clicked()), this, SLOT(toneAdjustTrebleReset()));
299 connect(lineEditCustomParamLAME
, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
300 connect(lineEditCustomParamOggEnc
, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
301 connect(lineEditCustomParamNeroAAC
, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
302 connect(lineEditCustomParamFLAC
, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
303 connect(lineEditCustomParamAften
, SIGNAL(editingFinished()), this, SLOT(customParamsChanged()));
304 connect(sliderMaxInstances
, SIGNAL(valueChanged(int)), this, SLOT(updateMaximumInstances(int)));
305 connect(checkBoxAutoDetectInstances
, SIGNAL(clicked(bool)), this, SLOT(autoDetectInstancesChanged(bool)));
306 connect(buttonBrowseCustomTempFolder
, SIGNAL(clicked()), this, SLOT(browseCustomTempFolderButtonClicked()));
307 connect(lineEditCustomTempFolder
, SIGNAL(textChanged(QString
)), this, SLOT(customTempFolderChanged(QString
)));
308 connect(checkBoxUseSystemTempFolder
, SIGNAL(clicked(bool)), this, SLOT(useCustomTempFolderChanged(bool)));
309 connect(buttonResetAdvancedOptions
, SIGNAL(clicked()), this, SLOT(resetAdvancedOptionsButtonClicked()));
310 connect(checkBoxRenameOutput
, SIGNAL(clicked(bool)), this, SLOT(renameOutputEnabledChanged(bool)));
311 connect(lineEditRenamePattern
, SIGNAL(editingFinished()), this, SLOT(renameOutputPatternChanged()));
312 connect(lineEditRenamePattern
, SIGNAL(textChanged(QString
)), this, SLOT(renameOutputPatternChanged(QString
)));
313 connect(labelShowRenameMacros
, SIGNAL(linkActivated(QString
)), this, SLOT(showRenameMacros(QString
)));
314 connect(checkBoxForceStereoDownmix
, SIGNAL(clicked(bool)), this, SLOT(forceStereoDownmixEnabledChanged(bool)));
315 updateLameAlgoQuality(sliderLameAlgoQuality
->value());
316 updateMaximumInstances(sliderMaxInstances
->value());
317 toneAdjustTrebleChanged(spinBoxToneAdjustTreble
->value());
318 toneAdjustBassChanged(spinBoxToneAdjustBass
->value());
319 customParamsChanged();
321 //Activate file menu actions
322 actionOpenFolder
->setData(QVariant::fromValue
<bool>(false));
323 actionOpenFolderRecursively
->setData(QVariant::fromValue
<bool>(true));
324 connect(actionOpenFolder
, SIGNAL(triggered()), this, SLOT(openFolderActionActivated()));
325 connect(actionOpenFolderRecursively
, SIGNAL(triggered()), this, SLOT(openFolderActionActivated()));
327 //Activate view menu actions
328 m_tabActionGroup
= new QActionGroup(this);
329 m_tabActionGroup
->addAction(actionSourceFiles
);
330 m_tabActionGroup
->addAction(actionOutputDirectory
);
331 m_tabActionGroup
->addAction(actionCompression
);
332 m_tabActionGroup
->addAction(actionMetaData
);
333 m_tabActionGroup
->addAction(actionAdvancedOptions
);
334 actionSourceFiles
->setData(0);
335 actionOutputDirectory
->setData(1);
336 actionMetaData
->setData(2);
337 actionCompression
->setData(3);
338 actionAdvancedOptions
->setData(4);
339 actionSourceFiles
->setChecked(true);
340 connect(m_tabActionGroup
, SIGNAL(triggered(QAction
*)), this, SLOT(tabActionActivated(QAction
*)));
342 //Activate style menu actions
343 m_styleActionGroup
= new QActionGroup(this);
344 m_styleActionGroup
->addAction(actionStylePlastique
);
345 m_styleActionGroup
->addAction(actionStyleCleanlooks
);
346 m_styleActionGroup
->addAction(actionStyleWindowsVista
);
347 m_styleActionGroup
->addAction(actionStyleWindowsXP
);
348 m_styleActionGroup
->addAction(actionStyleWindowsClassic
);
349 actionStylePlastique
->setData(0);
350 actionStyleCleanlooks
->setData(1);
351 actionStyleWindowsVista
->setData(2);
352 actionStyleWindowsXP
->setData(3);
353 actionStyleWindowsClassic
->setData(4);
354 actionStylePlastique
->setChecked(true);
355 actionStyleWindowsXP
->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based
) >= QSysInfo::WV_XP
&& lamexp_themes_enabled());
356 actionStyleWindowsVista
->setEnabled((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based
) >= QSysInfo::WV_VISTA
&& lamexp_themes_enabled());
357 connect(m_styleActionGroup
, SIGNAL(triggered(QAction
*)), this, SLOT(styleActionActivated(QAction
*)));
358 styleActionActivated(NULL
);
360 //Populate the language menu
361 m_languageActionGroup
= new QActionGroup(this);
362 QStringList translations
= lamexp_query_translations();
363 while(!translations
.isEmpty())
365 QString langId
= translations
.takeFirst();
366 QAction
*currentLanguage
= new QAction(this);
367 currentLanguage
->setData(langId
);
368 currentLanguage
->setText(lamexp_translation_name(langId
));
369 currentLanguage
->setIcon(QIcon(QString(":/flags/%1.png").arg(langId
)));
370 currentLanguage
->setCheckable(true);
371 m_languageActionGroup
->addAction(currentLanguage
);
372 menuLanguage
->insertAction(actionLoadTranslationFromFile
, currentLanguage
);
374 menuLanguage
->insertSeparator(actionLoadTranslationFromFile
);
375 connect(actionLoadTranslationFromFile
, SIGNAL(triggered(bool)), this, SLOT(languageFromFileActionActivated(bool)));
376 connect(m_languageActionGroup
, SIGNAL(triggered(QAction
*)), this, SLOT(languageActionActivated(QAction
*)));
378 //Activate tools menu actions
379 actionDisableUpdateReminder
->setChecked(!m_settings
->autoUpdateEnabled());
380 actionDisableSounds
->setChecked(!m_settings
->soundsEnabled());
381 actionDisableNeroAacNotifications
->setChecked(!m_settings
->neroAacNotificationsEnabled());
382 actionDisableSlowStartupNotifications
->setChecked(!m_settings
->antivirNotificationsEnabled());
383 actionDisableShellIntegration
->setChecked(!m_settings
->shellIntegrationEnabled());
384 actionDisableShellIntegration
->setDisabled(lamexp_portable_mode() && actionDisableShellIntegration
->isChecked());
385 actionCheckForBetaUpdates
->setChecked(m_settings
->autoUpdateCheckBeta() || lamexp_version_demo());
386 actionCheckForBetaUpdates
->setEnabled(!lamexp_version_demo());
387 actionHibernateComputer
->setChecked(m_settings
->hibernateComputer());
388 actionHibernateComputer
->setEnabled(lamexp_is_hibernation_supported());
389 connect(actionDisableUpdateReminder
, SIGNAL(triggered(bool)), this, SLOT(disableUpdateReminderActionTriggered(bool)));
390 connect(actionDisableSounds
, SIGNAL(triggered(bool)), this, SLOT(disableSoundsActionTriggered(bool)));
391 connect(actionDisableNeroAacNotifications
, SIGNAL(triggered(bool)), this, SLOT(disableNeroAacNotificationsActionTriggered(bool)));
392 connect(actionDisableSlowStartupNotifications
, SIGNAL(triggered(bool)), this, SLOT(disableSlowStartupNotificationsActionTriggered(bool)));
393 connect(actionDisableShellIntegration
, SIGNAL(triggered(bool)), this, SLOT(disableShellIntegrationActionTriggered(bool)));
394 connect(actionShowDropBoxWidget
, SIGNAL(triggered(bool)), this, SLOT(showDropBoxWidgetActionTriggered(bool)));
395 connect(actionHibernateComputer
, SIGNAL(triggered(bool)), this, SLOT(hibernateComputerActionTriggered(bool)));
396 connect(actionCheckForBetaUpdates
, SIGNAL(triggered(bool)), this, SLOT(checkForBetaUpdatesActionTriggered(bool)));
397 connect(actionImportCueSheet
, SIGNAL(triggered(bool)), this, SLOT(importCueSheetActionTriggered(bool)));
399 //Activate help menu actions
400 actionVisitHomepage
->setData(QString::fromLatin1(lamexp_website_url()));
401 actionVisitSupport
->setData(QString::fromLatin1(lamexp_support_url()));
402 actionDocumentFAQ
->setData(QString("%1/FAQ.html").arg(QApplication::applicationDirPath()));
403 actionDocumentChangelog
->setData(QString("%1/Changelog.html").arg(QApplication::applicationDirPath()));
404 actionDocumentTranslate
->setData(QString("%1/Translate.html").arg(QApplication::applicationDirPath()));
405 connect(actionCheckUpdates
, SIGNAL(triggered()), this, SLOT(checkUpdatesActionActivated()));
406 connect(actionVisitHomepage
, SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
407 connect(actionVisitSupport
, SIGNAL(triggered()), this, SLOT(visitHomepageActionActivated()));
408 connect(actionDocumentFAQ
, SIGNAL(triggered()), this, SLOT(documentActionActivated()));
409 connect(actionDocumentChangelog
, SIGNAL(triggered()), this, SLOT(documentActionActivated()));
410 connect(actionDocumentTranslate
, SIGNAL(triggered()), this, SLOT(documentActionActivated()));
412 //Center window in screen
413 QRect desktopRect
= QApplication::desktop()->screenGeometry();
414 QRect thisRect
= this->geometry();
415 move((desktopRect
.width() - thisRect
.width()) / 2, (desktopRect
.height() - thisRect
.height()) / 2);
416 setMinimumSize(thisRect
.width(), thisRect
.height());
419 m_banner
= new WorkingBanner(this);
421 //Create DropBox widget
422 m_dropBox
= new DropBox(this, m_fileListModel
, m_settings
);
423 connect(m_fileListModel
, SIGNAL(modelReset()), m_dropBox
, SLOT(modelChanged()));
424 connect(m_fileListModel
, SIGNAL(rowsInserted(QModelIndex
,int,int)), m_dropBox
, SLOT(modelChanged()));
425 connect(m_fileListModel
, SIGNAL(rowsRemoved(QModelIndex
,int,int)), m_dropBox
, SLOT(modelChanged()));
427 //Create message handler thread
428 m_messageHandler
= new MessageHandlerThread();
429 m_delayedFileList
= new QStringList();
430 m_delayedFileTimer
= new QTimer();
431 m_delayedFileTimer
->setSingleShot(true);
432 m_delayedFileTimer
->setInterval(5000);
433 connect(m_messageHandler
, SIGNAL(otherInstanceDetected()), this, SLOT(notifyOtherInstance()), Qt::QueuedConnection
);
434 connect(m_messageHandler
, SIGNAL(fileReceived(QString
)), this, SLOT(addFileDelayed(QString
)), Qt::QueuedConnection
);
435 connect(m_messageHandler
, SIGNAL(folderReceived(QString
, bool)), this, SLOT(addFolderDelayed(QString
, bool)), Qt::QueuedConnection
);
436 connect(m_messageHandler
, SIGNAL(killSignalReceived()), this, SLOT(close()), Qt::QueuedConnection
);
437 connect(m_delayedFileTimer
, SIGNAL(timeout()), this, SLOT(handleDelayedFiles()));
438 m_messageHandler
->start();
440 //Load translation file
441 QList
<QAction
*> languageActions
= m_languageActionGroup
->actions();
442 while(!languageActions
.isEmpty())
444 QAction
*currentLanguage
= languageActions
.takeFirst();
445 if(currentLanguage
->data().toString().compare(m_settings
->currentLanguage(), Qt::CaseInsensitive
) == 0)
447 currentLanguage
->setChecked(true);
448 languageActionActivated(currentLanguage
);
452 //Re-translate (make sure we translate once)
453 QEvent
languageChangeEvent(QEvent::LanguageChange
);
454 changeEvent(&languageChangeEvent
);
457 this->setAcceptDrops(true);
460 ////////////////////////////////////////////////////////////
462 ////////////////////////////////////////////////////////////
464 MainWindow::~MainWindow(void)
466 //Stop message handler thread
467 if(m_messageHandler
&& m_messageHandler
->isRunning())
469 m_messageHandler
->stop();
470 if(!m_messageHandler
->wait(2500))
472 m_messageHandler
->terminate();
473 m_messageHandler
->wait();
478 sourceFileView
->setModel(NULL
);
479 metaDataView
->setModel(NULL
);
482 LAMEXP_DELETE(m_tabActionGroup
);
483 LAMEXP_DELETE(m_styleActionGroup
);
484 LAMEXP_DELETE(m_languageActionGroup
);
485 LAMEXP_DELETE(m_banner
);
486 LAMEXP_DELETE(m_fileSystemModel
);
487 LAMEXP_DELETE(m_messageHandler
);
488 LAMEXP_DELETE(m_delayedFileList
);
489 LAMEXP_DELETE(m_delayedFileTimer
);
490 LAMEXP_DELETE(m_metaInfoModel
);
491 LAMEXP_DELETE(m_encoderButtonGroup
);
492 LAMEXP_DELETE(m_encoderButtonGroup
);
493 LAMEXP_DELETE(m_sourceFilesContextMenu
);
494 LAMEXP_DELETE(m_outputFolderFavoritesMenu
);
495 LAMEXP_DELETE(m_dropBox
);
498 ////////////////////////////////////////////////////////////
500 ////////////////////////////////////////////////////////////
503 * Add file to source list
505 void MainWindow::addFiles(const QStringList
&files
)
512 tabWidget
->setCurrentIndex(0);
514 FileAnalyzer
*analyzer
= new FileAnalyzer(files
);
515 connect(analyzer
, SIGNAL(fileSelected(QString
)), m_banner
, SLOT(setText(QString
)), Qt::QueuedConnection
);
516 connect(analyzer
, SIGNAL(fileAnalyzed(AudioFileModel
)), m_fileListModel
, SLOT(addFile(AudioFileModel
)), Qt::QueuedConnection
);
517 connect(m_banner
, SIGNAL(userAbort()), analyzer
, SLOT(abortProcess()), Qt::DirectConnection
);
519 m_banner
->show(tr("Adding file(s), please wait..."), analyzer
);
521 if(analyzer
->filesDenied())
523 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."))));
525 if(analyzer
->filesDummyCDDA())
527 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>"))));
529 if(analyzer
->filesCueSheet())
531 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."))));
533 if(analyzer
->filesRejected())
535 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."))));
538 LAMEXP_DELETE(analyzer
);
539 sourceFileView
->scrollToBottom();
544 * Add folder to source list
546 void MainWindow::addFolder(const QString
&path
, bool recursive
, bool delayed
)
548 QFileInfoList folderInfoList
;
549 folderInfoList
<< QFileInfo(path
);
550 QStringList fileList
;
552 m_banner
->show(tr("Scanning folder(s) for files, please wait..."));
554 QApplication::processEvents();
555 GetAsyncKeyState(VK_ESCAPE
);
557 while(!folderInfoList
.isEmpty())
559 if(GetAsyncKeyState(VK_ESCAPE
) & 0x0001)
561 MessageBeep(MB_ICONERROR
);
562 qWarning("Operation cancelled by user!");
567 QDir
currentDir(folderInfoList
.takeFirst().canonicalFilePath());
568 QFileInfoList fileInfoList
= currentDir
.entryInfoList(QDir::Files
| QDir::NoSymLinks
);
570 while(!fileInfoList
.isEmpty())
572 fileList
<< fileInfoList
.takeFirst().canonicalFilePath();
575 QApplication::processEvents();
579 folderInfoList
.append(currentDir
.entryInfoList(QDir::Dirs
| QDir::NoDotAndDotDot
| QDir::NoSymLinks
));
580 QApplication::processEvents();
585 QApplication::processEvents();
587 if(!fileList
.isEmpty())
591 addFilesDelayed(fileList
);
603 bool MainWindow::checkForUpdates(void)
605 bool bReadyToInstall
= false;
607 UpdateDialog
*updateDialog
= new UpdateDialog(m_settings
, this);
608 updateDialog
->exec();
610 if(updateDialog
->getSuccess())
612 m_settings
->autoUpdateLastCheck(QDate::currentDate().toString(Qt::ISODate
));
613 bReadyToInstall
= updateDialog
->updateReadyToInstall();
616 LAMEXP_DELETE(updateDialog
);
617 return bReadyToInstall
;
620 void MainWindow::refreshFavorites(void)
622 QList
<QAction
*> folderList
= m_outputFolderFavoritesMenu
->actions();
623 QStringList favorites
= m_settings
->favoriteOutputFolders().split("|", QString::SkipEmptyParts
);
624 while(favorites
.count() > 6) favorites
.removeFirst();
626 while(!folderList
.isEmpty())
628 QAction
*currentItem
= folderList
.takeFirst();
629 if(currentItem
->isSeparator()) break;
630 m_outputFolderFavoritesMenu
->removeAction(currentItem
);
631 LAMEXP_DELETE(currentItem
);
634 QAction
*lastItem
= m_outputFolderFavoritesMenu
->actions().first();
636 while(!favorites
.isEmpty())
638 QString path
= favorites
.takeLast();
639 if(QDir(path
).exists())
641 QAction
*action
= new QAction(QIcon(":/icons/folder_go.png"), QDir::toNativeSeparators(path
), this);
642 action
->setData(path
);
643 m_outputFolderFavoritesMenu
->insertAction(lastItem
, action
);
644 connect(action
, SIGNAL(triggered(bool)), this, SLOT(gotoFavoriteFolder()));
650 ////////////////////////////////////////////////////////////
652 ////////////////////////////////////////////////////////////
655 * Window is about to be shown
657 void MainWindow::showEvent(QShowEvent
*event
)
660 m_dropNoteLabel
->setGeometry(0, 0, sourceFileView
->width(), sourceFileView
->height());
661 sourceModelChanged();
663 if(!event
->spontaneous())
665 tabWidget
->setCurrentIndex(0);
670 m_firstTimeShown
= false;
671 QTimer::singleShot(0, this, SLOT(windowShown()));
675 if(m_settings
->dropBoxWidgetEnabled())
677 m_dropBox
->setVisible(true);
683 * Re-translate the UI
685 void MainWindow::changeEvent(QEvent
*e
)
687 if(e
->type() == QEvent::LanguageChange
)
689 int comboBoxIndex
[6];
691 //Backup combobox indices, as retranslateUi() resets
692 comboBoxIndex
[0] = comboBoxMP3ChannelMode
->currentIndex();
693 comboBoxIndex
[1] = comboBoxSamplingRate
->currentIndex();
694 comboBoxIndex
[2] = comboBoxAACProfile
->currentIndex();
695 comboBoxIndex
[3] = comboBoxAftenCodingMode
->currentIndex();
696 comboBoxIndex
[4] = comboBoxAftenDRCMode
->currentIndex();
697 comboBoxIndex
[5] = comboBoxNormalizationMode
->currentIndex();
699 //Re-translate from UIC
700 Ui::MainWindow::retranslateUi(this);
702 //Restore combobox indices
703 comboBoxMP3ChannelMode
->setCurrentIndex(comboBoxIndex
[0]);
704 comboBoxSamplingRate
->setCurrentIndex(comboBoxIndex
[1]);
705 comboBoxAACProfile
->setCurrentIndex(comboBoxIndex
[2]);
706 comboBoxAftenCodingMode
->setCurrentIndex(comboBoxIndex
[3]);
707 comboBoxAftenDRCMode
->setCurrentIndex(comboBoxIndex
[4]);
708 comboBoxNormalizationMode
->setCurrentIndex(comboBoxIndex
[5]);
710 //Update the window title
713 setWindowTitle(QString("%1 [!!! DEBUG BUILD !!!]").arg(windowTitle()));
715 else if(lamexp_version_demo())
717 setWindowTitle(QString("%1 [%2]").arg(windowTitle(), tr("DEMO VERSION")));
720 //Manually re-translate widgets that UIC doesn't handle
721 m_dropNoteLabel
->setText(QString("» %1 «").arg(tr("You can drop in audio files here!")));
722 m_outputFolderNoteBox
->setText(tr("Initializing directory outline, please be patient..."));
723 m_showDetailsContextAction
->setText(tr("Show Details"));
724 m_previewContextAction
->setText(tr("Open File in External Application"));
725 m_findFileContextAction
->setText(tr("Browse File Location"));
726 m_showFolderContextAction
->setText(tr("Browse Selected Folder"));
727 m_refreshFolderContextAction
->setText(tr("Refresh Directory Outline"));
728 m_addFavoriteFolderAction
->setText(tr("Bookmark Current Output Folder"));
729 m_exportCsvContextAction
->setText(tr("Export Meta Tags to CSV File"));
730 m_importCsvContextAction
->setText(tr("Import Meta Tags from CSV File"));
733 m_metaInfoModel
->clearData();
734 m_metaInfoModel
->setData(m_metaInfoModel
->index(4, 1), m_settings
->metaInfoPosition());
735 updateEncoder(m_settings
->compressionEncoder());
736 updateLameAlgoQuality(sliderLameAlgoQuality
->value());
737 updateMaximumInstances(sliderMaxInstances
->value());
738 renameOutputPatternChanged(lineEditRenamePattern
->text());
740 //Re-install shell integration
741 if(m_settings
->shellIntegrationEnabled())
743 ShellIntegration::install();
746 //Force resize, if needed
747 tabPageChanged(tabWidget
->currentIndex());
752 * File dragged over window
754 void MainWindow::dragEnterEvent(QDragEnterEvent
*event
)
756 QStringList formats
= event
->mimeData()->formats();
758 if(formats
.contains("application/x-qt-windows-mime;value=\"FileNameW\"", Qt::CaseInsensitive
) && formats
.contains("text/uri-list", Qt::CaseInsensitive
))
760 event
->acceptProposedAction();
765 * File dropped onto window
767 void MainWindow::dropEvent(QDropEvent
*event
)
771 QStringList droppedFiles
;
772 QList
<QUrl
> urls
= event
->mimeData()->urls();
774 while(!urls
.isEmpty())
776 QUrl currentUrl
= urls
.takeFirst();
777 QFileInfo
file(currentUrl
.toLocalFile());
784 qDebug("Dropped File: %s", file
.canonicalFilePath().toUtf8().constData());
785 droppedFiles
<< file
.canonicalFilePath();
790 qDebug("Dropped Folder: %s", file
.canonicalFilePath().toUtf8().constData());
791 QList
<QFileInfo
> list
= QDir(file
.canonicalFilePath()).entryInfoList(QDir::Files
| QDir::NoSymLinks
);
794 for(int j
= 0; j
< list
.count(); j
++)
796 droppedFiles
<< list
.at(j
).canonicalFilePath();
801 list
= QDir(file
.canonicalFilePath()).entryInfoList(QDir::Dirs
| QDir::NoDotAndDotDot
| QDir::NoSymLinks
);
802 for(int j
= 0; j
< list
.count(); j
++)
804 qDebug("Descending to Folder: %s", list
.at(j
).canonicalFilePath().toUtf8().constData());
805 urls
.prepend(QUrl::fromLocalFile(list
.at(j
).canonicalFilePath()));
811 if(!droppedFiles
.isEmpty())
813 addFilesDelayed(droppedFiles
, true);
818 * Window tries to close
820 void MainWindow::closeEvent(QCloseEvent
*event
)
822 if(m_banner
->isVisible() || m_delayedFileTimer
->isActive())
824 MessageBeep(MB_ICONEXCLAMATION
);
837 void MainWindow::resizeEvent(QResizeEvent
*event
)
839 if(event
) QMainWindow::resizeEvent(event
);
840 m_dropNoteLabel
->setGeometry(0, 0, sourceFileView
->width(), sourceFileView
->height());
842 if(QWidget
*port
= outputFolderView
->viewport())
844 m_outputFolderNoteBox
->setGeometry(16, (port
->height() - 64) / 2, port
->width() - 32, 64);
849 * Key press event filter
851 void MainWindow::keyPressEvent(QKeyEvent
*e
)
853 if(e
->key() == Qt::Key_F5
)
855 if(outputFolderView
->isVisible())
857 QTimer::singleShot(0, this, SLOT(refreshFolderContextActionTriggered()));
862 QMainWindow::keyPressEvent(e
);
868 bool MainWindow::eventFilter(QObject
*obj
, QEvent
*event
)
870 if(obj
== m_fileSystemModel
)
872 if(QApplication::overrideCursor() == NULL
)
874 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor
));
875 QTimer::singleShot(250, this, SLOT(restoreCursor()));
878 else if(obj
== outputFolderView
)
880 switch(event
->type())
884 case QEvent::KeyPress
:
885 case QEvent::KeyRelease
:
886 case QEvent::FocusIn
:
887 case QEvent::FocusOut
:
888 case QEvent::TouchEnd
:
889 outputFolderViewClicked(outputFolderView
->currentIndex());
893 else if(obj
== outputFolderLabel
)
895 switch(event
->type())
897 case QEvent::MouseButtonPress
:
898 if(dynamic_cast<QMouseEvent
*>(event
)->button() == Qt::LeftButton
)
900 QString path
= outputFolderLabel
->text();
901 if(!path
.endsWith(QDir::separator())) path
.append(QDir::separator());
902 ShellExecuteW(this->winId(), L
"explore", QWCHAR(path
), NULL
, NULL
, SW_SHOW
);
906 outputFolderLabel
->setForegroundRole(QPalette::Link
);
909 outputFolderLabel
->setForegroundRole(QPalette::WindowText
);
913 else if(obj
== outputFoldersFovoritesLabel
)
915 QMouseEvent
*mouseEvent
= dynamic_cast<QMouseEvent
*>(event
);
916 QPoint pos
= (mouseEvent
!= NULL
) ? mouseEvent
->pos() : QPoint();
917 QWidget
*sender
= dynamic_cast<QLabel
*>(obj
);
919 switch(event
->type())
922 outputFoldersFovoritesLabel
->setFrameShadow(QFrame::Raised
);
924 case QEvent::MouseButtonPress
:
925 outputFoldersFovoritesLabel
->setFrameShadow(QFrame::Sunken
);
927 case QEvent::MouseButtonRelease
:
928 outputFoldersFovoritesLabel
->setFrameShadow(QFrame::Raised
);
929 if(sender
&& mouseEvent
)
931 if(pos
.x() <= sender
->width() && pos
.y() <= sender
->height() && pos
.x() >= 0 && pos
.y() >= 0 && mouseEvent
->button() != Qt::MidButton
)
933 if(outputFolderView
->isEnabled())
935 m_outputFolderFavoritesMenu
->popup(sender
->mapToGlobal(pos
));
941 outputFoldersFovoritesLabel
->setFrameShadow(QFrame::Plain
);
945 else if(obj
== outputFoldersEditorLabel
)
947 QMouseEvent
*mouseEvent
= dynamic_cast<QMouseEvent
*>(event
);
948 QPoint pos
= (mouseEvent
!= NULL
) ? mouseEvent
->pos() : QPoint();
949 QWidget
*sender
= dynamic_cast<QLabel
*>(obj
);
951 switch(event
->type())
954 outputFoldersEditorLabel
->setFrameShadow(QFrame::Raised
);
956 case QEvent::MouseButtonPress
:
957 outputFoldersEditorLabel
->setFrameShadow(QFrame::Sunken
);
959 case QEvent::MouseButtonRelease
:
960 outputFoldersEditorLabel
->setFrameShadow(QFrame::Raised
);
961 if(sender
&& mouseEvent
)
963 if(pos
.x() <= sender
->width() && pos
.y() <= sender
->height() && pos
.x() >= 0 && pos
.y() >= 0 && mouseEvent
->button() != Qt::MidButton
)
965 if(outputFolderView
->isEnabled())
967 outputFolderView
->setEnabled(false);
968 outputFolderLabel
->setVisible(false);
969 outputFolderEdit
->setVisible(true);
970 outputFolderEdit
->setText(outputFolderLabel
->text());
971 outputFolderEdit
->selectAll();
972 outputFolderEdit
->setFocus();
978 outputFoldersEditorLabel
->setFrameShadow(QFrame::Plain
);
983 return QMainWindow::eventFilter(obj
, event
);
986 bool MainWindow::event(QEvent
*e
)
990 case lamexp_event_queryendsession
:
991 qWarning("System is shutting down, main window prepares to close...");
992 if(m_banner
->isVisible()) m_banner
->close();
993 if(m_delayedFileTimer
->isActive()) m_delayedFileTimer
->stop();
995 case lamexp_event_endsession
:
996 qWarning("System is shutting down, main window will close now...");
1001 QApplication::processEvents(QEventLoop::WaitForMoreEvents
& QEventLoop::ExcludeUserInputEvents
);
1004 m_fileListModel
->clearFiles();
1006 case QEvent::MouseButtonPress
:
1007 if(outputFolderEdit
->isVisible())
1009 QTimer::singleShot(0, this, SLOT(outputFolderEditFinished()));
1012 return QMainWindow::event(e
);
1016 bool MainWindow::winEvent(MSG
*message
, long *result
)
1018 return WinSevenTaskbar::handleWinEvent(message
, result
);
1021 ////////////////////////////////////////////////////////////
1023 ////////////////////////////////////////////////////////////
1025 // =========================================================
1026 // Show window slots
1027 // =========================================================
1032 void MainWindow::windowShown(void)
1034 QStringList arguments
= QApplication::arguments();
1037 bool firstRun
= false;
1038 for(int i
= 0; i
< arguments
.count(); i
++)
1040 if(!arguments
[i
].compare("--first-run", Qt::CaseInsensitive
)) firstRun
= true;
1044 if((m_settings
->licenseAccepted() <= 0) || firstRun
)
1048 if((m_settings
->licenseAccepted() == 0) || firstRun
)
1050 AboutDialog
*about
= new AboutDialog(m_settings
, this, true);
1051 iAccepted
= about
->exec();
1052 LAMEXP_DELETE(about
);
1057 m_settings
->licenseAccepted(-1);
1058 QApplication::processEvents();
1059 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY
), GetModuleHandle(NULL
), SND_RESOURCE
| SND_SYNC
);
1060 QMessageBox::critical(this, tr("License Declined"), tr("You have declined the license. Consequently the application will exit now!"), tr("Goodbye!"));
1061 QFileInfo uninstallerInfo
= QFileInfo(QString("%1/Uninstall.exe").arg(QApplication::applicationDirPath()));
1062 if(uninstallerInfo
.exists())
1064 QString uninstallerDir
= uninstallerInfo
.canonicalPath();
1065 QString uninstallerPath
= uninstallerInfo
.canonicalFilePath();
1066 for(int i
= 0; i
< 3; i
++)
1068 HINSTANCE res
= ShellExecuteW(this->winId(), L
"open", QWCHAR(QDir::toNativeSeparators(uninstallerPath
)), L
"/Force", QWCHAR(QDir::toNativeSeparators(uninstallerDir
)), SW_SHOWNORMAL
);
1069 if(reinterpret_cast<int>(res
) > 32) break;
1074 MoveFileEx(QWCHAR(QDir::toNativeSeparators(QFileInfo(QApplication::applicationFilePath()).canonicalFilePath())), NULL
, MOVEFILE_DELAY_UNTIL_REBOOT
| MOVEFILE_REPLACE_EXISTING
);
1076 QApplication::quit();
1080 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WOOHOO
), GetModuleHandle(NULL
), SND_RESOURCE
| SND_SYNC
);
1081 m_settings
->licenseAccepted(1);
1082 if(lamexp_version_demo()) showAnnounceBox();
1085 //Check for expiration
1086 if(lamexp_version_demo())
1088 if(QDate::currentDate() >= lamexp_version_expires())
1090 qWarning("Binary has expired !!!");
1091 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY
), GetModuleHandle(NULL
), SND_RESOURCE
| SND_SYNC
);
1092 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)
1096 QApplication::quit();
1101 //Slow startup indicator
1102 if(m_settings
->slowStartup() && m_settings
->antivirNotificationsEnabled())
1105 message
+= NOBR(tr("It seems that a bogus anti-virus software is slowing down the startup of LameXP.")).append("<br>");
1106 message
+= NOBR(tr("Please refer to the %1 document for details and solutions!")).arg("<a href=\"http://lamexp.git.sourceforge.net/git/gitweb.cgi?p=lamexp/lamexp;a=blob_plain;f=doc/FAQ.html;hb=HEAD#df406578\">F.A.Q.</a>").append("<br>");
1107 if(QMessageBox::warning(this, tr("Slow Startup"), message
, tr("Discard"), tr("Don't Show Again")) == 1)
1109 m_settings
->antivirNotificationsEnabled(false);
1110 actionDisableSlowStartupNotifications
->setChecked(!m_settings
->antivirNotificationsEnabled());
1115 if(QDate::currentDate() >= lamexp_version_date().addYears(1))
1117 qWarning("Binary is more than a year old, time to update!");
1118 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"));
1122 if(checkForUpdates())
1124 QApplication::quit();
1129 QApplication::quit();
1132 QEventLoop loop
; QTimer::singleShot(7000, &loop
, SLOT(quit()));
1133 PlaySound(MAKEINTRESOURCE(IDR_WAVE_WAITING
), GetModuleHandle(NULL
), SND_RESOURCE
| SND_ASYNC
);
1134 m_banner
->show(tr("Skipping update check this time, please be patient..."), &loop
);
1138 else if(m_settings
->autoUpdateEnabled())
1140 QDate lastUpdateCheck
= QDate::fromString(m_settings
->autoUpdateLastCheck(), Qt::ISODate
);
1141 if(!firstRun
&& (!lastUpdateCheck
.isValid() || QDate::currentDate() >= lastUpdateCheck
.addDays(14)))
1143 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)
1145 if(checkForUpdates())
1147 QApplication::quit();
1154 //Check for AAC support
1155 if(m_neroEncoderAvailable
)
1157 if(m_settings
->neroAacNotificationsEnabled())
1159 if(lamexp_tool_version("neroAacEnc.exe") < lamexp_toolver_neroaac())
1161 QString messageText
;
1162 messageText
+= NOBR(tr("LameXP detected that your version of the Nero AAC encoder is outdated!")).append("<br>");
1163 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>");
1164 messageText
+= NOBR(tr("You can download the latest version of the Nero AAC encoder from the Nero website at:")).append("<br>");
1165 messageText
+= "<nobr><tt>" + LINK(AboutDialog::neroAacUrl
) + "</tt></nobr><br><br>";
1166 messageText
+= NOBR(tr("(Hint: Please ignore the name of the downloaded ZIP file and check the included 'changelog.txt' instead!)")).append("<br>");
1167 QMessageBox::information(this, tr("AAC Encoder Outdated"), messageText
);
1173 if(m_settings
->neroAacNotificationsEnabled() && (!(m_fhgEncoderAvailable
|| m_qaacEncoderAvailable
)))
1175 QString appPath
= QDir(QCoreApplication::applicationDirPath()).canonicalPath();
1176 if(appPath
.isEmpty()) appPath
= QCoreApplication::applicationDirPath();
1177 QString messageText
;
1178 messageText
+= NOBR(tr("The Nero AAC encoder could not be found. AAC encoding support will be disabled.")).append("<br>");
1179 messageText
+= NOBR(tr("Please put 'neroAacEnc.exe', 'neroAacDec.exe' and 'neroAacTag.exe' into the LameXP directory!")).append("<br><br>");
1180 messageText
+= NOBR(tr("Your LameXP directory is located here:")).append("<br>");
1181 messageText
+= QString("<nobr><tt>%1</tt></nobr><br><br>").arg(FSLINK(QDir::toNativeSeparators(appPath
)));
1182 messageText
+= NOBR(tr("You can download the Nero AAC encoder for free from the official Nero website at:")).append("<br>");
1183 messageText
+= "<nobr><tt>" + LINK(AboutDialog::neroAacUrl
) + "</tt></nobr><br>";
1184 if(QMessageBox::information(this, tr("AAC Support Disabled"), messageText
, tr("Discard"), tr("Don't Show Again")) == 1)
1186 m_settings
->neroAacNotificationsEnabled(false);
1187 actionDisableNeroAacNotifications
->setChecked(!m_settings
->neroAacNotificationsEnabled());
1192 //Add files from the command-line
1193 for(int i
= 0; i
< arguments
.count() - 1; i
++)
1195 QStringList addedFiles
;
1196 if(!arguments
[i
].compare("--add", Qt::CaseInsensitive
))
1198 QFileInfo
currentFile(arguments
[++i
].trimmed());
1199 qDebug("Adding file from CLI: %s", currentFile
.absoluteFilePath().toUtf8().constData());
1200 addedFiles
.append(currentFile
.absoluteFilePath());
1202 if(!addedFiles
.isEmpty())
1204 addFilesDelayed(addedFiles
);
1208 //Add folders from the command-line
1209 for(int i
= 0; i
< arguments
.count() - 1; i
++)
1211 if(!arguments
[i
].compare("--add-folder", Qt::CaseInsensitive
))
1213 QFileInfo
currentFile(arguments
[++i
].trimmed());
1214 qDebug("Adding folder from CLI: %s", currentFile
.absoluteFilePath().toUtf8().constData());
1215 addFolder(currentFile
.absoluteFilePath(), false, true);
1217 if(!arguments
[i
].compare("--add-recursive", Qt::CaseInsensitive
))
1219 QFileInfo
currentFile(arguments
[++i
].trimmed());
1220 qDebug("Adding folder recursively from CLI: %s", currentFile
.absoluteFilePath().toUtf8().constData());
1221 addFolder(currentFile
.absoluteFilePath(), true, true);
1225 //Enable shell integration
1226 if(m_settings
->shellIntegrationEnabled())
1228 ShellIntegration::install();
1231 //Make DropBox visible
1232 if(m_settings
->dropBoxWidgetEnabled())
1234 m_dropBox
->setVisible(true);
1241 void MainWindow::showAnnounceBox(void)
1243 const unsigned int timeout
= 8U;
1245 const QString announceText
= QString("%1<br><br>%2<br><nobr><tt>%3</tt></nobr><br>").arg
1247 NOBR("We are still looking for LameXP translators!"),
1248 NOBR("If you are willing to translate LameXP to your language or to complete an existing translation, please refer to:"),
1249 LINK("http://mulder.brhack.net/public/doc/lamexp_translate.html")
1252 QMessageBox
*announceBox
= new QMessageBox(QMessageBox::Warning
, "We want you!", announceText
, QMessageBox::NoButton
, this);
1253 announceBox
->setWindowFlags(Qt::Window
| Qt::WindowTitleHint
| Qt::CustomizeWindowHint
);
1254 announceBox
->setIconPixmap(QIcon(":/images/Announcement.png").pixmap(64,79));
1256 QTimer
*timers
[timeout
+1];
1257 QPushButton
*buttons
[timeout
+1];
1259 for(unsigned int i
= 0; i
<= timeout
; i
++)
1261 QString text
= (i
> 0) ? QString("%1 (%2)").arg(tr("Discard"), QString::number(i
)) : tr("Discard");
1262 buttons
[i
] = announceBox
->addButton(text
, (i
> 0) ? QMessageBox::NoRole
: QMessageBox::AcceptRole
);
1265 for(unsigned int i
= 0; i
<= timeout
; i
++)
1267 buttons
[i
]->setEnabled(i
== 0);
1268 buttons
[i
]->setVisible(i
== timeout
);
1271 for(unsigned int i
= 0; i
< timeout
; i
++)
1273 timers
[i
] = new QTimer(this);
1274 timers
[i
]->setSingleShot(true);
1275 timers
[i
]->setInterval(1000);
1276 connect(timers
[i
], SIGNAL(timeout()), buttons
[i
+1], SLOT(hide()));
1277 connect(timers
[i
], SIGNAL(timeout()), buttons
[i
], SLOT(show()));
1280 connect(timers
[i
], SIGNAL(timeout()), timers
[i
-1], SLOT(start()));
1284 timers
[timeout
-1]->start();
1285 announceBox
->exec();
1287 for(unsigned int i
= 0; i
< timeout
; i
++)
1290 LAMEXP_DELETE(timers
[i
]);
1293 LAMEXP_DELETE(announceBox
);
1296 // =========================================================
1297 // Main button solots
1298 // =========================================================
1303 void MainWindow::encodeButtonClicked(void)
1305 static const unsigned __int64 oneGigabyte
= 1073741824ui
64;
1306 static const unsigned __int64 minimumFreeDiskspaceMultiplier
= 2ui
64;
1307 static const char *writeTestBuffer
= "LAMEXP_WRITE_TEST";
1311 if(m_fileListModel
->rowCount() < 1)
1313 QMessageBox::warning(this, tr("LameXP"), NOBR(tr("You must add at least one file to the list before proceeding!")));
1314 tabWidget
->setCurrentIndex(0);
1318 QString tempFolder
= m_settings
->customTempPathEnabled() ? m_settings
->customTempPath() : lamexp_temp_folder2();
1319 if(!QFileInfo(tempFolder
).exists() || !QFileInfo(tempFolder
).isDir())
1321 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)
1323 while(checkBoxUseSystemTempFolder
->isChecked() == m_settings
->customTempPathEnabledDefault()) checkBoxUseSystemTempFolder
->click();
1329 unsigned __int64 currentFreeDiskspace
= lamexp_free_diskspace(tempFolder
, &ok
);
1331 if(ok
&& (currentFreeDiskspace
< (oneGigabyte
* minimumFreeDiskspaceMultiplier
)))
1333 QStringList tempFolderParts
= tempFolder
.split("/", QString::SkipEmptyParts
, Qt::CaseInsensitive
);
1334 tempFolderParts
.takeLast();
1335 if(m_settings
->soundsEnabled()) PlaySound(MAKEINTRESOURCE(IDR_WAVE_WHAMMY
), GetModuleHandle(NULL
), SND_RESOURCE
| SND_SYNC
);
1336 QString lowDiskspaceMsg
= QString("%1<br>%2<br><br>%3<br>%4<br>").arg
1338 NOBR(tr("There are less than %1 GB of free diskspace available on your system's TEMP folder.").arg(QString::number(minimumFreeDiskspaceMultiplier
))),
1339 NOBR(tr("It is highly recommend to free up more diskspace before proceeding with the encode!")),
1340 NOBR(tr("Your TEMP folder is located at:")),
1341 QString("<nobr><tt>%1</tt></nobr>").arg(FSLINK(tempFolderParts
.join("\\")))
1343 switch(QMessageBox::warning(this, tr("Low Diskspace Warning"), lowDiskspaceMsg
, tr("Abort Encoding Process"), tr("Clean Disk Now"), tr("Ignore")))
1346 QProcess::startDetached(QString("%1/cleanmgr.exe").arg(lamexp_known_folder(lamexp_folder_systemfolder
)), QStringList() << "/D" << tempFolderParts
.first());
1351 QMessageBox::warning(this, tr("Low Diskspace"), tr("You are proceeding with low diskspace. Problems might occur!"));
1356 switch(m_settings
->compressionEncoder())
1358 case SettingsModel::MP3Encoder
:
1359 case SettingsModel::VorbisEncoder
:
1360 case SettingsModel::AACEncoder
:
1361 case SettingsModel::AC3Encoder
:
1362 case SettingsModel::FLACEncoder
:
1363 case SettingsModel::DCAEncoder
:
1364 case SettingsModel::PCMEncoder
:
1367 QMessageBox::warning(this, tr("LameXP"), tr("Sorry, an unsupported encoder has been chosen!"));
1368 tabWidget
->setCurrentIndex(3);
1372 if(!m_settings
->outputToSourceDir())
1374 QFile
writeTest(QString("%1/~%2.txt").arg(m_settings
->outputDir(), lamexp_rand_str()));
1375 if(!(writeTest
.open(QIODevice::ReadWrite
) && (writeTest
.write(writeTestBuffer
) == strlen(writeTestBuffer
))))
1377 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!")));
1378 tabWidget
->setCurrentIndex(1);
1395 void MainWindow::aboutButtonClicked(void)
1401 AboutDialog
*aboutBox
= new AboutDialog(m_settings
, this);
1403 LAMEXP_DELETE(aboutBox
);
1410 void MainWindow::closeButtonClicked(void)
1416 // =========================================================
1418 // =========================================================
1423 void MainWindow::tabPageChanged(int idx
)
1427 QList
<QAction
*> actions
= m_tabActionGroup
->actions();
1428 for(int i
= 0; i
< actions
.count(); i
++)
1431 int actionIndex
= actions
.at(i
)->data().toInt(&ok
);
1432 if(ok
&& actionIndex
== idx
)
1434 actions
.at(i
)->setChecked(true);
1438 int initialWidth
= this->width();
1439 int maximumWidth
= QApplication::desktop()->width();
1441 if(this->isVisible())
1443 while(tabWidget
->width() < tabWidget
->sizeHint().width())
1445 int previousWidth
= this->width();
1446 this->resize(this->width() + 1, this->height());
1447 if(this->frameGeometry().width() >= maximumWidth
) break;
1448 if(this->width() <= previousWidth
) break;
1452 if(idx
== tabWidget
->indexOf(tabOptions
) && scrollArea
->widget() && this->isVisible())
1454 for(int i
= 0; i
< 2; i
++)
1456 QApplication::processEvents();
1457 while(scrollArea
->viewport()->width() < scrollArea
->widget()->width())
1459 int previousWidth
= this->width();
1460 this->resize(this->width() + 1, this->height());
1461 if(this->frameGeometry().width() >= maximumWidth
) break;
1462 if(this->width() <= previousWidth
) break;
1466 else if(idx
== tabWidget
->indexOf(tabSourceFiles
))
1468 m_dropNoteLabel
->setGeometry(0, 0, sourceFileView
->width(), sourceFileView
->height());
1470 else if(idx
== tabWidget
->indexOf(tabOutputDir
))
1472 if(!m_fileSystemModel
)
1474 QTimer::singleShot(125, this, SLOT(initOutputFolderModel()));
1478 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED
;
1482 if(initialWidth
< this->width())
1484 QPoint prevPos
= this->pos();
1485 int delta
= (this->width() - initialWidth
) >> 2;
1486 move(prevPos
.x() - delta
, prevPos
.y());
1491 * Tab action triggered
1493 void MainWindow::tabActionActivated(QAction
*action
)
1495 if(action
&& action
->data().isValid())
1498 int index
= action
->data().toInt(&ok
);
1501 tabWidget
->setCurrentIndex(index
);
1506 // =========================================================
1508 // =========================================================
1511 * Style action triggered
1513 void MainWindow::styleActionActivated(QAction
*action
)
1515 //Change style setting
1516 if(action
&& action
->data().isValid())
1519 int actionIndex
= action
->data().toInt(&ok
);
1522 m_settings
->interfaceStyle(actionIndex
);
1526 //Set up the new style
1527 switch(m_settings
->interfaceStyle())
1530 if(actionStyleCleanlooks
->isEnabled())
1532 actionStyleCleanlooks
->setChecked(true);
1533 QApplication::setStyle(new QCleanlooksStyle());
1537 if(actionStyleWindowsVista
->isEnabled())
1539 actionStyleWindowsVista
->setChecked(true);
1540 QApplication::setStyle(new QWindowsVistaStyle());
1544 if(actionStyleWindowsXP
->isEnabled())
1546 actionStyleWindowsXP
->setChecked(true);
1547 QApplication::setStyle(new QWindowsXPStyle());
1551 if(actionStyleWindowsClassic
->isEnabled())
1553 actionStyleWindowsClassic
->setChecked(true);
1554 QApplication::setStyle(new QWindowsStyle());
1558 actionStylePlastique
->setChecked(true);
1559 QApplication::setStyle(new QPlastiqueStyle());
1563 //Force re-translate after style change
1564 changeEvent(new QEvent(QEvent::LanguageChange
));
1568 * Language action triggered
1570 void MainWindow::languageActionActivated(QAction
*action
)
1572 if(action
->data().type() == QVariant::String
)
1574 QString langId
= action
->data().toString();
1576 if(lamexp_install_translator(langId
))
1578 action
->setChecked(true);
1579 m_settings
->currentLanguage(langId
);
1585 * Load language from file action triggered
1587 void MainWindow::languageFromFileActionActivated(bool checked
)
1589 QFileDialog
dialog(this, tr("Load Translation"));
1590 dialog
.setFileMode(QFileDialog::ExistingFile
);
1591 dialog
.setNameFilter(QString("%1 (*.qm)").arg(tr("Translation Files")));
1595 QStringList selectedFiles
= dialog
.selectedFiles();
1596 if(lamexp_install_translator_from_file(selectedFiles
.first()))
1598 QList
<QAction
*> actions
= m_languageActionGroup
->actions();
1599 while(!actions
.isEmpty())
1601 actions
.takeFirst()->setChecked(false);
1606 languageActionActivated(m_languageActionGroup
->actions().first());
1611 // =========================================================
1613 // =========================================================
1616 * Disable update reminder action
1618 void MainWindow::disableUpdateReminderActionTriggered(bool checked
)
1622 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))
1624 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!"))));
1625 m_settings
->autoUpdateEnabled(false);
1629 m_settings
->autoUpdateEnabled(true);
1634 QMessageBox::information(this, tr("Update Reminder"), NOBR(tr("The update reminder has been re-enabled.")));
1635 m_settings
->autoUpdateEnabled(true);
1638 actionDisableUpdateReminder
->setChecked(!m_settings
->autoUpdateEnabled());
1642 * Disable sound effects action
1644 void MainWindow::disableSoundsActionTriggered(bool checked
)
1648 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))
1650 QMessageBox::information(this, tr("Sound Effects"), NOBR(tr("All sound effects have been disabled.")));
1651 m_settings
->soundsEnabled(false);
1655 m_settings
->soundsEnabled(true);
1660 QMessageBox::information(this, tr("Sound Effects"), NOBR(tr("The sound effects have been re-enabled.")));
1661 m_settings
->soundsEnabled(true);
1664 actionDisableSounds
->setChecked(!m_settings
->soundsEnabled());
1668 * Disable Nero AAC encoder action
1670 void MainWindow::disableNeroAacNotificationsActionTriggered(bool checked
)
1674 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))
1676 QMessageBox::information(this, tr("Nero AAC Notifications"), NOBR(tr("All Nero AAC Encoder notifications have been disabled.")));
1677 m_settings
->neroAacNotificationsEnabled(false);
1681 m_settings
->neroAacNotificationsEnabled(true);
1686 QMessageBox::information(this, tr("Nero AAC Notifications"), NOBR(tr("The Nero AAC Encoder notifications have been re-enabled.")));
1687 m_settings
->neroAacNotificationsEnabled(true);
1690 actionDisableNeroAacNotifications
->setChecked(!m_settings
->neroAacNotificationsEnabled());
1694 * Disable slow startup action
1696 void MainWindow::disableSlowStartupNotificationsActionTriggered(bool checked
)
1700 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))
1702 QMessageBox::information(this, tr("Slow Startup Notifications"), NOBR(tr("The slow startup notifications have been disabled.")));
1703 m_settings
->antivirNotificationsEnabled(false);
1707 m_settings
->antivirNotificationsEnabled(true);
1712 QMessageBox::information(this, tr("Slow Startup Notifications"), NOBR(tr("The slow startup notifications have been re-enabled.")));
1713 m_settings
->antivirNotificationsEnabled(true);
1716 actionDisableSlowStartupNotifications
->setChecked(!m_settings
->antivirNotificationsEnabled());
1720 * Import a Cue Sheet file
1722 void MainWindow::importCueSheetActionTriggered(bool checked
)
1731 QString selectedCueFile
;
1733 if(USE_NATIVE_FILE_DIALOG
)
1735 selectedCueFile
= QFileDialog::getOpenFileName(this, tr("Open Cue Sheet"), m_settings
->mostRecentInputPath(), QString("%1 (*.cue)").arg(tr("Cue Sheet File")));
1739 QFileDialog
dialog(this, tr("Open Cue Sheet"));
1740 dialog
.setFileMode(QFileDialog::ExistingFile
);
1741 dialog
.setNameFilter(QString("%1 (*.cue)").arg(tr("Cue Sheet File")));
1742 dialog
.setDirectory(m_settings
->mostRecentInputPath());
1745 selectedCueFile
= dialog
.selectedFiles().first();
1749 if(!selectedCueFile
.isEmpty())
1751 m_settings
->mostRecentInputPath(QFileInfo(selectedCueFile
).canonicalPath());
1752 CueImportDialog
*cueImporter
= new CueImportDialog(this, m_fileListModel
, selectedCueFile
);
1753 result
= cueImporter
->exec();
1754 LAMEXP_DELETE(cueImporter
);
1757 if(result
!= (-1)) break;
1763 * Show the "drop box" widget
1765 void MainWindow::showDropBoxWidgetActionTriggered(bool checked
)
1767 m_settings
->dropBoxWidgetEnabled(true);
1769 if(!m_dropBox
->isVisible())
1774 lamexp_blink_window(m_dropBox
);
1778 * Check for beta (pre-release) updates
1780 void MainWindow::checkForBetaUpdatesActionTriggered(bool checked
)
1782 bool checkUpdatesNow
= false;
1786 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))
1788 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")))
1790 checkUpdatesNow
= true;
1792 m_settings
->autoUpdateCheckBeta(true);
1796 m_settings
->autoUpdateCheckBeta(false);
1801 QMessageBox::information(this, tr("Beta Updates"), NOBR(tr("LameXP will <i>not</i> check for Beta (pre-release) updates from now on.")));
1802 m_settings
->autoUpdateCheckBeta(false);
1805 actionCheckForBetaUpdates
->setChecked(m_settings
->autoUpdateCheckBeta());
1809 if(checkForUpdates())
1811 QApplication::quit();
1817 * Hibernate computer action
1819 void MainWindow::hibernateComputerActionTriggered(bool checked
)
1823 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))
1825 QMessageBox::information(this, tr("Hibernate Computer"), NOBR(tr("LameXP will hibernate the computer on shutdown from now on.")));
1826 m_settings
->hibernateComputer(true);
1830 m_settings
->hibernateComputer(false);
1835 QMessageBox::information(this, tr("Hibernate Computer"), NOBR(tr("LameXP will <i>not</i> hibernate the computer on shutdown from now on.")));
1836 m_settings
->hibernateComputer(false);
1839 actionHibernateComputer
->setChecked(m_settings
->hibernateComputer());
1843 * Disable shell integration action
1845 void MainWindow::disableShellIntegrationActionTriggered(bool checked
)
1849 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))
1851 ShellIntegration::remove();
1852 QMessageBox::information(this, tr("Shell Integration"), NOBR(tr("The LameXP shell integration has been disabled.")));
1853 m_settings
->shellIntegrationEnabled(false);
1857 m_settings
->shellIntegrationEnabled(true);
1862 ShellIntegration::install();
1863 QMessageBox::information(this, tr("Shell Integration"), NOBR(tr("The LameXP shell integration has been re-enabled.")));
1864 m_settings
->shellIntegrationEnabled(true);
1867 actionDisableShellIntegration
->setChecked(!m_settings
->shellIntegrationEnabled());
1869 if(lamexp_portable_mode() && actionDisableShellIntegration
->isChecked())
1871 actionDisableShellIntegration
->setEnabled(false);
1875 // =========================================================
1877 // =========================================================
1880 * Visit homepage action
1882 void MainWindow::visitHomepageActionActivated(void)
1884 if(QAction
*action
= dynamic_cast<QAction
*>(QObject::sender()))
1886 if(action
->data().isValid() && (action
->data().type() == QVariant::String
))
1888 QDesktopServices::openUrl(QUrl(action
->data().toString()));
1896 void MainWindow::documentActionActivated(void)
1898 if(QAction
*action
= dynamic_cast<QAction
*>(QObject::sender()))
1900 if(action
->data().isValid() && (action
->data().type() == QVariant::String
))
1902 QFileInfo
document(action
->data().toString());
1903 QFileInfo
resource(QString(":/doc/%1.html").arg(document
.baseName()));
1904 if(document
.exists() && document
.isFile() && (document
.size() == resource
.size()))
1906 QDesktopServices::openUrl(QUrl::fromLocalFile(document
.canonicalFilePath()));
1910 QFile
source(resource
.filePath());
1911 QFile
output(QString("%1/%2.%3.html").arg(lamexp_temp_folder2(), document
.baseName(), lamexp_rand_str().left(8)));
1912 if(source
.open(QIODevice::ReadOnly
) && output
.open(QIODevice::ReadWrite
))
1914 output
.write(source
.readAll());
1915 action
->setData(output
.fileName());
1918 QDesktopServices::openUrl(QUrl::fromLocalFile(output
.fileName()));
1926 * Check for updates action
1928 void MainWindow::checkUpdatesActionActivated(void)
1935 bFlag
= checkForUpdates();
1940 QApplication::quit();
1944 // =========================================================
1945 // Source file slots
1946 // =========================================================
1949 * Add file(s) button
1951 void MainWindow::addFilesButtonClicked(void)
1957 if(USE_NATIVE_FILE_DIALOG
)
1959 QStringList fileTypeFilters
= DecoderRegistry::getSupportedTypes();
1960 QStringList selectedFiles
= QFileDialog::getOpenFileNames(this, tr("Add file(s)"), m_settings
->mostRecentInputPath(), fileTypeFilters
.join(";;"));
1961 if(!selectedFiles
.isEmpty())
1963 m_settings
->mostRecentInputPath(QFileInfo(selectedFiles
.first()).canonicalPath());
1964 addFiles(selectedFiles
);
1969 QFileDialog
dialog(this, tr("Add file(s)"));
1970 QStringList fileTypeFilters
= DecoderRegistry::getSupportedTypes();
1971 dialog
.setFileMode(QFileDialog::ExistingFiles
);
1972 dialog
.setNameFilter(fileTypeFilters
.join(";;"));
1973 dialog
.setDirectory(m_settings
->mostRecentInputPath());
1976 QStringList selectedFiles
= dialog
.selectedFiles();
1977 if(!selectedFiles
.isEmpty())
1979 m_settings
->mostRecentInputPath(QFileInfo(selectedFiles
.first()).canonicalPath());
1980 addFiles(selectedFiles
);
1988 * Open folder action
1990 void MainWindow::openFolderActionActivated(void)
1993 QString selectedFolder
;
1995 if(QAction
*action
= dynamic_cast<QAction
*>(QObject::sender()))
1999 if(USE_NATIVE_FILE_DIALOG
)
2001 selectedFolder
= QFileDialog::getExistingDirectory(this, tr("Add Folder"), m_settings
->mostRecentInputPath());
2005 QFileDialog
dialog(this, tr("Add Folder"));
2006 dialog
.setFileMode(QFileDialog::DirectoryOnly
);
2007 dialog
.setDirectory(m_settings
->mostRecentInputPath());
2010 selectedFolder
= dialog
.selectedFiles().first();
2014 if(!selectedFolder
.isEmpty())
2016 m_settings
->mostRecentInputPath(QDir(selectedFolder
).canonicalPath());
2017 addFolder(selectedFolder
, action
->data().toBool());
2024 * Remove file button
2026 void MainWindow::removeFileButtonClicked(void)
2028 if(sourceFileView
->currentIndex().isValid())
2030 int iRow
= sourceFileView
->currentIndex().row();
2031 m_fileListModel
->removeFile(sourceFileView
->currentIndex());
2032 sourceFileView
->selectRow(iRow
< m_fileListModel
->rowCount() ? iRow
: m_fileListModel
->rowCount()-1);
2037 * Clear files button
2039 void MainWindow::clearFilesButtonClicked(void)
2041 m_fileListModel
->clearFiles();
2045 * Move file up button
2047 void MainWindow::fileUpButtonClicked(void)
2049 if(sourceFileView
->currentIndex().isValid())
2051 int iRow
= sourceFileView
->currentIndex().row() - 1;
2052 m_fileListModel
->moveFile(sourceFileView
->currentIndex(), -1);
2053 sourceFileView
->selectRow(iRow
>= 0 ? iRow
: 0);
2058 * Move file down button
2060 void MainWindow::fileDownButtonClicked(void)
2062 if(sourceFileView
->currentIndex().isValid())
2064 int iRow
= sourceFileView
->currentIndex().row() + 1;
2065 m_fileListModel
->moveFile(sourceFileView
->currentIndex(), 1);
2066 sourceFileView
->selectRow(iRow
< m_fileListModel
->rowCount() ? iRow
: m_fileListModel
->rowCount()-1);
2071 * Show details button
2073 void MainWindow::showDetailsButtonClicked(void)
2078 MetaInfoDialog
*metaInfoDialog
= new MetaInfoDialog(this);
2079 QModelIndex index
= sourceFileView
->currentIndex();
2081 while(index
.isValid())
2085 index
= m_fileListModel
->index(index
.row() + 1, index
.column());
2086 sourceFileView
->selectRow(index
.row());
2090 index
= m_fileListModel
->index(index
.row() - 1, index
.column());
2091 sourceFileView
->selectRow(index
.row());
2094 AudioFileModel
&file
= (*m_fileListModel
)[index
];
2097 iResult
= metaInfoDialog
->exec(file
, index
.row() > 0, index
.row() < m_fileListModel
->rowCount() - 1);
2100 if(iResult
== INT_MAX
)
2102 m_metaInfoModel
->assignInfoFrom(file
);
2103 tabWidget
->setCurrentIndex(tabWidget
->indexOf(tabMetaData
));
2110 LAMEXP_DELETE(metaInfoDialog
);
2111 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents
);
2112 sourceFilesScrollbarMoved(0);
2116 * Show context menu for source files
2118 void MainWindow::sourceFilesContextMenu(const QPoint
&pos
)
2120 QAbstractScrollArea
*scrollArea
= dynamic_cast<QAbstractScrollArea
*>(QObject::sender());
2121 QWidget
*sender
= scrollArea
? scrollArea
->viewport() : dynamic_cast<QWidget
*>(QObject::sender());
2125 if(pos
.x() <= sender
->width() && pos
.y() <= sender
->height() && pos
.x() >= 0 && pos
.y() >= 0)
2127 m_sourceFilesContextMenu
->popup(sender
->mapToGlobal(pos
));
2133 * Scrollbar of source files moved
2135 void MainWindow::sourceFilesScrollbarMoved(int)
2137 sourceFileView
->resizeColumnToContents(0);
2141 * Open selected file in external player
2143 void MainWindow::previewContextActionTriggered(void)
2145 const static char *appNames
[3] = {"smplayer_portable.exe", "smplayer.exe", "mplayer.exe"};
2146 const static wchar_t *registryKey
= L
"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}";
2148 QModelIndex index
= sourceFileView
->currentIndex();
2149 if(!index
.isValid())
2154 QString mplayerPath
;
2155 HKEY registryKeyHandle
;
2157 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE
, registryKey
, 0, KEY_READ
, ®istryKeyHandle
) == ERROR_SUCCESS
)
2159 wchar_t Buffer
[4096];
2160 DWORD BuffSize
= sizeof(wchar_t*) * 4096;
2161 if(RegQueryValueExW(registryKeyHandle
, L
"InstallLocation", 0, 0, reinterpret_cast<BYTE
*>(Buffer
), &BuffSize
) == ERROR_SUCCESS
)
2163 mplayerPath
= QString::fromUtf16(reinterpret_cast<const unsigned short*>(Buffer
));
2167 if(!mplayerPath
.isEmpty())
2169 QDir
mplayerDir(mplayerPath
);
2170 if(mplayerDir
.exists())
2172 for(int i
= 0; i
< 3; i
++)
2174 if(mplayerDir
.exists(appNames
[i
]))
2176 QProcess::startDetached(mplayerDir
.absoluteFilePath(appNames
[i
]), QStringList() << QDir::toNativeSeparators(m_fileListModel
->getFile(index
).filePath()));
2183 QDesktopServices::openUrl(QString("file:///").append(m_fileListModel
->getFile(index
).filePath()));
2187 * Find selected file in explorer
2189 void MainWindow::findFileContextActionTriggered(void)
2191 QModelIndex index
= sourceFileView
->currentIndex();
2194 QString systemRootPath
;
2196 QDir
systemRoot(lamexp_known_folder(lamexp_folder_systemfolder
));
2197 if(systemRoot
.exists() && systemRoot
.cdUp())
2199 systemRootPath
= systemRoot
.canonicalPath();
2202 if(!systemRootPath
.isEmpty())
2204 QFileInfo
explorer(QString("%1/explorer.exe").arg(systemRootPath
));
2205 if(explorer
.exists() && explorer
.isFile())
2207 QProcess::execute(explorer
.canonicalFilePath(), QStringList() << "/select," << QDir::toNativeSeparators(m_fileListModel
->getFile(index
).filePath()));
2213 qWarning("SystemRoot directory could not be detected!");
2219 * Add all pending files
2221 void MainWindow::handleDelayedFiles(void)
2223 m_delayedFileTimer
->stop();
2225 if(m_delayedFileList
->isEmpty())
2230 if(m_banner
->isVisible())
2232 m_delayedFileTimer
->start(5000);
2236 QStringList selectedFiles
;
2237 tabWidget
->setCurrentIndex(0);
2239 while(!m_delayedFileList
->isEmpty())
2241 QFileInfo currentFile
= QFileInfo(m_delayedFileList
->takeFirst());
2242 if(!currentFile
.exists() || !currentFile
.isFile())
2246 selectedFiles
<< currentFile
.canonicalFilePath();
2249 addFiles(selectedFiles
);
2253 * Export Meta tags to CSV file
2255 void MainWindow::exportCsvContextActionTriggered(void)
2259 QString selectedCsvFile
;
2261 if(USE_NATIVE_FILE_DIALOG
)
2263 selectedCsvFile
= QFileDialog::getSaveFileName(this, tr("Save CSV file"), m_settings
->mostRecentInputPath(), QString("%1 (*.csv)").arg(tr("CSV File")));
2267 QFileDialog
dialog(this, tr("Save CSV file"));
2268 dialog
.setFileMode(QFileDialog::AnyFile
);
2269 dialog
.setAcceptMode(QFileDialog::AcceptSave
);
2270 dialog
.setNameFilter(QString("%1 (*.csv)").arg(tr("CSV File")));
2271 dialog
.setDirectory(m_settings
->mostRecentInputPath());
2274 selectedCsvFile
= dialog
.selectedFiles().first();
2278 if(!selectedCsvFile
.isEmpty())
2280 m_settings
->mostRecentInputPath(QFileInfo(selectedCsvFile
).canonicalPath());
2281 switch(m_fileListModel
->exportToCsv(selectedCsvFile
))
2283 case FileListModel::CsvError_NoTags
:
2284 QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, there are no meta tags that can be exported!")));
2286 case FileListModel::CsvError_FileOpen
:
2287 QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, failed to open CSV file for writing!")));
2289 case FileListModel::CsvError_FileWrite
:
2290 QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, failed to write to the CSV file!")));
2292 case FileListModel::CsvError_OK
:
2293 QMessageBox::information(this, tr("CSV Export"), NOBR(tr("The CSV files was created successfully!")));
2296 qWarning("exportToCsv: Unknown return code!");
2304 * Import Meta tags from CSV file
2306 void MainWindow::importCsvContextActionTriggered(void)
2310 QString selectedCsvFile
;
2312 if(USE_NATIVE_FILE_DIALOG
)
2314 selectedCsvFile
= QFileDialog::getOpenFileName(this, tr("Open CSV file"), m_settings
->mostRecentInputPath(), QString("%1 (*.csv)").arg(tr("CSV File")));
2318 QFileDialog
dialog(this, tr("Open CSV file"));
2319 dialog
.setFileMode(QFileDialog::ExistingFile
);
2320 dialog
.setNameFilter(QString("%1 (*.csv)").arg(tr("CSV File")));
2321 dialog
.setDirectory(m_settings
->mostRecentInputPath());
2324 selectedCsvFile
= dialog
.selectedFiles().first();
2328 if(!selectedCsvFile
.isEmpty())
2330 m_settings
->mostRecentInputPath(QFileInfo(selectedCsvFile
).canonicalPath());
2331 switch(m_fileListModel
->importFromCsv(this, selectedCsvFile
))
2333 case FileListModel::CsvError_FileOpen
:
2334 QMessageBox::critical(this, tr("CSV Import"), NOBR(tr("Sorry, failed to open CSV file for reading!")));
2336 case FileListModel::CsvError_FileRead
:
2337 QMessageBox::critical(this, tr("CSV Import"), NOBR(tr("Sorry, failed to read from the CSV file!")));
2339 case FileListModel::CsvError_NoTags
:
2340 QMessageBox::critical(this, tr("CSV Import"), NOBR(tr("Sorry, the CSV file does not contain any known fields!")));
2342 case FileListModel::CsvError_Incomplete
:
2343 QMessageBox::warning(this, tr("CSV Import"), NOBR(tr("CSV file is incomplete. Not all files were updated!")));
2345 case FileListModel::CsvError_OK
:
2346 QMessageBox::information(this, tr("CSV Import"), NOBR(tr("The CSV files was imported successfully!")));
2348 case FileListModel::CsvError_Aborted
:
2349 /* User aborted, ignore! */
2352 qWarning("exportToCsv: Unknown return code!");
2359 * Show or hide Drag'n'Drop notice after model reset
2361 void MainWindow::sourceModelChanged(void)
2363 m_dropNoteLabel
->setVisible(m_fileListModel
->rowCount() <= 0);
2366 // =========================================================
2367 // Output folder slots
2368 // =========================================================
2371 * Output folder changed (mouse clicked)
2373 void MainWindow::outputFolderViewClicked(const QModelIndex
&index
)
2375 if(outputFolderView
->currentIndex() != index
)
2377 outputFolderView
->setCurrentIndex(index
);
2380 if(m_fileSystemModel
&& index
.isValid())
2382 QString selectedDir
= m_fileSystemModel
->filePath(index
);
2383 if(selectedDir
.length() < 3) selectedDir
.append(QDir::separator());
2384 outputFolderLabel
->setText(QDir::toNativeSeparators(selectedDir
));
2385 m_settings
->outputDir(selectedDir
);
2389 outputFolderLabel
->setText(QDir::toNativeSeparators(m_settings
->outputDir()));
2394 * Output folder changed (mouse moved)
2396 void MainWindow::outputFolderViewMoved(const QModelIndex
&index
)
2398 if(QApplication::mouseButtons() & Qt::LeftButton
)
2400 outputFolderViewClicked(index
);
2405 * Goto desktop button
2407 void MainWindow::gotoDesktopButtonClicked(void)
2409 if(!m_fileSystemModel
)
2411 qWarning("File system model not initialized yet!");
2415 QString desktopPath
= QDesktopServices::storageLocation(QDesktopServices::DesktopLocation
);
2417 if(!desktopPath
.isEmpty() && QDir(desktopPath
).exists())
2419 outputFolderView
->setCurrentIndex(m_fileSystemModel
->index(desktopPath
));
2420 outputFolderViewClicked(outputFolderView
->currentIndex());
2421 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED
;
2425 buttonGotoDesktop
->setEnabled(false);
2430 * Goto home folder button
2432 void MainWindow::gotoHomeFolderButtonClicked(void)
2434 if(!m_fileSystemModel
)
2436 qWarning("File system model not initialized yet!");
2440 QString homePath
= QDesktopServices::storageLocation(QDesktopServices::HomeLocation
);
2442 if(!homePath
.isEmpty() && QDir(homePath
).exists())
2444 outputFolderView
->setCurrentIndex(m_fileSystemModel
->index(homePath
));
2445 outputFolderViewClicked(outputFolderView
->currentIndex());
2446 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED
;
2450 buttonGotoHome
->setEnabled(false);
2455 * Goto music folder button
2457 void MainWindow::gotoMusicFolderButtonClicked(void)
2459 if(!m_fileSystemModel
)
2461 qWarning("File system model not initialized yet!");
2465 QString musicPath
= QDesktopServices::storageLocation(QDesktopServices::MusicLocation
);
2467 if(!musicPath
.isEmpty() && QDir(musicPath
).exists())
2469 outputFolderView
->setCurrentIndex(m_fileSystemModel
->index(musicPath
));
2470 outputFolderViewClicked(outputFolderView
->currentIndex());
2471 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED
;
2475 buttonGotoMusic
->setEnabled(false);
2480 * Goto music favorite output folder
2482 void MainWindow::gotoFavoriteFolder(void)
2484 if(!m_fileSystemModel
)
2486 qWarning("File system model not initialized yet!");
2490 QAction
*item
= dynamic_cast<QAction
*>(QObject::sender());
2494 QDir
path(item
->data().toString());
2497 outputFolderView
->setCurrentIndex(m_fileSystemModel
->index(path
.canonicalPath()));
2498 outputFolderViewClicked(outputFolderView
->currentIndex());
2499 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED
;
2503 MessageBeep(MB_ICONERROR
);
2504 m_outputFolderFavoritesMenu
->removeAction(item
);
2505 item
->deleteLater();
2511 * Make folder button
2513 void MainWindow::makeFolderButtonClicked(void)
2517 if(!m_fileSystemModel
)
2519 qWarning("File system model not initialized yet!");
2523 QDir
basePath(m_fileSystemModel
->fileInfo(outputFolderView
->currentIndex()).absoluteFilePath());
2524 QString suggestedName
= tr("New Folder");
2526 if(!m_metaData
->fileArtist().isEmpty() && !m_metaData
->fileAlbum().isEmpty())
2528 suggestedName
= QString("%1 - %2").arg(m_metaData
->fileArtist(), m_metaData
->fileAlbum());
2530 else if(!m_metaData
->fileArtist().isEmpty())
2532 suggestedName
= m_metaData
->fileArtist();
2534 else if(!m_metaData
->fileAlbum().isEmpty())
2536 suggestedName
= m_metaData
->fileAlbum();
2540 for(int i
= 0; i
< m_fileListModel
->rowCount(); i
++)
2542 AudioFileModel audioFile
= m_fileListModel
->getFile(m_fileListModel
->index(i
, 0));
2543 if(!audioFile
.fileAlbum().isEmpty() || !audioFile
.fileArtist().isEmpty())
2545 if(!audioFile
.fileArtist().isEmpty() && !audioFile
.fileAlbum().isEmpty())
2547 suggestedName
= QString("%1 - %2").arg(audioFile
.fileArtist(), audioFile
.fileAlbum());
2549 else if(!audioFile
.fileArtist().isEmpty())
2551 suggestedName
= audioFile
.fileArtist();
2553 else if(!audioFile
.fileAlbum().isEmpty())
2555 suggestedName
= audioFile
.fileAlbum();
2562 suggestedName
= lamexp_clean_filename(suggestedName
);
2566 bool bApplied
= false;
2567 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();
2571 folderName
= lamexp_clean_filepath(folderName
.simplified());
2573 if(folderName
.isEmpty())
2575 MessageBeep(MB_ICONERROR
);
2580 QString newFolder
= folderName
;
2582 while(basePath
.exists(newFolder
))
2584 newFolder
= QString(folderName
).append(QString().sprintf(" (%d)", ++i
));
2587 if(basePath
.mkpath(newFolder
))
2589 QDir createdDir
= basePath
;
2590 if(createdDir
.cd(newFolder
))
2592 QModelIndex newIndex
= m_fileSystemModel
->index(createdDir
.canonicalPath());
2593 outputFolderView
->setCurrentIndex(newIndex
);
2594 outputFolderViewClicked(newIndex
);
2595 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED
;
2600 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!")));
2608 * Output to source dir changed
2610 void MainWindow::saveToSourceFolderChanged(void)
2612 m_settings
->outputToSourceDir(saveToSourceFolderCheckBox
->isChecked());
2616 * Prepend relative source file path to output file name changed
2618 void MainWindow::prependRelativePathChanged(void)
2620 m_settings
->prependRelativeSourcePath(prependRelativePathCheckBox
->isChecked());
2624 * Show context menu for output folder
2626 void MainWindow::outputFolderContextMenu(const QPoint
&pos
)
2628 QAbstractScrollArea
*scrollArea
= dynamic_cast<QAbstractScrollArea
*>(QObject::sender());
2629 QWidget
*sender
= scrollArea
? scrollArea
->viewport() : dynamic_cast<QWidget
*>(QObject::sender());
2631 if(pos
.x() <= sender
->width() && pos
.y() <= sender
->height() && pos
.x() >= 0 && pos
.y() >= 0)
2633 m_outputFolderContextMenu
->popup(sender
->mapToGlobal(pos
));
2638 * Show selected folder in explorer
2640 void MainWindow::showFolderContextActionTriggered(void)
2642 if(!m_fileSystemModel
)
2644 qWarning("File system model not initialized yet!");
2648 QString path
= QDir::toNativeSeparators(m_fileSystemModel
->filePath(outputFolderView
->currentIndex()));
2649 if(!path
.endsWith(QDir::separator())) path
.append(QDir::separator());
2650 ShellExecuteW(this->winId(), L
"explore", QWCHAR(path
), NULL
, NULL
, SW_SHOW
);
2654 * Refresh the directory outline
2656 void MainWindow::refreshFolderContextActionTriggered(void)
2658 QTimer::singleShot(0, this, SLOT(initOutputFolderModel()));
2661 const QString path = m_fileSystemModel->filePath(outputFolderView->currentIndex());
2662 m_fileSystemModel->flushCache();
2663 outputFolderView->reset();
2664 QModelIndex index = (!path.isEmpty()) ? m_fileSystemModel->index(path) : QModelIndex();
2668 outputFolderView->setCurrentIndex(index);
2669 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED;
2675 * Add current folder to favorites
2677 void MainWindow::addFavoriteFolderActionTriggered(void)
2679 QString path
= m_fileSystemModel
->filePath(outputFolderView
->currentIndex());
2680 QStringList favorites
= m_settings
->favoriteOutputFolders().split("|", QString::SkipEmptyParts
);
2682 if(!favorites
.contains(path
, Qt::CaseInsensitive
))
2684 favorites
.append(path
);
2685 while(favorites
.count() > 6) favorites
.removeFirst();
2689 MessageBeep(MB_ICONWARNING
);
2692 m_settings
->favoriteOutputFolders(favorites
.join("|"));
2697 * Output folder edit finished
2699 void MainWindow::outputFolderEditFinished(void)
2701 if(outputFolderEdit
->isHidden())
2703 return; //Not currently in edit mode!
2708 QString text
= QDir::fromNativeSeparators(outputFolderEdit
->text().trimmed());
2709 while(text
.startsWith('"') || text
.startsWith('/')) text
= text
.right(text
.length() - 1).trimmed();
2710 while(text
.endsWith('"') || text
.endsWith('/')) text
= text
.left(text
.length() - 1).trimmed();
2712 static const char *str
= "?*<>|\"";
2713 for(size_t i
= 0; str
[i
]; i
++) text
.replace(str
[i
], "_");
2715 if(!((text
.length() >= 2) && text
.at(0).isLetter() && text
.at(1) == QChar(':')))
2717 text
= QString("%1/%2").arg(QDir::fromNativeSeparators(outputFolderLabel
->text()), text
);
2720 if(text
.length() == 2) text
+= "/"; /* "X:" => "X:/" */
2722 while(text
.length() > 2)
2724 QFileInfo
info(text
);
2725 if(info
.exists() && info
.isDir())
2727 QModelIndex index
= m_fileSystemModel
->index(QFileInfo(info
.canonicalFilePath()).absoluteFilePath());
2731 outputFolderView
->setCurrentIndex(index
);
2732 outputFolderViewClicked(index
);
2736 else if(info
.exists() && info
.isFile())
2738 QModelIndex index
= m_fileSystemModel
->index(QFileInfo(info
.canonicalPath()).absoluteFilePath());
2742 outputFolderView
->setCurrentIndex(index
);
2743 outputFolderViewClicked(index
);
2748 text
= text
.left(text
.length() - 1).trimmed();
2751 outputFolderEdit
->setVisible(false);
2752 outputFolderLabel
->setVisible(true);
2753 outputFolderView
->setEnabled(true);
2755 if(!ok
) MessageBeep(MB_ICONERROR
);
2756 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED
;
2760 * Initialize file system model
2762 void MainWindow::initOutputFolderModel(void)
2764 if(m_outputFolderNoteBox
->isHidden())
2766 m_outputFolderNoteBox
->show();
2767 m_outputFolderViewInitCounter
= 4;
2769 if(m_fileSystemModel
)
2771 outputFolderView
->setModel(NULL
);
2772 LAMEXP_DELETE(m_fileSystemModel
);
2775 if(m_fileSystemModel
= new QFileSystemModelEx())
2777 m_fileSystemModel
->installEventFilter(this);
2778 connect(m_fileSystemModel
, SIGNAL(directoryLoaded(QString
)), this, SLOT(outputFolderDirectoryLoaded(QString
)));
2779 connect(m_fileSystemModel
, SIGNAL(rowsInserted(QModelIndex
,int,int)), this, SLOT(outputFolderRowsInserted(QModelIndex
,int,int)));
2781 outputFolderView
->setModel(m_fileSystemModel
);
2782 outputFolderView
->header()->setStretchLastSection(true);
2783 outputFolderView
->header()->hideSection(1);
2784 outputFolderView
->header()->hideSection(2);
2785 outputFolderView
->header()->hideSection(3);
2787 m_fileSystemModel
->setRootPath("");
2788 QModelIndex index
= m_fileSystemModel
->index(m_settings
->outputDir());
2789 if(index
.isValid()) outputFolderView
->setCurrentIndex(index
);
2790 outputFolderViewClicked(outputFolderView
->currentIndex());
2793 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED
;
2794 QTimer::singleShot(125, this, SLOT(initOutputFolderModel_doAsync()));
2799 * Initialize file system model (do NOT call this one directly!)
2801 void MainWindow::initOutputFolderModel_doAsync(void)
2803 if(m_outputFolderViewInitCounter
> 0)
2805 m_outputFolderViewInitCounter
--;
2806 QTimer::singleShot(125, this, SLOT(initOutputFolderModel_doAsync()));
2810 QTimer::singleShot(125, m_outputFolderNoteBox
, SLOT(hide()));
2811 outputFolderView
->setFocus();
2816 * Center current folder in view
2818 void MainWindow::centerOutputFolderModel(void)
2820 if(outputFolderView
->isVisible())
2822 centerOutputFolderModel_doAsync();
2823 QTimer::singleShot(125, this, SLOT(centerOutputFolderModel_doAsync()));
2828 * Center current folder in view (do NOT call this one directly!)
2830 void MainWindow::centerOutputFolderModel_doAsync(void)
2832 if(outputFolderView
->isVisible())
2834 m_outputFolderViewCentering
= true;
2835 const QModelIndex index
= outputFolderView
->currentIndex();
2836 outputFolderView
->scrollTo(index
, QAbstractItemView::PositionAtCenter
);
2837 outputFolderView
->setFocus();
2842 * File system model asynchronously loaded a dir
2844 void MainWindow::outputFolderDirectoryLoaded(const QString
&path
)
2846 if(m_outputFolderViewCentering
)
2848 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED
;
2853 * File system model inserted new items
2855 void MainWindow::outputFolderRowsInserted(const QModelIndex
&parent
, int start
, int end
)
2857 if(m_outputFolderViewCentering
)
2859 CENTER_CURRENT_OUTPUT_FOLDER_DELAYED
;
2864 * Directory view item was expanded by user
2866 void MainWindow::outputFolderItemExpanded(const QModelIndex
&item
)
2868 //We need to stop centering as soon as the user has expanded an item manually!
2869 m_outputFolderViewCentering
= false;
2872 // =========================================================
2873 // Metadata tab slots
2874 // =========================================================
2877 * Edit meta button clicked
2879 void MainWindow::editMetaButtonClicked(void)
2883 const QModelIndex index
= metaDataView
->currentIndex();
2887 m_metaInfoModel
->editItem(index
, this);
2889 if(index
.row() == 4)
2891 m_settings
->metaInfoPosition(m_metaData
->filePosition());
2897 * Reset meta button clicked
2899 void MainWindow::clearMetaButtonClicked(void)
2902 m_metaInfoModel
->clearData();
2906 * Meta tags enabled changed
2908 void MainWindow::metaTagsEnabledChanged(void)
2910 m_settings
->writeMetaTags(writeMetaDataCheckBox
->isChecked());
2914 * Playlist enabled changed
2916 void MainWindow::playlistEnabledChanged(void)
2918 m_settings
->createPlaylist(generatePlaylistCheckBox
->isChecked());
2921 // =========================================================
2922 // Compression tab slots
2923 // =========================================================
2928 void MainWindow::updateEncoder(int id
)
2930 m_settings
->compressionEncoder(id
);
2932 switch(m_settings
->compressionEncoder())
2934 case SettingsModel::VorbisEncoder
:
2935 radioButtonModeQuality
->setEnabled(true);
2936 radioButtonModeAverageBitrate
->setEnabled(true);
2937 radioButtonConstBitrate
->setEnabled(false);
2938 if(radioButtonConstBitrate
->isChecked()) radioButtonModeQuality
->setChecked(true);
2939 sliderBitrate
->setEnabled(true);
2941 case SettingsModel::AC3Encoder
:
2942 radioButtonModeQuality
->setEnabled(true);
2943 radioButtonModeQuality
->setChecked(true);
2944 radioButtonModeAverageBitrate
->setEnabled(false);
2945 radioButtonConstBitrate
->setEnabled(true);
2946 sliderBitrate
->setEnabled(true);
2948 case SettingsModel::FLACEncoder
:
2949 radioButtonModeQuality
->setEnabled(false);
2950 radioButtonModeQuality
->setChecked(true);
2951 radioButtonModeAverageBitrate
->setEnabled(false);
2952 radioButtonConstBitrate
->setEnabled(false);
2953 sliderBitrate
->setEnabled(true);
2955 case SettingsModel::PCMEncoder
:
2956 radioButtonModeQuality
->setEnabled(false);
2957 radioButtonModeQuality
->setChecked(true);
2958 radioButtonModeAverageBitrate
->setEnabled(false);
2959 radioButtonConstBitrate
->setEnabled(false);
2960 sliderBitrate
->setEnabled(false);
2962 case SettingsModel::AACEncoder
:
2963 radioButtonModeQuality
->setEnabled(true);
2964 radioButtonModeAverageBitrate
->setEnabled(!m_fhgEncoderAvailable
);
2965 if(m_fhgEncoderAvailable
&& radioButtonModeAverageBitrate
->isChecked()) radioButtonConstBitrate
->setChecked(true);
2966 radioButtonConstBitrate
->setEnabled(true);
2967 sliderBitrate
->setEnabled(true);
2969 case SettingsModel::DCAEncoder
:
2970 radioButtonModeQuality
->setEnabled(false);
2971 radioButtonModeAverageBitrate
->setEnabled(false);
2972 radioButtonConstBitrate
->setEnabled(true);
2973 radioButtonConstBitrate
->setChecked(true);
2974 sliderBitrate
->setEnabled(true);
2977 radioButtonModeQuality
->setEnabled(true);
2978 radioButtonModeAverageBitrate
->setEnabled(true);
2979 radioButtonConstBitrate
->setEnabled(true);
2980 sliderBitrate
->setEnabled(true);
2984 if(m_settings
->compressionEncoder() == SettingsModel::AACEncoder
)
2986 const QString encoderName
= m_qaacEncoderAvailable
? tr("QAAC (Apple)") : (m_fhgEncoderAvailable
? tr("FHG AAC (Winamp)") : (m_neroEncoderAvailable
? tr("Nero AAC") : tr("Not available!")));
2987 labelEncoderInfo
->setVisible(true);
2988 labelEncoderInfo
->setText(tr("Current AAC Encoder: %1").arg(encoderName
));
2992 labelEncoderInfo
->setVisible(false);
2995 updateRCMode(m_modeButtonGroup
->checkedId());
2999 * Update rate-control mode
3001 void MainWindow::updateRCMode(int id
)
3003 m_settings
->compressionRCMode(id
);
3005 switch(m_settings
->compressionEncoder())
3007 case SettingsModel::MP3Encoder
:
3008 switch(m_settings
->compressionRCMode())
3010 case SettingsModel::VBRMode
:
3011 sliderBitrate
->setMinimum(0);
3012 sliderBitrate
->setMaximum(9);
3015 sliderBitrate
->setMinimum(0);
3016 sliderBitrate
->setMaximum(13);
3020 case SettingsModel::VorbisEncoder
:
3021 switch(m_settings
->compressionRCMode())
3023 case SettingsModel::VBRMode
:
3024 sliderBitrate
->setMinimum(-2);
3025 sliderBitrate
->setMaximum(10);
3028 sliderBitrate
->setMinimum(4);
3029 sliderBitrate
->setMaximum(63);
3033 case SettingsModel::AC3Encoder
:
3034 switch(m_settings
->compressionRCMode())
3036 case SettingsModel::VBRMode
:
3037 sliderBitrate
->setMinimum(0);
3038 sliderBitrate
->setMaximum(16);
3041 sliderBitrate
->setMinimum(0);
3042 sliderBitrate
->setMaximum(18);
3046 case SettingsModel::AACEncoder
:
3047 switch(m_settings
->compressionRCMode())
3049 case SettingsModel::VBRMode
:
3050 sliderBitrate
->setMinimum(0);
3051 sliderBitrate
->setMaximum(20);
3054 sliderBitrate
->setMinimum(4);
3055 sliderBitrate
->setMaximum(63);
3059 case SettingsModel::FLACEncoder
:
3060 sliderBitrate
->setMinimum(0);
3061 sliderBitrate
->setMaximum(8);
3063 case SettingsModel::DCAEncoder
:
3064 sliderBitrate
->setMinimum(1);
3065 sliderBitrate
->setMaximum(128);
3067 case SettingsModel::PCMEncoder
:
3068 sliderBitrate
->setMinimum(0);
3069 sliderBitrate
->setMaximum(2);
3070 sliderBitrate
->setValue(1);
3073 sliderBitrate
->setMinimum(0);
3074 sliderBitrate
->setMaximum(0);
3078 updateBitrate(sliderBitrate
->value());
3084 void MainWindow::updateBitrate(int value
)
3086 m_settings
->compressionBitrate(value
);
3088 switch(m_settings
->compressionRCMode())
3090 case SettingsModel::VBRMode
:
3091 switch(m_settings
->compressionEncoder())
3093 case SettingsModel::MP3Encoder
:
3094 labelBitrate
->setText(tr("Quality Level %1").arg(9 - value
));
3096 case SettingsModel::VorbisEncoder
:
3097 labelBitrate
->setText(tr("Quality Level %1").arg(value
));
3099 case SettingsModel::AACEncoder
:
3100 labelBitrate
->setText(tr("Quality Level %1").arg(QString().sprintf("%.2f", static_cast<double>(value
* 5) / 100.0)));
3102 case SettingsModel::FLACEncoder
:
3103 labelBitrate
->setText(tr("Compression %1").arg(value
));
3105 case SettingsModel::AC3Encoder
:
3106 labelBitrate
->setText(tr("Quality Level %1").arg(qMin(1024, qMax(0, value
* 64))));
3108 case SettingsModel::PCMEncoder
:
3109 labelBitrate
->setText(tr("Uncompressed"));
3112 labelBitrate
->setText(QString::number(value
));
3116 case SettingsModel::ABRMode
:
3117 switch(m_settings
->compressionEncoder())
3119 case SettingsModel::MP3Encoder
:
3120 labelBitrate
->setText(QString("≈ %1 kbps").arg(SettingsModel::mp3Bitrates
[value
]));
3122 case SettingsModel::FLACEncoder
:
3123 labelBitrate
->setText(tr("Compression %1").arg(value
));
3125 case SettingsModel::AC3Encoder
:
3126 labelBitrate
->setText(QString("≈ %1 kbps").arg(SettingsModel::ac3Bitrates
[value
]));
3128 case SettingsModel::PCMEncoder
:
3129 labelBitrate
->setText(tr("Uncompressed"));
3132 labelBitrate
->setText(QString("≈ %1 kbps").arg(qMin(500, value
* 8)));
3137 switch(m_settings
->compressionEncoder())
3139 case SettingsModel::MP3Encoder
:
3140 labelBitrate
->setText(QString("%1 kbps").arg(SettingsModel::mp3Bitrates
[value
]));
3142 case SettingsModel::FLACEncoder
:
3143 labelBitrate
->setText(tr("Compression %1").arg(value
));
3145 case SettingsModel::AC3Encoder
:
3146 labelBitrate
->setText(QString("%1 kbps").arg(SettingsModel::ac3Bitrates
[value
]));
3148 case SettingsModel::DCAEncoder
:
3149 labelBitrate
->setText(QString("%1 kbps").arg(value
* 32));
3151 case SettingsModel::PCMEncoder
:
3152 labelBitrate
->setText(tr("Uncompressed"));
3155 labelBitrate
->setText(QString("%1 kbps").arg(qMin(500, value
* 8)));
3162 // =========================================================
3163 // Advanced option slots
3164 // =========================================================
3167 * Lame algorithm quality changed
3169 void MainWindow::updateLameAlgoQuality(int value
)
3176 text
= tr("Best Quality (Very Slow)");
3179 text
= tr("High Quality (Recommended)");
3182 text
= tr("Average Quality (Default)");
3185 text
= tr("Low Quality (Fast)");
3188 text
= tr("Poor Quality (Very Fast)");
3194 m_settings
->lameAlgoQuality(value
);
3195 labelLameAlgoQuality
->setText(text
);
3198 bool warning
= (value
== 0), notice
= (value
== 4);
3199 labelLameAlgoQualityWarning
->setVisible(warning
);
3200 labelLameAlgoQualityWarningIcon
->setVisible(warning
);
3201 labelLameAlgoQualityNotice
->setVisible(notice
);
3202 labelLameAlgoQualityNoticeIcon
->setVisible(notice
);
3203 labelLameAlgoQualitySpacer
->setVisible(warning
|| notice
);
3207 * Bitrate management endabled/disabled
3209 void MainWindow::bitrateManagementEnabledChanged(bool checked
)
3211 m_settings
->bitrateManagementEnabled(checked
);
3215 * Minimum bitrate has changed
3217 void MainWindow::bitrateManagementMinChanged(int value
)
3219 if(value
> spinBoxBitrateManagementMax
->value())
3221 spinBoxBitrateManagementMin
->setValue(spinBoxBitrateManagementMax
->value());
3222 m_settings
->bitrateManagementMinRate(spinBoxBitrateManagementMax
->value());
3226 m_settings
->bitrateManagementMinRate(value
);
3231 * Maximum bitrate has changed
3233 void MainWindow::bitrateManagementMaxChanged(int value
)
3235 if(value
< spinBoxBitrateManagementMin
->value())
3237 spinBoxBitrateManagementMax
->setValue(spinBoxBitrateManagementMin
->value());
3238 m_settings
->bitrateManagementMaxRate(spinBoxBitrateManagementMin
->value());
3242 m_settings
->bitrateManagementMaxRate(value
);
3247 * Channel mode has changed
3249 void MainWindow::channelModeChanged(int value
)
3251 if(value
>= 0) m_settings
->lameChannelMode(value
);
3255 * Sampling rate has changed
3257 void MainWindow::samplingRateChanged(int value
)
3259 if(value
>= 0) m_settings
->samplingRate(value
);
3263 * Nero AAC 2-Pass mode changed
3265 void MainWindow::neroAAC2PassChanged(bool checked
)
3267 m_settings
->neroAACEnable2Pass(checked
);
3271 * Nero AAC profile mode changed
3273 void MainWindow::neroAACProfileChanged(int value
)
3275 if(value
>= 0) m_settings
->aacEncProfile(value
);
3279 * Aften audio coding mode changed
3281 void MainWindow::aftenCodingModeChanged(int value
)
3283 if(value
>= 0) m_settings
->aftenAudioCodingMode(value
);
3287 * Aften DRC mode changed
3289 void MainWindow::aftenDRCModeChanged(int value
)
3291 if(value
>= 0) m_settings
->aftenDynamicRangeCompression(value
);
3295 * Aften exponent search size changed
3297 void MainWindow::aftenSearchSizeChanged(int value
)
3299 if(value
>= 0) m_settings
->aftenExponentSearchSize(value
);
3303 * Aften fast bit allocation changed
3305 void MainWindow::aftenFastAllocationChanged(bool checked
)
3307 m_settings
->aftenFastBitAllocation(checked
);
3311 * Normalization filter enabled changed
3313 void MainWindow::normalizationEnabledChanged(bool checked
)
3315 m_settings
->normalizationFilterEnabled(checked
);
3319 * Normalization max. volume changed
3321 void MainWindow::normalizationMaxVolumeChanged(double value
)
3323 m_settings
->normalizationFilterMaxVolume(static_cast<int>(value
* 100.0));
3327 * Normalization equalization mode changed
3329 void MainWindow::normalizationModeChanged(int mode
)
3331 m_settings
->normalizationFilterEqualizationMode(mode
);
3335 * Tone adjustment has changed (Bass)
3337 void MainWindow::toneAdjustBassChanged(double value
)
3339 m_settings
->toneAdjustBass(static_cast<int>(value
* 100.0));
3340 spinBoxToneAdjustBass
->setPrefix((value
> 0) ? "+" : QString());
3344 * Tone adjustment has changed (Treble)
3346 void MainWindow::toneAdjustTrebleChanged(double value
)
3348 m_settings
->toneAdjustTreble(static_cast<int>(value
* 100.0));
3349 spinBoxToneAdjustTreble
->setPrefix((value
> 0) ? "+" : QString());
3353 * Tone adjustment has been reset
3355 void MainWindow::toneAdjustTrebleReset(void)
3357 spinBoxToneAdjustBass
->setValue(m_settings
->toneAdjustBassDefault());
3358 spinBoxToneAdjustTreble
->setValue(m_settings
->toneAdjustTrebleDefault());
3359 toneAdjustBassChanged(spinBoxToneAdjustBass
->value());
3360 toneAdjustTrebleChanged(spinBoxToneAdjustTreble
->value());
3364 * Custom encoder parameters changed
3366 void MainWindow::customParamsChanged(void)
3368 lineEditCustomParamLAME
->setText(lineEditCustomParamLAME
->text().simplified());
3369 lineEditCustomParamOggEnc
->setText(lineEditCustomParamOggEnc
->text().simplified());
3370 lineEditCustomParamNeroAAC
->setText(lineEditCustomParamNeroAAC
->text().simplified());
3371 lineEditCustomParamFLAC
->setText(lineEditCustomParamFLAC
->text().simplified());
3372 lineEditCustomParamAften
->setText(lineEditCustomParamAften
->text().simplified());
3374 bool customParamsUsed
= false;
3375 if(!lineEditCustomParamLAME
->text().isEmpty()) customParamsUsed
= true;
3376 if(!lineEditCustomParamOggEnc
->text().isEmpty()) customParamsUsed
= true;
3377 if(!lineEditCustomParamNeroAAC
->text().isEmpty()) customParamsUsed
= true;
3378 if(!lineEditCustomParamFLAC
->text().isEmpty()) customParamsUsed
= true;
3379 if(!lineEditCustomParamAften
->text().isEmpty()) customParamsUsed
= true;
3381 labelCustomParamsIcon
->setVisible(customParamsUsed
);
3382 labelCustomParamsText
->setVisible(customParamsUsed
);
3383 labelCustomParamsSpacer
->setVisible(customParamsUsed
);
3385 m_settings
->customParametersLAME(lineEditCustomParamLAME
->text());
3386 m_settings
->customParametersOggEnc(lineEditCustomParamOggEnc
->text());
3387 m_settings
->customParametersAacEnc(lineEditCustomParamNeroAAC
->text());
3388 m_settings
->customParametersFLAC(lineEditCustomParamFLAC
->text());
3389 m_settings
->customParametersAften(lineEditCustomParamAften
->text());
3394 * Rename output files enabled changed
3396 void MainWindow::renameOutputEnabledChanged(bool checked
)
3398 m_settings
->renameOutputFilesEnabled(checked
);
3402 * Rename output files patterm changed
3404 void MainWindow::renameOutputPatternChanged(void)
3406 QString temp
= lineEditRenamePattern
->text().simplified();
3407 lineEditRenamePattern
->setText(temp
.isEmpty() ? m_settings
->renameOutputFilesPatternDefault() : temp
);
3408 m_settings
->renameOutputFilesPattern(lineEditRenamePattern
->text());
3412 * Rename output files patterm changed
3414 void MainWindow::renameOutputPatternChanged(const QString
&text
)
3416 QString
pattern(text
.simplified());
3418 pattern
.replace("<BaseName>", "The_White_Stripes_-_Fell_In_Love_With_A_Girl", Qt::CaseInsensitive
);
3419 pattern
.replace("<TrackNo>", "04", Qt::CaseInsensitive
);
3420 pattern
.replace("<Title>", "Fell In Love With A Girl", Qt::CaseInsensitive
);
3421 pattern
.replace("<Artist>", "The White Stripes", Qt::CaseInsensitive
);
3422 pattern
.replace("<Album>", "White Blood Cells", Qt::CaseInsensitive
);
3423 pattern
.replace("<Year>", "2001", Qt::CaseInsensitive
);
3424 pattern
.replace("<Comment>", "Encoded by LameXP", Qt::CaseInsensitive
);
3426 if(pattern
.compare(lamexp_clean_filename(pattern
)))
3428 if(lineEditRenamePattern
->palette().color(QPalette::Text
) != Qt::red
)
3430 MessageBeep(MB_ICONERROR
);
3431 SET_TEXT_COLOR(lineEditRenamePattern
, Qt::red
);
3436 if(lineEditRenamePattern
->palette().color(QPalette::Text
) != Qt::black
)
3438 MessageBeep(MB_ICONINFORMATION
);
3439 SET_TEXT_COLOR(lineEditRenamePattern
, Qt::black
);
3443 labelRanameExample
->setText(lamexp_clean_filename(pattern
));
3447 * Show list of rename macros
3449 void MainWindow::showRenameMacros(const QString
&text
)
3451 if(text
.compare("reset", Qt::CaseInsensitive
) == 0)
3453 lineEditRenamePattern
->setText(m_settings
->renameOutputFilesPatternDefault());
3457 const QString format
= QString("<tr><td><tt><%1></tt></td><td> </td><td>%2</td></tr>");
3459 QString message
= QString("<table>");
3460 message
+= QString(format
).arg("BaseName", tr("File name without extension"));
3461 message
+= QString(format
).arg("TrackNo", tr("Track number with leading zero"));
3462 message
+= QString(format
).arg("Title", tr("Track title"));
3463 message
+= QString(format
).arg("Artist", tr("Artist name"));
3464 message
+= QString(format
).arg("Album", tr("Album name"));
3465 message
+= QString(format
).arg("Year", tr("Year with (at least) four digits"));
3466 message
+= QString(format
).arg("Comment", tr("Comment"));
3467 message
+= "</table><br><br>";
3468 message
+= QString("%1<br>").arg(tr("Characters forbidden in file names:"));
3469 message
+= "<b><tt>\\ / : * ? < > |<br>";
3471 QMessageBox::information(this, tr("Rename Macros"), message
, tr("Discard"));
3474 void MainWindow::forceStereoDownmixEnabledChanged(bool checked
)
3476 m_settings
->forceStereoDownmix(checked
);
3480 * Maximum number of instances changed
3482 void MainWindow::updateMaximumInstances(int value
)
3484 labelMaxInstances
->setText(tr("%1 Instance(s)").arg(QString::number(value
)));
3485 m_settings
->maximumInstances(checkBoxAutoDetectInstances
->isChecked() ? NULL
: value
);
3489 * Auto-detect number of instances
3491 void MainWindow::autoDetectInstancesChanged(bool checked
)
3493 m_settings
->maximumInstances(checked
? NULL
: sliderMaxInstances
->value());
3497 * Browse for custom TEMP folder button clicked
3499 void MainWindow::browseCustomTempFolderButtonClicked(void)
3501 QString newTempFolder
;
3503 if(USE_NATIVE_FILE_DIALOG
)
3505 newTempFolder
= QFileDialog::getExistingDirectory(this, QString(), m_settings
->customTempPath());
3509 QFileDialog
dialog(this);
3510 dialog
.setFileMode(QFileDialog::DirectoryOnly
);
3511 dialog
.setDirectory(m_settings
->customTempPath());
3514 newTempFolder
= dialog
.selectedFiles().first();
3518 if(!newTempFolder
.isEmpty())
3520 QFile
writeTest(QString("%1/~%2.tmp").arg(newTempFolder
, lamexp_rand_str()));
3521 if(writeTest
.open(QIODevice::ReadWrite
))
3524 lineEditCustomTempFolder
->setText(QDir::toNativeSeparators(newTempFolder
));
3528 QMessageBox::warning(this, tr("Access Denied"), tr("Cannot write to the selected directory. Please choose another directory!"));
3534 * Custom TEMP folder changed
3536 void MainWindow::customTempFolderChanged(const QString
&text
)
3538 m_settings
->customTempPath(QDir::fromNativeSeparators(text
));
3542 * Use custom TEMP folder option changed
3544 void MainWindow::useCustomTempFolderChanged(bool checked
)
3546 m_settings
->customTempPathEnabled(!checked
);
3550 * Reset all advanced options to their defaults
3552 void MainWindow::resetAdvancedOptionsButtonClicked(void)
3554 sliderLameAlgoQuality
->setValue(m_settings
->lameAlgoQualityDefault());
3555 spinBoxBitrateManagementMin
->setValue(m_settings
->bitrateManagementMinRateDefault());
3556 spinBoxBitrateManagementMax
->setValue(m_settings
->bitrateManagementMaxRateDefault());
3557 spinBoxNormalizationFilter
->setValue(static_cast<double>(m_settings
->normalizationFilterMaxVolumeDefault()) / 100.0);
3558 spinBoxToneAdjustBass
->setValue(static_cast<double>(m_settings
->toneAdjustBassDefault()) / 100.0);
3559 spinBoxToneAdjustTreble
->setValue(static_cast<double>(m_settings
->toneAdjustTrebleDefault()) / 100.0);
3560 spinBoxAftenSearchSize
->setValue(m_settings
->aftenExponentSearchSizeDefault());
3561 comboBoxMP3ChannelMode
->setCurrentIndex(m_settings
->lameChannelModeDefault());
3562 comboBoxSamplingRate
->setCurrentIndex(m_settings
->samplingRateDefault());
3563 comboBoxAACProfile
->setCurrentIndex(m_settings
->aacEncProfileDefault());
3564 comboBoxAftenCodingMode
->setCurrentIndex(m_settings
->aftenAudioCodingModeDefault());
3565 comboBoxAftenDRCMode
->setCurrentIndex(m_settings
->aftenDynamicRangeCompressionDefault());
3566 comboBoxNormalizationMode
->setCurrentIndex(m_settings
->normalizationFilterEqualizationModeDefault());
3567 while(checkBoxBitrateManagement
->isChecked() != m_settings
->bitrateManagementEnabledDefault()) checkBoxBitrateManagement
->click();
3568 while(checkBoxNeroAAC2PassMode
->isChecked() != m_settings
->neroAACEnable2PassDefault()) checkBoxNeroAAC2PassMode
->click();
3569 while(checkBoxNormalizationFilter
->isChecked() != m_settings
->normalizationFilterEnabledDefault()) checkBoxNormalizationFilter
->click();
3570 while(checkBoxAutoDetectInstances
->isChecked() != (m_settings
->maximumInstancesDefault() < 1)) checkBoxAutoDetectInstances
->click();
3571 while(checkBoxUseSystemTempFolder
->isChecked() == m_settings
->customTempPathEnabledDefault()) checkBoxUseSystemTempFolder
->click();
3572 while(checkBoxAftenFastAllocation
->isChecked() != m_settings
->aftenFastBitAllocationDefault()) checkBoxAftenFastAllocation
->click();
3573 while(checkBoxRenameOutput
->isChecked() != m_settings
->renameOutputFilesEnabledDefault()) checkBoxRenameOutput
->click();
3574 while(checkBoxForceStereoDownmix
->isChecked() != m_settings
->forceStereoDownmixDefault()) checkBoxForceStereoDownmix
->click();
3575 lineEditCustomParamLAME
->setText(m_settings
->customParametersLAMEDefault());
3576 lineEditCustomParamOggEnc
->setText(m_settings
->customParametersOggEncDefault());
3577 lineEditCustomParamNeroAAC
->setText(m_settings
->customParametersAacEncDefault());
3578 lineEditCustomParamFLAC
->setText(m_settings
->customParametersFLACDefault());
3579 lineEditCustomTempFolder
->setText(QDir::toNativeSeparators(m_settings
->customTempPathDefault()));
3580 lineEditRenamePattern
->setText(m_settings
->renameOutputFilesPatternDefault());
3581 customParamsChanged();
3582 scrollArea
->verticalScrollBar()->setValue(0);
3585 // =========================================================
3586 // Multi-instance handling slots
3587 // =========================================================
3590 * Other instance detected
3592 void MainWindow::notifyOtherInstance(void)
3594 if(!m_banner
->isVisible())
3596 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
);
3602 * Add file from another instance
3604 void MainWindow::addFileDelayed(const QString
&filePath
, bool tryASAP
)
3606 if(tryASAP
&& !m_delayedFileTimer
->isActive())
3608 qDebug("Received file: %s", filePath
.toUtf8().constData());
3609 m_delayedFileList
->append(filePath
);
3610 QTimer::singleShot(0, this, SLOT(handleDelayedFiles()));
3613 m_delayedFileTimer
->stop();
3614 qDebug("Received file: %s", filePath
.toUtf8().constData());
3615 m_delayedFileList
->append(filePath
);
3616 m_delayedFileTimer
->start(5000);
3620 * Add files from another instance
3622 void MainWindow::addFilesDelayed(const QStringList
&filePaths
, bool tryASAP
)
3624 if(tryASAP
&& !m_delayedFileTimer
->isActive())
3626 qDebug("Received %d file(s).", filePaths
.count());
3627 m_delayedFileList
->append(filePaths
);
3628 QTimer::singleShot(0, this, SLOT(handleDelayedFiles()));
3632 m_delayedFileTimer
->stop();
3633 qDebug("Received %d file(s).", filePaths
.count());
3634 m_delayedFileList
->append(filePaths
);
3635 m_delayedFileTimer
->start(5000);
3640 * Add folder from another instance
3642 void MainWindow::addFolderDelayed(const QString
&folderPath
, bool recursive
)
3644 if(!m_banner
->isVisible())
3646 addFolder(folderPath
, recursive
, true);
3650 // =========================================================
3652 // =========================================================
3655 * Restore the override cursor
3657 void MainWindow::restoreCursor(void)
3659 QApplication::restoreOverrideCursor();