1 /*
2     SPDX-FileCopyrightText: 2004-2009 Sebastian Trueg <trueg@k3b.org>
3     SPDX-FileCopyrightText: 2009-2011 Michal Malek <michalm@jabster.pl>
4     SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org>
5 
6     SPDX-License-Identifier: GPL-2.0-or-later
7 */
8 
9 #include "k3baudioconvertingoptionwidget.h"
10 
11 #include "k3bpluginmanager.h"
12 #include "k3baudioencoder.h"
13 #include "k3bcore.h"
14 
15 #include <KComboBox>
16 #include <KConfig>
17 #include <KColorScheme>
18 #include <KLocalizedString>
19 #include <KDiskFreeSpaceInfo>
20 #include <KUrlRequester>
21 #include <KIconLoader>
22 
23 #include <QCheckBox>
24 #include <QLabel>
25 #include <QList>
26 #include <QStandardPaths>
27 #include <QTimer>
28 #include <QToolButton>
29 
30 
31 
32 class K3b::AudioConvertingOptionWidget::Private
33 {
34 public:
35     QList<AudioEncoder*> encoders;
36     QList<QString> extensions;
37 
38     QTimer freeSpaceUpdateTimer;
39 
40     KIO::filesize_t neededSize;
41 
42     AudioEncoder* encoderForIndex( int index ) const;
43     QString pluginNameForIndex( int index ) const;
44     QString extForIndex( int index ) const;
45     int indexForFileType( const QString& pluginName, const QString& ext ) const;
46 
47     QString defaultPluginName() const;
48     QString defaultExtension() const;
49 };
50 
51 
encoderForIndex(int index) const52 K3b::AudioEncoder* K3b::AudioConvertingOptionWidget::Private::encoderForIndex( int index ) const
53 {
54     if( index >= 0 && index < encoders.size() )
55         return encoders.at( index );
56     else
57         return 0;
58 }
59 
60 
pluginNameForIndex(int index) const61 QString K3b::AudioConvertingOptionWidget::Private::pluginNameForIndex( int index ) const
62 {
63     if( AudioEncoder* encoder = encoderForIndex( index ) )
64         return encoder->pluginInfo().pluginName();
65     else
66         return QString();
67 }
68 
69 
extForIndex(int index) const70 QString K3b::AudioConvertingOptionWidget::Private::extForIndex( int index ) const
71 {
72     if( index >= 0 && index < extensions.size() )
73         return extensions.at( index );
74     else
75         return "wav";
76 }
77 
78 
indexForFileType(const QString & pluginName,const QString & ext) const79 int K3b::AudioConvertingOptionWidget::Private::indexForFileType( const QString& pluginName, const QString& ext ) const
80 {
81     if( pluginName.isEmpty() ) {
82         int i = extensions.indexOf( ext );
83         if( i >= 0 )
84             return i;
85     }
86 
87     for( int i = 0; i < encoders.size(); ++i ) {
88         AudioEncoder* encoder = encoders.at( i );
89         if( encoder != 0 &&
90             encoder->pluginInfo().pluginName() == pluginName &&
91             extensions.at( i ) == ext ) {
92             return i;
93         }
94     }
95     return 0;
96 }
97 
98 
defaultPluginName() const99 QString K3b::AudioConvertingOptionWidget::Private::defaultPluginName() const
100 {
101     QString defaultExt = defaultExtension();
102     for( int i = 0; i < extensions.size(); ++i ) {
103         AudioEncoder* encoder = encoders.at( i );
104         if( extensions.at( i ) == defaultExt && encoder != 0 ) {
105             return encoder->pluginInfo().pluginName();
106         }
107     }
108     return QString();
109 }
110 
111 
defaultExtension() const112 QString K3b::AudioConvertingOptionWidget::Private::defaultExtension() const
113 {
114     // we prefer formats in this order:
115     // 1. ogg
116     // 2. mp3
117     // 3. flac
118     // 4. wave
119     bool ogg = false;
120     bool mp3 = false;
121     bool flac = false;
122     Q_FOREACH( const QString& ext, extensions ) {
123         if( ext == "ogg" )
124             ogg = true;
125         else if( ext == "mp3" )
126             mp3 = true;
127         else if( ext == "flac" )
128             flac = true;
129     }
130 
131     if( ogg )
132         return "ogg";
133     else if( mp3 )
134         return "mp3";
135     else if( flac )
136         return "flac";
137     else
138         return "wav";
139 }
140 
141 
AudioConvertingOptionWidget(QWidget * parent)142 K3b::AudioConvertingOptionWidget::AudioConvertingOptionWidget( QWidget* parent )
143     : QWidget( parent )
144 {
145     setupUi( this );
146 
147     d = new Private();
148 
149     connect( m_editBaseDir, SIGNAL(textChanged(QString)),
150              this, SLOT(slotUpdateFreeTempSpace()) );
151     connect( m_comboFileType, SIGNAL(activated(int)),
152              this, SLOT(slotEncoderChanged()) );
153     connect( &d->freeSpaceUpdateTimer, SIGNAL(timeout()),
154              this, SLOT(slotUpdateFreeTempSpace()) );
155     connect( m_checkCreatePlaylist, SIGNAL(toggled(bool)), this, SIGNAL(changed()) );
156     connect( m_checkSingleFile, SIGNAL(toggled(bool)), this, SIGNAL(changed()) );
157     connect( m_checkWriteCueFile, SIGNAL(toggled(bool)), this, SIGNAL(changed()) );
158     connect( m_comboFileType, SIGNAL(activated(int)), this, SIGNAL(changed()) );
159     connect( m_editBaseDir, SIGNAL(textChanged(QString)), this, SIGNAL(changed()) );
160     connect( m_buttonConfigurePlugin, SIGNAL(clicked()), this, SLOT(slotConfigurePlugin()) );
161 
162     m_editBaseDir->setMode( KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly );
163     m_buttonConfigurePlugin->setIcon( QIcon::fromTheme( "configure" ) );
164 
165     // FIXME: see if sox and the sox encoder are installed and if so do not put the internal wave
166     //        writer in the list of encoders.
167     m_comboFileType->addItem( i18n("Wave") );
168     d->encoders.append( 0 );
169     d->extensions.append( "wav" );
170 
171     // check the available encoding plugins
172     QList<K3b::Plugin*> fl = k3bcore->pluginManager()->plugins( "AudioEncoder" );
173     for( QList<K3b::Plugin *>::const_iterator it = fl.constBegin(); it != fl.constEnd(); ++it ) {
174         if( AudioEncoder* encoder = qobject_cast<AudioEncoder*>( *it ) ) {
175             QStringList ext = encoder->extensions();
176 
177             for( QStringList::const_iterator exIt = ext.constBegin();
178                 exIt != ext.constEnd(); ++exIt ) {
179                 m_comboFileType->addItem( encoder->fileTypeComment(*exIt) );
180                 d->encoders.append( encoder );
181                 d->extensions.append( *exIt );
182             }
183         }
184     }
185 
186     // refresh every 2 seconds
187     d->freeSpaceUpdateTimer.start(2000);
188     slotUpdateFreeTempSpace();
189 }
190 
191 
~AudioConvertingOptionWidget()192 K3b::AudioConvertingOptionWidget::~AudioConvertingOptionWidget()
193 {
194     delete d;
195 }
196 
197 
baseDir() const198 QString K3b::AudioConvertingOptionWidget::baseDir() const
199 {
200     return m_editBaseDir->url().toLocalFile();
201 }
202 
203 
setBaseDir(const QString & path)204 void K3b::AudioConvertingOptionWidget::setBaseDir( const QString& path )
205 {
206     m_editBaseDir->setUrl( QUrl::fromLocalFile( path ) );
207 }
208 
209 
setNeededSize(KIO::filesize_t size)210 void K3b::AudioConvertingOptionWidget::setNeededSize( KIO::filesize_t size )
211 {
212     d->neededSize = size;
213     if( d->neededSize > 0 )
214         m_labelNeededSpace->setText( KIO::convertSize( d->neededSize ) );
215     else
216         m_labelNeededSpace->setText( i18n("unknown") );
217 
218     slotUpdateFreeTempSpace();
219 }
220 
221 
slotConfigurePlugin()222 void K3b::AudioConvertingOptionWidget::slotConfigurePlugin()
223 {
224     // 0 for wave
225     if( AudioEncoder* enc = encoder() )
226     {
227         int ret = k3bcore->pluginManager()->execPluginDialog( enc, this );
228         if( ret == QDialog::Accepted )
229         {
230             emit changed();
231         }
232     }
233 }
234 
235 
slotUpdateFreeTempSpace()236 void K3b::AudioConvertingOptionWidget::slotUpdateFreeTempSpace()
237 {
238     KColorScheme::ForegroundRole textColor;
239 
240     KDiskFreeSpaceInfo diskInfo = KDiskFreeSpaceInfo::freeSpaceInfo( m_editBaseDir->url().toLocalFile() );
241     if( diskInfo.isValid() ) {
242         m_labelFreeSpace->setText( KIO::convertSize(diskInfo.available()) );
243 
244         if( d->neededSize > diskInfo.available() )
245             textColor = KColorScheme::NegativeText;
246         else
247             textColor = KColorScheme::NormalText;
248     }
249     else {
250         m_labelFreeSpace->setText( i18n("unknown") );
251         textColor = KColorScheme::NormalText;
252     }
253 
254     QPalette pal( m_labelFreeSpace->palette() );
255     pal.setBrush( QPalette::Disabled, QPalette::WindowText, KColorScheme( QPalette::Disabled, KColorScheme::Window ).foreground( textColor ) );
256     pal.setBrush( QPalette::Active,   QPalette::WindowText, KColorScheme( QPalette::Active,   KColorScheme::Window ).foreground( textColor ) );
257     pal.setBrush( QPalette::Inactive, QPalette::WindowText, KColorScheme( QPalette::Inactive, KColorScheme::Window ).foreground( textColor ) );
258     pal.setBrush( QPalette::Normal,   QPalette::WindowText, KColorScheme( QPalette::Normal,   KColorScheme::Window ).foreground( textColor ) );
259     m_labelFreeSpace->setPalette( pal );
260 }
261 
262 
slotEncoderChanged()263 void K3b::AudioConvertingOptionWidget::slotEncoderChanged()
264 {
265     if( Plugin* plugin = encoder() )
266         m_buttonConfigurePlugin->setEnabled( k3bcore->pluginManager()->hasPluginDialog( plugin ) );
267     else
268         m_buttonConfigurePlugin->setEnabled( false );
269 }
270 
271 
encoder() const272 K3b::AudioEncoder* K3b::AudioConvertingOptionWidget::encoder() const
273 {
274     return d->encoderForIndex( m_comboFileType->currentIndex() );  // 0 for wave
275 }
276 
277 
extension() const278 QString K3b::AudioConvertingOptionWidget::extension() const
279 {
280     return d->extForIndex( m_comboFileType->currentIndex() );
281 }
282 
283 
loadConfig(const KConfigGroup & c)284 void K3b::AudioConvertingOptionWidget::loadConfig( const KConfigGroup& c )
285 {
286     m_editBaseDir->setUrl( QUrl::fromLocalFile( c.readEntry( "last ripping directory", QStandardPaths::writableLocation(QStandardPaths::MusicLocation) ) ) );
287 
288     m_checkSingleFile->setChecked( c.readEntry( "single_file", false ) );
289     m_checkWriteCueFile->setChecked( c.readEntry( "write_cue_file", false ) );
290 
291     m_checkCreatePlaylist->setChecked( c.readEntry( "create_playlist", false ) );
292     m_checkPlaylistRelative->setChecked( c.readEntry( "relative_path_in_playlist", false ) );
293 
294     QString encoder;
295     QString filetype;
296     if( c.hasKey( "encoder" ) && c.hasKey( "filetype" ) ) {
297         encoder = c.readEntry( "encoder" );
298         filetype = c.readEntry( "filetype" );
299     }
300     else {
301         encoder = d->defaultPluginName();
302         filetype = d->defaultExtension();
303     }
304     m_comboFileType->setCurrentIndex( d->indexForFileType( encoder, filetype ) );
305 
306     slotEncoderChanged();
307 }
308 
309 
saveConfig(KConfigGroup c)310 void K3b::AudioConvertingOptionWidget::saveConfig( KConfigGroup c )
311 {
312     c.writePathEntry( "last ripping directory", m_editBaseDir->url().url() );
313 
314     c.writeEntry( "single_file", m_checkSingleFile->isChecked() );
315     c.writeEntry( "write_cue_file", m_checkWriteCueFile->isChecked() );
316 
317     c.writeEntry( "create_playlist", m_checkCreatePlaylist->isChecked() );
318     c.writeEntry( "relative_path_in_playlist", m_checkPlaylistRelative->isChecked() );
319 
320     c.writeEntry( "encoder", d->pluginNameForIndex( m_comboFileType->currentIndex() ) );
321     c.writeEntry( "filetype", d->extForIndex( m_comboFileType->currentIndex() ) );
322 }
323 
324 
325