File indexing completed on 2024-04-14 04:48:45

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