Version: (using KDE KDE 3.1) Installed from: Debian testing/unstable Packages OS: Linux The file save format of Umbrello should conform to the file format specified with the uml13.dtd to increase interoperability with other tools like ArgoUML, Rhapsody etc. which are also using XMI with this DTD.
I just tried to read an Umbrello 1.1.1 file with Poseidon UML CE 1.6.1 (see http://www.gentleware.com). No luck. I don't know whose fault this is. I'll let you hash it out.
The file format used by Umbrello does not conform to any version of the XMI standard. For some further discussion see e.g. http://www.dstc.edu.au/ListArchive/xmi/archive/2003/01/msg00009.html I'm starting work on changing the file format to at least remotely resemble XMI (the tricky part being to continue supporting the old format), but unfortunately the repair of this problem won't make it into umbrello-1.2.
Some progress was made, we now have a <UML:Model> tag. Associations are saved using the <UML:Association> tag appropriately (i.e. using the inner tags <UML:Association.connection> and <UML:AssociationEnd>). Generalizations are saved using the <UML:Generalization> tag, but no use is made of the "generalization" attribute (to be checked: is this okay?) Still on the TODO list (i.e. not ready for version 1.2) are at least the following: * Get rid of the non-standard tags such as <docsettings>, <diagrams>, <listview>, i.e. use the proper XMI extension mechanism. (Furthermore, for <diagram> use SVG.) * Saving of realizations. With the ID-based logic that Umbrello currently uses for saving/loading UMLAssociations, we would need a <UML:Realization> tag, but there is no such thing. * Validate the XMI produced.
A first interop test: http://www.jeckle.de/example1_xmiv11.xml Checkins to follow shortly.
Created an attachment (id=5760) [details] uml14.xmi (demonstrates XMI format from nsuml)
I plan to have the following two files loadable by umbrello shortly: http://cvs.sourceforge.net/viewcvs.py/nsuml/nsuml1_4/model/uml14.xml and the above attachment. For requests of interoperation with a specific tool, please give a URL of a sample, or create an attachment.
We're getting there: The classes (including attributes) and packages from the demo files are getting loaded. XMI tags not currently supported are UML:Tag, UML:Import, UML:Reference, UML:Multiplicity.
Setting to works-for-me to indicate that in principle, the XMI format used by umbrello is now standards compliant. Operations need a little more work, which will be done within the next few days.
Unfortunately the save format for template and stereotypes is not yet standards compliant, which probably means it will be that way in Umbrello 1.3. Generally the template and stereotype handling code in Umbrello needs major work.
> Unfortunately the save format for template and stereotypes is not yet > standards compliant, [...] Minor update: I managed to correct the save format for stereotypes just in time before the total freeze for 1.3. Another remark for 1.3: I've tried loading foreign XMI files into umbrello but haven't tried loading Umbrello generated files into other tools.
Need to reopen this because the "type" attribute of <UML:Attribute> should be an xmi.id not a plain name. Fix is forthcoming.
The "type" attribute of <UML:Attribute> and <UML:Parameter> is now an xmi.id not a plain name. (Unfortunately this change didn't make it into 1.3.) Also XML comments are handled properly. For example, it is now possible to load the following file: http://ncicb.nci.nih.gov/content/ncicblfs/caBIOmdlandxmi/caCORE2.1_XMI_Pub.xmi Nevertheless I leave this REOPENED because there is still more work to do.
Further tests with foreign XMI files show that forward references are ubiquitously used. However, until recently Umbrello only did ad hoc xmi.id resolution (the object referred to by an xmi.id must already be known at the point of reference during load.) Work is currently underway for adding a deferred type resolution pass.
The separate xmi.id resolution pass is now in place. Also, Umbrello's internal storage type for xmi.id's is now string (before, it was int) and this normalizes the ID handling across foreign vs. native XMI files.
From http://mde.abo.fi/tools/Coral/documentation/compatibility/ : > Umbrello 1.3 does not generate XMI files correctly since it does not > include the name of the properties in composition associations. > Therefore, Coral cannot load models generated by Umbrello.
From Ivan Porres (developer of Coral, http://sourceforge.net/projects/coral) <quote> The main problem with the generated XMI is that it does not add the names of the properties in compositions. For example: Umbrello generates: <UML:Model> <UML:Stereotype visibility="public" xmi.id="13" name="actor" /> <UML:Stereotype visibility="public" xmi.id="15" name="class" /> <UML:Stereotype visibility="public" xmi.id="17" name="datatype" /> <UML:DataType stereotype="17" visibility="public" xmi.id="16" name="void" /> <UML:Class visibility="public" xmi.id="6" name="UMLListView" > ... When it should generate: <UML:Model> <UML:ModelElement.stereotype> <UML:Stereotype visibility="public" xmi.id="13" name="actor" /> <UML:Stereotype visibility="public" xmi.id="15" name="class" /> <UML:Stereotype visibility="public" xmi.id="17" name="datatype" /> </UML:ModelElement.stereotype> <UML:Namespace.ownedElement> <UML:DataType stereotype="17" visibility="public" xmi.id="16" name="void" /> <UML:Class visibility="public" xmi.id="6" name="UMLListView" > <UML:Classifier.feature> <UML:Operation visibility="public" xmi.id="77" type="16" name="contentsMousePressEvent" /> <UML:Operation visibility="public" xmi.id="80" type="16" name="popupMenuSel" /> <UML:Operation visibility="public" xmi.id="32" type="16" name="addNewItem" /> <UML:Operation visibility="public" xmi.id="53" type="16" name="slotItemRenamed" /> <UML:Operation visibility="public" xmi.id="56" type="16" name="createChildUMLObject" /> </UML:Classifier.feature> Also, Umbrello does not conform to the UML 1.3 standard. IIRC, A UML 1.3 Operation does not have a property called type. Check the standard. Is this the return type of the operation? This is modeled by creating a Parameter with direction "return" and the desired type. </quote> Implemented these suggestions and updated the sample file http://uml.sourceforge.net/developers/CreateOperationUsingRightMousebuttonInListView.xmi
Might close this PR when Umbrello satisfies all of the following: http://www.innoq.com/iqgen/help-r2.1.0/basic-html/ch04s07.html
If on loading a foreign file nothing is displayed in the list view, try saving the model under a different name, and loading the saved file. Usually the list view is then properly populated.
Created an attachment (id=8666) [details] demonstrates XMI format from Unisys This file showcases recent work on umbrello cvs head for loading foreign files (in particular, associations are now getting loaded.)
From Marcus Alanen (developer of Coral, http://sourceforge.net/projects/coral) <quote> What is XMI.exporterEncoding ?? XMI 1.2 does not have it. The timestamp is missing. I suggest using RFC822-conformant dates. See man strftime, and use "%a, %d %b %Y %H:%M:%S %z" or take the code from Coral. XMI.model requires xmi.version. (or leave the whole XMI.model out, it's not required) UML 1.3 namespace is "http://schema.omg.org/spec/UML/1.3", or is the "omg.org/UML/1.3" some compatibility namespace? Poseidon uses an unofficial namespace as well for UML 1.4 + Diagrams. Not important... Packages (and thus also UML:Model) lacks - isAbstract="false" - isLeaf="false" - isRoot="false" - isSpecification="false"> [...] Classes lack: - isAbstract="false" - isLeaf="false" - isRoot="false" - isSpecification="false"> Generalization lacks: - name = "" - discriminator = "" - isSpecification = "false" Additionally, each subClass needs a <UML:GeneralizableElement.generalization> <UML:Generalization xmi.idref="e5" /> </UML:GeneralizableElement.generalization> where "e5" here means the id of the Generalization. There ought to be a similar thing for superclasses, <UML:GeneralizableElement.specialization> <UML:Generalization xmi.idref="e5" /> </UML:GeneralizableElement.specialization> but some tools skip this... Actors lack: - isAbstract="false" - isRoot="false" - isSpecification="false" - isLeaf="false" [...] Dependency is completely missing! </quote> <UML:Dependency> is now implemented. Further adjustments will follow shortly.
From Marcus Alanen (maalanen_AT_ra.abo.fi) <quote> Stereotype should have an icon="" and baseClass="" attribute. [...] AssociationEnds should not have isLeaf, isRoot, isAbstract. (isSpecification should be there) AssociationEnds should further have - isNavigable = "(true|false)" - type = "id" where id is the id of the class where we point to - ordering = "(unordered|ordered)" if order of elements matters - aggregation = "(none|aggregate|composite)" (nothing, empty diamond, black diamond) - targetScope = "(instance|classifier)" if it points to objects or classes - changeability = "(changeable|frozen|addOnly)" Above, I've tried to give the "most suitable" enumeration value first. Classes should have: <UML:Classifier.associationEnd> <UML:AssociationEnd xmi.idref="e3" /> </UML:Classifier.associationEnd> where e3 is the AssociationEnd they have. By the way you can add several easily with <UML:Classifier.associationEnd> <UML:AssociationEnd xmi.idref="e3" /> <UML:AssociationEnd xmi.idref="e4" /> <UML:AssociationEnd xmi.idref="e5" /> .... </UML:Classifier.associationEnd> instead of <UML:Classifier.associationEnd> <UML:AssociationEnd xmi.idref="e3" /> </UML:Classifier.associationEnd> <UML:Classifier.associationEnd> <UML:AssociationEnd xmi.idref="e4" /> </UML:Classifier.associationEnd> ... This goes for any such constructs. All AssociationEnds must have exactly one Multiplicity element as well: <UML:AssociationEnd.multiplicity> <UML:Multiplicity xmi.id="e7" > .... </UML:Multiplicity> </UML:AssociationEnd.multiplicity> There can be 0 to many MultiplicityRanges inside a Multiplicity. <UML:Multiplicity.range> <UML:MultiplicityRange xmi.id="e8" lower = "0" upper = "5" /> <UML:MultiplicityRange xmi.id="e8" lower = "12" upper = "14" /> <UML:MultiplicityRange xmi.id="e8" lower = "100" upper = "-1" /> </UML:Multiplicity.range> Regarding XMI.extensions, I think you should declare the XML namespace (with xmlns:umbrello="http://blahblah/") either - at top-level XMI together with the xmlns:UML definition, - at XMI.extensions - at *every* top-level element inside XMI.extensions: I think the first one is easiest, and hopefully doesn't cause any compatibility problems with other tools. Anyway, you need then a "umbrello:" prefix for every top-level element inside XMI.extensions: <umbrello:docsettings viewid="118" documentation="" uniqueid="133" /> <umbrello:diagrams> ....</ > <umbrello:listview> ....</ > ... etc.. The string doesn't have to be "umbrello", it can be anything you want, since the xmlns declaration is the key. </quote>
*** Currently, AssociationEnds sometimes have and sometimes don't the isNavigable and aggregation attributes. They are both mandatory. e.g. I get <UML:AssociationEnd ... aggregation="none" type="146" name="" /> <UML:AssociationEnd ... type="145" name="" /> as well as <UML:AssociationEnd ... aggregation="none" type="145" name="" /> <UML:AssociationEnd ... isNavigable="true" type="147" name="" /> *** Adding containment between a Class and another Class makes it use the "feature" property, which is incorrect (very much so, since feature ought to contain Feature-types, not Classes). It should use "ownedElement" instead. I.e. <UML:Class ... name="new_class" > <UML:Classifier.feature> <UML:Class name="new_class_1" /> </UML:Classifier.feature> </UML:Class> becomes s/feature/ownedElement. *** Dependency mustn't have isLeaf, isRoot, isAbstract. *** Generalization mustn't have isLeaf, isRoot, isAbstract.
CVS commit by okellogg: Comment by M. Alanen: > Additionally, each subClass needs a > <UML:GeneralizableElement.generalization> > <UML:Generalization xmi.idref="e5" /> > </UML:GeneralizableElement.generalization> > where "e5" here means the id of the Generalization. CCBUG:56184 M +15 -0 classifier.cpp 1.65 --- kdesdk/umbrello/umbrello/classifier.cpp #1.64:1.65 @@ -432,4 +432,19 @@ void UMLClassifier::saveToXMI(QDomDocume qElement.appendChild( tmplElement ); } + //save generalizations (we are the subclass, the other end is the superclass) + UMLAssociationList generalizations = getSpecificAssocs(Uml::at_Generalization); + if (generalizations.count()) { + QDomElement genElement = qDoc.createElement("UML:GeneralizableElement.generalization"); + for (UMLAssociation *a = generalizations.first(); a; a = generalizations.next()) { + // We are the subclass if we are at the role A end. + if (m_nId != a->getObjectId(Uml::A)) + continue; + QDomElement gElem = qDoc.createElement("UML:Generalization"); + gElem.setAttribute( "xmi.idref", ID2STR(a->getID()) ); + genElement.appendChild(gElem); + } + if (genElement.hasChildNodes()) + qElement.appendChild( genElement ); + } }
Marcus Alanen wrote: > AssociationEnds should further have > - isNavigable = "(true|false)" > - type = "id" where id is the id of the class where we point to > - ordering = "(unordered|ordered)" if order of elements matters > - aggregation = "(none|aggregate|composite)" (nothing, empty diamond, > black diamond) Just to make sure I am understanding, here are my assumptions: 1) Simple (undirected) association between class A and class B AssociationEnd A: isNavigable="true" AssociationEnd B: isNavigable="true 2) Directed association from class A to class B (arrowhead at B) AssociationEnd A: isNavigable="false" AssociationEnd B: isNavigable="true" 3) Aggregation: A has a reference to B (hollow diamond at A) AssociationEnd A: isNavigable="false" aggregation="aggregate" AssociationEnd B: isNavigable="true" aggregation="none" 4) Composition: A contains an instance of B (solid diamond at A) AssociationEnd A: isNavigable="false" aggregation="composite" AssociationEnd B: isNavigable="true" aggregation="none" aggregation="none" if not stated otherwise, targetScope="instance" and ordering="false" in all cases. Okay?
> 1) Simple (undirected) association between class A and class B > > AssociationEnd A: isNavigable="true" > AssociationEnd B: isNavigable="true Yes, OK. > 2) Directed association from class A to class B > (arrowhead at B) > > AssociationEnd A: isNavigable="false" > AssociationEnd B: isNavigable="true" I had to check... This is how we're doing it as well. OK. > 3) Aggregation: A has a reference to B > (hollow diamond at A) > > AssociationEnd A: isNavigable="false" aggregation="aggregate" > AssociationEnd B: isNavigable="true" aggregation="none" OK, although there's no reason why isNavigable couldn't be true also at the A end. The way you do it above, you should draw it as a hollow diamond at A, and an arrowhead at B. (In programming you even quite often have this case, where the "B" objects have a pointer to their parent "A" element) > 4) Composition: A contains an instance of B > (solid diamond at A) > > AssociationEnd A: isNavigable="false" aggregation="composite" > AssociationEnd B: isNavigable="true" aggregation="none" Ditto here. > aggregation="none" if not stated otherwise, > targetScope="instance" and ordering="false" in all cases. OK.
CVS commit by okellogg: Comment by M. Alanen: > Currently, AssociationEnds sometimes have and sometimes don't > the isNavigable and aggregation attributes. They are both mandatory. CCBUG:56184 M +10 -0 association.cpp 1.64 M +15 -2 association.h 1.33 M +27 -11 umlrole.cpp 1.37
Created an attachment (id=9024) [details] DiagramDynamic.xmi - state diagram created by TogetherSoft While Umbrello is approaching standard conformance for class diagram related objects, there is still much work to do for sequence and state diagram related objects. This file demonstrates the XMI for objects of a state diagram.
With the checkins of yesterday and today, Umbrello basically loads all of the samples from the XMI interop test presented at http://www.ida.his.se/~pesn/study/Study.pdf (see http://sourceforge.net/mailarchive/forum.php?thread_id=6540126&forum_id=472). More fine tuning is required. For example, after loading some of the files Umbrello appears to be empty. The trick in that case is to save the seemingly empty model, close Umbrello, and reload the saved file. Thanks to Anna Persson for providing the sample XMI files.
CVS commit by okellogg: load(): Fix loading of multiplicities from foreign XMI files. CCBUG:56184 M +1 -0 umlrole.cpp 1.39 --- kdesdk/umbrello/umbrello/umlrole.cpp #1.38:1.39 @@ -225,4 +225,5 @@ bool UMLRole::load( QDomElement & elemen continue; } + tempElement = n.toElement(); tag = tempElement.tagName(); if (!Uml::tagEq(tag, "Multiplicity")) {
The newly added support for association classes is not yet standard compliant (we should create the <UML:AssociationClass> element)
Some observatiosn regarding compliance of the classes: 1) Attribute doesn't inherit from GeneralizableElement and so it shoudln't have isRoot, isLeaf or isAbstract 2) isRoot always appears to be set to false. Is shoudl be true for root classes and Operations.
> Some observatiosn regarding compliance of the classes: > > 1) Attribute doesn't inherit from GeneralizableElement and so it shoudln't > have isRoot, isLeaf or isAbstract Verified. They should indeed be removed. > 2) isRoot always appears to be set to false. Is shoudl be true for root > classes and Operations. No. UML 1.3 section 2.5.3.18 (part 1) states "A root cannot have any Generalizations: self.isRoot implies self.generalization->isEmpty". I take this to mean that if you set isRoot of a Class to true, then you cannot add superclasses to that class anymore (Similarly for isLeaf: you can't add subclasses). The importance of using isRoot in the first place is quite questionable. Sometimes people would like to make their classes non-subclassable (i.e. isLeaf support), but even that is mostly bad design. But I _think_ Java's "final class..." supports this. I wouldn't bother with isLeaf or isRoot, but I'm all talk, no code.
Because Java has the final keyword this is where isLeaf is used (for either classes or methods) I must admit that I'd interpreted isRoot more as a doesn't have rather than a can't have. Off the top of my head I can't think of a construct that prevents superclassing (if that's a word?) graeme On 27 Jun 2005 10:32:24 -0000, Marcus Alanen <maalanen@abo.fi> wrote: [bugs.kde.org quoted mail]
> I must admit that I'd interpreted isRoot more as a doesn't have rather > than a can't have. Off the top of my head I can't think of a construct > that prevents superclassing (if that's a word?) I'd say the interpretation is still "can't have". The rule 2.5.3.18 explictly says "A root cannot have any Generalizations". So if isRoot == true it indeed prevents superclassing. I don't understand why anybody would need such a thing, though.
SVN commit 430870 by okellogg: save(): Comment #31 From graeme foster 2005-06-27 08:42: > 1) Attribute doesn't inherit from GeneralizableElement and so it shouldn't > have isRoot, isLeaf or isAbstract CCBUG:56184 M +3 -1 umlobject.cpp --- trunk/KDE/kdesdk/umbrello/umbrello/umlobject.cpp #430869:430870 @@ -451,7 +451,9 @@ */ QDomElement qElement = qDoc.createElement(tag); qElement.setAttribute( "isSpecification", "false" ); - if (m_BaseType != Uml::ot_Association && m_BaseType != Uml::ot_Role) { + if (m_BaseType != Uml::ot_Association && + m_BaseType != Uml::ot_Role && + m_BaseType != Uml::ot_Attribute) { qElement.setAttribute( "isLeaf", "false" ); qElement.setAttribute( "isRoot", "false" ); if (m_bAbstract)
SVN commit 483699 by okellogg: Give the <UML:Model> an xmi.id. Add the attribute "namespace" when saving the XMI of UMLObjects. These changes get Umbrello files imported into StarUML (http://www.staruml.com) CCBUG:56184 M +6 -0 umldoc.cpp M +7 -0 umldoc.h M +6 -0 umlobject.cpp --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umldoc.cpp #483698:483699 @@ -90,6 +90,7 @@ UMLDoc::UMLDoc() { m_Name = i18n("UML Model"); + m_modelID = "m1"; m_currentView = 0; m_uniqueID = 0; m_count = 0; @@ -1494,6 +1495,10 @@ return m_Name; } +Uml::IDType UMLDoc::getModelID() const { + return m_modelID; +} + void UMLDoc::saveToXMI(QIODevice& file, bool saveSubmodelFiles /* = false */) { QDomDocument doc; @@ -1570,6 +1575,7 @@ QDomElement contentNS = doc.createElement( "UML:Namespace.contents" ); QDomElement objectsElement = doc.createElement( "UML:Model" ); + objectsElement.setAttribute( "xmi.id", ID2STR(m_modelID) ); objectsElement.setAttribute( "name", m_Name ); objectsElement.setAttribute( "isSpecification", "false" ); objectsElement.setAttribute( "isAbstract", "false" ); --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umldoc.h #483698:483699 @@ -432,6 +432,12 @@ QString getName() const; /** + * Return the m_modelID (currently this a fixed value: + * Umbrello supports only a single document.) + */ + Uml::IDType getModelID() const; + + /** * Used to give a unique ID to any sort of object. * * @return A new unique ID. @@ -931,6 +937,7 @@ int m_uniqueID; QString m_Name; ///< name of this model as stored in the <UML:Model> tag + Uml::IDType m_modelID; ///< xmi.id of this model in the <UML:Model> int m_count; ///< auxiliary counter for the progress bar bool m_modified; KURL m_doc_url; --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umlobject.cpp #483698:483699 @@ -471,6 +471,12 @@ } qElement.setAttribute( "xmi.id", ID2STR(m_nId) ); qElement.setAttribute( "name", m_Name ); + Uml::IDType nmSpc; + if (m_pUMLPackage) + nmSpc = m_pUMLPackage->getID(); + else + nmSpc = UMLApp::app()->getDocument()->getModelID(); + qElement.setAttribute( "namespace", ID2STR(nmSpc) ); if (! m_Doc.isEmpty()) qElement.setAttribute( "comment", m_Doc ); //CHECK: uml13.dtd compliance #ifdef XMI_FLAT_PACKAGES
SVN commit 484294 by okellogg: First set of changes motivated by comments from Tom Morris for loading Umbrello files into ArgoUML-0.20alpha2. CCBUG:56184 M +1 -0 THANKS M +2 -1 umbrello/attribute.cpp M +1 -1 umbrello/classifier.cpp M +10 -6 umbrello/umlobject.cpp --- branches/KDE/3.5/kdesdk/umbrello/THANKS #484293:484294 @@ -46,6 +46,7 @@ martin <mv123q3 @hotmail.com> Rene Meyer <Rene.Meyer @sturmit.de> Laurent Montel <montel @kde.org> +Tom Morris <tfmorris @gmail.com> Lutz Mueller <lutz.mueller @gmx.de> Heiko Nardmann <heiko.nardmann @onlinehome.de> Dimitri Ognibene <ognibened @yahoo.it> --- branches/KDE/3.5/kdesdk/umbrello/umbrello/attribute.cpp #484293:484294 @@ -188,7 +188,8 @@ } else { attributeElement.setAttribute( "type", ID2STR(m_pSecondary->getID()) ); } - attributeElement.setAttribute( "initialValue", m_InitialValue ); + if (! m_InitialValue.isEmpty()) + attributeElement.setAttribute( "initialValue", m_InitialValue ); qElement.appendChild( attributeElement ); } --- branches/KDE/3.5/kdesdk/umbrello/umbrello/classifier.cpp #484293:484294 @@ -775,7 +775,7 @@ genElement.appendChild(gElem); } if (genElement.hasChildNodes()) - qElement.appendChild( genElement ); + classifierElement.appendChild( genElement ); } // save attributes --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umlobject.cpp #484293:484294 @@ -471,12 +471,16 @@ } qElement.setAttribute( "xmi.id", ID2STR(m_nId) ); qElement.setAttribute( "name", m_Name ); - Uml::IDType nmSpc; - if (m_pUMLPackage) - nmSpc = m_pUMLPackage->getID(); - else - nmSpc = UMLApp::app()->getDocument()->getModelID(); - qElement.setAttribute( "namespace", ID2STR(nmSpc) ); + if (m_BaseType != Uml::ot_Operation && + m_BaseType != Uml::ot_Role && + m_BaseType != Uml::ot_Attribute) { + Uml::IDType nmSpc; + if (m_pUMLPackage) + nmSpc = m_pUMLPackage->getID(); + else + nmSpc = UMLApp::app()->getDocument()->getModelID(); + qElement.setAttribute( "namespace", ID2STR(nmSpc) ); + } if (! m_Doc.isEmpty()) qElement.setAttribute( "comment", m_Doc ); //CHECK: uml13.dtd compliance #ifdef XMI_FLAT_PACKAGES
SVN commit 487430 by okellogg: load(): In UML 1.4, the aggregation attribute has a value "aggregate" instead of "shared". Thanks to Tom Morris for pointing this out. CCBUG:56184 M +2 -1 umlrole.cpp --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umlrole.cpp #487429:487430 @@ -298,7 +298,8 @@ QString aggregation = element.attribute("aggregation", "none"); if (aggregation == "composite") m_pAssoc->setAssocType(Uml::at_Composition); - else if (aggregation == "shared") + else if (aggregation == "shared" // UML1.3 + || aggregation == "aggregate") // UML1.4 m_pAssoc->setAssocType(Uml::at_Aggregation); /* else m_pAssoc->setAssocType(Uml::at_Association); */
SVN commit 490149 by okellogg: {set,get}{Name,Doc}, m_{Name,Doc}: Remove erroneous duplication from parent. load(): StarUML puts the aggregation value at role B so load the aggregation attribute on both roles. CCBUG:56184 M +11 -28 umlrole.cpp M +0 -31 umlrole.h --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umlrole.cpp #490148:490149 @@ -55,14 +55,6 @@ return m_Multi; } -QString UMLRole::getName() const { - return m_Name; -} - -QString UMLRole::getDoc() const { - return m_Doc; -} - void UMLRole::setObject (UMLObject *obj) { // because we will get the id of this role from the parent // object, we CANT allow UMLRoles to take other UMLRoles as @@ -89,16 +81,6 @@ emit modified(); } -void UMLRole::setName( const QString &roleName ) { - m_Name = roleName; - emit modified(); -} - -void UMLRole::setDoc( const QString &doc ) { - m_Doc = doc; - emit modified(); -} - Uml::Role_Type UMLRole::getRole() { return m_role; } @@ -294,16 +276,17 @@ // the component roles/linked items needs to be done in order to get things // right. *sigh* -b.t. - if (m_role == Uml::A) { // setting association type from the role (A) - QString aggregation = element.attribute("aggregation", "none"); - if (aggregation == "composite") - m_pAssoc->setAssocType(Uml::at_Composition); - else if (aggregation == "shared" // UML1.3 - || aggregation == "aggregate") // UML1.4 - m_pAssoc->setAssocType(Uml::at_Aggregation); - /* else - m_pAssoc->setAssocType(Uml::at_Association); */ - } + // Setting association type from the role (A) + // Determination of the "aggregation" attribute used to be done only + // when (m_role == Uml::A) but some XMI writers (e.g. StarUML) place + // the aggregation attribute at role B. + // The role end with the aggregation unequal to "none" wins. + QString aggregation = element.attribute("aggregation", "none"); + if (aggregation == "composite") + m_pAssoc->setAssocType(Uml::at_Composition); + else if (aggregation == "shared" // UML1.3 + || aggregation == "aggregate") // UML1.4 + m_pAssoc->setAssocType(Uml::at_Aggregation); if (!element.hasAttribute("isNavigable")) { /* Backward compatibility mode: In Umbrello version 1.3.x the --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umlrole.h #490148:490149 @@ -67,20 +67,6 @@ QString getMultiplicity() const; /** - * Returns the name assigned to the role. - * - * @return The name assigned to the role. - */ - QString getName() const; - - /** - * Returns the documentation for the role. - * - * @return The documentation text for the role. - */ - QString getDoc() const; - - /** * Sets the UMLObject playing the role in the association. * * @param obj Pointer to the UMLObject of role. @@ -101,20 +87,6 @@ */ void setMultiplicity ( const QString &multi ); - /** - * Sets the name of the role. - * - * @param roleName The name of role. - */ - void setName( const QString &roleName ); - - /** - * Sets the documentation on the role. - * - * @param doc The string with the documentation. - */ - void setDoc( const QString &doc ); - UMLAssociation * getParentAssociation (); // Sets the m_SecondaryId @@ -152,13 +124,10 @@ /** do some initialization at construction time */ void init (UMLAssociation * parent, UMLObject * parentObj, Uml::Role_Type r); - QString m_Doc; UMLAssociation * m_pAssoc; Uml::Role_Type m_role; - QString m_Name; QString m_Multi; Uml::Changeability_Type m_Changeability; - }; #endif
Created an attachment (id=14038) [details] EAExample-DesignModel-xmi12.xmi - XMI file created by Enterprise Architect This demonstrates the XMI format of Enterprise Architect 5.00.764, XMI.exporterVersion 4.1. On exporting, it is important to select the XMI version 1.2 in the "Export Package to XMI" options.
> EAExample-DesignModel-xmi12.xmi - XMI file created by Enterprise Architect > This demonstrates the XMI format of Enterprise Architect 5.00.764, > XMI.exporterVersion 4.1. Hi, please note that Enterprise Architect creates very bad XMI files: - AssociationEndRoles shouldn't have "type" and "isOrdered", I think. - TaggedValues come directly after an element, even though there should be the slot name in-between. - Constraint elements should be used as associations, not compositions. - The same "xmi.id" value is used multiple times for different elements. (!) - Diagrams are serialized in some weird way, probably just their own invention. In general XMI compliance between tools is nonexisting.
SVN commit 492999 by okellogg: Add Java code import (still work in progress.) CCBUG:56184 M +1 -0 Makefile.am AM javaimport.cpp [License: GPL (v2+)] AM javaimport.h [License: GPL (v2+)] M +5 -0 uml.cpp --- branches/KDE/3.5/kdesdk/umbrello/umbrello/Makefile.am #492998:492999 @@ -52,6 +52,7 @@ idlimport.cpp \ import_utils.cpp \ infowidget.cpp \ +javaimport.cpp \ kstartuplogo.cpp \ linepath.cpp \ linkwidget.cpp \ ** branches/KDE/3.5/kdesdk/umbrello/umbrello/javaimport.cpp #property svn:executable + * ** branches/KDE/3.5/kdesdk/umbrello/umbrello/javaimport.h #property svn:executable + * --- branches/KDE/3.5/kdesdk/umbrello/umbrello/uml.cpp #492998:492999 @@ -51,6 +51,7 @@ #include "cppimport.h" #include "idlimport.h" #include "adaimport.h" +#include "javaimport.h" #include "docwindow.h" #include "codegenerator.h" #include "generatorinfo.h" @@ -1420,6 +1421,8 @@ QString preselectedExtension; if (m_activeLanguage == "IDL") { preselectedExtension = i18n("*.idl|IDL Files (*.idl)"); + } else if (m_activeLanguage == "Java") { + preselectedExtension = i18n("*.java|Java Files (*.java)"); } else if (m_activeLanguage == "Ada") { preselectedExtension = i18n("*.ads *.ada|Ada Files (*.ads *.ada)"); } else { @@ -1432,6 +1435,8 @@ const QString& firstFile = fileList.first(); if (firstFile.endsWith(".idl")) classImporter = new IDLImport(); + else if (firstFile.endsWith(".java")) + classImporter = new JavaImport(); else if (firstFile.contains( QRegExp("\\.ad[sba]$") )) classImporter = new AdaImport(); else
Created an attachment (id=14121) [details] poseidon321.xmi - XMI file exported from Poseidon 3.2.1 (Sorry for the previous bogus post, I got the bug# wrong) This file contains a directed aggregation from Klasse_2 to Klasse_1 (hollow diamond at Klasse2, stick arrowhead at Klasse_1). The display of that is not yet implemented in Umbrello so the stick arrowhead is missing. Also there is a <UML:Abstraction> from Klasse_2 (client) to Schnittstelle_1 (supplier) which Umbrello will deal with shortly.
> ------- Additional Comment #41 From Marcus Alanen 2005-12-29 18:10 > [...] > In general XMI compliance between tools is nonexisting. Hmm... The aim is to make Umbrello load the XMI from as many other tools as ever possible. ATM I'm still concentrating on the static structure elements of class diagrams. Please do give details if you find something missing.
SVN commit 493938 by okellogg: Support loading of <UML:Abstraction> as demonstrated in http://bugs.kde.org/attachment.cgi?id=14121&action=view CCBUG:56184 M +7 -12 association.cpp M +5 -0 umldoc.cpp --- branches/KDE/3.5/kdesdk/umbrello/umbrello/association.cpp #493937:493938 @@ -192,7 +192,8 @@ UMLDoc * doc = UMLApp::app()->getDocument(); UMLObject * obj[2] = { NULL, NULL }; if (m_AssocType == Uml::at_Generalization || - m_AssocType == Uml::at_Dependency) { + m_AssocType == Uml::at_Realization || + m_AssocType == Uml::at_Dependency) { for (unsigned r = Uml::A; r <= Uml::B; r++) { const QString fetch = (m_AssocType == Uml::at_Generalization ? r == Uml::A ? "child" : "parent" @@ -221,15 +222,9 @@ QString tag = tempElement.tagName(); if (Model_Utils::isCommonXMIAttribute(tag)) continue; - bool isGeneralization = (m_AssocType == Uml::at_Generalization && - (tagEq(tag, "child") || tagEq(tag, "parent") || - tagEq(tag, "subtype") || tagEq(tag, "supertype"))); - bool isDependency = (m_AssocType == Uml::at_Dependency && - (tagEq(tag, "client") || tagEq(tag, "supplier"))); - if (!isGeneralization && !isDependency) { - kdDebug() << "UMLAssociation::load: cannot load " << tag << endl; - continue; - } + // Permitted tag names: + // roleA: "child" "subtype" "client" + // roleB: "parent" "supertype" "supplier" QString idStr = tempElement.attribute( "xmi.id", "" ); if (idStr.isEmpty()) idStr = tempElement.attribute( "xmi.idref", "" ); @@ -242,8 +237,8 @@ } if (idStr.isEmpty()) { kdError() << "UMLAssociation::load (type " << m_AssocType - << ", id " << ID2STR(getID()) << "): " - << "xmi id not given for " << tag << endl; + << ", id " << ID2STR(getID()) << "): " + << "xmi id not given for " << tag << endl; continue; } // Since we know for sure that we're dealing with a non --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umldoc.cpp #493937:493938 @@ -2146,6 +2146,8 @@ if (tagEq(type, "Association") || tagEq(type, "AssociationClass") || tagEq(type, "Generalization") || + tagEq(type, "Realization") || + tagEq(type, "Abstraction") || tagEq(type, "Dependency")) { if ( !status ) { // Some interim umbrello versions saved empty UML:Associations, @@ -2279,6 +2281,9 @@ pObject = new UMLAssociation(); } else if (tagEq(type, "Generalization")) { pObject = new UMLAssociation(Uml::at_Generalization); + } else if (tagEq(type, "Realization") || + tagEq(type, "Abstraction")) { + pObject = new UMLAssociation(Uml::at_Realization); } else if (tagEq(type, "Dependency")) { pObject = new UMLAssociation(Uml::at_Dependency); }
SVN commit 496548 by okellogg: UMLRole::saveToXMI(): Change aggregation="shared" to "aggregate". UMLAssociation::saveToXMI(): Save abstraction as <UML:Abstraction>. Thanks to Tom Morris for clarifying. CCBUG:56184 CCMAIL:tfmorris@gmail.com M +8 -2 association.cpp M +1 -1 umlrole.cpp --- branches/KDE/3.5/kdesdk/umbrello/umbrello/association.cpp #496547:496548 @@ -161,8 +161,7 @@ } void UMLAssociation::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) { - if (m_AssocType == Uml::at_Generalization || - m_AssocType == Uml::at_Realization) { + if (m_AssocType == Uml::at_Generalization) { QDomElement assocElement = UMLObject::save("UML:Generalization", qDoc); assocElement.setAttribute( "discriminator", "" ); assocElement.setAttribute( "child", ID2STR(getObjectId(A)) ); @@ -170,6 +169,13 @@ qElement.appendChild( assocElement ); return; } + if (m_AssocType == Uml::at_Realization) { + QDomElement assocElement = UMLObject::save("UML:Abstraction", qDoc); + assocElement.setAttribute( "client", ID2STR(getObjectId(A)) ); + assocElement.setAttribute( "supplier", ID2STR(getObjectId(B)) ); + qElement.appendChild( assocElement ); + return; + } if (m_AssocType == Uml::at_Dependency) { QDomElement assocElement = UMLObject::save("UML:Dependency", qDoc); assocElement.setAttribute( "client", ID2STR(getObjectId(A)) ); --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umlrole.cpp #496547:496548 @@ -118,7 +118,7 @@ roleElement.setAttribute("aggregation", "composite"); break; case Uml::at_Aggregation: - roleElement.setAttribute("aggregation", "shared"); + roleElement.setAttribute("aggregation", "aggregate"); break; default: roleElement.setAttribute("aggregation", "none");
From Tom Morris <tfmorris@gmail.com> Subject: RE: Loading Umbrello file into Argo [...] > > - aggregation="shared" (no such value in UML 1.4. Legal values are > > none, > > aggregate, composite) > > Ah. In XMI 1.2, it's "shared", see OMG document > formal/02-01-01, pg. A-41 of > the PDF: > <!ELEMENT UML:AssociationEnd.aggregation EMPTY > > > <!ATTLIST UML:AssociationEnd.aggregation > > xmi.value (none | shared | composite) #REQUIRED > If you look at the introducation to that appendix, the DTD is described as being generated from UML 1.1 specification using the XMI 1.2 generation rules. The DTD in the UML 1.3 specification on the other hand appears to have been generated using the UML 1.3 spec, but the XMI 1.0 production rules. It appears there isn't a good ready-to-use DTD in either of these specs. If look page 2-78 of the UML 1.3 specification, you'll see values allowed for the AggregationKind element.
The stereotypes of classes are 'lost' when importing an XMI file from argoUML (tested against argoUML 0.18 and 0.20) I assume this links back to the file-format issue?
SVN commit 511268 by okellogg: Load and resolve stereotypes as generated by Sun's Metadata Repository (http://mdr.netbeans.org) and as used by ArgoUML 0.20. Thanks to Edward Nash for noticing the problem. CCBUG:56184 M +4 -1 umldoc.cpp M +31 -3 umlobject.cpp --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umldoc.cpp #511267:511268 @@ -826,7 +826,10 @@ } UMLObject* UMLDoc::findObjectById(Uml::IDType id) { - return Model_Utils::findObjectInList(id, m_objectList); + UMLObject *o = Model_Utils::findObjectInList(id, m_objectList); + if (o == NULL) + o = findStereotypeById(id); + return o; } UMLStereotype * UMLDoc::findStereotypeById(Uml::IDType id) { --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umlobject.cpp #511267:511268 @@ -416,6 +416,11 @@ if (! m_SecondaryId.isEmpty()) { m_pSecondary = pDoc->findObjectById(STR2ID(m_SecondaryId)); if (m_pSecondary != NULL) { + if (m_pSecondary->getBaseType() == Uml::ot_Stereotype) { + m_pStereotype = static_cast<UMLStereotype*>(m_pSecondary); + m_pStereotype->incrRefCount(); + m_pSecondary = NULL; + } m_SecondaryId = ""; maybeSignalObjectCreated(); return true; @@ -665,9 +670,9 @@ } /**** End of XMI_FLAT_PACKAGES and old files handling ****************/ - // If the name is not set, let's check whether the attributes are saved - // as child nodes. - if (m_Name.isEmpty()) { + // If the node has child nodes, check whether attributes can be + // extracted from them. + if (element.hasChildNodes()) { QDomNode node = element.firstChild(); if (node.isComment()) node = node.nextSibling(); @@ -698,6 +703,29 @@ if (ownerScope.isEmpty()) ownerScope = elem.text(); m_bStatic = (ownerScope == "classifier"); + } else if (Uml::tagEq(tag, "stereotype")) { + QString stereo = elem.attribute("xmi.value", ""); + if (stereo.isEmpty() && elem.hasChildNodes()) { + /* like so: + <UML:ModelElement.stereotype> + <UML:Stereotype xmi.idref = '07CD'/> + </UML:ModelElement.stereotype> + */ + QDomNode stereoNode = elem.firstChild(); + QDomElement stereoElem = stereoNode.toElement(); + tag = stereoElem.tagName(); + if (Uml::tagEq(tag, "Stereotype")) { + stereo = stereoElem.attribute("xmi.idref", ""); + } + } + if (! stereo.isEmpty()) { + Uml::IDType stereoID = STR2ID(stereo); + m_pStereotype = umldoc->findStereotypeById(stereoID); + if (m_pStereotype) + m_pStereotype->incrRefCount(); + else + m_SecondaryId = stereo; // leave it to resolveRef() + } } node = node.nextSibling(); if (node.isComment())
Will documents created with v. 1.5.2 ever be usable with a standard XMI-supporting software like ArgoUML, Rational Rose or Poseidon? I think it's a good idea to NOT name the generated files "XMI" files. If they don't validate, they aren't XMI. Nor does umbrello in that case support XMI. If you claim to support XMI, the resulting files should BE XMI files. This confuses users A LOT. Is there a way I can reconstruct the Umbrello file to a more or less usable XMI file? For example an XSLT or a list of incompatibilities that I'll have to remove?
I propose renaming the "XMI file" item in the save dialog to "Umbrello XMI-like file" or "UMB file" or something like that. That way you wont confuse users. At this moment probably a lot people are editing their UML models using Umbrello with the false hope/idea that the resulting file is a XMI file. It isn't. Confusing.
> Comment #50 From Philip Van Hoof > Will documents created with v. 1.5.2 ever be usable > with a standard XMI-supporting software like ArgoUML, > Rational Rose or Poseidon? As you may have noticed from the length of this PR, it's not so simple. There exist many dialects of XMI and it's difficult enough to grok most of them on importing, let alone concoct something that will be understood by most other tools on the market. We're always talking about specific problems between two specific versions of two specific tools. You can help in this effort by making detailed reports of the problems you encounter. Please state the exact tools and versions used; attach the XMI files(s) in question, and try to narrow down the problem as far as possible, and be as specific as possible. Thanks.
> ArgoUML, Rational Rose or Poseidon I could add that none of these tools produce standards-compliant XMI as far as I know. However, there certainly is a point in realizing that Umbrello or other open-source tools should be as compatible as reasonably possible with tools with a large userbase. Old Poseidon releases (and Argo?) is UML 1.4 by the way, Umbrello is 1.3 I think. So technically they even cannot be compatible. Newer Poseidon releases use a mixture of UML 1.4 and UML 2.0; I do not think it is worth spending time for compatibility purposes until they have migrated completely to UML 2.0. I'm not sure which UML version Rational Rose uses. My biggest gripe with the open-source UML tools in general is the lack of compatible diagram formats.
SVN commit 616054 by okellogg: Further fixes for loading Poseidon 4.1 xmi, e.g. http://uml2svg.sourceforge.net/samples/CoffeeMachine.xmi CCBUG:56184 M +6 -3 classifier.cpp --- branches/KDE/3.5/kdesdk/umbrello/umbrello/classifier.cpp #616053:616054 @@ -877,8 +877,10 @@ tagEq(tag, "Classifier.feature") || tagEq(tag, "Namespace.ownedElement") || tagEq(tag, "Namespace.contents")) { - if (! load(element)) - return false; + load(element); + // Not evaluating the return value from load() + // because we want a best effort. + } else if ((child = makeChildObject(tag)) != NULL) { if (child->loadFromXMI(element)) { switch (child->getBaseType()) { @@ -908,7 +910,8 @@ UMLDoc *umldoc = UMLApp::app()->getDocument(); UMLObject *pObject = Object_Factory::makeObjectFromXMI(tag); if (pObject == NULL) { - totalSuccess = false; + // Not setting totalSuccess to false + // because we want a best effort. continue; } pObject->setUMLPackage(this);
Created an attachment (id=21243) [details] http://fisheye.codehaus.org/browse/~raw,r=2486/mapbuilder/tags/mapbuilder-lib-1_5-rc1/mapbuilder/design/uml/mapbuilder.xmi This file demonstrates the XMI 1.2 produced by Netbeans XMI Writer 1.0, metamodel version 1.4.3.
SVN commit 692032 by okellogg: UMLObject::loadStereotype(): New, factored from loadFromXMI(). Further adjustments for loading attachment 21243 [details] (Netbeans XMI) CCBUG:56184 M +1 -0 model_utils.cpp M +3 -5 umldoc.cpp M +32 -23 umlobject.cpp M +8 -0 umlobject.h --- branches/KDE/3.5/kdesdk/umbrello/umbrello/model_utils.cpp #692031:692032 @@ -287,6 +287,7 @@ Uml::tagEq(tag, "isActive") || Uml::tagEq(tag, "namespace") || Uml::tagEq(tag, "ownerScope") || + Uml::tagEq(tag, "ModelElement.stereotype") || Uml::tagEq(tag, "GeneralizableElement.generalization") || Uml::tagEq(tag, "specialization") || //NYI Uml::tagEq(tag, "clientDependency") || //NYI --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umldoc.cpp #692031:692032 @@ -1660,16 +1660,14 @@ // From here on, it's support for stereotypes, pre 1.5.5 versions, and foreign files if (tagEq(type, "Namespace.ownedElement") || tagEq(type, "Namespace.contents") || - tagEq(type, "Model") || tagEq(type, "ModelElement.stereotype")) { + tagEq(type, "Model")) { //CHECK: Umbrello currently assumes that nested elements // are ownedElements anyway. // Therefore the <UML:Namespace.ownedElement> tag is of no // significance. if( !loadUMLObjectsFromXMI( tempElement ) ) { - if (! tagEq(type, "ModelElement.stereotype")) { // not yet implemented - kWarning() << "failed load on " << type << endl; - return false; - } + kWarning() << "failed load on " << type << endl; + return false; } continue; } --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umlobject.cpp #692031:692032 @@ -543,6 +543,36 @@ return true; } +bool UMLObject::loadStereotype(QDomElement & element) { + QString tag = element.tagName(); + if (!Uml::tagEq(tag, "stereotype")) + return false; + QString stereo = element.attribute("xmi.value", ""); + if (stereo.isEmpty() && element.hasChildNodes()) { + /* like so: + <UML:ModelElement.stereotype> + <UML:Stereotype xmi.idref = '07CD'/> + </UML:ModelElement.stereotype> + */ + QDomNode stereoNode = element.firstChild(); + QDomElement stereoElem = stereoNode.toElement(); + tag = stereoElem.tagName(); + if (Uml::tagEq(tag, "Stereotype")) { + stereo = stereoElem.attribute("xmi.idref", ""); + } + } + if (stereo.isEmpty()) + return false; + Uml::IDType stereoID = STR2ID(stereo); + UMLDoc *pDoc = UMLApp::app()->getDocument(); + m_pStereotype = pDoc->findStereotypeById(stereoID); + if (m_pStereotype) + m_pStereotype->incrRefCount(); + else + m_SecondaryId = stereo; // leave it to resolveRef() + return true; +} + bool UMLObject::loadFromXMI( QDomElement & element) { UMLDoc* umldoc = UMLApp::app()->getDocument(); if (umldoc == NULL) { @@ -674,29 +704,8 @@ if (ownerScope.isEmpty()) ownerScope = elem.text(); m_bStatic = (ownerScope == "classifier"); - } else if (Uml::tagEq(tag, "stereotype")) { - QString stereo = elem.attribute("xmi.value", ""); - if (stereo.isEmpty() && elem.hasChildNodes()) { - /* like so: - <UML:ModelElement.stereotype> - <UML:Stereotype xmi.idref = '07CD'/> - </UML:ModelElement.stereotype> - */ - QDomNode stereoNode = elem.firstChild(); - QDomElement stereoElem = stereoNode.toElement(); - tag = stereoElem.tagName(); - if (Uml::tagEq(tag, "Stereotype")) { - stereo = stereoElem.attribute("xmi.idref", ""); - } - } - if (! stereo.isEmpty()) { - Uml::IDType stereoID = STR2ID(stereo); - m_pStereotype = umldoc->findStereotypeById(stereoID); - if (m_pStereotype) - m_pStereotype->incrRefCount(); - else - m_SecondaryId = stereo; // leave it to resolveRef() - } + } else { + loadStereotype(elem); } node = node.nextSibling(); if (node.isComment()) --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umlobject.h #692031:692032 @@ -303,6 +303,14 @@ virtual bool loadFromXMI( QDomElement & element ); /** + * Analyzes the given QDomElement for a reference to a stereotype. + * + * @param element QDomElement to analyze. + * @return True if a stereotype reference was found, else false. + */ + bool loadStereotype(QDomElement & element); + + /** * Returns true if this UMLObject has classifier scope, * otherwise false (the default). */
You need to log in before you can comment on or make changes to this bug.