Bug 139856

Summary: should be able to duplicate sequence diagrams
Product: [Applications] umbrello Reporter: Gaël de Chalendar (aka Kleag) <kleagg>
Component: generalAssignee: Oliver Kellogg <okellogg>
Status: RESOLVED FIXED    
Severity: wishlist    
Priority: NOR    
Version: unspecified   
Target Milestone: ---   
Platform: unspecified   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:

Description Gaël de Chalendar (aka Kleag) 2007-01-10 14:46:17 UTC
Version:           1.5.51 (using KDE 3.5.4, compiled sources)
Compiler:          Target: i586-mandriva-linux-gnu
OS:                Linux (i686) release 2.6.17-5mdvcustom

Often, two or more sequence diagrams are designed to model various possibilities (when a condition is verified or not f.e.). You should be able to just duplicate the first one and do little changes on the new instance.
Comment 1 Oliver Kellogg 2007-04-09 14:45:14 UTC
SVN commit 651811 by okellogg:

makeWidgetFromXMI(): Add creation of MessageWidget.
 Remove compatibility hacks for ancient XMI files while at it.
CCBUG:139856


 M  +18 -22    widget_factory.cpp  


--- branches/KDE/3.5/kdesdk/umbrello/umbrello/widget_factory.cpp #651810:651811
@@ -44,6 +44,7 @@
 #include "notewidget.h"
 #include "boxwidget.h"
 #include "associationwidget.h"
+#include "messagewidget.h"
 #include "objectwidget.h"
 #include "messagewidget.h"
 #include "statewidget.h"
