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