1
2 #include "optionssimple.h"
3 #include "config.h"
4 #include "outputdirectory.h"
5 #include "global.h"
6 #include "codecproblems.h"
7
8 #include <QApplication>
9 #include <QLayout>
10 #include <QBoxLayout>
11 #include <QLabel>
12 #include <QString>
13 #include <QToolTip>
14
15 #include <KLocale>
16 #include <KIcon>
17 #include <KMessageBox>
18 #include <KComboBox>
19 #include <QCheckBox>
20 #include <KPushButton>
21 #include <QFile>
22 #include <KStandardDirs>
23
24
25 // FIXME when changing the output directory, check if the profile is a user defined and set it to 'User defined', if it is
26
27 // TODO hide lossless/hybrid/etc. when not available
OptionsSimple(Config * _config,const QString & text,QWidget * parent)28 OptionsSimple::OptionsSimple( Config *_config, /*OptionsDetailed* _optionsDetailed,*/ const QString &text, QWidget *parent )
29 : QWidget( parent ),
30 config( _config )
31 {
32 const int fontHeight = QFontMetrics(QApplication::font()).boundingRect("M").size().height();
33
34 QGridLayout *grid = new QGridLayout( this );
35 grid->setMargin( fontHeight );
36 grid->setSpacing( fontHeight );
37
38 QLabel *lQuality = new QLabel( i18n("Quality:"), this );
39 grid->addWidget( lQuality, 0, 0 );
40
41 QHBoxLayout *topBoxQuality = new QHBoxLayout();
42 grid->addLayout( topBoxQuality, 0, 1 );
43 cProfile = new KComboBox( this );
44 topBoxQuality->addWidget( cProfile );
45 connect( cProfile, SIGNAL(activated(int)), this, SLOT(profileChanged()) );
46 topBoxQuality->addSpacing( 0.25*fontHeight );
47 pProfileRemove = new KPushButton( KIcon("edit-delete"), i18n("Remove"), this );
48 topBoxQuality->addWidget( pProfileRemove );
49 pProfileRemove->setToolTip( i18n("Remove the selected profile") );
50 pProfileRemove->hide();
51 connect( pProfileRemove, SIGNAL(clicked()), this, SLOT(profileRemove()) );
52 pProfileInfo = new KPushButton( KIcon("dialog-information"), i18n("Info"), this );
53 topBoxQuality->addWidget( pProfileInfo );
54 pProfileInfo->setToolTip( i18n("Information about the selected profile") );
55 // cProfile->setFixedHeight( pProfileInfo->minimumSizeHint().height() );
56 connect( pProfileInfo, SIGNAL(clicked()), this, SLOT(profileInfo()) );
57 topBoxQuality->addStretch( );
58
59 topBoxQuality->addSpacing( fontHeight );
60
61 QLabel *lFormat = new QLabel( i18n("Format:"), this );
62 grid->addWidget( lFormat, 0, 2 );
63
64 QHBoxLayout *topBoxFormat = new QHBoxLayout();
65 grid->addLayout( topBoxFormat, 0, 3 );
66 cFormat = new KComboBox( this );
67 topBoxFormat->addWidget( cFormat );
68 // connect( cFormat, SIGNAL(activated(int)), this, SLOT(formatChanged()) );
69 connect( cFormat, SIGNAL(activated(int)), this, SLOT(somethingChanged()) );
70 topBoxFormat->addSpacing( 0.25*fontHeight );
71 pFormatInfo = new KPushButton( KIcon("dialog-information"), i18n("Info"), this );
72 topBoxFormat->addWidget( pFormatInfo );
73 pFormatInfo->setToolTip( i18n("Information about the selected file format") );
74 // cFormat->setFixedHeight( pFormatInfo->minimumSizeHint().height() );
75 connect( pFormatInfo, SIGNAL(clicked()), this, SLOT(formatInfo()) );
76 topBoxFormat->addSpacing( 0.25*fontHeight );
77 QLabel *formatHelp = new QLabel( "<a href=\"format-help\">" + i18n("More formats...") + "</a>", this );
78 topBoxFormat->addWidget( formatHelp );
79 connect( formatHelp, SIGNAL(linkActivated(const QString&)), this, SLOT(showHelp()) );
80 topBoxFormat->addStretch( );
81
82 QLabel *lOutput = new QLabel( i18n("Destination:"), this );
83 grid->addWidget( lOutput, 1, 0 );
84
85 QHBoxLayout *middleBox = new QHBoxLayout();
86 grid->addLayout( middleBox, 1, 1, 1, 3 );
87 outputDirectory = new OutputDirectory( config, this );
88 middleBox->addWidget( outputDirectory );
89 connect( outputDirectory, SIGNAL(modeChanged(int)), this, SLOT(outputDirectoryChanged()) );
90 connect( outputDirectory, SIGNAL(directoryChanged(const QString&)), this, SLOT(outputDirectoryChanged()) );
91
92 QHBoxLayout *estimSizeBox = new QHBoxLayout();
93 grid->addLayout( estimSizeBox, 2, 0 );
94 estimSizeBox->addStretch();
95 lEstimSize = new QLabel( QString(QChar(8776))+"? B / min." );
96 lEstimSize->hide(); // hide for now because most plugins report inaccurate data
97 estimSizeBox->addWidget( lEstimSize );
98
99 QLabel *lOptional = new QLabel( i18n("Optional:") );
100 grid->addWidget( lOptional, 3, 0 );
101
102 QHBoxLayout *optionalBox = new QHBoxLayout();
103 grid->addLayout( optionalBox, 3, 1 );
104 cReplayGain = new QCheckBox( i18n("Calculate Replay Gain tags"), this );
105 optionalBox->addWidget( cReplayGain );
106 connect( cReplayGain, SIGNAL(toggled(bool)), this, SLOT(somethingChanged()) );
107 optionalBox->addStretch();
108
109 QLabel *lInfo = new QLabel( text, this );
110 grid->addWidget( lInfo, 4, 0, 1, 4, Qt::AlignVCenter | Qt::AlignCenter );
111 grid->setRowStretch( 4, 1 );
112
113 grid->setColumnStretch( 1, 1 );
114 grid->setColumnStretch( 3, 1 );
115 }
116
~OptionsSimple()117 OptionsSimple::~OptionsSimple()
118 {}
119
init()120 void OptionsSimple::init()
121 {
122 updateProfiles();
123 }
124
setReplayGainEnabled(bool enabled,const QString & toolTip)125 void OptionsSimple::setReplayGainEnabled( bool enabled, const QString& toolTip )
126 {
127 cReplayGain->setEnabled(enabled);
128 cReplayGain->setToolTip(toolTip);
129 if( !enabled )
130 {
131 QPalette notificationPalette = cReplayGain->palette();
132 notificationPalette.setColor( QPalette::Disabled, QPalette::WindowText, QColor(174,127,130) );
133 cReplayGain->setPalette( notificationPalette );
134 }
135 }
136
setReplayGainChecked(bool enabled)137 void OptionsSimple::setReplayGainChecked( bool enabled )
138 {
139 cReplayGain->setChecked(enabled);
140 }
141
currentProfile()142 QString OptionsSimple::currentProfile()
143 {
144 return cProfile->currentText();
145 }
146
currentFormat()147 QString OptionsSimple::currentFormat()
148 {
149 return cFormat->currentText();
150 }
151
isReplayGainChecked()152 bool OptionsSimple::isReplayGainChecked()
153 {
154 return cReplayGain->isChecked();
155 }
156
updateProfiles()157 void OptionsSimple::updateProfiles()
158 {
159 const QString lastProfile = cProfile->currentText();
160 QStringList sProfile;
161 cProfile->clear();
162
163 sProfile += i18n("Very low");
164 sProfile += i18n("Low");
165 sProfile += i18n("Medium");
166 sProfile += i18n("High");
167 sProfile += i18n("Very high");
168 sProfile += i18n("Lossless");
169 // sProfile += i18n("Hybrid"); // currently unused
170 sProfile += config->customProfiles();
171 sProfile += i18n("User defined");
172 cProfile->addItems( sProfile );
173
174 if( cProfile->findText(lastProfile) != -1 )
175 {
176 cProfile->setCurrentIndex( cProfile->findText(lastProfile) );
177 }
178 else
179 {
180 profileChanged();
181 }
182 }
183
profileInfo()184 void OptionsSimple::profileInfo()
185 {
186 const QString sProfileString = cProfile->currentText();
187
188 QString info;
189
190 if( sProfileString == i18n("Very low") )
191 {
192 info = i18n("Encoding files with a very low quality can be useful if you have a mobile device where your storage space is limited.\nIt is not recommended to save your music in this quality without a copy of higher quality.");
193 }
194 else if( sProfileString == i18n("Low") )
195 {
196 info = i18n("Encoding files with a low quality can be useful if you have a mobile device where your storage space is limited.\nIt is not recommended to save your music in this quality without a copy of higher quality.");
197 }
198 else if( sProfileString == i18n("Medium") )
199 {
200 info = i18n("Encoding files with a medium quality is a compromise between quality and file size.\nMost people might not hear much of a difference to the original files but you should only use it to save music if your storage space is limited.");
201 }
202 else if( sProfileString == i18n("High") )
203 {
204 info = i18n("Encoding files with a high quality is a good choice if you have enough storage space available. You can use this to save your music.");
205 }
206 else if( sProfileString == i18n("Very high") )
207 {
208 info = i18n("Encoding files with a very high quality is fine if you have enough storage space.");
209 }
210 else if( sProfileString == i18n("Lossless") )
211 {
212 info = i18n("Encoding files lossless will preserve the quality of the original file.\nIt is only then useful if the original file has a good quality (e.g. audio CD).\nThe file size will be big, so you should only use it if you have enough storage space.");
213 }
214 else if( sProfileString == i18n("Hybrid") )
215 {
216 // info = i18n("This produces two files. One lossy compressed playable file and one correction file.\nBoth files together result in a file that is equivalent to the input file.");
217 }
218 else if( sProfileString == i18n("User defined") )
219 {
220 info = i18n("You can define your own profile in the \"Detailed\" tab.");
221 }
222 else // the info button is hidden when showing user defined profiles
223 {
224 info = i18n("This is a user defined profile.");
225 }
226
227 KMessageBox::information( this, info, i18n("Profile info for %1",sProfileString) );
228 }
229
profileRemove()230 void OptionsSimple::profileRemove()
231 {
232 const QString profileName = cProfile->currentText();
233
234 const int ret = KMessageBox::questionYesNo( this, i18n("Do you really want to remove the profile: %1").arg(profileName), i18n("Remove profile?") );
235 if( ret == KMessageBox::Yes )
236 {
237 QDomDocument list("soundkonverter_profilelist");
238
239 QFile listFile( KStandardDirs::locateLocal("data","soundkonverter/profiles.xml") );
240 if( listFile.open( QIODevice::ReadOnly ) )
241 {
242 if( list.setContent( &listFile ) )
243 {
244 QDomElement root = list.documentElement();
245 if( root.nodeName() == "soundkonverter" && root.attribute("type") == "profilelist" )
246 {
247 QDomElement profileElement;
248 QDomNodeList conversionOptionsElements = root.elementsByTagName("conversionOptions");
249 for( int i=0; i<conversionOptionsElements.count(); i++ )
250 {
251 if( conversionOptionsElements.at(i).toElement().attribute("profileName") == profileName )
252 {
253 delete config->data.profiles[profileName];
254 config->data.profiles.remove(profileName);
255 root.removeChild(conversionOptionsElements.at(i));
256 break;
257 }
258 }
259 }
260 }
261 listFile.close();
262 }
263
264 if( listFile.open( QIODevice::WriteOnly ) )
265 {
266 updateProfiles();
267 emit customProfilesEdited();
268
269 QTextStream stream(&listFile);
270 stream << list.toString();
271 listFile.close();
272 }
273 }
274 }
275
formatInfo()276 void OptionsSimple::formatInfo()
277 {
278 const QString format = cFormat->currentText();
279 const QString info = config->pluginLoader()->codecDescription(format);
280
281 if( !info.isEmpty() )
282 {
283 KMessageBox::information( this, info, i18n("Format info for %1",format), QString(), KMessageBox::Notify | KMessageBox::AllowLink );
284 }
285 else
286 {
287 KMessageBox::information( this, i18n("Sorry, no format information available.") );
288 }
289 }
290
profileChanged()291 void OptionsSimple::profileChanged()
292 {
293 const QString profile = cProfile->currentText();
294 const QString lastFormat = cFormat->currentText();
295 cFormat->clear();
296
297 pProfileRemove->hide();
298 pProfileInfo->show();
299
300 if( profile == i18n("Very low") || profile == i18n("Low") || profile == i18n("Medium") || profile == i18n("High") || profile == i18n("Very high") )
301 {
302 cFormat->addItems( config->pluginLoader()->formatList(PluginLoader::Encode,PluginLoader::Lossy) );
303 }
304 else if( profile == i18n("Lossless") )
305 {
306 cFormat->addItems( config->pluginLoader()->formatList(PluginLoader::Encode,PluginLoader::Lossless) );
307 }
308 else if( profile == i18n("Hybrid") )
309 {
310 cFormat->addItems( config->pluginLoader()->formatList(PluginLoader::Encode,PluginLoader::Hybrid) );
311 }
312 else if( profile == i18n("User defined") )
313 {
314 cFormat->addItems( config->pluginLoader()->formatList(PluginLoader::Encode,PluginLoader::CompressionType(PluginLoader::InferiorQuality|PluginLoader::Lossy|PluginLoader::Lossless|PluginLoader::Hybrid)) );
315 }
316 else
317 {
318 foreach( const QString& profileName, config->data.profiles.keys() )
319 {
320 if( profileName == profile )
321 {
322 const ConversionOptions *conversionOptions = config->data.profiles.value( profileName );
323 if( conversionOptions )
324 {
325 cFormat->addItem( conversionOptions->codecName );
326 outputDirectory->setMode( (OutputDirectory::Mode)conversionOptions->outputDirectoryMode );
327 outputDirectory->setDirectory( conversionOptions->outputDirectory );
328 cReplayGain->setChecked( conversionOptions->replaygain );
329 pProfileRemove->show();
330 pProfileInfo->hide();
331 }
332 break;
333 }
334 }
335 }
336
337 if( cFormat->findText(lastFormat) != -1 )
338 {
339 cFormat->setCurrentIndex( cFormat->findText(lastFormat) );
340 }
341
342 somethingChanged();
343 }
344
345 // void OptionsSimple::formatChanged()
346 // {
347 // QStringList errorList;
348 // cReplayGain->setEnabled( config->pluginLoader()->canReplayGain(cFormat->currentText(),currentPlugin,&errorList) );
349 // if( !cReplayGain->isEnabled() )
350 // {
351 // if( !errorList.isEmpty() )
352 // {
353 // errorList.prepend( i18n("Replay Gain is not supported for the %1 file format.\nPossible solutions are listed below.",cFormat->currentText()) );
354 // }
355 // else
356 // {
357 // errorList += i18n("Replay Gain is not supported for the %1 file format.\nPlease check your distribution's package manager in order to install an additional Replay Gain plugin.",cFormat->currentText());
358 // }
359 // cReplayGain->setToolTip( errorList.join("\n\n") );
360 // }
361 // else
362 // {
363 // cReplayGain->setToolTip( "" );
364 // }
365 // }
366
outputDirectoryChanged()367 void OptionsSimple::outputDirectoryChanged()
368 {
369 const QString profileName = cProfile->currentText();
370 const ConversionOptions *conversionOptions = config->data.profiles.value( profileName );
371 if( conversionOptions )
372 {
373 if( conversionOptions->outputDirectoryMode != outputDirectory->mode() || conversionOptions->outputDirectory != outputDirectory->directory() )
374 {
375 cProfile->setCurrentIndex( cProfile->findText(i18n("User defined")) );
376 profileChanged();
377 }
378 }
379 }
380
somethingChanged()381 void OptionsSimple::somethingChanged()
382 {
383 emit optionsChanged();
384 }
385
currentDataRateChanged(int dataRate)386 void OptionsSimple::currentDataRateChanged( int dataRate )
387 {
388 if( dataRate > 0 )
389 {
390 const QString dataRateString = Global::prettyNumber(dataRate,"B");
391 lEstimSize->setText( QString(QChar(8776))+" "+dataRateString+" / min." );
392 lEstimSize->setToolTip( i18n("Using the current conversion options will create files with approximately %1 per minute.").arg(dataRateString) );
393 }
394 else
395 {
396 lEstimSize->setText( QString(QChar(8776))+" ? B / min." );
397 lEstimSize->setToolTip( "" );
398 }
399 }
400
setCurrentProfile(const QString & profile)401 void OptionsSimple::setCurrentProfile( const QString& profile )
402 {
403 // TODO check profile (and don't change, if not available)
404 cProfile->setCurrentIndex( cProfile->findText(profile) );
405 profileChanged();
406 }
407
setCurrentFormat(const QString & format)408 void OptionsSimple::setCurrentFormat( const QString& format )
409 {
410 cFormat->setCurrentIndex( cFormat->findText(format) );
411 // formatChanged();
412 }
413
setCurrentOutputDirectory(const QString & directory)414 void OptionsSimple::setCurrentOutputDirectory( const QString& directory )
415 {
416 outputDirectory->setDirectory( directory );
417 outputDirectoryChanged();
418 }
419
setCurrentOutputDirectoryMode(int mode)420 void OptionsSimple::setCurrentOutputDirectoryMode( int mode )
421 {
422 outputDirectory->setMode( (OutputDirectory::Mode)mode );
423 outputDirectoryChanged();
424 }
425
showHelp()426 void OptionsSimple::showHelp()
427 {
428 QList<CodecProblems::Problem> problemList;
429 QMap<QString,QStringList> problems = config->pluginLoader()->encodeProblems();
430 for( int i=0; i<problems.count(); i++ )
431 {
432 CodecProblems::Problem problem;
433 problem.codecName = problems.keys().at(i);
434 if( problem.codecName != "wav" )
435 {
436 problem.solutions = problems.value(problem.codecName);
437 problemList += problem;
438 }
439 }
440 CodecProblems *problemsDialog = new CodecProblems( CodecProblems::Debug, problemList, this );
441 problemsDialog->exec();
442 }
443