@@ -152,33 +153,28 @@
 UMLWidget* makeWidgetFromXMI(const QString& tag,
                              const QString& idStr, UMLView *view) {
     UMLWidget *widget = NULL;
-    if (tag == "statewidget" || tag == "notewidget" || tag == "boxwidget" ||
-        tag == "floatingtext" || tag == "activitywidget" || tag == "forkjoin" ||
-            // tests for backward compatibility:
-            tag == "UML:StateWidget" || tag == "UML:NoteWidget" ||
-            tag == "UML:FloatingTextWidget" || tag == "UML:ActivityWidget") {
+
         // Loading of widgets which do NOT represent any UMLObject, 
         // just graphic stuff with no real model information
         //FIXME while boxes and texts are just diagram objects, activities and
         // states should be UMLObjects
-        if (tag == "statewidget"
-                || tag == "UML:StateWidget") {         // for bkwd compatibility
-            widget = new StateWidget(view, StateWidget::Normal, Uml::id_Reserved);
-        } else if (tag == "notewidget"
-                   || tag == "UML:NoteWidget") {          // for bkwd compatibility
-            widget = new NoteWidget(view, Uml::id_Reserved);
-        } else if (tag == "boxwidget") {
-            widget = new BoxWidget(view, Uml::id_Reserved);
-        } else if (tag == "floatingtext"
-                   || tag == "UML:FloatingTextWidget") {  // for bkwd compatibility
-            widget = new FloatingTextWidget(view, Uml::tr_Floating, "", Uml::id_Reserved);
-        } else if (tag == "activitywidget"
-                   || tag == "UML:ActivityWidget") {      // for bkwd compatibility
-            widget = new ActivityWidget(view, ActivityWidget::Initial, Uml::id_Reserved);
-        } else if (tag == "forkjoin") {
-            widget = new ForkJoinWidget(view, false, Uml::id_Reserved);
-        }
+    if (tag == "statewidget") {
+        widget = new StateWidget(view, StateWidget::Normal, Uml::id_Reserved);
+    } else if (tag == "notewidget") {
+        widget = new NoteWidget(view, Uml::id_Reserved);
+    } else if (tag == "boxwidget") {
+        widget = new BoxWidget(view, Uml::id_Reserved);
+    } else if (tag == "floatingtext") {
+        widget = new FloatingTextWidget(view, Uml::tr_Floating, "", Uml::id_Reserved);
+    } else if (tag == "activitywidget") {
+        widget = new ActivityWidget(view, ActivityWidget::Initial, Uml::id_Reserved);
+    } else if (tag == "messagewidget") {
+        widget = new MessageWidget(view, Uml::sequence_message_asynchronous, Uml::id_Reserved);
+    } else if (tag == "forkjoin") {
+        widget = new ForkJoinWidget(view, false, Uml::id_Reserved);
     } else {
+        // Loading of widgets which represent an UMLObject
+
         // Find the UMLObject and create the Widget to represent it
         Uml::IDType id = STR2ID(idStr);
         UMLDoc *umldoc = UMLApp::app()->getDocument();
Comment 2 Oliver Kellogg 2007-04-09 14:48:56 UTC
SVN commit 651813 by okellogg:

addWidget(), case wt_Object: Remove incorrect call to IDChangeLog::findNewID(pWidget->getID()).
 The only ID subject to change is the local ID.
CCBUG:139856


 M  +1 -6      umlview.cpp  


--- branches/KDE/3.5/kdesdk/umbrello/umbrello/umlview.cpp #651812:651813
@@ -1586,16 +1586,11 @@
                 kDebug() << "UMLView::addWidget(): pObjectWidget is NULL" << endl;
                 return false;
             }
-            Uml::IDType newID = log->findNewID( pWidget -> getID() );
-            if (newID == Uml::id_None) {
-                return false;
-            }
-            pObjectWidget -> setID( newID );
             Uml::IDType nNewLocalID = getLocalID();
             Uml::IDType nOldLocalID = pObjectWidget -> getLocalID();
             m_pIDChangesLog->addIDChange( nOldLocalID, nNewLocalID );
             pObjectWidget -> setLocalID( nNewLocalID );
-            UMLObject *pObject = m_pDoc -> findObjectById( newID );
+            UMLObject *pObject = m_pDoc->findObjectById(pWidget->getID());
             if( !pObject ) {
                 kDebug() << "addWidget::Can't find UMLObject" << endl;
                 return false;
Comment 3 Oliver Kellogg 2007-04-14 15:57:03 UTC
SVN commit 653888 by okellogg:

m_widgetAId,m_widgetBId,m_textId: Temporary store for loadFromXMI().
Move widget resolution from loadFromXMI() to activate().
Sequence diagrams can now be copied but the placement of the widgets
in the target diagram is not yet correct.  While that is not fixed,
the widgets can anyway be rearranged manually.
BUG:139856


 M  +1 -1      ChangeLog  
 M  +44 -66    umbrello/messagewidget.cpp  
 M  +7 -0      umbrello/messagewidget.h  


--- branches/KDE/3.5/kdesdk/umbrello/ChangeLog #653887:653888
@@ -27,7 +27,7 @@
 * Ada code generator always generates methods abstract even if abstract box not checked (142093)
 * Missing "with" on Ada code generation for aggregation (142392)
 * Operation Properties "Type" combo box too small (143319)
-* Support duplication of diagrams (143581)
+* Support duplication of diagrams (139856, 143581)
 * Crash on changing multiplicity in an association in ERD (143909)
 * Class diagram in folder not loaded correctly from xmi (144119)
 
--- branches/KDE/3.5/kdesdk/umbrello/umbrello/messagewidget.cpp #653887:653888
@@ -406,11 +406,45 @@
 
 bool MessageWidget::activate(IDChangeLog * Log /*= 0*/) {
     m_pView->resetPastePoint();
-    UMLWidget::activate(Log);
-    if (m_pOw[Uml::A] == NULL || m_pOw[Uml::B] == NULL) {
-        kDebug() << "MessageWidget::activate: can't make message" << endl;
+    // UMLWidget::activate(Log);   CHECK: I don't think we need this ?
+    UMLWidget *pWA = m_pView->findWidget(m_widgetAId);
+    if (pWA == NULL) {
+        kDebug() << "MessageWidget::activate: role A object "
+            << ID2STR(m_widgetAId) << " not found" << endl;
         return false;
     }
+    UMLWidget *pWB = m_pView->findWidget(m_widgetBId);
+    if (pWB == NULL) {
+        kDebug() << "MessageWidget::activate: role B object "
+            << ID2STR(m_widgetBId) << " not found" << endl;
+        return false;
+    }
+    m_pOw[Uml::A] = dynamic_cast<ObjectWidget*>(pWA);
+    if (m_pOw[Uml::A] == NULL) {
+        kDebug() << "MessageWidget::activate: role A widget "
+            << ID2STR(m_widgetAId) << " is not an ObjectWidget" << endl;
+        return false;
+    }
+    m_pOw[Uml::B] = dynamic_cast<ObjectWidget*>(pWB);
+    if (m_pOw[Uml::B] == NULL) {
+        kDebug() << "MessageWidget::activate: role B widget "
+            << ID2STR(m_widgetBId) << " is not an ObjectWidget" << endl;
+        return false;
+    }
+    updateResizability();
+
+    UMLClassifier *c = dynamic_cast<UMLClassifier*>(pWB->getUMLObject());
+    UMLOperation *op = NULL;
+    if (c) {
+        Uml::IDType opId = STR2ID(m_CustomOp);
+        op = dynamic_cast<UMLOperation*>( c->findChildObjectById(opId, true) );
+        if (op) {
+            // If the UMLOperation is set, m_CustomOp isn't used anyway.
+            // Just setting it empty for the sake of sanity.
+            m_CustomOp = QString::null;
+        }
+    }
+
     if( !m_pFText ) {
         Uml::Text_Role tr = Uml::tr_Seq_Message;
         if (m_pOw[Uml::A] == m_pOw[Uml::B])
@@ -418,6 +452,8 @@
         m_pFText = new FloatingTextWidget( m_pView, tr, "" );
         m_pFText->setFont(UMLWidget::getFont());
     }
+    if (op)
+        setOperation(op);  // This requires a valid m_pFText.
     setLinkAndTextPos();
     m_pFText -> setText("");
     m_pFText->setActivated();
@@ -719,64 +755,12 @@
     QString sequenceMessageType = qElement.attribute( "sequencemessagetype", "1001" );
     m_sequenceMessageType = (Uml::Sequence_Message_Type)sequenceMessageType.toInt();
 
-    Uml::IDType aId = STR2ID(widgetaid);
-    Uml::IDType bId = STR2ID(widgetbid);
+    m_widgetAId = STR2ID(widgetaid);
+    m_widgetBId = STR2ID(widgetbid);
+    m_textId = STR2ID(textid);
 
-    UMLWidget *pWA = m_pView -> findWidget( aId );
-    if (pWA == NULL) {
-        kDebug() << "MessageWidget::loadFromXMI: role A object "
-        << ID2STR(aId) << " not found" << endl;
-        return false;
-    }
-    UMLWidget *pWB = m_pView -> findWidget( bId );
-    if (pWB == NULL) {
-        kDebug() << "MessageWidget::loadFromXMI: role B object "
-        << ID2STR(bId) << " not found" << endl;
-        return false;
-    }
-    m_pOw[Uml::A] = dynamic_cast<ObjectWidget*>(pWA);
-    if (m_pOw[Uml::A] == NULL) {
-        kDebug() << "MessageWidget::loadFromXMI: role A widget "
-        << ID2STR(aId) << " is not an ObjectWidget" << endl;
-        return false;
-    }
-    m_pOw[Uml::B] = dynamic_cast<ObjectWidget*>(pWB);
-    if (m_pOw[Uml::B] == NULL) {
-        kDebug() << "MessageWidget::loadFromXMI: role B widget "
-        << ID2STR(bId) << " is not an ObjectWidget" << endl;
-        return false;
-    }
-    updateResizability();
-
-    UMLClassifier *c = dynamic_cast<UMLClassifier*>( pWB->getUMLObject() );
-    UMLOperation *op = NULL;
-    if (c) {
-        Uml::IDType opId = STR2ID(m_CustomOp);
-        op = dynamic_cast<UMLOperation*>( c->findChildObjectById(opId, true) );
-        if (op) {
-            // If the UMLOperation is set, m_CustomOp isn't used anyway.
-            // Just setting it empty for the sake of sanity.
-            m_CustomOp = QString::null;
-        }
-    }
-
-    Uml::IDType textId = STR2ID(textid);
-    if (textId != Uml::id_None) {
-        UMLWidget *flotext = m_pView -> findWidget( textId );
-        if (flotext != NULL) {
-            // This only happens when loading files produced by
-            // umbrello-1.3-beta2.
-            m_pFText = static_cast<FloatingTextWidget*>(flotext);
-            setLinkAndTextPos();
-            return true;
-        }
-    } else {
-        // no textid stored -> get unique new one
-        textId = UniqueID::gen();
-    }
-
     Uml::Text_Role tr = Uml::tr_Seq_Message;
-    if (m_pOw[Uml::A] == m_pOw[Uml::B])
+    if (m_widgetAId == m_widgetBId)
         tr = Uml::tr_Seq_Message_Self;
 
     //now load child elements
@@ -785,7 +769,7 @@
     if ( !element.isNull() ) {
         QString tag = element.tagName();
         if (tag == "floatingtext") {
-            m_pFText = new FloatingTextWidget( m_pView, tr, getOperationText(m_pView), textId );
+            m_pFText = new FloatingTextWidget( m_pView, tr, getOperationText(m_pView), m_textId );
             if( ! m_pFText->loadFromXMI(element) ) {
                 // Most likely cause: The FloatingTextWidget is empty.
                 delete m_pFText;
@@ -796,12 +780,6 @@
             << tag << endl;
         }
     }
-    if (op)                // Do it here and not earlier because now we have the
-        setOperation(op);  // m_pFText and setOperation() can make connections.
-
-    // always need this
-    setLinkAndTextPos();
-
     return true;
 }
 
--- branches/KDE/3.5/kdesdk/umbrello/umbrello/messagewidget.h #653887:653888
@@ -378,6 +378,13 @@
     ObjectWidget * m_pOw[2];
     FloatingTextWidget * m_pFText;
     int m_nY;
+    /**
+     * The following variables are used by loadFromXMI() as an intermediate
+     * store. activate() resolves the IDs, i.e. after activate() the variables
+     * m_pOw[] and m_pFText can be used.
+     */
+    Uml::IDType m_widgetAId, m_widgetBId, m_textId;
+
 public slots:
     void slotWidgetMoved(Uml::IDType id);
     void slotMenuSelection(int sel);