summaryrefslogtreecommitdiffstats
path: root/umbrello/umbrello/petaltree2uml.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'umbrello/umbrello/petaltree2uml.cpp')
-rw-r--r--umbrello/umbrello/petaltree2uml.cpp631
1 files changed, 631 insertions, 0 deletions
diff --git a/umbrello/umbrello/petaltree2uml.cpp b/umbrello/umbrello/petaltree2uml.cpp
new file mode 100644
index 00000000..41563785
--- /dev/null
+++ b/umbrello/umbrello/petaltree2uml.cpp
@@ -0,0 +1,631 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "petaltree2uml.h"
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "petalnode.h"
+#include "codeimport/import_utils.h"
+#include "package.h"
+#include "classifier.h"
+#include "attribute.h"
+#include "operation.h"
+#include "association.h"
+#include "umlrole.h"
+#include "actor.h"
+#include "usecase.h"
+#include "component.h"
+#include "node.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umllistview.h"
+#include "umllistviewitem.h"
+
+namespace Import_Rose {
+
+/**
+ * Return the given string without surrounding quotation marks.
+ * Also remove a possible prefix "Logical View::", it is not modeled in Umbrello.
+ */
+QString clean(const QString& s) {
+ if (s.isNull())
+ return QString();
+ QString str = s;
+ str.remove("\"");
+ str.remove(QRegExp("^Logical View::"));
+ return str;
+}
+
+/**
+ * Extract the quid attribute from a petal node and return it as a Uml::IDType.
+ */
+Uml::IDType quid(const PetalNode *node) {
+ QString quidStr = node->findAttribute("quid").string;
+ if (quidStr.isEmpty())
+ return Uml::id_None;
+ quidStr.remove("\"");
+ return STR2ID(quidStr);
+}
+
+/**
+ * Extract the quidu attribute from a petal node.
+ */
+QString quidu(const PetalNode *node) {
+ QString quiduStr = node->findAttribute("quidu").string;
+ if (quiduStr.isEmpty())
+ return QString();
+ quiduStr.remove("\"");
+ return quiduStr;
+}
+
+/**
+ * Determine the model type corresponding to a name.
+ * If the given name consists only of letters, digits, underscores, and
+ * scope separators, then return Uml::ot_Class, else return Uml::ot_Datatype.
+ */
+Uml::Object_Type typeToCreate(const QString& name) {
+ QString n = name;
+ n.remove(QRegExp("^.*::")); // don't consider the scope prefix, it may contain spaces
+ Uml::Object_Type t = (n.contains(QRegExp("\\W")) ? Uml::ot_Datatype : Uml::ot_Class);
+ return t;
+}
+
+/**
+ * Transfer the Rose attribute "exportControl" to the Umbrello object given.
+ *
+ * @param from Pointer to PetalNode from which to read the "exportControl" attribute
+ * @param to Pointer to UMLObject in which to set the Uml::Visibility
+ */
+void transferVisibility(const PetalNode *from, UMLObject *to) {
+ QString vis = from->findAttribute("exportControl").string;
+ if (!vis.isEmpty()) {
+ Uml::Visibility v = Uml::Visibility::fromString(clean(vis.lower()));
+ to->setVisibility(v);
+ }
+}
+
+/**
+ * ClassifierListReader factors the common processing for attributes, operations,
+ * and operation parameters.
+ */
+class ClassifierListReader {
+public:
+ /// constructor
+ ClassifierListReader(const char* attributeTag,
+ const char* elementName,
+ const char* itemTypeDesignator) :
+ m_attributeTag(attributeTag),
+ m_elementName(elementName),
+ m_itemTypeDesignator(itemTypeDesignator) {
+ }
+ /// destructor
+ virtual ~ClassifierListReader() {}
+
+ /**
+ * Return a UMLClassifierListItem of the specific type desired.
+ * Abstract method to be implemented by inheriting classes.
+ */
+ virtual UMLObject *createListItem() = 0;
+
+ virtual void setTypeReferences(UMLObject *item,
+ const QString& quid, const QString& type) {
+ if (!quid.isEmpty()) {
+ item->setSecondaryId(quid);
+ }
+ if (!type.isEmpty()) {
+ item->setSecondaryFallback(type);
+ }
+ }
+
+ /**
+ * Insert the given UMLClassifierListItem at the parent Umbrello object.
+ * Abstract method to be implemented by inheriting classes.
+ * NB the parent Umbrello object is not included in the ClassifierListReader
+ * class - it must be added at inheriting classes.
+ *
+ * @param node The PetalNode which corresponds to the parent Umbrello object.
+ * @param o The UMLObject to insert.
+ */
+ virtual void insertAtParent(const PetalNode *node, UMLObject *o) = 0;
+
+ /**
+ * Iterate over the attributes of the given PetalNode and for each recognized
+ * attribute do the following:
+ * - invoke createListItem()
+ * - fill common properties such as name, unique ID, visibility, etc. into
+ * the new UMLClassifierListItem
+ * - invoke insertAtParent() with the new classifier list item as the argument
+ * This is the user entry point.
+ */
+ void read(const PetalNode *node, const QString& name) {
+ PetalNode *attributes = node->findAttribute(m_attributeTag).node;
+ if (attributes == NULL) {
+#ifdef VERBOSE_DEBUGGING
+ kDebug() << "read(" << name << "): no " << m_attributeTag << " found"
+ << endl;
+#endif
+ return;
+ }
+ PetalNode::NameValueList attributeList = attributes->attributes();
+ for (uint i = 0; i < attributeList.count(); i++) {
+ PetalNode *attNode = attributeList[i].second.node;
+ QStringList initialArgs = attNode->initialArgs();
+ if (attNode->name() != m_elementName) {
+ kDebug() << "read(" << name << "): expecting " << m_elementName
+ << ", " << "found " << initialArgs[0] << endl;
+ continue;
+ }
+ UMLObject *item = createListItem();
+ if (initialArgs.count() > 1)
+ item->setName(clean(initialArgs[1]));
+ item->setID(quid(attNode));
+ QString quidref = quidu(attNode);
+ QString type = clean(attNode->findAttribute(m_itemTypeDesignator).string);
+ setTypeReferences(item, quidref, type);
+ transferVisibility(attNode, item);
+ QString doc = attNode->findAttribute("documentation").string;
+ if (! doc.isEmpty())
+ item->setDoc(doc);
+ insertAtParent(attNode, item);
+ }
+ }
+protected:
+ const QString m_attributeTag, m_elementName, m_itemTypeDesignator;
+};
+
+class AttributesReader : public ClassifierListReader {
+public:
+ AttributesReader(UMLClassifier *c)
+ : ClassifierListReader("class_attributes", "ClassAttribute", "type") {
+ m_classifier = c;
+ }
+ virtual ~AttributesReader() {}
+ UMLObject *createListItem() {
+ return new UMLAttribute(m_classifier);
+ }
+ void insertAtParent(const PetalNode *, UMLObject *item) {
+ m_classifier->addAttribute(static_cast<UMLAttribute*>(item));
+ }
+protected:
+ UMLClassifier *m_classifier;
+};
+
+class ParametersReader : public ClassifierListReader {
+public:
+ ParametersReader(UMLOperation *op)
+ : ClassifierListReader("parameters", "Parameter", "type") {
+ m_operation = op;
+ }
+ virtual ~ParametersReader() {}
+ UMLObject *createListItem() {
+ return new UMLAttribute(m_operation);
+ }
+ void insertAtParent(const PetalNode *, UMLObject *item) {
+ m_operation->addParm(static_cast<UMLAttribute*>(item));
+ }
+protected:
+ UMLOperation *m_operation;
+};
+
+class OperationsReader : public ClassifierListReader {
+public:
+ OperationsReader(UMLClassifier *c)
+ : ClassifierListReader("operations", "Operation", "result") {
+ m_classifier = c;
+ }
+ virtual ~OperationsReader() {}
+ UMLObject *createListItem() {
+ return new UMLOperation(m_classifier);
+ }
+ void insertAtParent(const PetalNode *node, UMLObject *item) {
+ UMLOperation *op = static_cast<UMLOperation*>(item);
+ ParametersReader parmReader(op);
+ parmReader.read(node, m_classifier->getName());
+ m_classifier->addOperation(op);
+ }
+protected:
+ UMLClassifier *m_classifier;
+};
+
+class SuperclassesReader : public ClassifierListReader {
+public:
+ SuperclassesReader(UMLClassifier *c)
+ : ClassifierListReader("superclasses", "Inheritance_Relationship", "supplier") {
+ m_classifier = c;
+ }
+ virtual ~SuperclassesReader() {}
+ UMLObject *createListItem() {
+ return new UMLAssociation(Uml::at_Generalization);
+ }
+ /**
+ * Override parent implementation: The secondary data is not for the
+ * UMLAssociation itself but for its role B object.
+ */
+ void setTypeReferences(UMLObject *item,
+ const QString& quid, const QString& type) {
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(item);
+ if (!quid.isEmpty()) {
+ assoc->getUMLRole(Uml::B)->setSecondaryId(quid);
+ }
+ if (!type.isEmpty()) {
+ assoc->getUMLRole(Uml::B)->setSecondaryFallback(type);
+ }
+ }
+ void insertAtParent(const PetalNode *, UMLObject *item) {
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(item);
+ assoc->setObject(m_classifier, Uml::A);
+ UMLApp::app()->getDocument()->addAssociation(assoc);
+ }
+protected:
+ UMLClassifier *m_classifier;
+};
+
+class RealizationsReader : public ClassifierListReader {
+public:
+ RealizationsReader(UMLClassifier *c)
+ : ClassifierListReader("realized_interfaces", "Realize_Relationship", "supplier") {
+ m_classifier = c;
+ }
+ virtual ~RealizationsReader() {}
+ UMLObject *createListItem() {
+ return new UMLAssociation(Uml::at_Realization);
+ }
+ /**
+ * Override parent implementation: The secondary data is not for the
+ * UMLAssociation itself but for its role B object.
+ */
+ void setTypeReferences(UMLObject *item,
+ const QString& quid, const QString& type) {
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(item);
+ if (!quid.isEmpty()) {
+ assoc->getUMLRole(Uml::B)->setSecondaryId(quid);
+ }
+ if (!type.isEmpty()) {
+ assoc->getUMLRole(Uml::B)->setSecondaryFallback(type);
+ }
+ }
+ void insertAtParent(const PetalNode *, UMLObject *item) {
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(item);
+ assoc->setObject(m_classifier, Uml::A);
+ UMLApp::app()->getDocument()->addAssociation(assoc);
+ }
+protected:
+ UMLClassifier *m_classifier;
+};
+
+/**
+ * Handle a controlled unit.
+ *
+ * @param node Pointer to the PetalNode which may contain a controlled unit
+ * @param name Name of the current node
+ * @param id QUID of the current node
+ * @param parentPkg Pointer to the current parent UMLPackage.
+ * @return True if the node actually contained a controlled unit.
+ */
+bool handleControlledUnit(PetalNode *node, const QString& name, Uml::IDType id, UMLPackage *parentPkg) {
+ if (node->findAttribute("is_unit").string != "TRUE")
+ return false;
+ bool is_loaded = (node->findAttribute("is_loaded").string != "FALSE");
+ QString file_name = node->findAttribute("file_name").string;
+ if (file_name.isEmpty()) {
+ kError() << "handleControlledUnit(" << name
+ << "): attribute file_name not found (?)" << endl;
+ return true;
+ }
+ // To Be Continued.
+
+ return true;
+}
+
+/**
+ * Create an Umbrello object from a PetalNode of the Logical View.
+ *
+ * @return True for success.
+ * Given a PetalNode for which the mapping to Umbrello is not yet
+ * implemented umbrellify() is a no-op but also returns true.
+ */
+bool umbrellify(PetalNode *node, UMLPackage *parentPkg = NULL) {
+ if (node == NULL) {
+ kError() << "umbrellify: node is NULL" << endl;
+ return false;
+ }
+ QStringList args = node->initialArgs();
+ QString objType = args[0];
+ QString name = clean(args[1]);
+ Uml::IDType id = quid(node);
+
+ if (objType == "Class_Category") {
+ UMLObject *o = Import_Utils::createUMLObject(Uml::ot_Package, name, parentPkg);
+ o->setID(id);
+ PetalNode *logical_models = node->findAttribute("logical_models").node;
+ if (logical_models) {
+ UMLPackage *localParent = static_cast<UMLPackage*>(o);
+ PetalNode::NameValueList atts = logical_models->attributes();
+ for (uint i = 0; i < atts.count(); i++) {
+ umbrellify(atts[i].second.node, localParent);
+ }
+ } else if (!handleControlledUnit(node, name, id, parentPkg)) {
+ kDebug() << "umbrellify: handling of " << objType << " " << name
+ << " is not yet implemented" << endl;
+ }
+
+ } else if (objType == "Class") {
+ UMLObject *o = Import_Utils::createUMLObject(Uml::ot_Class, name, parentPkg);
+ o->setID(id);
+ UMLClassifier *c = static_cast<UMLClassifier*>(o);
+ // set stereotype
+ QString stereotype = clean(node->findAttribute("stereotype").string);
+ if (!stereotype.isEmpty()) {
+ if (stereotype.lower() == "interface")
+ c->setBaseType(Uml::ot_Interface);
+ else
+ c->setStereotype(stereotype);
+ }
+ // insert attributes
+ AttributesReader attReader(c);
+ attReader.read(node, c->getName());
+ // insert operations
+ OperationsReader opReader(c);
+ opReader.read(node, c->getName());
+ // insert generalizations
+ SuperclassesReader superReader(c);
+ superReader.read(node, c->getName());
+ // insert realizations
+ RealizationsReader realReader(c);
+ realReader.read(node, c->getName());
+
+ } else if (objType == "Association") {
+ PetalNode *roles = node->findAttribute("roles").node;
+ if (node == NULL) {
+ kError() << "umbrellify: cannot find roles of Association" << endl;
+ return false;
+ }
+ UMLAssociation *assoc = new UMLAssociation(Uml::at_UniAssociation);
+ PetalNode::NameValueList roleList = roles->attributes();
+ for (uint i = 0; i <= 1; i++) {
+ PetalNode *roleNode = roleList[i].second.node;
+ if (roleNode == NULL) {
+ kError() << "umbrellify: roleNode of Association is NULL" << endl;
+ return false;
+ }
+ if (roleNode->name() != "Role") {
+ kDebug() << "umbrellify(" << name << "): expecting Role, found \""
+ << roleNode->name() << endl;
+ continue;
+ }
+ // index 0 corresponds to Umbrello roleB
+ // index 1 corresponds to Umbrello roleA
+ UMLRole *role = assoc->getUMLRole((Uml::Role_Type) !i);
+ QStringList initialArgs = roleNode->initialArgs();
+ if (initialArgs.count() > 1) {
+ QString roleName = clean(initialArgs[1]);
+ if (! roleName.startsWith("$UNNAMED"))
+ role->setName(roleName);
+ }
+ role->setID(quid(roleNode));
+ QString quidref = quidu(roleNode);
+ QString type = clean(roleNode->findAttribute("supplier").string);
+ if (!quidref.isEmpty()) {
+ role->setSecondaryId(quidref);
+ }
+ if (!type.isEmpty()) {
+ role->setSecondaryFallback(type);
+ }
+ QString label = clean(roleNode->findAttribute("label").string);
+ if (!label.isEmpty()) {
+ role->setName(label);
+ }
+ QString client_cardinality = clean(roleNode->findAttribute("client_cardinality").string);
+ if (!client_cardinality.isEmpty()) {
+ role->setMultiplicity(client_cardinality);
+ }
+ QString is_navigable = clean(roleNode->findAttribute("is_navigable").string);
+ if (is_navigable == "FALSE") {
+ assoc->setAssocType(Uml::at_Association);
+ }
+ QString is_aggregate = clean(roleNode->findAttribute("is_aggregate").string);
+ if (is_aggregate == "TRUE") {
+ assoc->setAssocType(Uml::at_Aggregation);
+ }
+ QString containment = clean(roleNode->findAttribute("Containment").string);
+ if (containment == "By Value") {
+ assoc->setAssocType(Uml::at_Composition);
+ }
+ QString doc = roleNode->findAttribute("documentation").string;
+ if (! doc.isEmpty())
+ role->setDoc(doc);
+ }
+ UMLApp::app()->getDocument()->addAssociation(assoc);
+
+ } else {
+ kDebug() << "umbrellify: object type " << objType
+ << " is not yet implemented" << endl;
+ }
+ return true;
+}
+
+Uml::ListView_Type folderType(UMLListViewItem *parent) {
+ Uml::ListView_Type type = Uml::lvt_Unknown;
+ switch (parent->getType()) {
+ case Uml::lvt_Logical_View:
+ case Uml::lvt_Logical_Folder:
+ type = Uml::lvt_Logical_Folder;
+ break;
+ case Uml::lvt_UseCase_View:
+ case Uml::lvt_UseCase_Folder:
+ type = Uml::lvt_UseCase_Folder;
+ break;
+ case Uml::lvt_Component_View:
+ case Uml::lvt_Component_Folder:
+ type = Uml::lvt_Component_Folder;
+ break;
+ case Uml::lvt_Deployment_View:
+ case Uml::lvt_Deployment_Folder:
+ type = Uml::lvt_Deployment_Folder;
+ break;
+ default:
+ break;
+ }
+ return type;
+}
+
+/**
+ * Create an Umbrello object from a PetalNode of the UseCase, Component,
+ * or Deployment View.
+ *
+ * @return True for success.
+ * Given a PetalNode for which the mapping to Umbrello is not yet
+ * implemented umbrellify() is a no-op but also returns true.
+ */
+bool umbrellify(PetalNode *node, const QString& modelsName, UMLListViewItem *parent) {
+ if (node == NULL) {
+ kError() << "umbrellify(" << modelsName << "): node is NULL" << endl;
+ return false;
+ }
+ QStringList args = node->initialArgs();
+ QString objType = args[0];
+ QString name = clean(args[1]);
+ Uml::IDType id = quid(node);
+ UMLObject *obj = NULL;
+ UMLListViewItem *item = NULL;
+
+ if (objType == "Class_Category") {
+ Uml::ListView_Type lvType = folderType(parent);
+ item = new UMLListViewItem( parent, name, lvType, id );
+ } else if (objType == "Class") {
+ QString stereotype = clean(node->findAttribute("stereotype").string);
+ if (stereotype == "Actor") {
+ UMLActor *act = new UMLActor(name, id);
+ item = new UMLListViewItem(parent, name, Uml::lvt_Actor, act);
+ obj = act;
+ } else {
+ kDebug() << "umbrellify(" << name << "): handling of Class stereotype "
+ << stereotype << " is not yet implemented" << endl;
+ }
+ } else if (objType == "UseCase") {
+ UMLUseCase *uc = new UMLUseCase(name, id);
+ item = new UMLListViewItem(parent, name, Uml::lvt_UseCase, uc);
+ obj = uc;
+ } else if (objType == "SubSystem") {
+ UMLComponent *comp = new UMLComponent(name, id);
+ item = new UMLListViewItem(parent, name, Uml::lvt_Component, comp);
+ obj = comp;
+ } else if (objType == "Processor" || objType == "Device") {
+ UMLNode *un = new UMLNode(name, id);
+ un->setStereotype(objType.lower());
+ item = new UMLListViewItem(parent, name, Uml::lvt_Node, un);
+ obj = un;
+ } else {
+ kDebug() << "umbrellify: object type " << objType
+ << " is not yet implemented" << endl;
+ return true;
+ }
+ PetalNode *models = node->findAttribute(modelsName).node;
+ if (models) {
+ PetalNode::NameValueList atts = models->attributes();
+ for (uint i = 0; i < atts.count(); i++) {
+ if (! umbrellify(atts[i].second.node, modelsName, item))
+ return false;
+ }
+ }
+ if (obj) {
+ QString doc = node->findAttribute("documentation").string;
+ if (! doc.isEmpty())
+ obj->setDoc(doc);
+ UMLDoc *theDocument = UMLApp::app()->getDocument();
+ theDocument->addUMLObject(obj);
+ }
+ return true;
+}
+
+/**
+ * Auxiliary function for UseCase/Component/Deployment view import
+ */
+bool importView(PetalNode *root, const QString& rootName,
+ const QString& modelsName, UMLListViewItem *lvParent) {
+ PetalNode *viewRoot = root->findAttribute(rootName).node;
+ if (viewRoot == NULL) {
+ kDebug() << "importView: cannot find " << rootName << endl;
+ return false;
+ }
+ PetalNode *models = viewRoot->findAttribute(modelsName).node;
+ if (models == NULL) {
+ kError() << "importView: cannot find " << modelsName
+ << " of " << rootName << endl;
+ return false;
+ }
+ PetalNode::NameValueList atts = models->attributes();
+ for (uint i = 0; i < atts.count(); i++) {
+ umbrellify(atts[i].second.node, modelsName, lvParent);
+ }
+ return true;
+}
+
+bool petalTree2Uml(PetalNode *root) {
+ if (root == NULL) {
+ kError() << "petalTree2Uml: root is NULL" << endl;
+ return false;
+ }
+ if (root->name() != "Design") {
+ kError() << "petalTree2Uml: expecting root name Design" << endl;
+ return false;
+ }
+ /*************************** import Logical View ********************************/
+ PetalNode *root_category = root->findAttribute("root_category").node;
+ if (root_category == NULL) {
+ kError() << "petalTree2Uml: cannot find root_category" << endl;
+ return false;
+ }
+ if (root_category->name() != "Class_Category") {
+ kError() << "petalTree2Uml: expecting root_category object Class_Category"
+ << endl;
+ return false;
+ }
+ PetalNode *logical_models = root_category->findAttribute("logical_models").node;
+ if (logical_models == NULL) {
+ kError() << "petalTree2Uml: cannot find logical_models" << endl;
+ return false;
+ }
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ umldoc->setCurrentRoot(Uml::mt_Logical);
+ Import_Utils::assignUniqueIdOnCreation(false);
+ PetalNode::NameValueList atts = logical_models->attributes();
+ for (uint i = 0; i < atts.count(); i++) {
+ umbrellify(atts[i].second.node);
+ }
+
+ /** Shorthand for UMLApp::app()->getListView() **/
+ UMLListView *lv = UMLApp::app()->getListView();
+
+ /*************************** import Use Case View ********************************/
+ umldoc->setCurrentRoot(Uml::mt_UseCase);
+ importView(root, "root_usecase_package", "logical_models", lv->theUseCaseView());
+
+ /*************************** import Component View *******************************/
+ umldoc->setCurrentRoot(Uml::mt_Component);
+ importView(root, "root_subsystem", "physical_models", lv->theComponentView());
+
+ /*************************** import Deployment View ******************************/
+ umldoc->setCurrentRoot(Uml::mt_Deployment);
+ importView(root, "process_structure", "ProcsNDevs", lv->theDeploymentView());
+
+ /*************************** wrap up ********************************/
+ umldoc->setCurrentRoot(Uml::mt_Logical);
+ Import_Utils::assignUniqueIdOnCreation(true);
+ umldoc->resolveTypes();
+ return true;
+}
+
+} // namespace Import_Rose
+