File indexing completed on 2024-04-28 16:07:51

0001 /**
0002   This file belong to the KMPlayer project, a movie player plugin for Konqueror
0003   Copyright (C) 2009  Koos Vriezen <koos.vriezen@gmail.com>
0004 
0005   This library is free software; you can redistribute it and/or
0006   modify it under the terms of the GNU Lesser General Public
0007   License as published by the Free Software Foundation; either
0008   version 2 of the License, or (at your option) any later version.
0009 
0010   This library is distributed in the hope that it will be useful,
0011   but WITHOUT ANY WARRANTY; without even the implied warranty of
0012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013   Lesser General Public License for more details.
0014 
0015   You should have received a copy of the GNU Lesser General Public
0016   License along with this library; if not, write to the Free Software
0017   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0018 **/
0019 
0020 #include <qfile.h>
0021 #include <qurl.h>
0022 #include <qtextstream.h>
0023 #include <qbytearray.h>
0024 #include <qinputdialog.h>
0025 #include <QStandardPaths>
0026 
0027 #include <kfiledialog.h>
0028 #include <ksharedconfig.h>
0029 #include <klocalizedstring.h>
0030 #include <kdebug.h>
0031 
0032 #include "kmplayer_lists.h"
0033 #include "kmplayer.h"
0034 #include "mediaobject.h"
0035 
0036 
0037 KDE_NO_EXPORT void ListsSource::play (KMPlayer::Mrl *mrl) {
0038     if (m_player->source () == this)
0039         Source::play (mrl);
0040     else if (mrl)
0041         mrl->activate ();
0042 }
0043 
0044 KDE_NO_EXPORT void ListsSource::activate () {
0045     activated = true;
0046     play (m_current ? m_current->mrl () : NULL);
0047 }
0048 
0049 QString ListsSource::prettyName ()
0050 {
0051     return ((KMPlayer::PlaylistRole *)m_document->role (KMPlayer::RolePlaylist))->caption ();
0052 }
0053 
0054 KDE_NO_CDTOR_EXPORT FileDocument::FileDocument (short i, const QString &s, KMPlayer::Source *src)
0055  : KMPlayer::SourceDocument (src, s), load_tree_version ((unsigned int)-1) {
0056     id = i;
0057 }
0058 
0059 KDE_NO_EXPORT KMPlayer::Node *FileDocument::childFromTag(const QString &tag) {
0060     if (tag == QString::fromLatin1 (nodeName ()))
0061         return this;
0062     return 0L;
0063 }
0064 
0065 void FileDocument::readFromFile (const QString & fn) {
0066     QFile file (fn);
0067     kDebug () << "readFromFile " << fn;
0068     if (QFileInfo (file).exists ()) {
0069         file.open (QIODevice::ReadOnly);
0070         QTextStream inxml (&file);
0071         inxml.setCodec("UTF-8");
0072         KMPlayer::readXML (this, inxml, QString (), false);
0073         normalize ();
0074     }
0075     load_tree_version = m_tree_version;
0076 }
0077 
0078 void FileDocument::writeToFile (const QString & fn) {
0079     QFile file (fn);
0080     kDebug () << "writeToFile " << fn;
0081     file.open (QIODevice::WriteOnly | QIODevice::Truncate);
0082     file.write (outerXML ().toUtf8 ());
0083     load_tree_version = m_tree_version;
0084 }
0085 
0086 void FileDocument::sync (const QString &fn)
0087 {
0088     if (resolved && load_tree_version != m_tree_version)
0089         writeToFile (fn);
0090 }
0091 
0092 KDE_NO_CDTOR_EXPORT Recents::Recents (KMPlayerApp *a)
0093     : FileDocument (id_node_recent_document, "recents://"),
0094       app(a) {
0095     title = i18n ("Most Recent");
0096     bookmarkable = false;
0097 }
0098 
0099 KDE_NO_EXPORT void Recents::activate () {
0100     if (!resolved)
0101         defer ();
0102 }
0103 
0104 KDE_NO_EXPORT void Recents::defer () {
0105     if (!resolved) {
0106         resolved = true;
0107         readFromFile(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/recent.xml");
0108     }
0109 }
0110 
0111 KDE_NO_EXPORT KMPlayer::Node *Recents::childFromTag (const QString & tag) {
0112     // kDebug () << nodeName () << " childFromTag " << tag;
0113     if (tag == QString::fromLatin1 ("item"))
0114         return new Recent (m_doc, app);
0115     else if (tag == QString::fromLatin1 ("group"))
0116         return new Group (m_doc, app);
0117     return FileDocument::childFromTag (tag);
0118 }
0119 
0120 KDE_NO_EXPORT void Recents::message (KMPlayer::MessageType msg, void *data) {
0121     if (KMPlayer::MsgChildFinished == msg)
0122         finish ();
0123     else
0124         FileDocument::message (msg, data);
0125 }
0126 
0127 KDE_NO_CDTOR_EXPORT
0128 Recent::Recent (KMPlayer::NodePtr & doc, KMPlayerApp * a, const QString &url)
0129   : KMPlayer::Mrl (doc, id_node_recent_node), app (a) {
0130     src = url;
0131     setAttribute (KMPlayer::Ids::attr_url, url);
0132 }
0133 
0134 KDE_NO_EXPORT void Recent::closed () {
0135     src = getAttribute (KMPlayer::Ids::attr_url);
0136     Mrl::closed ();
0137 }
0138 
0139 KDE_NO_EXPORT void Recent::activate () {
0140     app->openDocumentFile (KUrl (src));
0141 }
0142 
0143 KDE_NO_CDTOR_EXPORT
0144 Group::Group (KMPlayer::NodePtr & doc, KMPlayerApp * a, const QString & pn)
0145   : KMPlayer::Element (doc, KMPlayer::id_node_group_node), app (a) {
0146     title = pn;
0147     if (!pn.isEmpty ())
0148         setAttribute (KMPlayer::Ids::attr_title, pn);
0149 }
0150 
0151 KDE_NO_EXPORT KMPlayer::Node *Group::childFromTag (const QString & tag) {
0152     if (tag == QString::fromLatin1 ("item"))
0153         return new Recent (m_doc, app);
0154     else if (tag == QString::fromLatin1 ("group"))
0155         return new Group (m_doc, app);
0156     return 0L;
0157 }
0158 
0159 KDE_NO_EXPORT void Group::closed () {
0160     title = getAttribute (KMPlayer::Ids::attr_title);
0161     Element::closed ();
0162 }
0163 
0164 void *Group::role (KMPlayer::RoleType msg, void *content)
0165 {
0166     if (KMPlayer::RolePlaylist == msg)
0167         return (KMPlayer::PlaylistRole *) this ;
0168     return Element::role (msg, content);
0169 }
0170 
0171 KDE_NO_EXPORT void Playlist::defer () {
0172     if (playmode) {
0173         KMPlayer::Document::defer ();
0174         // Hack: Node::undefer will restart first item when state=init
0175         if (firstChild() && KMPlayer::Node::state_init == firstChild()->state)
0176             firstChild()->state = KMPlayer::Node::state_activated;
0177     } else if (!resolved) {
0178         resolved = true;
0179         readFromFile(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/playlist.xml");
0180     }
0181 }
0182 
0183 KDE_NO_EXPORT void Playlist::activate () {
0184     if (playmode)
0185         KMPlayer::Document::activate ();
0186     else if (!resolved)
0187         defer ();
0188 }
0189 
0190 KDE_NO_CDTOR_EXPORT Playlist::Playlist (KMPlayerApp *a, KMPlayer::Source *s, bool plmode)
0191     : FileDocument (KMPlayer::id_node_playlist_document, "Playlist://", s),
0192       app(a),
0193       playmode (plmode) {
0194     title = i18n ("Persistent Playlists");
0195     bookmarkable = false;
0196 }
0197 
0198 KDE_NO_EXPORT KMPlayer::Node *Playlist::childFromTag (const QString & tag) {
0199     // kDebug () << nodeName () << " childFromTag " << tag;
0200     QByteArray ba = tag.toUtf8 ();
0201     const char *name = ba.constData ();
0202     if (!strcmp (name, "item"))
0203         return new PlaylistItem (m_doc, app, playmode);
0204     else if (!strcmp (name, "group"))
0205         return new PlaylistGroup (m_doc, app, playmode);
0206     else if (!strcmp (name, "object"))
0207         return new HtmlObject (m_doc, app, playmode);
0208     return FileDocument::childFromTag (tag);
0209 }
0210 
0211 KDE_NO_EXPORT void Playlist::message (KMPlayer::MessageType msg, void *data) {
0212     if (KMPlayer::MsgChildFinished == msg && !playmode)
0213         finish ();
0214     else
0215         FileDocument::message (msg, data);
0216 }
0217 
0218 KDE_NO_CDTOR_EXPORT
0219 PlaylistItemBase::PlaylistItemBase (KMPlayer::NodePtr &d, short i, KMPlayerApp *a, bool pm)
0220     : KMPlayer::Mrl (d, i), app (a), playmode (pm) {
0221     editable = !pm;
0222 }
0223 
0224 KDE_NO_EXPORT void PlaylistItemBase::activate () {
0225     if (playmode) {
0226         Mrl::activate ();
0227     } else {
0228         ListsSource * source = static_cast <ListsSource *> (app->player ()->sources () ["listssource"]);
0229         Playlist *pl = new Playlist (app, source, true);
0230         KMPlayer::NodePtr n = pl;
0231         pl->src.clear ();
0232         QString data;
0233         QString pn;
0234         if (parentNode ()->id == KMPlayer::id_node_group_node) {
0235             data = QString ("<playlist>") +
0236                 parentNode ()->innerXML () +
0237                 QString ("</playlist>");
0238             pn = ((KMPlayer::PlaylistRole *)parentNode ()->role (KMPlayer::RolePlaylist))->caption ();
0239         } else {
0240             data = outerXML ();
0241             pn = title.isEmpty () ? src : title;
0242         }
0243         pl->setCaption (pn);
0244         //kDebug () << "cloning to " << data;
0245         QTextStream inxml (&data, QIODevice::ReadOnly);
0246         KMPlayer::readXML (pl, inxml, QString (), false);
0247         pl->normalize ();
0248         KMPlayer::Node *cur = pl->firstChild ();
0249         pl->mrl ()->resolved = !!cur;
0250         if (parentNode ()->id == KMPlayer::id_node_group_node && cur) {
0251             KMPlayer::Node *sister = parentNode ()->firstChild ();
0252             while (sister && cur && sister != this) {
0253                 sister = sister->nextSibling ();
0254                 cur = cur->nextSibling ();
0255             }
0256         }
0257         bool reset_only = source == app->player ()->source ();
0258         if (reset_only)
0259             app->player ()->stop ();
0260         source->setDocument (pl, cur);
0261         if (reset_only) {
0262             source->activate ();
0263             app->setCaption (pn);
0264         } else
0265             app->player ()->setSource (source);
0266     }
0267 }
0268 
0269 void PlaylistItemBase::closed () {
0270     title = getAttribute (KMPlayer::Ids::attr_title);
0271     Mrl::closed ();
0272 }
0273 
0274 KDE_NO_CDTOR_EXPORT
0275 PlaylistItem::PlaylistItem (KMPlayer::NodePtr & doc, KMPlayerApp *a, bool pm, const QString &url)
0276  : PlaylistItemBase (doc, KMPlayer::id_node_playlist_item, a, pm) {
0277     src = url;
0278     setAttribute (KMPlayer::Ids::attr_url, url);
0279 }
0280 
0281 KDE_NO_EXPORT void PlaylistItem::closed () {
0282     src = getAttribute (KMPlayer::Ids::attr_url);
0283     PlaylistItemBase::closed ();
0284 }
0285 
0286 KDE_NO_EXPORT void PlaylistItem::begin () {
0287     if (playmode && firstChild ())
0288         firstChild ()->activate ();
0289     else
0290         Mrl::begin ();
0291 }
0292 
0293 KDE_NO_EXPORT void PlaylistItem::setNodeName (const QString & s) {
0294     bool uri = s.startsWith (QChar ('/'));
0295     if (!uri) {
0296         int p = s.indexOf ("://");
0297         uri = p > 0 && p < 10;
0298     }
0299     if (uri) {
0300         if (title.isEmpty () || title == src)
0301             title = s;
0302         src = s;
0303         setAttribute (KMPlayer::Ids::attr_url, s);
0304     } else {
0305         title = s;
0306         setAttribute (KMPlayer::Ids::attr_title, s);
0307     }
0308 }
0309 
0310 KDE_NO_CDTOR_EXPORT
0311 PlaylistGroup::PlaylistGroup (KMPlayer::NodePtr &doc, KMPlayerApp *a, const QString &pn)
0312   : KMPlayer::Element (doc, KMPlayer::id_node_group_node), app (a), playmode (false) {
0313     title = pn;
0314     editable = true;
0315     if (!pn.isEmpty ())
0316         setAttribute (KMPlayer::Ids::attr_title, pn);
0317 }
0318 
0319 KDE_NO_CDTOR_EXPORT
0320 PlaylistGroup::PlaylistGroup (KMPlayer::NodePtr &doc, KMPlayerApp *a, bool lm)
0321   : KMPlayer::Element (doc, KMPlayer::id_node_group_node), app (a), playmode (lm) {
0322     editable = !lm;
0323 }
0324 
0325 KDE_NO_EXPORT KMPlayer::Node *PlaylistGroup::childFromTag (const QString &tag) {
0326     QByteArray ba = tag.toUtf8 ();
0327     const char *name = ba.constData ();
0328     if (!strcmp (name, "item"))
0329         return new PlaylistItem (m_doc, app, playmode);
0330     else if (!strcmp (name, "group"))
0331         return new PlaylistGroup (m_doc, app, playmode);
0332     else if (!strcmp (name, "object"))
0333         return new HtmlObject (m_doc, app, playmode);
0334     return 0L;
0335 }
0336 
0337 KDE_NO_EXPORT void PlaylistGroup::closed () {
0338     title = getAttribute (KMPlayer::Ids::attr_title);
0339     Element::closed ();
0340 }
0341 
0342 KDE_NO_EXPORT void PlaylistGroup::setNodeName (const QString &t) {
0343     title = t;
0344     setAttribute (KMPlayer::Ids::attr_title, t);
0345 }
0346 
0347 void *PlaylistGroup::role (KMPlayer::RoleType msg, void *content)
0348 {
0349     if (KMPlayer::RolePlaylist == msg)
0350         return (KMPlayer::PlaylistRole *) this ;
0351     return Element::role (msg, content);
0352 }
0353 
0354 KDE_NO_CDTOR_EXPORT
0355 HtmlObject::HtmlObject (KMPlayer::NodePtr &doc, KMPlayerApp *a, bool pm)
0356   : PlaylistItemBase (doc, KMPlayer::id_node_html_object, a, pm) {}
0357 
0358 KDE_NO_EXPORT void HtmlObject::activate () {
0359     if (playmode)
0360         KMPlayer::Mrl::activate ();
0361     else
0362         PlaylistItemBase::activate ();
0363 }
0364 
0365 KDE_NO_EXPORT void HtmlObject::closed () {
0366     for (Node *n = firstChild (); n; n = n->nextSibling ()) {
0367         if (n->id == KMPlayer::id_node_param) {
0368             KMPlayer::Element *e = static_cast <KMPlayer::Element *> (n);
0369             QString name = e->getAttribute (KMPlayer::Ids::attr_name);
0370             if (name == "type")
0371                 mimetype = e->getAttribute (KMPlayer::Ids::attr_value);
0372             else if (name == "movie")
0373                 src = e->getAttribute (KMPlayer::Ids::attr_value);
0374         } else if (n->id == KMPlayer::id_node_html_embed) {
0375             KMPlayer::Element *e = static_cast <KMPlayer::Element *> (n);
0376             QString type = e->getAttribute (KMPlayer::Ids::attr_type);
0377             if (!type.isEmpty ())
0378                 mimetype = type;
0379             QString asrc = e->getAttribute (KMPlayer::Ids::attr_src);
0380             if (!asrc.isEmpty ())
0381                 src = asrc;
0382         }
0383     }
0384     PlaylistItemBase::closed ();
0385 }
0386 
0387 KDE_NO_EXPORT KMPlayer::Node *HtmlObject::childFromTag (const QString & tag) {
0388     QByteArray ba = tag.toUtf8 ();
0389     const char *name = ba.constData ();
0390     if (!strcasecmp (name, "param"))
0391         return new KMPlayer::DarkNode (m_doc, name, KMPlayer::id_node_param);
0392     else if (!strcasecmp (name, "embed"))
0393         return new KMPlayer::DarkNode(m_doc, name,KMPlayer::id_node_html_embed);
0394     return NULL;
0395 }
0396 
0397 Generator::Generator (KMPlayerApp *a)
0398  : FileDocument (id_node_gen_document, QString (),
0399             a->player ()->sources () ["listssource"]),
0400    app (a), qprocess (NULL), data (NULL)
0401 {}
0402 
0403 KMPlayer::Node *Generator::childFromTag (const QString &tag) {
0404     QByteArray ba = tag.toUtf8();
0405     const char *ctag = ba.constData ();
0406     if (!strcmp (ctag, "generator"))
0407         return new GeneratorElement (m_doc, tag, id_node_gen_generator);
0408     return NULL;
0409 }
0410 
0411 QString Generator::genReadAsk (KMPlayer::Node *n) {
0412     QString title;
0413     QString desc;
0414     QString type = static_cast <Element *> (n)->getAttribute (
0415             KMPlayer::Ids::attr_type);
0416     QString key = static_cast<Element*>(n)->getAttribute ("key");
0417     QString def = static_cast<Element*>(n)->getAttribute ("default");
0418     QString input;
0419     KConfigGroup cfg(KSharedConfig::openConfig(), "Generator Defaults");
0420     if (!key.isEmpty ())
0421         def = cfg.readEntry (key, def);
0422     if (type == "file") {
0423         input = KFileDialog::getOpenFileName (KUrl (def), QString(), app);
0424     } else if (type == "dir") {
0425         input = KFileDialog::getExistingDirectoryUrl (KUrl (def), app).toLocalFile ();
0426         if (!input.isEmpty ())
0427             input += QChar ('/');
0428     } else {
0429         for (KMPlayer::Node *c = n->firstChild (); c; c = c->nextSibling ())
0430             switch (c->id) {
0431                 case id_node_gen_title:
0432                     title = c->innerText ().simplified ();
0433                     break;
0434                 case id_node_gen_description:
0435                     desc = c->innerText ().simplified ();
0436                     break;
0437             }
0438         input = QInputDialog::getText(0, title, desc, QLineEdit::Normal, def);
0439     }
0440     if (input.isNull ())
0441         canceled = true;
0442     else if (!key.isEmpty ())
0443         cfg.writeEntry (key, input);
0444     return input;
0445 }
0446 
0447 QString Generator::genReadUriGet (KMPlayer::Node *n) {
0448     QString str;
0449     bool first = true;
0450     for (KMPlayer::Node *c = n->firstChild (); c && !canceled; c = c->nextSibling ()) {
0451         QString key;
0452         QString val;
0453         switch (c->id) {
0454         case id_node_gen_http_key_value: {
0455             KMPlayer::Node *q = c->firstChild ();
0456             if (q) {
0457                 key = genReadString (q);
0458                 q = q->nextSibling ();
0459                 if (q && !canceled)
0460                     val = genReadString (q);
0461             }
0462             break;
0463         }
0464         default:
0465             key = genReadString (c);
0466             break;
0467         }
0468         if (!key.isEmpty ()) {
0469             if (first) {
0470                 str += QChar ('?');
0471                 first = false;
0472             } else {
0473                 str += QChar ('&');
0474             }
0475             str += QUrl::toPercentEncoding (key);
0476             if (!val.isEmpty ())
0477                 str += QChar ('=') + QString (QUrl::toPercentEncoding (val));
0478         }
0479     }
0480     return str;
0481 }
0482 
0483 QString Generator::genReadString (KMPlayer::Node *n) {
0484     QString str;
0485     bool need_quote = quote;
0486     bool find_resource = false;
0487     quote = false;
0488     for (KMPlayer::Node *c = n->firstChild (); c && !canceled; c = c->nextSibling ())
0489         switch (c->id) {
0490         case id_node_gen_uri:
0491         case id_node_gen_sequence:
0492             str += genReadString (c);
0493             break;
0494         case id_node_gen_literal:
0495             str += c->innerText ().simplified ();
0496             break;
0497         case id_node_gen_predefined: {
0498             QString val = static_cast <Element *>(c)->getAttribute ("key");
0499             if (val == "data" || val == "sysdata") {
0500                 str += "kmplayer";
0501                 find_resource = true;
0502             }
0503             break;
0504         }
0505         case id_node_gen_http_get:
0506             str += genReadUriGet (c);
0507             break;
0508         case id_node_gen_ask:
0509             str += genReadAsk (c);
0510             break;
0511         case KMPlayer::id_node_text:
0512              str += c->nodeValue ().simplified ();
0513         }
0514     if (find_resource)
0515         str = QStandardPaths::locate(QStandardPaths::GenericDataLocation, str);
0516     if (!static_cast <Element *>(n)->getAttribute ("encoding").isEmpty ())
0517         str = QUrl::toPercentEncoding (str);
0518     if (need_quote) {
0519         //from QProcess' parseCombinedArgString
0520         str.replace (QChar ('"'), QString ("\"\"\""));
0521         str = QChar ('"') + str + QChar ('"');
0522         quote = true;
0523     }
0524     return str;
0525 }
0526 
0527 QString Generator::genReadInput (KMPlayer::Node *n) {
0528     quote = false;
0529     return genReadString (n);
0530 }
0531 
0532 QString Generator::genReadProcess (KMPlayer::Node *n) {
0533     QString process;
0534     QString str;
0535     quote = true;
0536     for (KMPlayer::Node *c = n->firstChild (); c && !canceled; c = c->nextSibling ())
0537         switch (c->id) {
0538         case id_node_gen_program:
0539             process = QString (genReadString (c));
0540             break;
0541         case id_node_gen_argument:
0542             process += QChar (' ') + genReadString (c);
0543             break;
0544         }
0545     return process;
0546 }
0547 
0548 void Generator::activate () {
0549     QString input;
0550     canceled = false;
0551     KMPlayer::Node *n = firstChild ();
0552     if (n && n->id == id_node_gen_generator) {
0553         title = static_cast<Element *>(n)->getAttribute (
0554                 KMPlayer::Ids::attr_name);
0555         for (KMPlayer::Node *c = n->firstChild (); c && !canceled; c = c->nextSibling ())
0556             switch (c->id) {
0557             case id_node_gen_input:
0558                 input = genReadInput (c);
0559                 break;
0560             case id_node_gen_process:
0561                 process = genReadProcess (c);
0562             }
0563     }
0564     if (canceled)
0565         return;
0566     if (!input.isEmpty () && process.isEmpty ()) {
0567         message (KMPlayer::MsgInfoString, &input);
0568         //openFile (m_control->m_app, input);
0569     } else if (!process.isEmpty ()) {
0570         data = new QTextStream (&buffer);
0571         if (input.isEmpty ()) {
0572             message (KMPlayer::MsgInfoString, &process);
0573             begin ();
0574         } else {
0575             QString cmdline (input + " | " + process);
0576             message (KMPlayer::MsgInfoString, &cmdline);
0577             if (!media_info)
0578                 media_info = new KMPlayer::MediaInfo (
0579                         this, KMPlayer::MediaManager::Data);
0580             state = state_activated;
0581             media_info->wget (input);
0582         }
0583     }
0584 }
0585 
0586 void Generator::begin () {
0587     if (!qprocess) {
0588         qprocess = new QProcess (app);
0589         connect (qprocess, SIGNAL (started ()),
0590                  this, SLOT (started ()));
0591         connect (qprocess, SIGNAL (error (QProcess::ProcessError)),
0592                  this, SLOT (error (QProcess::ProcessError)));
0593         connect (qprocess, SIGNAL (finished (int, QProcess::ExitStatus)),
0594                  this, SLOT (finished ()));
0595         connect (qprocess, SIGNAL (readyReadStandardOutput ()),
0596                  this, SLOT (readyRead ()));
0597     }
0598     QString info;
0599     if (media_info)
0600         info = QString ("Input data ") +
0601             QString::number (media_info->rawData ().size () / 1024.0) + "kb | ";
0602     info += process;
0603     message (KMPlayer::MsgInfoString, &info);
0604     kDebug() << process;
0605     qprocess->start (process);
0606     state = state_began;
0607 }
0608 
0609 void Generator::deactivate () {
0610     if (qprocess) {
0611         disconnect (qprocess, SIGNAL (started ()),
0612                     this, SLOT (started ()));
0613         disconnect (qprocess, SIGNAL (error (QProcess::ProcessError)),
0614                     this, SLOT (error (QProcess::ProcessError)));
0615         disconnect (qprocess, SIGNAL (finished (int, QProcess::ExitStatus)),
0616                     this, SLOT (finished ()));
0617         disconnect (qprocess, SIGNAL (readyReadStandardOutput ()),
0618                     this, SLOT (readyRead ()));
0619         qprocess->kill ();
0620         qprocess->deleteLater ();
0621     }
0622     qprocess = NULL;
0623     delete data;
0624     data = NULL;
0625     buffer.clear ();
0626     FileDocument::deactivate ();
0627 }
0628 
0629 void Generator::message (KMPlayer::MessageType msg, void *content) {
0630     if (KMPlayer::MsgMediaReady == msg) {
0631         if (!media_info->rawData ().size ()) {
0632             QString err ("No input data received");
0633             message (KMPlayer::MsgInfoString, &err);
0634             deactivate ();
0635         } else {
0636             begin ();
0637         }
0638     } else {
0639         FileDocument::message (msg, content);
0640     }
0641 }
0642 
0643 void Generator::readyRead () {
0644     if (qprocess->bytesAvailable ())
0645         *data << qprocess->readAll();
0646     if (qprocess->state () == QProcess::NotRunning) {
0647         if (!buffer.isEmpty ()) {
0648             Playlist *pl = new Playlist (app, m_source, true);
0649             KMPlayer::NodePtr n = pl;
0650             pl->src.clear ();
0651             QTextStream stream (&buffer, QIODevice::ReadOnly);
0652             KMPlayer::readXML (pl, stream, QString (), false);
0653             pl->title = title;
0654             pl->normalize ();
0655             message (KMPlayer::MsgInfoString, NULL);
0656             bool reset_only = m_source == app->player ()->source ();
0657             if (reset_only)
0658                 app->player ()->stop ();
0659             m_source->setDocument (pl, pl);
0660             if (reset_only) {
0661                 m_source->activate ();
0662                 app->setCaption (getAttribute(KMPlayer::Ids::attr_name));
0663             } else {
0664                 app->player ()->setSource (m_source);
0665             }
0666         } else {
0667             QString err ("No data received");
0668             message (KMPlayer::MsgInfoString, &err);
0669         }
0670         deactivate ();
0671     }
0672 }
0673 
0674 void Generator::started () {
0675     if (media_info) {
0676         QByteArray &ba = media_info->rawData ();
0677         // TODO validate utf8
0678         if (ba.size ())
0679             qprocess->write (ba);
0680         qprocess->closeWriteChannel ();
0681         return;
0682     }
0683     message (KMPlayer::MsgInfoString, &process);
0684 }
0685 
0686 void Generator::error (QProcess::ProcessError err) {
0687     kDebug () << (int)err;
0688     QString msg ("Couldn't start process");
0689     message (KMPlayer::MsgInfoString, &msg);
0690     deactivate ();
0691 }
0692 
0693 void Generator::finished () {
0694     if (active () && state_deferred != state)
0695         readyRead ();
0696 }
0697 
0698 struct GeneratorTag {
0699     const char *tag;
0700     short id;
0701 } gen_tags[] = {
0702     { "input", id_node_gen_input },
0703     { "process", id_node_gen_process },
0704     { "uri", id_node_gen_uri },
0705     { "literal", id_node_gen_literal },
0706     { "ask", id_node_gen_ask },
0707     { "title", id_node_gen_title },
0708     { "description", id_node_gen_description },
0709     { "process", id_node_gen_process },
0710     { "program", id_node_gen_program },
0711     { "argument", id_node_gen_argument },
0712     { "predefined", id_node_gen_predefined },
0713     { "http-get", id_node_gen_http_get },
0714     { "key-value", id_node_gen_http_key_value },
0715     { "key", id_node_gen_sequence },
0716     { "value", id_node_gen_sequence },
0717     { "sequence", id_node_gen_sequence },
0718     { NULL, -1 }
0719 };
0720 
0721 KMPlayer::Node *GeneratorElement::childFromTag (const QString &tag) {
0722     QByteArray ba = tag.toUtf8();
0723     const char *ctag = ba.constData ();
0724     for (GeneratorTag *t = gen_tags; t->tag; ++t)
0725         if (!strcmp (ctag, t->tag))
0726             return new GeneratorElement (m_doc, tag, t->id);
0727     return NULL;
0728 }
0729