1 //
2 // C++ Implementation: opener
3 //
4 // Description:
5 //
6 //
7 // Author: Daniel Faust <hessijames@gmail.com>, (C) 2008
8 //
9 // Copyright: See COPYING file that comes with this distribution
10 //
11 //
12 #include "playlistopener.h"
13 #include "../options.h"
14 #include "../config.h"
15 #include "../codecproblems.h"
16 
17 #include <QApplication>
18 #include <KLocale>
19 #include <KPushButton>
20 #include <QLabel>
21 #include <QLayout>
22 #include <QHBoxLayout>
23 #include <KMessageBox>
24 #include <KFileDialog>
25 #include <QDir>
26 #include <KIcon>
27 
28 
PlaylistOpener(Config * _config,QWidget * parent,Qt::WFlags f)29 PlaylistOpener::PlaylistOpener( Config *_config, QWidget *parent, Qt::WFlags f )
30     : KDialog( parent, f ),
31     dialogAborted( false ),
32     config( _config )
33 {
34     setCaption( i18n("Add playlist") );
35     setWindowIcon( KIcon("view-media-playlist") );
36     setButtons( 0 );
37 
38     const int fontHeight = QFontMetrics(QApplication::font()).boundingRect("M").size().height();
39 
40     QWidget *widget = new QWidget();
41     setMainWidget( widget );
42 
43     QGridLayout *mainGrid = new QGridLayout( widget );
44 
45     options = new Options( config, i18n("Select your desired output options and click on \"Ok\"."), widget );
46     mainGrid->addWidget( options, 1, 0 );
47 
48     // add a horizontal box layout for the control elements
49     QHBoxLayout *controlBox = new QHBoxLayout();
50     mainGrid->addLayout( controlBox, 2, 0 );
51     controlBox->addStretch();
52 
53     pAdd = new KPushButton( KIcon("dialog-ok"), i18n("Ok"), widget );
54     controlBox->addWidget( pAdd );
55     connect( pAdd, SIGNAL(clicked()), this, SLOT(okClickedSlot()) );
56     pCancel = new KPushButton( KIcon("dialog-cancel"), i18n("Cancel"), widget );
57     controlBox->addWidget( pCancel );
58     connect( pCancel, SIGNAL(clicked()), this, SLOT(reject()) );
59 
60     fileDialog = new KFileDialog( KUrl("kfiledialog:///soundkonverter-add-media"), "*.m3u", this );
61     fileDialog->setWindowTitle( i18n("Add Files") );
62     fileDialog->setMode( KFile::File | KFile::ExistingOnly );
63     connect( fileDialog, SIGNAL(accepted()), this, SLOT(fileDialogAccepted()) );
64     connect( fileDialog, SIGNAL(rejected()), this, SLOT(reject()) );
65     const int dialogReturnCode = fileDialog->exec();
66     if( dialogReturnCode == QDialog::Rejected )
67         dialogAborted = true;
68 
69         // Prevent the dialog from beeing too wide because of the directory history
70     if( parent && width() > parent->width() )
71         setInitialSize( QSize(parent->width()-fontHeight,sizeHint().height()) );
72     KSharedConfig::Ptr conf = KGlobal::config();
73     KConfigGroup group = conf->group( "PlaylistOpener" );
74     restoreDialogSize( group );
75 }
76 
~PlaylistOpener()77 PlaylistOpener::~PlaylistOpener()
78 {
79     KSharedConfig::Ptr conf = KGlobal::config();
80     KConfigGroup group = conf->group( "PlaylistOpener" );
81     saveDialogSize( group );
82 }
83 
fileDialogAccepted()84 void PlaylistOpener::fileDialogAccepted()
85 {
86     QStringList errorList;
87     //    codec    @0 files @1 solutions
88     QMap< QString, QList<QStringList> > problems;
89 //     QStringList messageList;
90     QString fileName;
91     QStringList filesNotFound;
92 
93     urls.clear();
94     KUrl playlistUrl = fileDialog->selectedUrl();
95     QFile playlistFile( playlistUrl.toLocalFile() );
96     if( playlistFile.open(QIODevice::ReadOnly) )
97     {
98         QTextStream stream(&playlistFile);
99         QString line;
100         do
101         {
102             line = stream.readLine();
103             if( !line.startsWith("#EXTM3U") && !line.startsWith("#EXTINF") && !line.isEmpty() )
104             {
105                 QUrl url(line);
106                 if( url.isRelative() ) url = QUrl( playlistUrl.path() + "/" + line );
107                 url = url.adjusted(QUrl::NormalizePathSegments);
108 
109                 if( !url.isLocalFile() || QFile::exists(url.toLocalFile()) ) urls += url;
110                 else filesNotFound += url.url(QUrl::PreferLocalFile);
111             }
112         } while( !line.isNull() );
113         playlistFile.close();
114     }
115 
116     const bool canDecodeAac = config->pluginLoader()->canDecode( "m4a/aac" );
117     const bool canDecodeAlac = config->pluginLoader()->canDecode( "m4a/alac" );
118     const bool checkM4a = ( !canDecodeAac || !canDecodeAlac ) && canDecodeAac != canDecodeAlac;
119 
120     for( int i=0; i<urls.count(); i++ )
121     {
122         QString mimeType;
123         QString codecName = config->pluginLoader()->getCodecFromFile( urls.at(i), &mimeType, checkM4a );
124 
125         if( !config->pluginLoader()->canDecode(codecName,&errorList) )
126         {
127             fileName = urls.at(i).url(QUrl::PreferLocalFile);
128 
129             if( codecName.isEmpty() )
130                 codecName = mimeType;
131             if( codecName.isEmpty() )
132                 codecName = fileName.right(fileName.length()-fileName.lastIndexOf(".")-1);
133 
134             if( problems.value(codecName).count() < 2 )
135             {
136                 problems[codecName] += QStringList();
137                 problems[codecName] += QStringList();
138             }
139             problems[codecName][0] += fileName;
140             if( !errorList.isEmpty() )
141             {
142                 problems[codecName][1] += errorList;
143             }
144             else
145             {
146                 problems[codecName][1] += i18n("This file type is unknown to soundKonverter.\nMaybe you need to install an additional soundKonverter plugin.\nYou should have a look at your distribution's package manager for this.");
147             }
148             urls.removeAt(i);
149             i--;
150         }
151     }
152 
153     QList<CodecProblems::Problem> problemList;
154     for( int i=0; i<problems.count(); i++ )
155     {
156         CodecProblems::Problem problem;
157         problem.codecName = problems.keys().at(i);
158         if( problem.codecName != "wav" )
159         {
160             #if QT_VERSION >= 0x040500
161                 problems[problem.codecName][1].removeDuplicates();
162             #else
163                 QStringList found;
164                 for( int j=0; j<problems.value(problem.codecName).at(1).count(); j++ )
165                 {
166                     if( found.contains(problems.value(problem.codecName).at(1).at(j)) )
167                     {
168                         problems[problem.codecName][1].removeAt(j);
169                         j--;
170                     }
171                     else
172                     {
173                         found += problems.value(problem.codecName).at(1).at(j);
174                     }
175                 }
176             #endif
177             problem.solutions = problems.value(problem.codecName).at(1);
178             if( problems.value(problem.codecName).at(0).count() <= 3 )
179             {
180                 problem.affectedFiles = problems.value(problem.codecName).at(0);
181             }
182             else
183             {
184                 problem.affectedFiles += problems.value(problem.codecName).at(0).at(0);
185                 problem.affectedFiles += problems.value(problem.codecName).at(0).at(1);
186                 problem.affectedFiles += i18n("... and %1 more files",problems.value(problem.codecName).at(0).count()-2);
187             }
188             problemList += problem;
189 //             messageList += "<b>Possible solutions for " + codecName + "</b>:\n" + problems.value(codecName).at(1).join("\n<b>or</b>\n") + i18n("\n\nAffected files:\n") + affectedFiles.join("\n");
190         }
191     }
192 
193     if( problemList.count() > 0 )
194     {
195         CodecProblems *problemsDialog = new CodecProblems( CodecProblems::Decode, problemList, this );
196         problemsDialog->exec();
197     }
198 
199 //     if( !messageList.isEmpty() )
200 //     {
201 //         messageList.prepend( i18n("Some files can't be decoded.\nPossible solutions are listed below.") );
202 //         QMessageBox *messageBox = new QMessageBox( this );
203 //         messageBox->setIcon( QMessageBox::Information );
204 //         messageBox->setWindowTitle( i18n("Missing backends") );
205 //         messageBox->setText( messageList.join("\n\n").replace("\n","<br>") );
206 //         messageBox->setTextFormat( Qt::RichText );
207 //         messageBox->exec();
208 //     }
209 
210     if( !filesNotFound.isEmpty() )
211     {
212         int filesNotFoundCount = filesNotFound.count();
213         if( filesNotFoundCount > 5 )
214         {
215             do {
216                 filesNotFound.removeLast();
217             } while( filesNotFound.count() >= 5 );
218             filesNotFound += i18n("... and %1 more files",filesNotFoundCount-4);
219         }
220         filesNotFound.prepend( i18n("The following files couldn't be found:\n") );
221         QMessageBox *messageBox = new QMessageBox( this );
222         messageBox->setIcon( QMessageBox::Information );
223         messageBox->setWindowTitle( i18n("Files not found") );
224         messageBox->setText( filesNotFound.join("\n").replace("\n","<br>") );
225         messageBox->setTextFormat( Qt::RichText );
226         messageBox->exec();
227     }
228 
229     if( urls.count() <= 0 ) reject();
230 }
231 
okClickedSlot()232 void PlaylistOpener::okClickedSlot()
233 {
234     ConversionOptions *conversionOptions = options->currentConversionOptions();
235     if( conversionOptions )
236     {
237         options->accepted();
238         emit openFiles( urls, conversionOptions );
239         accept();
240     }
241     else
242     {
243         KMessageBox::error( this, i18n("No conversion options selected.") );
244     }
245 }
246