/* dtkComposerReader.cpp --- * * Author: Julien Wintz * Copyright (C) 2008-2011 - Julien Wintz, Inria. * Created: Mon Jan 30 23:41:08 2012 (+0100) * Version: $Id: 4450f9f843cf02fc2fdeab3a49a21276ea4f3122 $ * Last-Updated: mar. févr. 4 18:10:26 2014 (+0100) * By: Nicolas Niclausse * Update #: 863 */ /* Commentary: * */ /* Change log: * */ #include "dtkComposerFactory.h" #include "dtkComposerGraph.h" #include "dtkComposerNodeBoolean.h" #include "dtkComposerNodeComposite.h" #include "dtkComposerNodeControl.h" #include "dtkComposerNodeControlCase.h" #include "dtkComposerNodeFile.h" #include "dtkComposerNodeInteger.h" #include "dtkComposerNodeLeafData.h" #include "dtkComposerNodeLeafProcess.h" #include "dtkComposerNodeLeafView.h" #include "dtkComposerNodeReal.h" #include "dtkComposerNodeString.h" #include "dtkComposerReader.h" #include "dtkComposerScene.h" #include "dtkComposerScene_p.h" #include "dtkComposerSceneEdge.h" #include "dtkComposerSceneNode.h" #include "dtkComposerSceneNodeComposite.h" #include "dtkComposerSceneNodeControl.h" #include "dtkComposerSceneNodeLeaf.h" #include "dtkComposerSceneNote.h" #include "dtkComposerScenePort.h" #include "dtkComposerStackUtils.h" #include "dtkComposerTransmitter.h" #include "dtkComposerTransmitterProxy.h" #include "dtkComposerTransmitterVariant.h" #include #include #include #include #include #include // ///////////////////////////////////////////////////////////////// // dtkComposerReaderPrivate // ///////////////////////////////////////////////////////////////// class dtkComposerReaderPrivate { public: bool check(const QDomDocument& document); public: dtkComposerFactory *factory; dtkComposerScene *scene; dtkComposerGraph *graph; public: QHash node_map; public: dtkComposerSceneNodeComposite *root; dtkComposerSceneNodeComposite *node; public: dtkComposerSceneNodeControl *control; public: QStringList missing_implementation; QStringList default_implementation; }; bool dtkComposerReaderPrivate::check(const QDomDocument& document) { missing_implementation.clear(); default_implementation.clear(); QStringList implementations; implementations << dtkAbstractDataFactory::instance()->implementations(); implementations << dtkAbstractProcessFactory::instance()->implementations(); implementations << dtkAbstractViewFactory::instance()->implementations(); QDomNodeList nodes = document.elementsByTagName("implementation"); for (int i = 0; i < nodes.count(); i++) { QString composition_implementation = nodes.at(i).toElement().text(); if (composition_implementation.isEmpty()) { default_implementation << QString("- %1\n").arg(nodes.at(i).parentNode().toElement().attribute("type")); } else if (!implementations.contains(composition_implementation)) { missing_implementation << QString("- %1\n").arg(composition_implementation); } } return (missing_implementation.count() + default_implementation.count()) == 0; } // ///////////////////////////////////////////////////////////////// // dtkComposerReader // ///////////////////////////////////////////////////////////////// dtkComposerReader::dtkComposerReader(void) : d(new dtkComposerReaderPrivate) { d->factory = NULL; d->scene = NULL; d->root = NULL; d->graph = NULL; d->control = NULL; } dtkComposerReader::~dtkComposerReader(void) { delete d; d = NULL; } void dtkComposerReader::setFactory(dtkComposerFactory *factory) { d->factory = factory; } void dtkComposerReader::setScene(dtkComposerScene *scene) { d->scene = scene; } void dtkComposerReader::setGraph(dtkComposerGraph *graph) { d->graph = graph; } bool dtkComposerReader::read(const QString& fileName, bool append) { QString content; QFile file(fileName); QByteArray c_bytes; if (!file.open(QIODevice::ReadOnly)) return false; if (!dtkIsBinary(fileName)) { c_bytes = file.readAll(); content = QString::fromUtf8(c_bytes.data()); } else { QDataStream stream(&file); stream >> c_bytes; QByteArray u_bytes = QByteArray::fromHex(qUncompress(c_bytes)); content = QString::fromUtf8(u_bytes.data(), u_bytes.size()); } file.close(); return this->readString(content, append); } bool dtkComposerReader::readString(const QString& data, bool append, bool paste) { QDomDocument document("dtk"); if (!document.setContent(data)) { qDebug() << "reader: no content" << data.size(); return false; } if (!d->check(document)) { if (d->missing_implementation.count() > 0) { if (qApp && qobject_cast(qApp)) { QMessageBox msgBox; msgBox.setText("Node implementations are missing. Load anyway?"); msgBox.setInformativeText("You will be able to load the composition structure but evaluation will fail if you do not set the missing implementations up."); msgBox.setDetailedText(QString("The following implementations are missing:\n%1").arg(d->missing_implementation.join(""))); msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Cancel); if (msgBox.exec() == QMessageBox::Cancel) return false; } else { dtkError() << "Can't load composition, mission implementation(s):" << d->missing_implementation.join(""); return false; } } if (d->default_implementation.count() > 0) { QMessageBox msgBox; msgBox.setText("Default implementations are used. Load anyway?"); msgBox.setInformativeText("You will be able to load the composition structure and run the evaluation correctly as long as the default implementations fits your needs."); msgBox.setDetailedText(QString("The following default implementations are used:\n%1").arg(d->default_implementation.join(""))); msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Cancel); if (msgBox.exec() == QMessageBox::Cancel) return false; } } // Clear scene if applicable if (!append) this->clear(); d->node_map.clear(); // -- d->root = d->scene->root(); if (!append) { d->node = d->root; d->graph->addNode(d->root); } else if (paste) { d->node = d->scene->current(); } else { d->node = new dtkComposerSceneNodeComposite; d->node->wrap(new dtkComposerNodeComposite); d->node->setParent(d->scene->current()); d->scene->current()->addNode(d->node); d->graph->addNode(d->node); } // Feeding scene with notes QDomNodeList notes = document.firstChild().childNodes(); for (int i = 0; i < notes.count(); i++) if (notes.at(i).toElement().tagName() == "note") this->readNote(notes.at(i)); // Feeding scene with nodes QDomNodeList nodes = document.firstChild().childNodes(); for (int i = 0; i < nodes.count(); i++) if (nodes.at(i).toElement().tagName() == "node") if (!(this->readNode(nodes.at(i), paste))) { this->clear(); return false; } // Feeding scene with edges QDomNodeList edges = document.firstChild().childNodes(); for (int i = 0; i < edges.count(); i++) if (edges.at(i).toElement().tagName() == "edge") this->readEdge(edges.at(i)); // -- if (!append) d->scene->setRoot(d->root); else if (!paste) d->scene->addItem(d->node); d->graph->layout(); // -- return true; } dtkComposerSceneNote *dtkComposerReader::readNote(QDomNode node) { qreal x = node.toElement().attribute("x").toFloat(); qreal y = node.toElement().attribute("y").toFloat(); qreal w = node.toElement().attribute("w").toFloat(); qreal h = node.toElement().attribute("h").toFloat(); dtkComposerSceneNote *note = new dtkComposerSceneNote; note->setPos(QPointF(x, y)); note->setSize(QSizeF(w, h)); note->setText(node.childNodes().at(0).toText().data()); d->node->addNote(note); note->setParent(d->node); return note; } dtkComposerSceneNode *dtkComposerReader::readNode(QDomNode node, bool paste) { // qDebug() << Q_FUNC_INFO << "reading node" << node.toElement().attribute("type"); QDomNodeList childNodes = node.childNodes(); QList ports; QList notes; QList nodes; QList edges; QList blocks; QDomNode header; QDomNode footer; for (int i = 0; i < childNodes.count(); i++) if (childNodes.at(i).toElement().tagName() == "port") ports << childNodes.at(i); for (int i = 0; i < childNodes.count(); i++) if (childNodes.at(i).toElement().tagName() == "note") notes << childNodes.at(i); for (int i = 0; i < childNodes.count(); i++) if (childNodes.at(i).toElement().tagName() == "node") nodes << childNodes.at(i); for (int i = 0; i < childNodes.count(); i++) if (childNodes.at(i).toElement().tagName() == "edge") edges << childNodes.at(i); for (int i = 0; i < childNodes.count(); i++) if (childNodes.at(i).toElement().tagName() == "block") blocks << childNodes.at(i); for (int i = 0; i < childNodes.count(); i++) if (childNodes.at(i).toElement().tagName() == "header") header = childNodes.at(i); for (int i = 0; i < childNodes.count(); i++) if (childNodes.at(i).toElement().tagName() == "footer") footer = childNodes.at(i); // -- dtkComposerSceneNode *n = NULL; QString type_n = node.toElement().attribute("type"); if (blocks.count()) { qreal w = node.toElement().attribute("w").toFloat() - 4.0; qreal h = node.toElement().attribute("h").toFloat() - 4.0; n = new dtkComposerSceneNodeControl; n->wrap(d->factory->create(node.toElement().attribute("type"))); n->setParent(d->node); d->node->addNode(n); d->graph->addNode(n); n->resize(w, h); } else if (node.toElement().tagName() == "block") { if (dtkComposerNodeControlCase *control = dynamic_cast(d->control->wrapee())) { if (node.toElement().attribute("title") != "Case#default") { dtkComposerSceneNodeComposite *b = new dtkComposerSceneNodeComposite; control->addBlock(); b->wrap(control->block(control->blockCount() - 1)); d->control->addBlock(b); d->graph->addBlock(d->control); } n = d->control->blocks().last(); } else { n = d->control->blocks().at(node.toElement().attribute("blockid").toInt()); qreal x = node.toElement().attribute("x").toFloat(); qreal y = node.toElement().attribute("y").toFloat(); qreal w = node.toElement().attribute("w").toFloat() - 4; qreal h = node.toElement().attribute("h").toFloat() - 4; d->control->setBlockSize(dynamic_cast(n), x, y, w, h); } } else if (node.toElement().tagName() == "header") { n = d->control->header(); } else if (node.toElement().tagName() == "footer") { n = d->control->footer(); } else if ( type_n == "composite" || type_n == "world" || type_n == "remote" || type_n == "spawn") { dtkComposerNode *c = d->factory->create(type_n); if (c) { n = new dtkComposerSceneNodeComposite; n->wrap(c); n->setParent(d->node); d->node->addNode(n); d->graph->addNode(n); if (paste) d->scene->addItem(n); } else { if (qApp && qobject_cast(qApp)) { QMessageBox msgBox; msgBox.setText("Can't create node " + type_n); msgBox.setInformativeText("You are not be able to load the composition."); if (type_n == "remote") msgBox.setDetailedText("You need to compile DTK with DTK_BUILD_SUPPORT_DISTRIBUTED"); else msgBox.setDetailedText("You need to compile DTK with DTK_BUILD_MPI"); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.exec(); } else { dtkError() << "Can't read composition, the following node is unknown:" << node.toElement().attribute("type"); } return NULL; } } else { n = new dtkComposerSceneNodeLeaf; dtkComposerNode *new_node = d->factory->create(node.toElement().attribute("type")); if (!new_node) { if (qApp && qobject_cast(qApp)) { QMessageBox msgBox; msgBox.setText("Can't create core node."); msgBox.setInformativeText("You are not be able to load the composition."); msgBox.setDetailedText(QString("The following node is unknown:\n%1").arg(node.toElement().attribute("type"))); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.exec(); } else { dtkError() << "Can't read composition, the following node is unknown:" << node.toElement().attribute("type"); } delete n; return NULL; } n->wrap(new_node); n->setParent(d->node); d->node->addNode(n); d->graph->addNode(n); } QPointF position; if (node.toElement().hasAttribute("x")) position.setX(node.toElement().attribute("x").toFloat()); if (node.toElement().hasAttribute("y")) position.setY(node.toElement().attribute("y").toFloat()); if (paste) n->setPos(position + QPointF(100, 100)); else n->setPos(position); if (node.toElement().hasAttribute("title")) n->setTitle(node.toElement().attribute("title")); int id = node.toElement().attribute("id").toInt(); d->node_map.insert(id, n); // -- dtkComposerSceneNodeComposite *t = d->node; if (dtkComposerSceneNodeControl *control = dynamic_cast(n)) { control->layout(); d->control = control; this->readNode(header); for (int i = 0; i < blocks.count(); i++) { d->control = control; if (!this->readNode(blocks.at(i))) return NULL; } d->control = control; this->readNode(footer); // --- next/previous for loops if (dtkComposerSceneNodeComposite *body = control->block("Body")) { foreach (dtkComposerScenePort *port, body->inputPorts()) { if (int loop = port->loop()) { dtkComposerTransmitter *variant = port->node()->wrapee()->receivers().at(port->node()->inputPorts().indexOf(port)); if (dtkComposerSceneNodeComposite *conditional = control->block("Conditional")) { foreach (dtkComposerScenePort *i, conditional->inputPorts()) { if (i->loop() == loop) { dtkComposerTransmitter *proxy = i->node()->wrapee()->receivers().at(i->node()->inputPorts().indexOf(i)); dtkComposerTransmitterLinkList valid_edges; dtkComposerTransmitterLinkList invalid_edges; dtkComposerTransmitter::onTransmittersConnected(variant, proxy, valid_edges, invalid_edges); dtkComposerPropagateEdgeValidity(d->root, valid_edges, invalid_edges); } } } } } foreach (dtkComposerScenePort *port, body->outputPorts()) { if (int loop = port->loop()) { dtkComposerTransmitter *variant = port->node()->wrapee()->emitters().at(port->node()->outputPorts().indexOf(port)); if (dtkComposerSceneNodeComposite *increment = control->block("Increment")) { foreach (dtkComposerScenePort *i, increment->inputPorts()) { if (i->loop() == loop) { dtkComposerTransmitter *proxy = i->node()->wrapee()->receivers().at(i->node()->inputPorts().indexOf(i)); dtkComposerTransmitterLinkList valid_edges; dtkComposerTransmitterLinkList invalid_edges; dtkComposerTransmitter::onTransmittersConnected(variant, proxy, valid_edges, invalid_edges); dtkComposerPropagateEdgeValidity(d->root, valid_edges, invalid_edges); } } } } } } // --- } if (dtkComposerSceneNodeComposite *composite = dynamic_cast(n)) { d->node = composite; for (int i = 0; i < ports.count(); i++) { if (ports.at(i).toElement().attribute("type") == "input") { dtkComposerScenePort *port = new dtkComposerScenePort(dtkComposerScenePort::Input, composite); if (ports.at(i).toElement().hasAttribute("label")) port->setLabel(ports.at(i).toElement().attribute("label")); composite->addInputPort(port); if (ports.at(i).toElement().attribute("kind") == "proxy") { dtkComposerTransmitter *proxy = new dtkComposerTransmitterProxy(composite->wrapee()); proxy->setRequired(false); composite->wrapee()->appendReceiver(proxy); } if (ports.at(i).toElement().attribute("kind") == "variant") { dtkComposerTransmitter *variant = new dtkComposerTransmitterVariant(composite->wrapee()); variant->setRequired(false); composite->wrapee()->appendReceiver(variant); } if (ports.at(i).toElement().hasAttribute("loop")) port->setLoop(ports.at(i).toElement().attribute("loop").toInt()); } else { dtkComposerScenePort *port = new dtkComposerScenePort(dtkComposerScenePort::Output, composite); if (ports.at(i).toElement().hasAttribute("label")) port->setLabel(ports.at(i).toElement().attribute("label")); composite->addOutputPort(port); if (ports.at(i).toElement().attribute("kind") == "proxy") { dtkComposerTransmitter *proxy = new dtkComposerTransmitterProxy(composite->wrapee()); proxy->setRequired(false); composite->wrapee()->appendEmitter(proxy); } if (ports.at(i).toElement().attribute("kind") == "variant") { dtkComposerTransmitter *variant = new dtkComposerTransmitterVariant(composite->wrapee()); variant->setRequired(false); composite->wrapee()->appendEmitter(variant); } if (ports.at(i).toElement().hasAttribute("loop")) port->setLoop(ports.at(i).toElement().attribute("loop").toInt()); // ---- twins for loops if (ports.at(i).toElement().hasAttribute("twin")) { int twin = ports.at(i).toElement().attribute("twin").toInt(); QString block; if (ports.at(i).toElement().hasAttribute("block")) block = ports.at(i).toElement().attribute("block"); dtkComposerNode *wrapee = NULL; if (block.isEmpty()) wrapee = composite->wrapee(); else if (d->control) { wrapee = d->control->block(block)->wrapee(); } if (wrapee) { dtkComposerTransmitterVariant *variant = dynamic_cast(composite->wrapee()->emitters().last()); if (variant) { variant->setTwin(dynamic_cast(wrapee->receivers().at(twin))); dynamic_cast(d->control->wrapee())->appendInputTwin(variant->twin()); dynamic_cast(d->control->wrapee())->appendOutputTwin(variant); } } } // ---------- } } composite->layout(); for (int i = 0; i < notes.count(); i++) this->readNote(notes.at(i)); for (int i = 0; i < nodes.count(); i++) if (!this->readNode(nodes.at(i))) return NULL; for (int i = 0; i < edges.count(); i++) this->readEdge(edges.at(i)); } if (dtkComposerSceneNodeLeaf *leaf = dynamic_cast(n)) { for (int i = 0; i < childNodes.count(); i++) { if (childNodes.at(i).toElement().tagName() == "flag") { leaf->flag(QColor(childNodes.at(i).childNodes().at(0).toText().data())); } } for (int i = 0; i < ports.count(); i++) { if (ports.at(i).toElement().hasAttribute("label")) { if (ports.at(i).toElement().attribute("type") == "input") leaf->inputPorts().at(ports.at(i).toElement().attribute("id").toUInt())->setLabel(ports.at(i).toElement().attribute("label")); else leaf->outputPorts().at(ports.at(i).toElement().attribute("id").toUInt())->setLabel(ports.at(i).toElement().attribute("label")); } } if (dtkComposerNodeBoolean *boolean = dynamic_cast(leaf->wrapee())) { for (int i = 0; i < childNodes.count(); i++) { if (childNodes.at(i).toElement().tagName() == "value") { boolean->setValue(childNodes.at(i).childNodes().at(0).toText().data() == "true"); } } } if (dtkComposerNodeInteger *integer = dynamic_cast(leaf->wrapee())) { for (int i = 0; i < childNodes.count(); i++) { if (childNodes.at(i).toElement().tagName() == "value") { integer->setValue(childNodes.at(i).childNodes().at(0).toText().data().toLongLong()); } } } if (dtkComposerNodeReal *real = dynamic_cast(leaf->wrapee())) { for (int i = 0; i < childNodes.count(); i++) { if (childNodes.at(i).toElement().tagName() == "value") { real->setValue(childNodes.at(i).childNodes().at(0).toText().data().toDouble()); } } } if (dtkComposerNodeString *s = dynamic_cast(leaf->wrapee())) { for (int i = 0; i < childNodes.count(); i++) { if (childNodes.at(i).toElement().tagName() == "value") { s->setValue(childNodes.at(i).childNodes().at(0).toText().data()); } } } if (dtkComposerNodeFile *f = dynamic_cast(leaf->wrapee())) { for (int i = 0; i < childNodes.count(); i++) { if (childNodes.at(i).toElement().tagName() == "value") { f->setValue(childNodes.at(i).childNodes().at(0).toText().data()); } } } if (dtkComposerNodeDirectory *f = dynamic_cast(leaf->wrapee())) { for (int i = 0; i < childNodes.count(); i++) { if (childNodes.at(i).toElement().tagName() == "value") { f->setValue(childNodes.at(i).childNodes().at(0).toText().data()); } } } if (dtkComposerNodeLeafData *data_node = dynamic_cast(leaf->wrapee())) { for (int i = 0; i < childNodes.count(); i++) { if (childNodes.at(i).toElement().tagName() == "implementation") { data_node->createData(childNodes.at(i).childNodes().at(0).toText().data()); } } } if (dtkComposerNodeLeafProcess *process_node = dynamic_cast(leaf->wrapee())) { for (int i = 0; i < childNodes.count(); i++) { if (childNodes.at(i).toElement().tagName() == "implementation") { process_node->createProcess(childNodes.at(i).childNodes().at(0).toText().data()); } } } if (dtkComposerNodeLeafView *view_node = dynamic_cast(leaf->wrapee())) { for (int i = 0; i < childNodes.count(); i++) { if (childNodes.at(i).toElement().tagName() == "implementation") { view_node->createView(childNodes.at(i).childNodes().at(0).toText().data()); } } } this->extend(node, leaf); } d->node = t; // -- return n; } dtkComposerSceneEdge *dtkComposerReader::readEdge(QDomNode node) { QDomElement source = node.firstChildElement("source"); QDomElement destin = node.firstChildElement("destination"); int source_node = source.attribute("node").toInt(); int destin_node = destin.attribute("node").toInt(); int source_id = source.attribute("id").toInt(); int destin_id = destin.attribute("id").toInt(); QString source_type = source.attribute("type"); QString destin_type = destin.attribute("type"); dtkComposerSceneEdge *edge = new dtkComposerSceneEdge; if (source_type == "input") if (source_id >= d->node_map.value(source_node)->inputPorts().count()) goto handle_failure; else edge->setSource(d->node_map.value(source_node)->inputPorts().at(source_id)); else if (source_id >= d->node_map.value(source_node)->outputPorts().count()) goto handle_failure; else edge->setSource(d->node_map.value(source_node)->outputPorts().at(source_id)); if (destin_type == "input") if (destin_id >= d->node_map.value(destin_node)->inputPorts().count()) goto handle_failure; else edge->setDestination(d->node_map.value(destin_node)->inputPorts().at(destin_id)); else if (destin_id >= d->node_map.value(destin_node)->outputPorts().count()) goto handle_failure; else edge->setDestination(d->node_map.value(destin_node)->outputPorts().at(destin_id)); edge->link(); edge->adjust(); d->node->addEdge(edge); edge->setParent(d->node); dtkComposerTransmitterConnection(d->scene->root(), d->node, edge); d->graph->addEdge(edge); return edge; handle_failure: dtkWarn() << "Can't create edge from " << d->node_map.value(source_node)->title() << "to" << d->node_map.value(destin_node)->title(); delete edge; return NULL; } void dtkComposerReader::extend(const QDomNode& node, dtkComposerSceneNodeLeaf *leaf) { Q_UNUSED(node); Q_UNUSED(leaf); } void dtkComposerReader::clear(void) { // Composer if (d->scene) d->scene->clear(); if (d->graph) d->graph->clear(); // Factory dtkAbstractViewFactory::instance()->clear(); }