/** * 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 uDebug() << "read(" << name << "): no " << m_attributeTag << " found"; #endif return; } PetalNode::NameValueList attributeList = attributes->attributes(); for (int i = 0; i < attributeList.count(); ++i) { PetalNode *attNode = attributeList[i].second.node; QStringList initialArgs = attNode->initialArgs(); if (attNode->name() != m_elementName) { uDebug() << "read(" << name << "): expecting " << m_elementName << ", " << "found " << initialArgs[0]; 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); } }
/** * This is really an auxiliary method for loadFromMDL() but is kept in a * separate file to reflect that it is not coupled with the parser * (other than by the PetalNode.) * * @param root the root of the tree * @return true for success. */ bool petalTree2Uml(PetalNode *root) { if (root == NULL) { uError() << "petalTree2Uml: root is NULL"; return false; } if (root->name() != "Design") { uError() << "petalTree2Uml: expecting root name Design"; return false; } //*************************** import Logical View ******************************** PetalNode *root_category = root->findAttribute("root_category").node; if (root_category == NULL) { uError() << "petalTree2Uml: cannot find root_category"; return false; } if (root_category->name() != "Class_Category") { uError() << "petalTree2Uml: expecting root_category object Class_Category"; return false; } PetalNode *logical_models = root_category->findAttribute("logical_models").node; if (logical_models == NULL) { uError() << "petalTree2Uml: cannot find logical_models"; return false; } UMLDoc *umldoc = UMLApp::app()->document(); umldoc->setCurrentRoot(Uml::ModelType::Logical); Import_Utils::assignUniqueIdOnCreation(false); PetalNode::NameValueList atts = logical_models->attributes(); for (int i = 0; i < atts.count(); ++i) { umbrellify(atts[i].second.node); } // Shorthand for UMLApp::app()->listView() UMLListView *lv = UMLApp::app()->listView(); //*************************** import Use Case View ******************************** umldoc->setCurrentRoot(Uml::ModelType::UseCase); importView(root, "root_usecase_package", "logical_models", lv->theUseCaseView()); //*************************** import Component View ******************************* umldoc->setCurrentRoot(Uml::ModelType::Component); importView(root, "root_subsystem", "physical_models", lv->theComponentView()); //*************************** import Deployment View ****************************** umldoc->setCurrentRoot(Uml::ModelType::Deployment); importView(root, "process_structure", "ProcsNDevs", lv->theDeploymentView()); //*************************** wrap up ******************************** umldoc->setCurrentRoot(Uml::ModelType::Logical); Import_Utils::assignUniqueIdOnCreation(true); umldoc->resolveTypes(); return true; }
QDebug operator<<(QDebug _out, const PetalNode::NameValueList &p) { Indenter out(_out.nospace(), "PetalNode::NameValueList"); for (int i = 0; i < p.count(); ++i) { out << i << ": " << p[i]; } return out; }
/** * 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) { uDebug() << "importView: cannot find " << rootName; return false; } PetalNode *models = viewRoot->findAttribute(modelsName).node; if (models == NULL) { uError() << "importView: cannot find " << modelsName << " of " << rootName; return false; } PetalNode::NameValueList atts = models->attributes(); for (int i = 0; i < atts.count(); ++i) { umbrellify(atts[i].second.node, modelsName, lvParent); } return true; }
/** * Read attributes of a node. * @param initialArgs Tokens on the line of the opening "(" of the node * but with leading whitespace and the opening "(" removed. * @param stream The QTextStream from which to read following lines. * @return Pointer to the created PetalNode or NULL on error. */ PetalNode *readAttributes(QStringList initialArgs, QTextStream& stream) { methodName(QLatin1String("readAttributes")); if (initialArgs.count() == 0) { uError() << loc() << "initialArgs is empty"; return NULL; } PetalNode::NodeType nt; QString type = shift(initialArgs); if (type == QLatin1String("object")) nt = PetalNode::nt_object; else if (type == QLatin1String("list")) nt = PetalNode::nt_list; else { uError() << loc() << "unknown node type " << type; return NULL; } PetalNode *node = new PetalNode(nt); bool seenClosing = checkClosing(initialArgs); node->setInitialArgs(initialArgs); if (seenClosing) return node; PetalNode::NameValueList attrs; QString line; while (!(line = stream.readLine()).isNull()) { linum++; line = line.trimmed(); if (line.isEmpty()) continue; QStringList tokens = scan(line); QString stringOrNodeOpener = shift(tokens); QString name; if (nt == PetalNode::nt_object && !stringOrNodeOpener.contains(QRegExp(QLatin1String("^[A-Za-z]")))) { uError() << loc() << "unexpected line " << line; delete node; return NULL; } PetalNode::StringOrNode value; if (nt == PetalNode::nt_object) { name = stringOrNodeOpener; if (tokens.count() == 0) { // expect verbatim text to follow on subsequent lines value.string = collectVerbatimText(stream); PetalNode::NameValue attr(name, value); attrs.append(attr); if (nClosures) { // Decrement nClosures exactly once, namely for the own scope. // Each recursion of readAttributes() is only responsible for // its own scope. I.e. each further scope closing is handled by // an outer recursion in case of multiple closing parentheses. nClosures--; break; } continue; } stringOrNodeOpener = shift(tokens); } else if (stringOrNodeOpener != QLatin1String("(")) { value.string = stringOrNodeOpener; PetalNode::NameValue attr; attr.second = value; attrs.append(attr); if (tokens.count() && tokens.first() != QLatin1String(")")) { uDebug() << loc() << "NYI - immediate list entry with more than one item"; } if (checkClosing(tokens)) break; continue; } if (stringOrNodeOpener == QLatin1String("(")) { QString nxt = tokens.first(); if (isImmediateValue(nxt)) { value.string = extractImmediateValues(tokens); } else if (nxt == QLatin1String("value") || nxt.startsWith(QLatin1Char('"'))) { value.string = extractValue(tokens, stream); } else { value.node = readAttributes(tokens, stream); if (value.node == NULL) { delete node; return NULL; } } PetalNode::NameValue attr(name, value); attrs.append(attr); if (nClosures) { // Decrement nClosures exactly once, namely for the own scope. // Each recursion of readAttributes() is only responsible for // its own scope. I.e. each further scope closing is handled by // an outer recursion in case of multiple closing parentheses. nClosures--; break; } } else { value.string = stringOrNodeOpener; bool seenClosing = checkClosing(tokens); PetalNode::NameValue attr(name, value); attrs.append(attr); if (seenClosing) { break; } } } node->setAttributes(attrs); return node; }
/** * 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) { uError() << "umbrellify(" << modelsName << "): node is NULL"; 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") { UMLListViewItem::ListViewType 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, UMLListViewItem::lvt_Actor, act); obj = act; } else { uDebug() << "umbrellify(" << name << "): handling of Class stereotype " << stereotype << " is not yet implemented"; } } else if (objType == "UseCase") { UMLUseCase *uc = new UMLUseCase(name, id); item = new UMLListViewItem(parent, name, UMLListViewItem::lvt_UseCase, uc); obj = uc; } else if (objType == "SubSystem") { UMLComponent *comp = new UMLComponent(name, id); item = new UMLListViewItem(parent, name, UMLListViewItem::lvt_Component, comp); obj = comp; } else if (objType == "Processor" || objType == "Device") { UMLNode *un = new UMLNode(name, id); un->setStereotype(objType.toLower()); item = new UMLListViewItem(parent, name, UMLListViewItem::lvt_Node, un); obj = un; } else { uDebug() << "umbrellify: object type " << objType << " is not yet implemented"; return true; } PetalNode *models = node->findAttribute(modelsName).node; if (models) { PetalNode::NameValueList atts = models->attributes(); for (int 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()->document(); theDocument->addUMLObject(obj); } 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) { uError() << "umbrellify: node is NULL"; 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(UMLObject::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 (int i = 0; i < atts.count(); ++i) { umbrellify(atts[i].second.node, localParent); } } else if (!handleControlledUnit(node, name, id, parentPkg)) { uDebug() << "umbrellify: handling of " << objType << " " << name << " is not yet implemented"; } } else if (objType == "Class") { UMLObject *o = Import_Utils::createUMLObject(UMLObject::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.toLower() == "interface") c->setBaseType(UMLObject::ot_Interface); else c->setStereotype(stereotype); } // insert attributes AttributesReader attReader(c); attReader.read(node, c->name()); // insert operations OperationsReader opReader(c); opReader.read(node, c->name()); // insert generalizations SuperclassesReader superReader(c); superReader.read(node, c->name()); // insert realizations RealizationsReader realReader(c); realReader.read(node, c->name()); } else if (objType == "Association") { PetalNode *roles = node->findAttribute("roles").node; if (node == NULL) { uError() << "umbrellify: cannot find roles of Association"; return false; } UMLAssociation *assoc = new UMLAssociation(Uml::AssociationType::UniAssociation); PetalNode::NameValueList roleList = roles->attributes(); for (uint i = 0; i <= 1; ++i) { PetalNode *roleNode = roleList[i].second.node; if (roleNode == NULL) { uError() << "umbrellify: roleNode of Association is NULL"; return false; } if (roleNode->name() != "Role") { uDebug() << "umbrellify(" << name << "): expecting Role, found \"" << roleNode->name(); 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(QLatin1String("$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->setAssociationType(Uml::AssociationType::Association); } QString is_aggregate = clean(roleNode->findAttribute("is_aggregate").string); if (is_aggregate == "TRUE") { assoc->setAssociationType(Uml::AssociationType::Aggregation); } QString containment = clean(roleNode->findAttribute("Containment").string); if (containment == "By Value") { assoc->setAssociationType(Uml::AssociationType::Composition); } QString doc = roleNode->findAttribute("documentation").string; if (! doc.isEmpty()) role->setDoc(doc); } UMLApp::app()->document()->addAssociation(assoc); } else { uDebug() << "umbrellify: object type " << objType << " is not yet implemented"; } return true; }