1 /**
2 This file belong to the KMPlayer project, a movie player plugin for Konqueror
3 Copyright (C) 2009 Koos Vriezen <koos.vriezen@gmail.com>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library 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 GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 **/
19
20 #include <qfile.h>
21 #include <qurl.h>
22 #include <qtextstream.h>
23 #include <qbytearray.h>
24 #include <qinputdialog.h>
25 #include <QStandardPaths>
26
27 #include <kfiledialog.h>
28 #include <ksharedconfig.h>
29 #include <klocale.h>
30 #include <kdebug.h>
31
32 #include "kmplayer_lists.h"
33 #include "kmplayer.h"
34 #include "mediaobject.h"
35
36
play(KMPlayer::Mrl * mrl)37 KDE_NO_EXPORT void ListsSource::play (KMPlayer::Mrl *mrl) {
38 if (m_player->source () == this)
39 Source::play (mrl);
40 else if (mrl)
41 mrl->activate ();
42 }
43
activate()44 KDE_NO_EXPORT void ListsSource::activate () {
45 activated = true;
46 play (m_current ? m_current->mrl () : NULL);
47 }
48
prettyName()49 QString ListsSource::prettyName ()
50 {
51 return ((KMPlayer::PlaylistRole *)m_document->role (KMPlayer::RolePlaylist))->caption ();
52 }
53
FileDocument(short i,const QString & s,KMPlayer::Source * src)54 KDE_NO_CDTOR_EXPORT FileDocument::FileDocument (short i, const QString &s, KMPlayer::Source *src)
55 : KMPlayer::SourceDocument (src, s), load_tree_version ((unsigned int)-1) {
56 id = i;
57 }
58
childFromTag(const QString & tag)59 KDE_NO_EXPORT KMPlayer::Node *FileDocument::childFromTag(const QString &tag) {
60 if (tag == QString::fromLatin1 (nodeName ()))
61 return this;
62 return 0L;
63 }
64
readFromFile(const QString & fn)65 void FileDocument::readFromFile (const QString & fn) {
66 QFile file (fn);
67 kDebug () << "readFromFile " << fn;
68 if (QFileInfo (file).exists ()) {
69 file.open (QIODevice::ReadOnly);
70 QTextStream inxml (&file);
71 inxml.setCodec("UTF-8");
72 KMPlayer::readXML (this, inxml, QString (), false);
73 normalize ();
74 }
75 load_tree_version = m_tree_version;
76 }
77
writeToFile(const QString & fn)78 void FileDocument::writeToFile (const QString & fn) {
79 QFile file (fn);
80 kDebug () << "writeToFile " << fn;
81 file.open (QIODevice::WriteOnly | QIODevice::Truncate);
82 file.write (outerXML ().toUtf8 ());
83 load_tree_version = m_tree_version;
84 }
85
sync(const QString & fn)86 void FileDocument::sync (const QString &fn)
87 {
88 if (resolved && load_tree_version != m_tree_version)
89 writeToFile (fn);
90 }
91
Recents(KMPlayerApp * a)92 KDE_NO_CDTOR_EXPORT Recents::Recents (KMPlayerApp *a)
93 : FileDocument (id_node_recent_document, "recents://"),
94 app(a) {
95 title = i18n ("Most Recent");
96 bookmarkable = false;
97 }
98
activate()99 KDE_NO_EXPORT void Recents::activate () {
100 if (!resolved)
101 defer ();
102 }
103
defer()104 KDE_NO_EXPORT void Recents::defer () {
105 if (!resolved) {
106 resolved = true;
107 readFromFile(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/recent.xml");
108 }
109 }
110
childFromTag(const QString & tag)111 KDE_NO_EXPORT KMPlayer::Node *Recents::childFromTag (const QString & tag) {
112 // kDebug () << nodeName () << " childFromTag " << tag;
113 if (tag == QString::fromLatin1 ("item"))
114 return new Recent (m_doc, app);
115 else if (tag == QString::fromLatin1 ("group"))
116 return new Group (m_doc, app);
117 return FileDocument::childFromTag (tag);
118 }
119
message(KMPlayer::MessageType msg,void * data)120 KDE_NO_EXPORT void Recents::message (KMPlayer::MessageType msg, void *data) {
121 if (KMPlayer::MsgChildFinished == msg)
122 finish ();
123 else
124 FileDocument::message (msg, data);
125 }
126
127 KDE_NO_CDTOR_EXPORT
Recent(KMPlayer::NodePtr & doc,KMPlayerApp * a,const QString & url)128 Recent::Recent (KMPlayer::NodePtr & doc, KMPlayerApp * a, const QString &url)
129 : KMPlayer::Mrl (doc, id_node_recent_node), app (a) {
130 src = url;
131 setAttribute (KMPlayer::Ids::attr_url, url);
132 }
133
closed()134 KDE_NO_EXPORT void Recent::closed () {
135 src = getAttribute (KMPlayer::Ids::attr_url);
136 Mrl::closed ();
137 }
138
activate()139 KDE_NO_EXPORT void Recent::activate () {
140 app->openDocumentFile (KUrl (src));
141 }
142
143 KDE_NO_CDTOR_EXPORT
Group(KMPlayer::NodePtr & doc,KMPlayerApp * a,const QString & pn)144 Group::Group (KMPlayer::NodePtr & doc, KMPlayerApp * a, const QString & pn)
145 : KMPlayer::Element (doc, KMPlayer::id_node_group_node), app (a) {
146 title = pn;
147 if (!pn.isEmpty ())
148 setAttribute (KMPlayer::Ids::attr_title, pn);
149 }
150
childFromTag(const QString & tag)151 KDE_NO_EXPORT KMPlayer::Node *Group::childFromTag (const QString & tag) {
152 if (tag == QString::fromLatin1 ("item"))
153 return new Recent (m_doc, app);
154 else if (tag == QString::fromLatin1 ("group"))
155 return new Group (m_doc, app);
156 return 0L;
157 }
158
closed()159 KDE_NO_EXPORT void Group::closed () {
160 title = getAttribute (KMPlayer::Ids::attr_title);
161 Element::closed ();
162 }
163
role(KMPlayer::RoleType msg,void * content)164 void *Group::role (KMPlayer::RoleType msg, void *content)
165 {
166 if (KMPlayer::RolePlaylist == msg)
167 return (KMPlayer::PlaylistRole *) this ;
168 return Element::role (msg, content);
169 }
170
defer()171 KDE_NO_EXPORT void Playlist::defer () {
172 if (playmode) {
173 KMPlayer::Document::defer ();
174 // Hack: Node::undefer will restart first item when state=init
175 if (firstChild() && KMPlayer::Node::state_init == firstChild()->state)
176 firstChild()->state = KMPlayer::Node::state_activated;
177 } else if (!resolved) {
178 resolved = true;
179 readFromFile(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/playlist.xml");
180 }
181 }
182
activate()183 KDE_NO_EXPORT void Playlist::activate () {
184 if (playmode)
185 KMPlayer::Document::activate ();
186 else if (!resolved)
187 defer ();
188 }
189
Playlist(KMPlayerApp * a,KMPlayer::Source * s,bool plmode)190 KDE_NO_CDTOR_EXPORT Playlist::Playlist (KMPlayerApp *a, KMPlayer::Source *s, bool plmode)
191 : FileDocument (KMPlayer::id_node_playlist_document, "Playlist://", s),
192 app(a),
193 playmode (plmode) {
194 title = i18n ("Persistent Playlists");
195 bookmarkable = false;
196 }
197
childFromTag(const QString & tag)198 KDE_NO_EXPORT KMPlayer::Node *Playlist::childFromTag (const QString & tag) {
199 // kDebug () << nodeName () << " childFromTag " << tag;
200 QByteArray ba = tag.toUtf8 ();
201 const char *name = ba.constData ();
202 if (!strcmp (name, "item"))
203 return new PlaylistItem (m_doc, app, playmode);
204 else if (!strcmp (name, "group"))
205 return new PlaylistGroup (m_doc, app, playmode);
206 else if (!strcmp (name, "object"))
207 return new HtmlObject (m_doc, app, playmode);
208 return FileDocument::childFromTag (tag);
209 }
210
message(KMPlayer::MessageType msg,void * data)211 KDE_NO_EXPORT void Playlist::message (KMPlayer::MessageType msg, void *data) {
212 if (KMPlayer::MsgChildFinished == msg && !playmode)
213 finish ();
214 else
215 FileDocument::message (msg, data);
216 }
217
218 KDE_NO_CDTOR_EXPORT
PlaylistItemBase(KMPlayer::NodePtr & d,short i,KMPlayerApp * a,bool pm)219 PlaylistItemBase::PlaylistItemBase (KMPlayer::NodePtr &d, short i, KMPlayerApp *a, bool pm)
220 : KMPlayer::Mrl (d, i), app (a), playmode (pm) {
221 editable = !pm;
222 }
223
activate()224 KDE_NO_EXPORT void PlaylistItemBase::activate () {
225 if (playmode) {
226 Mrl::activate ();
227 } else {
228 ListsSource * source = static_cast <ListsSource *> (app->player ()->sources () ["listssource"]);
229 Playlist *pl = new Playlist (app, source, true);
230 KMPlayer::NodePtr n = pl;
231 pl->src.clear ();
232 QString data;
233 QString pn;
234 if (parentNode ()->id == KMPlayer::id_node_group_node) {
235 data = QString ("<playlist>") +
236 parentNode ()->innerXML () +
237 QString ("</playlist>");
238 pn = ((KMPlayer::PlaylistRole *)parentNode ()->role (KMPlayer::RolePlaylist))->caption ();
239 } else {
240 data = outerXML ();
241 pn = title.isEmpty () ? src : title;
242 }
243 pl->setCaption (pn);
244 //kDebug () << "cloning to " << data;
245 QTextStream inxml (&data, QIODevice::ReadOnly);
246 KMPlayer::readXML (pl, inxml, QString (), false);
247 pl->normalize ();
248 KMPlayer::Node *cur = pl->firstChild ();
249 pl->mrl ()->resolved = !!cur;
250 if (parentNode ()->id == KMPlayer::id_node_group_node && cur) {
251 KMPlayer::Node *sister = parentNode ()->firstChild ();
252 while (sister && cur && sister != this) {
253 sister = sister->nextSibling ();
254 cur = cur->nextSibling ();
255 }
256 }
257 bool reset_only = source == app->player ()->source ();
258 if (reset_only)
259 app->player ()->stop ();
260 source->setDocument (pl, cur);
261 if (reset_only) {
262 source->activate ();
263 app->setCaption (pn);
264 } else
265 app->player ()->setSource (source);
266 }
267 }
268
closed()269 void PlaylistItemBase::closed () {
270 title = getAttribute (KMPlayer::Ids::attr_title);
271 Mrl::closed ();
272 }
273
274 KDE_NO_CDTOR_EXPORT
PlaylistItem(KMPlayer::NodePtr & doc,KMPlayerApp * a,bool pm,const QString & url)275 PlaylistItem::PlaylistItem (KMPlayer::NodePtr & doc, KMPlayerApp *a, bool pm, const QString &url)
276 : PlaylistItemBase (doc, KMPlayer::id_node_playlist_item, a, pm) {
277 src = url;
278 setAttribute (KMPlayer::Ids::attr_url, url);
279 }
280
closed()281 KDE_NO_EXPORT void PlaylistItem::closed () {
282 src = getAttribute (KMPlayer::Ids::attr_url);
283 PlaylistItemBase::closed ();
284 }
285
begin()286 KDE_NO_EXPORT void PlaylistItem::begin () {
287 if (playmode && firstChild ())
288 firstChild ()->activate ();
289 else
290 Mrl::begin ();
291 }
292
setNodeName(const QString & s)293 KDE_NO_EXPORT void PlaylistItem::setNodeName (const QString & s) {
294 bool uri = s.startsWith (QChar ('/'));
295 if (!uri) {
296 int p = s.indexOf ("://");
297 uri = p > 0 && p < 10;
298 }
299 if (uri) {
300 if (title.isEmpty () || title == src)
301 title = s;
302 src = s;
303 setAttribute (KMPlayer::Ids::attr_url, s);
304 } else {
305 title = s;
306 setAttribute (KMPlayer::Ids::attr_title, s);
307 }
308 }
309
310 KDE_NO_CDTOR_EXPORT
PlaylistGroup(KMPlayer::NodePtr & doc,KMPlayerApp * a,const QString & pn)311 PlaylistGroup::PlaylistGroup (KMPlayer::NodePtr &doc, KMPlayerApp *a, const QString &pn)
312 : KMPlayer::Element (doc, KMPlayer::id_node_group_node), app (a), playmode (false) {
313 title = pn;
314 editable = true;
315 if (!pn.isEmpty ())
316 setAttribute (KMPlayer::Ids::attr_title, pn);
317 }
318
319 KDE_NO_CDTOR_EXPORT
PlaylistGroup(KMPlayer::NodePtr & doc,KMPlayerApp * a,bool lm)320 PlaylistGroup::PlaylistGroup (KMPlayer::NodePtr &doc, KMPlayerApp *a, bool lm)
321 : KMPlayer::Element (doc, KMPlayer::id_node_group_node), app (a), playmode (lm) {
322 editable = !lm;
323 }
324
childFromTag(const QString & tag)325 KDE_NO_EXPORT KMPlayer::Node *PlaylistGroup::childFromTag (const QString &tag) {
326 QByteArray ba = tag.toUtf8 ();
327 const char *name = ba.constData ();
328 if (!strcmp (name, "item"))
329 return new PlaylistItem (m_doc, app, playmode);
330 else if (!strcmp (name, "group"))
331 return new PlaylistGroup (m_doc, app, playmode);
332 else if (!strcmp (name, "object"))
333 return new HtmlObject (m_doc, app, playmode);
334 return 0L;
335 }
336
closed()337 KDE_NO_EXPORT void PlaylistGroup::closed () {
338 title = getAttribute (KMPlayer::Ids::attr_title);
339 Element::closed ();
340 }
341
setNodeName(const QString & t)342 KDE_NO_EXPORT void PlaylistGroup::setNodeName (const QString &t) {
343 title = t;
344 setAttribute (KMPlayer::Ids::attr_title, t);
345 }
346
role(KMPlayer::RoleType msg,void * content)347 void *PlaylistGroup::role (KMPlayer::RoleType msg, void *content)
348 {
349 if (KMPlayer::RolePlaylist == msg)
350 return (KMPlayer::PlaylistRole *) this ;
351 return Element::role (msg, content);
352 }
353
354 KDE_NO_CDTOR_EXPORT
HtmlObject(KMPlayer::NodePtr & doc,KMPlayerApp * a,bool pm)355 HtmlObject::HtmlObject (KMPlayer::NodePtr &doc, KMPlayerApp *a, bool pm)
356 : PlaylistItemBase (doc, KMPlayer::id_node_html_object, a, pm) {}
357
activate()358 KDE_NO_EXPORT void HtmlObject::activate () {
359 if (playmode)
360 KMPlayer::Mrl::activate ();
361 else
362 PlaylistItemBase::activate ();
363 }
364
closed()365 KDE_NO_EXPORT void HtmlObject::closed () {
366 for (Node *n = firstChild (); n; n = n->nextSibling ()) {
367 if (n->id == KMPlayer::id_node_param) {
368 KMPlayer::Element *e = static_cast <KMPlayer::Element *> (n);
369 QString name = e->getAttribute (KMPlayer::Ids::attr_name);
370 if (name == "type")
371 mimetype = e->getAttribute (KMPlayer::Ids::attr_value);
372 else if (name == "movie")
373 src = e->getAttribute (KMPlayer::Ids::attr_value);
374 } else if (n->id == KMPlayer::id_node_html_embed) {
375 KMPlayer::Element *e = static_cast <KMPlayer::Element *> (n);
376 QString type = e->getAttribute (KMPlayer::Ids::attr_type);
377 if (!type.isEmpty ())
378 mimetype = type;
379 QString asrc = e->getAttribute (KMPlayer::Ids::attr_src);
380 if (!asrc.isEmpty ())
381 src = asrc;
382 }
383 }
384 PlaylistItemBase::closed ();
385 }
386
childFromTag(const QString & tag)387 KDE_NO_EXPORT KMPlayer::Node *HtmlObject::childFromTag (const QString & tag) {
388 QByteArray ba = tag.toUtf8 ();
389 const char *name = ba.constData ();
390 if (!strcasecmp (name, "param"))
391 return new KMPlayer::DarkNode (m_doc, name, KMPlayer::id_node_param);
392 else if (!strcasecmp (name, "embed"))
393 return new KMPlayer::DarkNode(m_doc, name,KMPlayer::id_node_html_embed);
394 return NULL;
395 }
396
Generator(KMPlayerApp * a)397 Generator::Generator (KMPlayerApp *a)
398 : FileDocument (id_node_gen_document, QString (),
399 a->player ()->sources () ["listssource"]),
400 app (a), qprocess (NULL), data (NULL)
401 {}
402
childFromTag(const QString & tag)403 KMPlayer::Node *Generator::childFromTag (const QString &tag) {
404 QByteArray ba = tag.toUtf8();
405 const char *ctag = ba.constData ();
406 if (!strcmp (ctag, "generator"))
407 return new GeneratorElement (m_doc, tag, id_node_gen_generator);
408 return NULL;
409 }
410
genReadAsk(KMPlayer::Node * n)411 QString Generator::genReadAsk (KMPlayer::Node *n) {
412 QString title;
413 QString desc;
414 QString type = static_cast <Element *> (n)->getAttribute (
415 KMPlayer::Ids::attr_type);
416 QString key = static_cast<Element*>(n)->getAttribute ("key");
417 QString def = static_cast<Element*>(n)->getAttribute ("default");
418 QString input;
419 KConfigGroup cfg(KSharedConfig::openConfig(), "Generator Defaults");
420 if (!key.isEmpty ())
421 def = cfg.readEntry (key, def);
422 if (type == "file") {
423 input = KFileDialog::getOpenFileName (KUrl (def), QString(), app);
424 } else if (type == "dir") {
425 input = KFileDialog::getExistingDirectoryUrl (KUrl (def), app).toLocalFile ();
426 if (!input.isEmpty ())
427 input += QChar ('/');
428 } else {
429 for (KMPlayer::Node *c = n->firstChild (); c; c = c->nextSibling ())
430 switch (c->id) {
431 case id_node_gen_title:
432 title = c->innerText ().simplified ();
433 break;
434 case id_node_gen_description:
435 desc = c->innerText ().simplified ();
436 break;
437 }
438 input = QInputDialog::getText(0, title, desc, QLineEdit::Normal, def);
439 }
440 if (input.isNull ())
441 canceled = true;
442 else if (!key.isEmpty ())
443 cfg.writeEntry (key, input);
444 return input;
445 }
446
genReadUriGet(KMPlayer::Node * n)447 QString Generator::genReadUriGet (KMPlayer::Node *n) {
448 QString str;
449 bool first = true;
450 for (KMPlayer::Node *c = n->firstChild (); c && !canceled; c = c->nextSibling ()) {
451 QString key;
452 QString val;
453 switch (c->id) {
454 case id_node_gen_http_key_value: {
455 KMPlayer::Node *q = c->firstChild ();
456 if (q) {
457 key = genReadString (q);
458 q = q->nextSibling ();
459 if (q && !canceled)
460 val = genReadString (q);
461 }
462 break;
463 }
464 default:
465 key = genReadString (c);
466 break;
467 }
468 if (!key.isEmpty ()) {
469 if (first) {
470 str += QChar ('?');
471 first = false;
472 } else {
473 str += QChar ('&');
474 }
475 str += QUrl::toPercentEncoding (key);
476 if (!val.isEmpty ())
477 str += QChar ('=') + QString (QUrl::toPercentEncoding (val));
478 }
479 }
480 return str;
481 }
482
genReadString(KMPlayer::Node * n)483 QString Generator::genReadString (KMPlayer::Node *n) {
484 QString str;
485 bool need_quote = quote;
486 bool find_resource = false;
487 quote = false;
488 for (KMPlayer::Node *c = n->firstChild (); c && !canceled; c = c->nextSibling ())
489 switch (c->id) {
490 case id_node_gen_uri:
491 case id_node_gen_sequence:
492 str += genReadString (c);
493 break;
494 case id_node_gen_literal:
495 str += c->innerText ().simplified ();
496 break;
497 case id_node_gen_predefined: {
498 QString val = static_cast <Element *>(c)->getAttribute ("key");
499 if (val == "data" || val == "sysdata") {
500 str += "kmplayer";
501 find_resource = true;
502 }
503 break;
504 }
505 case id_node_gen_http_get:
506 str += genReadUriGet (c);
507 break;
508 case id_node_gen_ask:
509 str += genReadAsk (c);
510 break;
511 case KMPlayer::id_node_text:
512 str += c->nodeValue ().simplified ();
513 }
514 if (find_resource)
515 str = QStandardPaths::locate(QStandardPaths::GenericDataLocation, str);
516 if (!static_cast <Element *>(n)->getAttribute ("encoding").isEmpty ())
517 str = QUrl::toPercentEncoding (str);
518 if (need_quote) {
519 //from QProcess' parseCombinedArgString
520 str.replace (QChar ('"'), QString ("\"\"\""));
521 str = QChar ('"') + str + QChar ('"');
522 quote = true;
523 }
524 return str;
525 }
526
genReadInput(KMPlayer::Node * n)527 QString Generator::genReadInput (KMPlayer::Node *n) {
528 quote = false;
529 return genReadString (n);
530 }
531
genReadProcess(KMPlayer::Node * n)532 QString Generator::genReadProcess (KMPlayer::Node *n) {
533 QString process;
534 QString str;
535 quote = true;
536 for (KMPlayer::Node *c = n->firstChild (); c && !canceled; c = c->nextSibling ())
537 switch (c->id) {
538 case id_node_gen_program:
539 process = QString (genReadString (c));
540 break;
541 case id_node_gen_argument:
542 process += QChar (' ') + genReadString (c);
543 break;
544 }
545 return process;
546 }
547
activate()548 void Generator::activate () {
549 QString input;
550 canceled = false;
551 KMPlayer::Node *n = firstChild ();
552 if (n && n->id == id_node_gen_generator) {
553 title = static_cast<Element *>(n)->getAttribute (
554 KMPlayer::Ids::attr_name);
555 for (KMPlayer::Node *c = n->firstChild (); c && !canceled; c = c->nextSibling ())
556 switch (c->id) {
557 case id_node_gen_input:
558 input = genReadInput (c);
559 break;
560 case id_node_gen_process:
561 process = genReadProcess (c);
562 }
563 }
564 if (canceled)
565 return;
566 if (!input.isEmpty () && process.isEmpty ()) {
567 message (KMPlayer::MsgInfoString, &input);
568 //openFile (m_control->m_app, input);
569 } else if (!process.isEmpty ()) {
570 data = new QTextStream (&buffer);
571 if (input.isEmpty ()) {
572 message (KMPlayer::MsgInfoString, &process);
573 begin ();
574 } else {
575 QString cmdline (input + " | " + process);
576 message (KMPlayer::MsgInfoString, &cmdline);
577 if (!media_info)
578 media_info = new KMPlayer::MediaInfo (
579 this, KMPlayer::MediaManager::Data);
580 state = state_activated;
581 media_info->wget (input);
582 }
583 }
584 }
585
begin()586 void Generator::begin () {
587 if (!qprocess) {
588 qprocess = new QProcess (app);
589 connect (qprocess, SIGNAL (started ()),
590 this, SLOT (started ()));
591 connect (qprocess, SIGNAL (error (QProcess::ProcessError)),
592 this, SLOT (error (QProcess::ProcessError)));
593 connect (qprocess, SIGNAL (finished (int, QProcess::ExitStatus)),
594 this, SLOT (finished ()));
595 connect (qprocess, SIGNAL (readyReadStandardOutput ()),
596 this, SLOT (readyRead ()));
597 }
598 QString info;
599 if (media_info)
600 info = QString ("Input data ") +
601 QString::number (media_info->rawData ().size () / 1024.0) + "kb | ";
602 info += process;
603 message (KMPlayer::MsgInfoString, &info);
604 kDebug() << process;
605 qprocess->start (process);
606 state = state_began;
607 }
608
deactivate()609 void Generator::deactivate () {
610 if (qprocess) {
611 disconnect (qprocess, SIGNAL (started ()),
612 this, SLOT (started ()));
613 disconnect (qprocess, SIGNAL (error (QProcess::ProcessError)),
614 this, SLOT (error (QProcess::ProcessError)));
615 disconnect (qprocess, SIGNAL (finished (int, QProcess::ExitStatus)),
616 this, SLOT (finished ()));
617 disconnect (qprocess, SIGNAL (readyReadStandardOutput ()),
618 this, SLOT (readyRead ()));
619 qprocess->kill ();
620 qprocess->deleteLater ();
621 }
622 qprocess = NULL;
623 delete data;
624 data = NULL;
625 buffer.clear ();
626 FileDocument::deactivate ();
627 }
628
message(KMPlayer::MessageType msg,void * content)629 void Generator::message (KMPlayer::MessageType msg, void *content) {
630 if (KMPlayer::MsgMediaReady == msg) {
631 if (!media_info->rawData ().size ()) {
632 QString err ("No input data received");
633 message (KMPlayer::MsgInfoString, &err);
634 deactivate ();
635 } else {
636 begin ();
637 }
638 } else {
639 FileDocument::message (msg, content);
640 }
641 }
642
readyRead()643 void Generator::readyRead () {
644 if (qprocess->bytesAvailable ())
645 *data << qprocess->readAll();
646 if (qprocess->state () == QProcess::NotRunning) {
647 if (!buffer.isEmpty ()) {
648 Playlist *pl = new Playlist (app, m_source, true);
649 KMPlayer::NodePtr n = pl;
650 pl->src.clear ();
651 QTextStream stream (&buffer, QIODevice::ReadOnly);
652 KMPlayer::readXML (pl, stream, QString (), false);
653 pl->title = title;
654 pl->normalize ();
655 message (KMPlayer::MsgInfoString, NULL);
656 bool reset_only = m_source == app->player ()->source ();
657 if (reset_only)
658 app->player ()->stop ();
659 m_source->setDocument (pl, pl);
660 if (reset_only) {
661 m_source->activate ();
662 app->setCaption (getAttribute(KMPlayer::Ids::attr_name));
663 } else {
664 app->player ()->setSource (m_source);
665 }
666 } else {
667 QString err ("No data received");
668 message (KMPlayer::MsgInfoString, &err);
669 }
670 deactivate ();
671 }
672 }
673
started()674 void Generator::started () {
675 if (media_info) {
676 QByteArray &ba = media_info->rawData ();
677 // TODO validate utf8
678 if (ba.size ())
679 qprocess->write (ba);
680 qprocess->closeWriteChannel ();
681 return;
682 }
683 message (KMPlayer::MsgInfoString, &process);
684 }
685
error(QProcess::ProcessError err)686 void Generator::error (QProcess::ProcessError err) {
687 kDebug () << (int)err;
688 QString msg ("Couldn't start process");
689 message (KMPlayer::MsgInfoString, &msg);
690 deactivate ();
691 }
692
finished()693 void Generator::finished () {
694 if (active () && state_deferred != state)
695 readyRead ();
696 }
697
698 struct GeneratorTag {
699 const char *tag;
700 short id;
701 } gen_tags[] = {
702 { "input", id_node_gen_input },
703 { "process", id_node_gen_process },
704 { "uri", id_node_gen_uri },
705 { "literal", id_node_gen_literal },
706 { "ask", id_node_gen_ask },
707 { "title", id_node_gen_title },
708 { "description", id_node_gen_description },
709 { "process", id_node_gen_process },
710 { "program", id_node_gen_program },
711 { "argument", id_node_gen_argument },
712 { "predefined", id_node_gen_predefined },
713 { "http-get", id_node_gen_http_get },
714 { "key-value", id_node_gen_http_key_value },
715 { "key", id_node_gen_sequence },
716 { "value", id_node_gen_sequence },
717 { "sequence", id_node_gen_sequence },
718 { NULL, -1 }
719 };
720
childFromTag(const QString & tag)721 KMPlayer::Node *GeneratorElement::childFromTag (const QString &tag) {
722 QByteArray ba = tag.toUtf8();
723 const char *ctag = ba.constData ();
724 for (GeneratorTag *t = gen_tags; t->tag; ++t)
725 if (!strcmp (ctag, t->tag))
726 return new GeneratorElement (m_doc, tag, t->id);
727 return NULL;
728 }
729
730