Version: (using KDE Devel) Installed from: Compiled sources Acceptance of umbrello could be helped if we offered an import facility for Rose petal files. One way of achieving this would be to use a standalone converter, such as http://crazybeans.sourceforge.net/ which already has an XMI generator. The generator would need to be expanded to also convert the diagram information to the umbrello specific format (the <diagrams> in the <XMI.extension> tag.)
What's a rose petal file? Is it just an XMI-according-to-rational UML file?
"Petal" file is the Rose name for "model" file, see for example http://xmlmodeling.com/book/examples/AppendixC/Bibliography.mdl
Crazybeans seems to be very sensitive to the exact version of Rose MDL file used and crashes more often than not. A simpler way forward might be the Unisys XMI plugin for Rose, ftp://www6.software.ibm.com/software/developer/library/rational/2834/Rose/RoseXMLTools1.3.6.01.zip the downside being that it is a Win32 app. Anyway, I tried importing the XMI produced by this converter and the results are promising. The biggest problem remains the loss of the diagram info. For further details see #56184.
Maybe we can steal code from, or even work together with: http://bouml.free.fr The Rose model import of v2.0 works quite well but is still missing the diagrams.
SVN commit 503042 by okellogg: Rose import, take 1: Define an internal representation (the PetalNode) and parse MDL files into this representation. Up next: Walk the PetalNode tree for building Umbrello objects. CCBUG:81364 M +2 -0 Makefile.am A import_rose.cpp [License: GPL (v2+)] A import_rose.h [License: no copyright] A petalnode.cpp [License: GPL (v2+)] A petalnode.h [License: GPL (v2+)] M +5 -1 uml.cpp M +5 -1 umldoc.cpp --- branches/KDE/3.5/kdesdk/umbrello/umbrello/Makefile.am #503041:503042 @@ -51,6 +51,7 @@ kplayerslideraction.cpp \ hierarchicalcodeblock.cpp \ idlimport.cpp \ +import_rose.cpp \ import_utils.cpp \ infowidget.cpp \ javaimport.cpp \ @@ -72,6 +73,7 @@ ownedhierarchicalcodeblock.cpp \ package.cpp \ packagewidget.cpp \ +petalnode.cpp \ plugin.cpp \ pluginloader.cpp \ pythonimport.cpp \ --- branches/KDE/3.5/kdesdk/umbrello/umbrello/uml.cpp #503041:503042 @@ -682,7 +682,11 @@ } else { KURL url=KFileDialog::getOpenURL(":open-umbrello-file", - i18n("*.xmi *.xmi.tgz *.xmi.tar.bz2|All Supported Files (*.xmi, *.xmi.tgz, *.xmi.tar.bz2)\n*.xmi|Uncompressed XMI Files (*.xmi)\n*.xmi.tgz|Gzip Compressed XMI Files (*.xmi.tgz)\n*.xmi.tar.bz2|Bzip2 Compressed XMI Files (*.xmi.tar.bz2)"), this, i18n("Open File")); + i18n("*.xmi *.xmi.tgz *.xmi.tar.bz2 *.mdl|All Supported Files (*.xmi, *.xmi.tgz, *.xmi.tar.bz2, *.mdl)\n" + "*.xmi|Uncompressed XMI Files (*.xmi)\n" + "*.xmi.tgz|Gzip Compressed XMI Files (*.xmi.tgz)\n" + "*.xmi.tar.bz2|Bzip2 Compressed XMI Files (*.xmi.tar.bz2)\n" + "*.mdl|Rose model files"), this, i18n("Open File")); if(!url.isEmpty()) { if(m_doc->openDocument(url)) fileOpenRecent->addURL( url ); --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umldoc.cpp #503041:503042 @@ -60,6 +60,7 @@ #include "stereotype.h" #include "classifierlistitem.h" #include "object_factory.h" +#include "import_rose.h" #include "model_utils.h" #include "widget_utils.h" #include "uml.h" @@ -496,7 +497,10 @@ newDocument(); return false; } - status = loadFromXMI( file, ENC_UNKNOWN ); + if (filetype.endsWith(".mdl")) + status = Import_Rose::loadFromMDL(file); + else + status = loadFromXMI( file, ENC_UNKNOWN ); } file.close();
SVN commit 503608 by okellogg: petalTree2Uml(): New. Start making Umbrello objects from the PetalNode tree. CCBUG:81364 M +1 -0 Makefile.am M +27 -30 import_rose.cpp M +14 -0 petalnode.cpp M +10 -1 petalnode.h A petaltree2uml.cpp [License: GPL (v2+)] A petaltree2uml.h [License: GPL (v2+)] --- branches/KDE/3.5/kdesdk/umbrello/umbrello/Makefile.am #503607:503608 @@ -74,6 +74,7 @@ package.cpp \ packagewidget.cpp \ petalnode.cpp \ +petaltree2uml.cpp \ plugin.cpp \ pluginloader.cpp \ pythonimport.cpp \ --- branches/KDE/3.5/kdesdk/umbrello/umbrello/import_rose.cpp #503607:503608 @@ -23,6 +23,7 @@ #include <kdebug.h> // app includes #include "petalnode.h" +#include "petaltree2uml.h" namespace Import_Rose { @@ -37,9 +38,17 @@ // counter indicating how many additional node closings // have been seen. -QString comment; // comment buffer - uint linum; // line number +QString g_methodName; +void methodName(QString m) { + g_methodName = m; +} +/** + * Auxiliary function for diagnostics: Return current location. + */ +QString loc() { + return "Import_Rose::" + g_methodName + " line " + linum + ": "; +} /** * Split a line into lexemes. @@ -96,18 +105,13 @@ return false; if (tokens.last() == ")") { // For a single closing parenthesis, we just return true. - // But if there are more closing parentheses, we need to set the - // seenClosure for each corresponding scope to true. + // But if there are more closing parentheses, we need to increment + // nClosures for each scope. tokens.pop_back(); while (tokens.count() && tokens.last() == ")") { nClosures++; tokens.pop_back(); } - /* - if (tokens.last() == ")") { - kdError() << "Import_Rose::checkClosing:" << linum - << " too many ')' in file " << endl; - } */ return true; } return false; @@ -161,32 +165,29 @@ QString collectVerbatimText(QTextStream& stream) { QString result; - const QRegExp closingParenth("^\\s*\\)"); QString line; + methodName("collectVerbatimText"); while ((line = stream.readLine()) != QString::null) { linum++; line = line.stripWhiteSpace(); if (line.isEmpty() || line.startsWith(")")) break; if (line[0] != '|') { - kdError() << "Import_Rose::collectVerbatimText " << linum - << ": expecting '|' at start of verbatim text" << endl; + kdError() << loc() << "expecting '|' at start of verbatim text" << endl; return QString::null; } else { result += line.mid(1) + "\n"; } } if (line == QString::null) { - kdError() << "Import_Rose::collectVerbatimText " << linum - << ": premature EOF" << endl; + kdError() << loc() << "premature EOF" << endl; return QString::null; } if (! line.isEmpty()) { for (uint i = 0; i < line.length(); i++) { const QChar& clParenth = line[i]; if (clParenth != ')') { - kdError() << "Import_Rose::collectVerbatimText " << linum - << ": expected ')', found: " << clParenth << endl; + kdError() << loc() << "expected ')', found: " << clParenth << endl; return QString::null; } nClosures++; @@ -216,6 +217,7 @@ * The line ending '\n' of each line is preserved. */ QString extractValue(QStringList& l, QTextStream& stream) { + methodName("extractValue"); if (l.count() == 0) return QString::null; if (l.first() == "(") @@ -232,8 +234,7 @@ } else { result = shift(l); if (l.first() != ")") { - kdError() << "Import_Rose::extractValue " << linum - << ": expecting closing parenthesis" << endl; + kdError() << loc() << "expecting closing parenthesis" << endl; return result; } l.pop_front(); @@ -253,10 +254,10 @@ * @return Pointer to the created PetalNode or NULL on error. */ PetalNode *readAttributes(QStringList initialArgs, QTextStream& stream) { + methodName("readAttributes"); if (initialArgs.count() == 0) { - kdError() << "Import_Rose::readAttributes " << linum - << ": firstLine is empty" << endl; - return false; + kdError() << loc() << "initialArgs is empty" << endl; + return NULL; } PetalNode::NodeType nt; QString type = shift(initialArgs); @@ -265,8 +266,7 @@ else if (type == "list") nt = PetalNode::nt_list; else { - kdError() << "Import_Rose::readAttributes " << linum - << ": unknown node type " << type << endl; + kdError() << loc() << "unknown node type " << type << endl; return NULL; } PetalNode *node = new PetalNode(nt); @@ -285,8 +285,7 @@ QString stringOrNodeOpener = shift(tokens); QString name; if (nt == PetalNode::nt_object && !stringOrNodeOpener.contains(QRegExp("^[A-Za-z]"))) { - kdError() << "Import_Rose::readAttributes " << linum - << ": unexpected line " << line << endl; + kdError() << loc() << "unexpected line " << line << endl; return NULL; } PetalNode::StringOrNode value; @@ -312,8 +311,8 @@ PetalNode::NameValue attr(QString::null, value); attrs.append(attr); if (tokens.count() && tokens.first() != ")") { - kdDebug() << "Import_Rose::readAttributes " << linum - << ": NYI - immediate list entry with more than one item" << endl; + kdDebug() << loc() + << "NYI - immediate list entry with more than one item" << endl; } if (checkClosing(tokens)) break; @@ -380,9 +379,7 @@ file.close(); if (root == NULL) return false; - // @todo traverse the PetalNode tree and create Umbrello model objects - // - return true; + return petalTree2Uml(root); } } --- branches/KDE/3.5/kdesdk/umbrello/umbrello/petalnode.cpp #503607:503608 @@ -27,6 +27,12 @@ return m_initialArgs; } +QString PetalNode::name() const { + if (m_initialArgs.count() == 0) + return QString::null; + return m_initialArgs.first(); +} + PetalNode::NameValueList PetalNode::attributes() const { return m_attributes; } @@ -45,3 +51,11 @@ m_attributes = vl; } +PetalNode::StringOrNode PetalNode::findAttribute(QString name) const { + for (uint i = 0; i < m_attributes.count(); i++) { + if (m_attributes[i].first == name) + return m_attributes[i].second; + } + return StringOrNode(); +} + --- branches/KDE/3.5/kdesdk/umbrello/umbrello/petalnode.h #503607:503608 @@ -49,7 +49,8 @@ QString string; PetalNode *node; StringOrNode() { node = 0; } - virtual ~StringOrNode() { /* if (node) delete node; */ } + virtual ~StringOrNode() { } + bool isEmpty() { return (string.isEmpty() && node == 0); } }; typedef QPair<QString, StringOrNode> NameValue; typedef QValueList<NameValue> NameValueList; @@ -62,11 +63,19 @@ // getters NodeType type() const; QStringList initialArgs() const; // name and other initial args + QString name() const; // convenience function: equal to initialArgs().first() NameValueList attributes() const; // setters //void setType(NodeType nt); see constructor void setInitialArgs(QStringList args); void setAttributes(NameValueList vl); + // utilities + /** + * Find an attribute by name. + * @return The value of the attribute. StringOrNode::isEmpty() returns true + * if the name could not be found. + */ + StringOrNode findAttribute(QString name) const; private: NodeType m_type; QStringList m_initialArgs;
SVN commit 511453 by okellogg: Import objects of the UseCase, Component, and Deployment View (management of the objects at the UMLDoc is TBD.) CCBUG:81364 M +125 -3 petaltree2uml.cpp --- branches/KDE/3.5/kdesdk/umbrello/umbrello/petaltree2uml.cpp #511452:511453 @@ -23,8 +23,13 @@ #include "operation.h" #include "association.h" #include "umlrole.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 { @@ -143,7 +148,7 @@ PetalNode *attributes = node->findAttribute(m_attributeTag).node; if (attributes == NULL) { #ifdef VERBOSE_DEBUGGING - kdDebug() << "umbrellify(" << name << "): no " << m_attributeTag << " found" + kdDebug() << "read(" << name << "): no " << m_attributeTag << " found" << endl; #endif return; @@ -153,7 +158,7 @@ PetalNode *attNode = attributeList[i].second.node; QStringList initialArgs = attNode->initialArgs(); if (attNode->name() != m_elementName) { - kdDebug() << "umbrellify(" << name << "): expecting " << m_elementName + kdDebug() << "read(" << name << "): expecting " << m_elementName << ", " << "found " << initialArgs[0] << endl; continue; } @@ -294,7 +299,7 @@ }; /** - * Create an Umbrello object from a PetalNode. + * 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 @@ -441,6 +446,78 @@ 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, UMLListViewItem *parent) { + if (node == NULL) { + kdError() << "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") { + Uml::ListView_Type lvType = folderType(parent); + UMLListViewItem *item = new UMLListViewItem( parent, name, lvType, id ); + PetalNode *logical_models = node->findAttribute("logical_models").node; + if (logical_models == NULL) { + kdError() << "umbrellify: cannot find logical_models" << endl; + return false; + } + PetalNode::NameValueList atts = logical_models->attributes(); + for (uint i = 0; i < atts.count(); i++) { + umbrellify(atts[i].second.node, item); + } + } else if (objType == "UseCase") { + UMLUseCase *uc = new UMLUseCase(name, id); + UMLListViewItem *item = new UMLListViewItem(parent, name, Uml::lvt_UseCase, uc); + } else if (objType == "SubSystem") { + UMLComponent *comp = new UMLComponent(name, id); + UMLListViewItem *item = new UMLListViewItem(parent, name, Uml::lvt_Component, comp); + } else if (objType == "Processor" || objType == "Device") { + UMLNode *un = new UMLNode(name, id); + un->setStereotype(objType.lower()); + UMLListViewItem *item = new UMLListViewItem(parent, name, Uml::lvt_Node, un); + } else { + kdDebug() << "umbrellify: object type " << objType + << " is not yet implemented" << endl; + } + return true; +} + bool petalTree2Uml(PetalNode *root) { if (root == NULL) { kdError() << "petalTree2Uml: root is NULL" << endl; @@ -450,6 +527,7 @@ kdError() << "petalTree2Uml: expecting root name Design" << endl; return false; } + /********************************** import Logical View *************************************/ PetalNode *root_category = root->findAttribute("root_category").node; if (root_category == NULL) { kdError() << "petalTree2Uml: cannot find root_category" << endl; @@ -471,6 +549,50 @@ 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 *************************************/ + PetalNode *root_usecase_package = root->findAttribute("root_usecase_package").node; + if (root_usecase_package) { + PetalNode *logical_models = root_usecase_package->findAttribute("logical_models").node; + if (logical_models == NULL) { + kdError() << "petalTree2Uml: cannot find logical_models of root_usecase_package" << endl; + return false; + } + PetalNode::NameValueList atts = logical_models->attributes(); + for (uint i = 0; i < atts.count(); i++) { + umbrellify(atts[i].second.node, lv->theUseCaseView()); + } + } + /********************************** import Component View ************************************/ + PetalNode *root_subsystem = root->findAttribute("root_subsystem").node; + if (root_subsystem) { + PetalNode *physical_models = root_subsystem->findAttribute("physical_models").node; + if (physical_models == NULL) { + kdError() << "petalTree2Uml: cannot find physical_models of root_subsystem" << endl; + return false; + } + PetalNode::NameValueList atts = physical_models->attributes(); + for (uint i = 0; i < atts.count(); i++) { + umbrellify(atts[i].second.node, lv->theComponentView()); + } + } + /********************************** import Deployment View ***********************************/ + PetalNode *process_structure = root->findAttribute("process_structure").node; + if (process_structure) { + PetalNode *ProcsNDevs = process_structure->findAttribute("ProcsNDevs").node; + if (ProcsNDevs == NULL) { + kdError() << "petalTree2Uml: cannot find ProcsNDevs of process_structure" << endl; + return false; + } + PetalNode::NameValueList atts = ProcsNDevs->attributes(); + for (uint i = 0; i < atts.count(); i++) { + umbrellify(atts[i].second.node, lv->theDeploymentView()); + } + } + /********************************** wrap up *************************************/ Import_Utils::assignUniqueIdOnCreation(true); umldoc->resolveTypes(); return true;
Support for loading separate .cat and .sub files is coming in a few days.
SVN commit 575645 by okellogg: New class UMLFolder gives folders a representation in the document. Change the document model to match the listview appearance: UMLDoc::m_objects is replaced by m_root, an array of modelviews with one element for each of the Logical, UseCase, Component, Deployment, and EntityRelationship models. This prepares for implementing the loading of Rose controlled units. Stuff known to need work: - Support for external folders is temporarily broken - On loading previous XMI files, the contents of user created folders appear okay in the listview but are not located inside the proper UMLFolder in the document - The Datatypes folder appears multiple times in the list view - Diagrams should appear in the XMI.extension of the respective UMLFolder CCBUG:87252 CCBUG:81364 M +2 -0 Makefile.am M +0 -4 artifact.h M +9 -5 association.cpp M +6 -5 classifier.cpp M +4 -6 clipboard/umldrag.cpp M +0 -1 codeimport/import_utils.cpp M +4 -6 dialogs/umloperationdialog.cpp M +4 -3 entity.cpp M +0 -5 enum.h A folder.cpp [License: GPL (v2+)] A folder.h [License: GPL (v2+)] M +9 -1 listpopupmenu.cpp M +7 -0 main.cpp M +2 -1 messagewidget.cpp M +149 -15 model_utils.cpp M +28 -4 model_utils.h M +47 -9 object_factory.cpp M +2 -6 object_factory.h M +6 -11 operation.cpp M +63 -32 package.cpp M +10 -11 package.h M +3 -1 uml.cpp M +230 -222 umldoc.cpp M +32 -20 umldoc.h M +676 -753 umllistview.cpp M +75 -107 umllistview.h M +67 -166 umllistviewitem.cpp M +3 -11 umllistviewitem.h M +63 -7 umlnamespace.h M +14 -46 umlobject.cpp M +1 -7 umlobject.h M +53 -54 umlview.cpp M +2 -1 umlwidget.cpp A uniqueid.cpp [License: no copyright] A uniqueid.h [License: GPL (v2+)] M +0 -3 usecase.h
SVN commit 579333 by okellogg: 1. Move ownership and basic management of UMLViews from UMLDoc to UMLFolder. This closes out the TODO mentioned in commit 575645, "Diagrams should appear in the XMI.extension of the respective UMLFolder". The only remaining TODO is "Support for external folders is temporarily broken". 2. Move convert_*() and typeIs*() utility functions from UMLListView to Model_Utils. CCBUG:81364 M +8 -7 clipboard/umlclipboard.cpp M +163 -6 folder.cpp M +56 -0 folder.h M +472 -1 model_utils.cpp M +79 -0 model_utils.h M +55 -82 umldoc.cpp M +1 -19 umldoc.h M +67 -521 umllistview.cpp M +0 -76 umllistview.h M +8 -8 umllistviewitem.cpp M +1 -1 umlobject.cpp M +5 -5 umlview.cpp
SVN commit 682168 by okellogg: handleControlledUnit(): New. To be fleshed out Real Soon Now. CCBUG:81364 M +33 -8 petaltree2uml.cpp --- trunk/KDE/kdesdk/umbrello/umbrello/petaltree2uml.cpp #682167:682168 @@ -304,6 +304,30 @@ }; /** + * 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, 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. @@ -324,15 +348,16 @@ UMLObject *o = Import_Utils::createUMLObject(Uml::ot_Package, name, parentPkg); o->setID(id); PetalNode *logical_models = node->findAttribute("logical_models").node; - if (logical_models == NULL) { - kError() << "umbrellify: cannot find logical_models" << endl; - return false; + 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)) { + kDebug() << "umbrellify: handling of " << objType << " " << name + << " is not yet implemented" << endl; } - 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 (objType == "Class") { UMLObject *o = Import_Utils::createUMLObject(Uml::ot_Class, name, parentPkg);
You need to log in before you can comment on or make changes to this bug.