umbrello API Documentation

umlview.cpp

00001 /***************************************************************************
00002  *                                                                         *
00003  *   This program is free software; you can redistribute it and/or modify  *
00004  *   it under the terms of the GNU General Public License as published by  *
00005  *   the Free Software Foundation; either version 2 of the License, or     *
00006  *   (at your option) any later version.                                   *
00007  *                                                                         *
00008  *   copyright (C) 2002-2007                                               *
00009  *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
00010  ***************************************************************************/
00011 
00012 // own header
00013 #include "umlview.h"
00014 
00015 // system includes
00016 #include <climits>
00017 #include <math.h>
00018 
00019 // include files for Qt
00020 #include <qpixmap.h>
00021 #include <qpicture.h>
00022 #include <qprinter.h>
00023 #include <qpainter.h>
00024 #include <qstring.h>
00025 #include <qstringlist.h>
00026 #include <qobjectlist.h>
00027 #include <qobjectdict.h>
00028 #include <qdragobject.h>
00029 #include <qpaintdevicemetrics.h>
00030 #include <qfileinfo.h>
00031 #include <qptrlist.h>
00032 #include <qcolor.h>
00033 #include <qwmatrix.h>
00034 #include <qregexp.h>
00035 
00036 //kde include files
00037 #include <ktempfile.h>
00038 #include <kio/netaccess.h>
00039 #include <kmessagebox.h>
00040 #include <kprinter.h>
00041 #include <kcursor.h>
00042 #include <kfiledialog.h>
00043 #include <kinputdialog.h>
00044 #include <klocale.h>
00045 #include <kdebug.h>
00046 
00047 // application specific includes
00048 #include "umlviewimageexporter.h"
00049 #include "listpopupmenu.h"
00050 #include "uml.h"
00051 #include "umldoc.h"
00052 #include "umlobject.h"
00053 #include "docwindow.h"
00054 #include "assocrules.h"
00055 #include "umlrole.h"
00056 #include "umlviewcanvas.h"
00057 #include "dialogs/classoptionspage.h"
00058 #include "dialogs/umlviewdialog.h"
00059 #include "clipboard/idchangelog.h"
00060 #include "clipboard/umldrag.h"
00061 #include "widget_factory.h"
00062 #include "floatingtextwidget.h"
00063 #include "classifierwidget.h"
00064 #include "classifier.h"
00065 #include "packagewidget.h"
00066 #include "package.h"
00067 #include "folder.h"
00068 #include "componentwidget.h"
00069 #include "nodewidget.h"
00070 #include "artifactwidget.h"
00071 #include "datatypewidget.h"
00072 #include "enumwidget.h"
00073 #include "entitywidget.h"
00074 #include "actorwidget.h"
00075 #include "usecasewidget.h"
00076 #include "notewidget.h"
00077 #include "boxwidget.h"
00078 #include "associationwidget.h"
00079 #include "objectwidget.h"
00080 #include "messagewidget.h"
00081 #include "statewidget.h"
00082 #include "forkjoinwidget.h"
00083 #include "activitywidget.h"
00084 #include "seqlinewidget.h"
00085 #include "uniqueid.h"
00086 #include "umllistviewitemlist.h"
00087 #include "umllistviewitem.h"
00088 #include "umllistview.h"
00089 #include "umlobjectlist.h"
00090 #include "association.h"
00091 #include "attribute.h"
00092 #include "model_utils.h"
00093 #include "object_factory.h"
00094 #include "umlwidget.h"
00095 #include "toolbarstatefactory.h"
00096 
00097 
00098 // control the manual DoubleBuffering of QCanvas
00099 // with a define, so that this memory X11 effect can
00100 // be tested more easily
00101 #define MANUAL_CONTROL_DOUBLE_BUFFERING
00102 
00103 // static members
00104 const int UMLView::defaultCanvasSize = 1300;
00105 
00106 using namespace Uml;
00107 
00108 
00109 // constructor
00110 UMLView::UMLView(UMLFolder *parentFolder) : QCanvasView(UMLApp::app()->getMainViewWidget()) {
00111     init();
00112     m_pDoc = UMLApp::app()->getDocument();
00113     m_pFolder = parentFolder;
00114 }
00115 
00116 void UMLView::init() {
00117     // Initialize loaded/saved data
00118     m_nID = Uml::id_None;
00119     m_pDoc = NULL;
00120     m_Documentation = "";
00121     m_Type = dt_Undefined;
00122     m_bUseSnapToGrid = false;
00123     m_bUseSnapComponentSizeToGrid = false;
00124     m_bShowSnapGrid = false;
00125     m_nSnapX = 10;
00126     m_nSnapY = 10;
00127     m_nZoom = 100;
00128     m_nCanvasWidth = UMLView::defaultCanvasSize;
00129     m_nCanvasHeight = UMLView::defaultCanvasSize;
00130     m_nCollaborationId = 0;
00131 
00132     // Initialize other data
00133     m_AssociationList.setAutoDelete( true );
00134 
00135     //Setup up booleans
00136     m_bChildDisplayedDoc = false;
00137     m_bPaste = false;
00138     m_bActivated = false;
00139     m_bCreateObject = false;
00140     m_bDrawSelectedOnly = false;
00141     m_bPopupShowing = false;
00142     m_bStartedCut = false;
00143     //clear pointers
00144     m_PastePoint = QPoint(0, 0);
00145     m_pIDChangesLog = 0;
00146     m_pMenu = 0;
00147 
00148     m_pImageExporter = new UMLViewImageExporter(this);
00149 
00150     //setup graphical items
00151     viewport() -> setBackgroundMode( Qt::NoBackground );
00152     setCanvas( new UMLViewCanvas( this ) );
00153     // don't set the quite frequent update rate for each
00154     // diagram, as that causes also an update of invisible
00155     // diagrams, which can cost high CPU load for many
00156     // diagrams.
00157     // Instead: set the updatePeriod to 20 on Show event,
00158     //          and switch update back off on Hide event
00159     canvas() -> setUpdatePeriod( -1 );
00160     resizeContents(defaultCanvasSize, defaultCanvasSize);
00161     canvas() -> resize(defaultCanvasSize, defaultCanvasSize);
00162     setAcceptDrops(true);
00163     viewport() -> setAcceptDrops(true);
00164     setDragAutoScroll(false);
00165 
00166     viewport() -> setMouseTracking(false);
00167 
00168     //setup signals
00169     connect( this, SIGNAL(sigRemovePopupMenu()), this, SLOT(slotRemovePopupMenu() ) );
00170     connect( UMLApp::app(), SIGNAL( sigCutSuccessful() ),
00171              this, SLOT( slotCutSuccessful() ) );
00172 
00173     // Create the ToolBarState factory. This class is not a singleton, because it
00174     // needs a pointer to this object.
00175     m_pToolBarStateFactory = new ToolBarStateFactory(this);
00176     m_pToolBarState = m_pToolBarStateFactory->getState(WorkToolBar::tbb_Arrow);
00177 
00178 }
00179 
00180 UMLView::~UMLView() {
00181     delete m_pImageExporter;
00182 
00183     if(m_pIDChangesLog) {
00184         delete    m_pIDChangesLog;
00185         m_pIDChangesLog = 0;
00186     }
00187 
00188     // before we can delete the QCanvas, all widgets must be explicitly
00189     // removed
00190     // otherwise the implicit remove of the contained widgets will cause
00191     // events which would demand a valid connected QCanvas
00192     // ==> this causes umbrello to crash for some - larger?? - projects
00193     // first avoid all events, which would cause some update actions
00194     // on deletion of each removed widget
00195     blockSignals( true );
00196     removeAllWidgets();
00197 
00198     delete m_pToolBarStateFactory;
00199     m_pToolBarStateFactory = NULL;
00200 
00201     // Qt Doc for QCanvasView::~QCanvasView () states:
00202     // "Destroys the canvas view. The associated canvas is not deleted."
00203     // we should do it now
00204     delete canvas();
00205 }
00206 
00207 QString UMLView::getName() const {
00208     return m_Name;
00209 }
00210 
00211 void UMLView::setName(const QString &name) {
00212     m_Name = name;
00213 }
00214 
00215 int UMLView::generateCollaborationId() {
00216     return ++m_nCollaborationId;
00217 }
00218 
00219 void UMLView::print(KPrinter *pPrinter, QPainter & pPainter) {
00220     int height, width;
00221     //get the size of the page
00222     pPrinter->setFullPage( true );
00223     QPaintDeviceMetrics metrics(pPrinter);
00224     QFontMetrics fm = pPainter.fontMetrics(); // use the painter font metrics, not the screen fm!
00225     int fontHeight  = fm.lineSpacing();
00226     uint left, right, top, bottom;
00227     // fetch printer margins individual for all four page sides, as at least top and bottom are not the same
00228     pPrinter->margins ( &top, &left, &bottom, &right );
00229     // give a little extra space at each side
00230     left += 2;
00231     right += 2;
00232     top += 2;
00233     bottom += 2;
00234 
00235     if(pPrinter->orientation() == KPrinter::Landscape) {
00236         // we are printing in LANDSCAPE --> swap marginX and marginY
00237         uint right_old = right;
00238         // the DiagramRight side is printed at PrintersTop
00239         right = top;
00240         // the DiagramTop side is printed at PrintersLeft
00241         top = left;
00242         // the DiagramLeft side is printed at PrintersBottom
00243         left = bottom;
00244         // the DiagramBottom side is printed at PrintersRight
00245         bottom = right_old;
00246     }
00247 
00248     // The printer will probably use a different font with different font metrics,
00249     // force the widgets to update accordingly on paint
00250     forceUpdateWidgetFontMetrics(&pPainter);
00251 
00252     width = metrics.width() - left - right;
00253     height = metrics.height() - top - bottom;
00254 
00255     //get the smallest rect holding the diagram
00256     QRect rect = getDiagramRect();
00257     //now draw to printer
00258 
00259 #if 0
00260     int offsetX = 0, offsetY = 0, widthX = 0, heightY = 0;
00261     // respect the margin
00262     pPainter.translate(marginX, marginY);
00263 
00264     // clip away everything outside of the margin
00265     pPainter.setClipRect(marginX, marginY,
00266                          width, metrics.height() - marginY * 2);
00267 
00268     //loop until all of the picture is printed
00269     int numPagesX = (int)ceil((double)rect.width()/(double)width);
00270     int numPagesY = (int)ceil((double)rect.height()/(double)height);
00271     int page = 0;
00272 
00273     // print the canvas to multiple pages
00274     for (int pageY = 0; pageY < numPagesY; ++pageY) {
00275         // tile vertically
00276         offsetY = pageY * height + rect.y();
00277         heightY = (pageY + 1) * height > rect.height()
00278                   ? rect.height() - pageY * height
00279                   : height;
00280         for (int pageX = 0; pageX < numPagesX; ++pageX) {
00281             // tile horizontally
00282             offsetX = pageX * width + rect.x();
00283             widthX = (pageX + 1) * width > rect.width()
00284                      ? rect.width() - pageX * width
00285                      : width;
00286 
00287             // make sure the part of the diagram is painted at the correct
00288             // place in the printout
00289             pPainter.translate(-offsetX,-offsetY);
00290             getDiagram(QRect(offsetX, offsetY,widthX, heightY),
00291                        pPainter);
00292             // undo the translation so the coordinates for the painter
00293             // correspond to the page again
00294             pPainter.translate(offsetX,offsetY);
00295 
00296             //draw foot note
00297             QString string = i18n("Diagram: %2 Page %1").arg(page + 1).arg(getName());
00298             QColor textColor(50, 50, 50);
00299             pPainter.setPen(textColor);
00300             pPainter.drawLine(0, height + 2, width, height + 2);
00301             pPainter.drawText(0, height + 4, width, fontHeight, Qt::AlignLeft, string);
00302 
00303             if(pageX+1 < numPagesX || pageY+1 < numPagesY) {
00304                 pPrinter -> newPage();
00305                 page++;
00306             }
00307         }
00308     }
00309 #else
00310     // be gentle - as described in Qt-Doc "The Coordinate System"
00311     pPainter.save();
00312 
00313     int diagramHeight = rect.height();
00314     // + 4+fontHeight between diagram and footline as space-buffer
00315     // + 2            between line and foot-text
00316     // + 1            for foot-line
00317     // + fontHeight   for foot-text
00318     // ==============
00319     // (2*fontHeight) + 7
00320     int footHeight = (2*fontHeight) + 7;
00321     int footTop    = rect.y() + diagramHeight  + 4+fontHeight;
00322     int drawHeight = diagramHeight  + footHeight;
00323 
00324     // set window of painter to dimensions of diagram
00325     // set window to viewport relation so that x:y isn't changed
00326     double dScaleX = (double)rect.width()/ (double)width;
00327     double dScaleY = (double)drawHeight/ (double)height;
00328     // select the scaling factor so that the larger dimension
00329     // fits on the printer page -> use the larger scaling factor
00330     // -> the virtual diagram window has some additional space at the
00331     // shorter dimension
00332     double dScaleUse = ( dScaleX > dScaleY )?dScaleX:dScaleY;
00333 
00334     int windowWidth  = (int)ceil(dScaleUse*width);
00335     int windowHeight = (int)ceil(dScaleUse*height);
00336 #ifdef DEBUG_PRINTING
00337     kDebug() << "drawHeight: " << drawHeight << ", width: " << rect.width()
00338               << "\nPageHeight: " << height << ", PageWidht: " << width
00339               << "\nScaleY: " << dScaleY << ", ScaleX: " << dScaleX
00340               << "\ndScaleUse: " << dScaleUse
00341               << "\nVirtualSize: Width: " << windowWidth << ", Height: " << windowHeight
00342               << "\nFoot Top: " << footTop
00343               << endl;
00344 #endif
00345     // set virtual drawing area window - where diagram fits 100% in
00346     pPainter.setWindow( rect.x(), rect.y(), windowWidth, windowHeight );
00347 
00348     // set viewport - the physical mapping
00349     // --> Qt's QPainter will map all drawed elements from diagram area ( window )
00350     //     to printer area ( viewport )
00351     pPainter.setViewport( left, top, width, height );
00352 
00353     // get Diagram
00354     getDiagram(QRect(rect.x(), rect.y(), windowWidth, diagramHeight), pPainter);
00355 
00356     //draw foot note
00357     QString string = i18n("Diagram: %2 Page %1").arg( 1).arg(getName());
00358     QColor textColor(50, 50, 50);
00359     pPainter.setPen(textColor);
00360     pPainter.drawLine(rect.x(), footTop    , windowWidth, footTop);
00361     pPainter.drawText(rect.x(), footTop + 3, windowWidth, fontHeight, Qt::AlignLeft, string);
00362 
00363     // now restore scaling
00364     pPainter.restore();
00365 
00366 #endif
00367     // next painting will most probably be to a different device (i.e. the screen)
00368     forceUpdateWidgetFontMetrics(0);
00369 }
00370 
00371 void UMLView::setupNewWidget(UMLWidget *w) {
00372     w->setX( m_Pos.x() );
00373     w->setY( m_Pos.y() );
00374     w->setVisible( true );
00375     w->setActivated();
00376     w->setFont( getFont() );
00377     w->slotColorChanged( getID() );
00378     w->slotLineWidthChanged( getID() );
00379     resizeCanvasToItems();
00380     m_WidgetList.append( w );
00381     m_pDoc->setModified();
00382 }
00383 
00384 void UMLView::contentsMouseReleaseEvent(QMouseEvent* ome) {
00385     m_pToolBarState->mouseRelease(ome);
00386 }
00387 
00388 void UMLView::slotToolBarChanged(int c) {
00389     m_pToolBarState->cleanBeforeChange();
00390     m_pToolBarState = m_pToolBarStateFactory->getState((WorkToolBar::ToolBar_Buttons)c);
00391     m_pToolBarState->init();
00392 
00393     m_bPaste = false;
00394 }
00395 
00396 void UMLView::showEvent(QShowEvent* /*se*/) {
00397 
00398 # ifdef MANUAL_CONTROL_DOUBLE_BUFFERING
00399     //kWarning() << "Show Event for " << getName() << endl;
00400     canvas()->setDoubleBuffering( true );
00401     // as the diagram gets now visible again,
00402     // the update of the diagram elements shall be
00403     // at the normal value of 20
00404     canvas()-> setUpdatePeriod( 20 );
00405 # endif
00406 
00407     UMLApp* theApp = UMLApp::app();
00408     WorkToolBar* tb = theApp->getWorkToolBar();
00409     connect(tb,SIGNAL(sigButtonChanged(int)), this, SLOT(slotToolBarChanged(int)));
00410     connect(this,SIGNAL(sigResetToolBar()), tb, SLOT(slotResetToolBar()));
00411     connect(m_pDoc, SIGNAL(sigObjectCreated(UMLObject *)),
00412             this, SLOT(slotObjectCreated(UMLObject *)));
00413     connect(this, SIGNAL(sigAssociationRemoved(AssociationWidget*)),
00414             UMLApp::app()->getDocWindow(), SLOT(slotAssociationRemoved(AssociationWidget*)));
00415     connect(this, SIGNAL(sigWidgetRemoved(UMLWidget*)),
00416             UMLApp::app()->getDocWindow(), SLOT(slotWidgetRemoved(UMLWidget*)));
00417     resetToolbar();
00418 
00419 }
00420 
00421 void UMLView::hideEvent(QHideEvent* /*he*/) {
00422     UMLApp* theApp = UMLApp::app();
00423     WorkToolBar* tb = theApp->getWorkToolBar();
00424     disconnect(tb,SIGNAL(sigButtonChanged(int)), this, SLOT(slotToolBarChanged(int)));
00425     disconnect(this,SIGNAL(sigResetToolBar()), tb, SLOT(slotResetToolBar()));
00426     disconnect(m_pDoc, SIGNAL(sigObjectCreated(UMLObject *)), this, SLOT(slotObjectCreated(UMLObject *)));
00427     disconnect(this, SIGNAL(sigAssociationRemoved(AssociationWidget*)),
00428                UMLApp::app()->getDocWindow(), SLOT(slotAssociationRemoved(AssociationWidget*)));
00429     disconnect(this, SIGNAL(sigWidgetRemoved(UMLWidget*)),
00430                UMLApp::app()->getDocWindow(), SLOT(slotWidgetRemoved(UMLWidget*)));
00431 
00432 # ifdef MANUAL_CONTROL_DOUBLE_BUFFERING
00433     //kWarning() << "Hide Event for " << getName() << endl;
00434     canvas()->setDoubleBuffering( false );
00435     // a periodic update of all - also invisible - diagrams
00436     // can cause a very high CPU load if more than 100diagrams
00437     // are inside a project - and this without any need
00438     // => switch the update off for hidden diagrams
00439     canvas()-> setUpdatePeriod( -1 );
00440 # endif
00441 }
00442 
00443 void UMLView::slotObjectCreated(UMLObject* o) {
00444     m_bPaste = false;
00445     //check to see if we want the message
00446     //may be wanted by someone else e.g. list view
00447     if (!m_bCreateObject)  {
00448         return;
00449     }
00450 
00451     UMLWidget* newWidget = Widget_Factory::createWidget(this, o);
00452     if (newWidget == NULL)
00453         return;
00454     newWidget->setVisible( true );
00455     newWidget->setActivated();
00456     newWidget->setFont( getFont() );
00457     newWidget->slotColorChanged( getID() );
00458     newWidget->slotLineWidthChanged( getID() );
00459     newWidget->updateComponentSize();
00460     if (m_Type == Uml::dt_Sequence) {
00461         // Set proper position on the sequence line widget which is
00462         // attached to the object widget.
00463         ObjectWidget *ow = dynamic_cast<ObjectWidget*>(newWidget);
00464         if (ow)
00465             ow->moveEvent(NULL);
00466     }
00467     m_bCreateObject = false;
00468     m_WidgetList.append(newWidget);
00469     switch (o->getBaseType()) {
00470     case ot_Actor:
00471     case ot_UseCase:
00472     case ot_Class:
00473     case ot_Package:
00474     case ot_Component:
00475     case ot_Node:
00476     case ot_Artifact:
00477     case ot_Interface:
00478     case ot_Enum:
00479     case ot_Entity:
00480     case ot_Datatype:
00481         createAutoAssociations(newWidget);
00482         // We need to invoke createAutoAttributeAssociations()
00483         // on all other widgets again because the newly created
00484         // widget might saturate some latent attribute assocs.
00485         for (UMLWidgetListIt it(m_WidgetList); it.current(); ++it) {
00486             UMLWidget *w = it.current();
00487             if (w != newWidget)
00488                 createAutoAttributeAssociations(w);
00489         }
00490         break;
00491     default:
00492         break;
00493     }
00494     resizeCanvasToItems();
00495 }
00496 
00497 void UMLView::slotObjectRemoved(UMLObject * o) {
00498     m_bPaste = false;
00499     Uml::IDType id = o->getID();
00500     UMLWidgetListIt it( m_WidgetList );
00501     UMLWidget *obj;
00502 
00503     while ((obj = it.current()) != 0 ) {
00504         ++it;
00505         if(obj -> getID() != id)
00506             continue;
00507         removeWidget(obj);
00508     }
00509 }
00510 
00511 void UMLView::contentsDragEnterEvent(QDragEnterEvent *e) {
00512     UMLDrag::LvTypeAndID_List tidList;
00513     if(!UMLDrag::getClip3TypeAndID(e, tidList)) {
00514         return;
00515     }
00516     UMLDrag::LvTypeAndID_It tidIt(tidList);
00517     UMLDrag::LvTypeAndID * tid = tidIt.current();
00518     if (!tid) {
00519         kDebug() << "UMLView::contentsDragEnterEvent: "
00520                   << "UMLDrag::getClip3TypeAndID returned empty list" << endl;
00521         return;
00522     }
00523     ListView_Type lvtype = tid->type;
00524     Uml::IDType id = tid->id;
00525 
00526     Diagram_Type diagramType = getType();
00527 
00528     UMLObject* temp = 0;
00529     //if dragging diagram - might be a drag-to-note
00530     if (Model_Utils::typeIsDiagram(lvtype)) {
00531         e->accept(true);
00532         return;
00533     }
00534     //can't drag anything onto state/activity diagrams
00535     if( diagramType == dt_State || diagramType == dt_Activity) {
00536         e->accept(false);
00537         return;
00538     }
00539     //make sure can find UMLObject
00540     if( !(temp = m_pDoc->findObjectById(id) ) ) {
00541         kDebug() << "object " << ID2STR(id) << " not found" << endl;
00542         e->accept(false);
00543         return;
00544     }
00545     //make sure dragging item onto correct diagram
00546     // concept - class,seq,coll diagram
00547     // actor,usecase - usecase diagram
00548     Object_Type ot = temp->getBaseType();
00549     bool bAccept = true;
00550     switch (diagramType) {
00551         case dt_UseCase:
00552             if ((widgetOnDiagram(id) && ot == ot_Actor) ||
00553                 (ot != ot_Actor && ot != ot_UseCase))
00554                 bAccept = false;
00555             break;
00556         case dt_Class:
00557             if (widgetOnDiagram(id) ||
00558                 (ot != ot_Class &&
00559                  ot != ot_Package &&
00560                  ot != ot_Interface &&
00561                  ot != ot_Enum &&
00562                  ot != ot_Datatype)) {
00563                 bAccept = false;
00564             }
00565             break;
00566         case dt_Sequence:
00567         case dt_Collaboration:
00568             if (ot != ot_Class &&
00569                 ot != ot_Interface &&
00570                 ot != ot_Actor)
00571                 bAccept = false;
00572             break;
00573         case dt_Deployment:
00574             if (widgetOnDiagram(id))
00575                 bAccept = false;
00576             else if (ot != ot_Interface &&
00577                      ot != ot_Package &&
00578                      ot != ot_Component &&
00579                      ot != ot_Class &&
00580                      ot != ot_Node)
00581                 bAccept = false;
00582             else if (ot == ot_Package &&
00583                      temp->getStereotype() != "subsystem")
00584                 bAccept = false;
00585             break;
00586         case dt_Component:
00587             if (widgetOnDiagram(id) ||
00588                 (ot != ot_Interface &&
00589                  ot != ot_Package &&
00590                  ot != ot_Component &&
00591                  ot != ot_Artifact &&
00592                  ot != ot_Class))
00593                 bAccept = false;
00594             if (ot == ot_Class && !temp->getAbstract())
00595                 bAccept = false;
00596             break;
00597         case dt_EntityRelationship:
00598             if (ot != ot_Entity)
00599                 bAccept = false;
00600             break;
00601         default:
00602             break;
00603     }
00604     e->accept(bAccept);
00605 }
00606 
00607 void UMLView::contentsDropEvent(QDropEvent *e) {
00608     UMLDrag::LvTypeAndID_List tidList;
00609     if( !UMLDrag::getClip3TypeAndID(e, tidList) ) {
00610         return;
00611     }
00612     UMLDrag::LvTypeAndID_It tidIt(tidList);
00613     UMLDrag::LvTypeAndID * tid = tidIt.current();
00614     if (!tid) {
00615         kDebug() << "UMLView::contentsDropEvent: "
00616                   << "UMLDrag::getClip3TypeAndID returned empty list" << endl;
00617         return;
00618     }
00619     ListView_Type lvtype = tid->type;
00620     Uml::IDType id = tid->id;
00621 
00622     if (Model_Utils::typeIsDiagram(lvtype)) {
00623         UMLWidget *w = NULL;
00624         for (w = m_WidgetList.first(); w; w = m_WidgetList.next()) {
00625             if (w->getBaseType() == Uml::wt_Note && w->onWidget(e->pos()))
00626                 break;
00627         }
00628         if (w) {
00629             NoteWidget *note = static_cast<NoteWidget*>(w);
00630             note->setDiagramLink(id);
00631         }
00632         return;
00633     }
00634     UMLObject* o = m_pDoc->findObjectById(id);
00635     if( !o ) {
00636         kDebug() << "UMLView::contentsDropEvent: object id=" << ID2STR(id)
00637                   << " not found" << endl;
00638         return;
00639     }
00640     m_bCreateObject = true;
00641     m_Pos = (e->pos() * 100 ) / m_nZoom;
00642 
00643     slotObjectCreated(o);
00644 
00645     m_pDoc -> setModified(true);
00646 }
00647 
00648 ObjectWidget * UMLView::onWidgetLine( const QPoint &point ) {
00649     UMLWidget *obj;
00650     for (UMLWidgetListIt it(m_WidgetList); (obj = it.current()) != NULL; ++it) {
00651         ObjectWidget *ow = dynamic_cast<ObjectWidget*>(obj);
00652         if (ow == NULL)
00653             continue;
00654         SeqLineWidget *pLine = ow->getSeqLine();
00655         if (pLine == NULL) {
00656             kError() << "UMLView::onWidgetLine: SeqLineWidget of " << ow->getName()
00657                 << " (id=" << ID2STR(ow->getLocalID()) << ") is NULL" << endl;
00658             continue;
00659         }
00660         if (pLine->onWidget(point))
00661             return ow;
00662     }
00663     return 0;
00664 }
00665 
00666 UMLWidget *UMLView::getWidgetAt(QPoint p) {
00667     int relativeSize = 10000;  // start with an arbitrary large number
00668     UMLWidget *obj, *retObj = NULL;
00669     UMLWidgetListIt it(m_WidgetList);
00670     for (UMLWidgetListIt it(m_WidgetList); (obj = it.current()) != NULL; ++it) {
00671         const int s = obj->onWidget(p);
00672         if (!s)
00673             continue;
00674         if (s < relativeSize) {
00675             relativeSize = s;
00676             retObj = obj;
00677         }
00678     }
00679     return retObj;
00680 }
00681 
00682 void UMLView::checkMessages(ObjectWidget * w) {
00683     if(getType() != dt_Sequence)
00684         return;
00685 
00686     MessageWidgetListIt it( m_MessageList );
00687     MessageWidget *obj;
00688     while ( (obj = it.current()) != 0 ) {
00689         ++it;
00690         if(! obj -> contains(w))
00691             continue;
00692         //make sure message doesn't have any associations
00693         removeAssociations(obj);
00694         obj -> cleanup();
00695         //make sure not in selected list
00696         m_SelectedList.remove(obj);
00697         m_MessageList.remove(obj);
00698         delete obj;
00699     }
00700 }
00701 
00702 bool UMLView::widgetOnDiagram(Uml::IDType id) {
00703     UMLWidget *obj;
00704 
00705     UMLWidgetListIt it( m_WidgetList );
00706     while ( (obj = it.current()) != 0 ) {
00707         ++it;
00708         if(id == obj -> getID())
00709             return true;
00710     }
00711 
00712     MessageWidgetListIt mit( m_MessageList );
00713     while ( (obj = (UMLWidget*)mit.current()) != 0 ) {
00714         ++mit;
00715         if(id == obj -> getID())
00716             return true;
00717     }
00718 
00719     return false;
00720 }
00721 
00722 void UMLView::contentsMouseMoveEvent(QMouseEvent* ome) {
00723     m_pToolBarState->mouseMove(ome);
00724 }
00725 
00726 // search both our UMLWidget AND MessageWidget lists
00727 UMLWidget * UMLView::findWidget( Uml::IDType id ) {
00728 
00729     UMLWidgetListIt it( m_WidgetList );
00730     UMLWidget * obj = NULL;
00731     while ( (obj = it.current()) != 0 ) {
00732         ++it;
00733         // object widgets are special..the widget id is held by 'localId' attribute (crappy!)
00734         if( obj -> getBaseType() == wt_Object ) {
00735             if( static_cast<ObjectWidget *>( obj ) -> getLocalID() == id )
00736                 return obj;
00737         } else if( obj -> getID() == id ) {
00738             return obj;
00739         }
00740     }
00741 
00742     MessageWidgetListIt mit( m_MessageList );
00743     while ( (obj = (UMLWidget*)mit.current()) != 0 ) {
00744         ++mit;
00745         if( obj -> getID() == id )
00746             return obj;
00747     }
00748 
00749     return 0;
00750 }
00751 
00752 
00753 
00754 AssociationWidget * UMLView::findAssocWidget( Uml::IDType id ) {
00755     AssociationWidget *obj;
00756     AssociationWidgetListIt it( m_AssociationList );
00757     while ( (obj = it.current()) != 0 ) {
00758         ++it;
00759         UMLAssociation* umlassoc = obj -> getAssociation();
00760         if ( umlassoc && umlassoc->getID() == id ) {
00761             return obj;
00762         }
00763     }
00764     return 0;
00765 }
00766 
00767 AssociationWidget * UMLView::findAssocWidget(UMLWidget *pWidgetA,
00768                                              UMLWidget *pWidgetB, const QString& roleNameB) {
00769     AssociationWidget *assoc;
00770     AssociationWidgetListIt it(m_AssociationList);
00771     while ((assoc = it.current()) != 0) {
00772         ++it;
00773         const Association_Type testType = assoc->getAssocType();
00774         if (testType != Uml::at_Association &&
00775             testType != Uml::at_UniAssociation &&
00776             testType != Uml::at_Composition &&
00777             testType != Uml::at_Aggregation)
00778             continue;
00779         if (pWidgetA->getID() == assoc->getWidgetID(A) &&
00780             pWidgetB->getID() == assoc->getWidgetID(B) &&
00781             assoc->getRoleName(Uml::B) == roleNameB)
00782             return assoc;
00783     }
00784     return 0;
00785 }
00786 
00787 
00788 AssociationWidget * UMLView::findAssocWidget(Association_Type at,
00789         UMLWidget *pWidgetA, UMLWidget *pWidgetB) {
00790     AssociationWidget *assoc;
00791     AssociationWidgetListIt it(m_AssociationList);
00792     while ((assoc = it.current()) != 0) {
00793         ++it;
00794         Association_Type testType = assoc->getAssocType();
00795         if (testType != at)
00796             continue;
00797         if (pWidgetA->getID() == assoc->getWidgetID(A) &&
00798                 pWidgetB->getID() == assoc->getWidgetID(B))
00799             return assoc;
00800     }
00801     return 0;
00802 }
00803 
00804 void UMLView::removeWidget(UMLWidget * o) {
00805     if(!o)
00806         return;
00807 
00808     emit sigWidgetRemoved(o);
00809 
00810     removeAssociations(o);
00811 
00812     Widget_Type t = o->getBaseType();
00813     if(getType() == dt_Sequence && t == wt_Object)
00814         checkMessages( static_cast<ObjectWidget*>(o) );
00815 
00816     o -> cleanup();
00817     m_SelectedList.remove(o);
00818     disconnect( this, SIGNAL( sigRemovePopupMenu() ), o, SLOT( slotRemovePopupMenu() ) );
00819     disconnect( this, SIGNAL( sigClearAllSelected() ), o, SLOT( slotClearAllSelected() ) );
00820     disconnect( this, SIGNAL(sigColorChanged(Uml::IDType)), o, SLOT(slotColorChanged(Uml::IDType)));
00821     if (t == wt_Message)
00822         m_MessageList.remove(static_cast<MessageWidget*>(o));
00823     else
00824         m_WidgetList.remove(o);
00825     m_pDoc->setModified();
00826     delete o;
00827 }
00828 
00829 bool UMLView::getUseFillColor() const {
00830     return m_Options.uiState.useFillColor;
00831 }
00832 
00833 void UMLView::setUseFillColor(bool ufc) {
00834     m_Options.uiState.useFillColor = ufc;
00835 }
00836 
00837 QColor UMLView::getFillColor() const {
00838     return m_Options.uiState.fillColor;
00839 }
00840 
00841 void UMLView::setFillColor(const QColor &color) {
00842     m_Options.uiState.fillColor = color;
00843     emit sigColorChanged( getID() );
00844     canvas()->setAllChanged();
00845 }
00846 
00847 QColor UMLView::getLineColor() const {
00848     return m_Options.uiState.lineColor;
00849 }
00850 
00851 void UMLView::setLineColor(const QColor &color) {
00852     m_Options.uiState.lineColor = color;
00853     emit sigColorChanged( getID() );
00854     canvas() -> setAllChanged();
00855 }
00856 
00857 uint UMLView::getLineWidth() const {
00858     return m_Options.uiState.lineWidth;
00859 }
00860 
00861 void UMLView::setLineWidth(uint width) {
00862     m_Options.uiState.lineWidth = width;
00863     emit sigLineWidthChanged( getID() );
00864     canvas() -> setAllChanged();
00865 }
00866 
00867 void UMLView::contentsMouseDoubleClickEvent(QMouseEvent* ome) {
00868     m_pToolBarState->mouseDoubleClick(ome);
00869 }
00870 
00871 QRect UMLView::getDiagramRect() {
00872     int startx, starty, endx, endy;
00873     startx = starty = INT_MAX;
00874     endx = endy = 0;
00875     UMLWidgetListIt it( m_WidgetList );
00876     UMLWidget *obj;
00877     while ( (obj = it.current()) != 0 ) {
00878         ++it;
00879         if (! obj->isVisible())
00880             continue;
00881         int objEndX = obj -> getX() + obj -> getWidth();
00882         int objEndY = obj -> getY() + obj -> getHeight();
00883         int objStartX = obj -> getX();
00884         int objStartY = obj -> getY();
00885         if (startx >= objStartX)
00886             startx = objStartX;
00887         if (starty >= objStartY)
00888             starty = objStartY;
00889         if(endx <= objEndX)
00890             endx = objEndX;
00891         if(endy <= objEndY)
00892             endy = objEndY;
00893     }
00894     //if seq. diagram, make sure print all of the lines
00895     if (getType() == dt_Sequence ) {
00896         for (UMLWidgetListIt it(m_WidgetList); (obj = it.current()) != NULL; ++it) {
00897             ObjectWidget *ow = dynamic_cast<ObjectWidget*>(obj);
00898             if (ow == NULL)
00899                 continue;
00900             int y = ow->getEndLineY();
00901             if (endy < y)
00902                 endy = y;
00903         }
00904     }
00905 
00906     /* now we need another look at the associations, because they are no
00907      * UMLWidgets */
00908     AssociationWidgetListIt assoc_it (m_AssociationList);
00909     AssociationWidget * assoc_obj;
00910     QRect rect;
00911 
00912     while ((assoc_obj = assoc_it.current()) != 0)
00913     {
00914         /* get the rectangle around all segments of the assoc */
00915         rect = assoc_obj->getAssocLineRectangle();
00916 
00917         if (startx >= rect.x())
00918             startx = rect.x();
00919         if (starty >= rect.y())
00920             starty = rect.y();
00921         if (endx <= rect.x() + rect.width())
00922             endx = rect.x() + rect.width();
00923         if (endy <= rect.y() + rect.height())
00924             endy = rect.y() + rect.height();
00925         ++assoc_it; // next assoc
00926     }
00927 
00928     /* Margin causes problems of black border around the edge
00929        // Margin:
00930        startx -= 24;
00931        starty -= 20;
00932        endx += 24;
00933        endy += 20;
00934     */
00935 
00936     return QRect(startx, starty,  endx - startx, endy - starty);
00937 }
00938 
00939 void UMLView::setSelected(UMLWidget * w, QMouseEvent * /*me*/) {
00940     //only add if wasn't in list
00941     if(!m_SelectedList.remove(w))
00942         m_SelectedList.append(w);
00943     int count = m_SelectedList.count();
00944     //only call once - if we select more, no need to keep clearing  window
00945 
00946     // if count == 1, widget will update the doc window with their data when selected
00947     if( count == 2 )
00948         updateDocumentation( true );//clear doc window
00949 
00950     /* selection changed, we have to make sure the copy and paste items
00951      * are correctly enabled/disabled */
00952     UMLApp::app()->slotCopyChanged();
00953 }
00954 
00955 void UMLView::clearSelected() {
00956     m_SelectedList.clear();
00957     emit sigClearAllSelected();
00958     //m_pDoc -> enableCutCopy(false);
00959 }
00960 
00961 //TODO Only used in MLApp::handleCursorKeyReleaseEvent
00962 void UMLView::moveSelectedBy(int dX, int dY) {
00963     for (UMLWidget *w = m_SelectedList.first(); w; w = m_SelectedList.next())
00964         w->moveBy(dX, dY);
00965 }
00966 
00967 void UMLView::selectionUseFillColor(bool useFC) {
00968     UMLWidget * temp = 0;
00969     for(temp=(UMLWidget *)m_SelectedList.first();temp;temp=(UMLWidget *)m_SelectedList.next())
00970         temp -> setUseFillColour(useFC);
00971 }
00972 
00973 void UMLView::selectionSetFont( const QFont &font )
00974 {
00975     UMLWidget * temp = 0;
00976     for(temp=(UMLWidget *)m_SelectedList.first();temp;temp=(UMLWidget *)m_SelectedList.next())
00977         temp -> setFont( font );
00978 }
00979 
00980 void UMLView::selectionSetLineColor( const QColor &color )
00981 {
00982     UMLWidget * temp = 0;
00983     for (temp = m_SelectedList.first(); temp; temp = m_SelectedList.next()) {
00984         temp->setLineColor(color);
00985         temp->setUsesDiagramLineColour(false);
00986     }
00987     AssociationWidgetList assoclist = getSelectedAssocs();
00988     for (AssociationWidget *aw = assoclist.first(); aw; aw = assoclist.next()) {
00989         aw->setLineColor(color);
00990         aw->setUsesDiagramLineColour(false);
00991     }
00992 }
00993 
00994 void UMLView::selectionSetLineWidth( uint width )
00995 {
00996     UMLWidget * temp = 0;
00997     for (temp = m_SelectedList.first(); temp; temp = m_SelectedList.next()) {
00998         temp->setLineWidth(width);
00999         temp->setUsesDiagramLineWidth(false);
01000     }
01001     AssociationWidgetList assoclist = getSelectedAssocs();
01002     for (AssociationWidget *aw = assoclist.first(); aw; aw = assoclist.next()) {
01003         aw->setLineWidth(width);
01004         aw->setUsesDiagramLineWidth(false);
01005     }
01006 }
01007 
01008 void UMLView::selectionSetFillColor( const QColor &color )
01009 {
01010     UMLWidget * temp = 0;
01011     for(temp=(UMLWidget *) m_SelectedList.first();
01012             temp;
01013             temp=(UMLWidget *)m_SelectedList.next()) {
01014         temp -> setFillColour( color );
01015         temp -> setUsesDiagramFillColour(false);
01016     }
01017 }
01018 
01019 void UMLView::selectionToggleShow(int sel)
01020 {
01021     // loop through all selected items
01022     for(UMLWidget *temp = (UMLWidget *)m_SelectedList.first();
01023             temp; temp=(UMLWidget *)m_SelectedList.next()) {
01024         Widget_Type type = temp->getBaseType();
01025         ClassifierWidget *cw = dynamic_cast<ClassifierWidget*>(temp);
01026 
01027         // toggle the show setting sel
01028         switch (sel)
01029         {
01030             // some setting are only available for class, some for interface and some
01031             // for both
01032         case ListPopupMenu::mt_Show_Attributes_Selection:
01033             if (type == wt_Class)
01034                 cw -> toggleShowAtts();
01035             break;
01036         case ListPopupMenu::mt_Show_Operations_Selection:
01037             if (cw)
01038                 cw -> toggleShowOps();
01039             break;
01040         case ListPopupMenu::mt_Visibility_Selection:
01041             if (cw)
01042                 cw -> toggleShowVisibility();
01043             break;
01044         case ListPopupMenu::mt_DrawAsCircle_Selection:
01045             if (type == wt_Interface)
01046                 cw -> toggleDrawAsCircle();
01047             break;
01048         case ListPopupMenu::mt_Show_Operation_Signature_Selection:
01049             if (cw)
01050                 cw -> toggleShowOpSigs();
01051             break;
01052         case ListPopupMenu::mt_Show_Attribute_Signature_Selection:
01053             if (type == wt_Class)
01054                 cw -> toggleShowAttSigs();
01055             break;
01056         case ListPopupMenu::mt_Show_Packages_Selection:
01057             if (cw)
01058                 cw -> toggleShowPackage();
01059             break;
01060         case ListPopupMenu::mt_Show_Stereotypes_Selection:
01061             if (type == wt_Class)
01062                 cw -> toggleShowStereotype();
01063             break;
01064         case ListPopupMenu::mt_Show_Public_Only_Selection:
01065             if (cw)
01066                 cw -> toggleShowPublicOnly();
01067             break;
01068         default:
01069             break;
01070         } // switch (sel)
01071     }
01072 }
01073 
01074 void UMLView::deleteSelection()
01075 {
01076     /*
01077        Don't delete text widget that are connect to associations as these will
01078        be cleaned up by the associations.
01079     */
01080     UMLWidget * temp = 0;
01081     for(temp=(UMLWidget *) m_SelectedList.first();
01082             temp;
01083             temp=(UMLWidget *)m_SelectedList.next())
01084     {
01085         if( temp -> getBaseType() == wt_Text &&
01086                 ((FloatingTextWidget *)temp) -> getRole() != tr_Floating )
01087         {
01088             m_SelectedList.remove(); // remove advances the iterator to the next position,
01089             m_SelectedList.prev();      // let's allow for statement do the advancing
01090             temp -> hide();
01091         } else {
01092             removeWidget(temp);
01093         }
01094     }
01095 
01096     // Delete any selected associations.
01097     AssociationWidgetListIt assoc_it( m_AssociationList );
01098     AssociationWidget* assocwidget = 0;
01099     while((assocwidget=assoc_it.current())) {
01100         ++assoc_it;
01101         if( assocwidget-> getSelected() )
01102             removeAssoc(assocwidget);
01103         // MARK
01104     }
01105 
01106     /* we also have to remove selected messages from sequence diagrams */
01107     MessageWidget * cur_msgWgt;
01108 
01109     /* loop through all messages and check the selection state */
01110     for (cur_msgWgt = m_MessageList.first(); cur_msgWgt;
01111             cur_msgWgt = m_MessageList.next())
01112     {
01113         if (cur_msgWgt->getSelected() == true)
01114         {
01115             removeWidget(cur_msgWgt);  // Remove message - it is selected.
01116         }
01117     }
01118 
01119     // sometimes we miss one widget, so call this function again to remove it as
01120     // well
01121     if (m_SelectedList.count() != 0)
01122         deleteSelection();
01123 
01124     //make sure list empty - it should be anyway, just a check.
01125     m_SelectedList.clear();
01126 }
01127 
01128 void UMLView::selectAll()
01129 {
01130     selectWidgets(0, 0, canvas()->width(), canvas()->height());
01131 }
01132 
01133 Uml::IDType UMLView::getLocalID() {
01134     m_nLocalID = UniqueID::gen();
01135     return m_nLocalID;
01136 }
01137 
01138 bool UMLView::isSavedInSeparateFile() {
01139     if (getOptionState().generalState.tabdiagrams) {
01140         // Umbrello currently does not support external folders
01141         // when tabbed diagrams are enabled.
01142         return false;
01143     }
01144     const QString msgPrefix("UMLView::isSavedInSeparateFile(" + getName() + "): ");
01145     UMLListView *listView = UMLApp::app()->getListView();
01146     UMLListViewItem *lvItem = listView->findItem(m_nID);
01147     if (lvItem == NULL) {
01148         kError() << msgPrefix
01149                   << "listView->findUMLObject(this) returns false" << endl;
01150         return false;
01151     }
01152     UMLListViewItem *parentItem = dynamic_cast<UMLListViewItem*>( lvItem->parent() );
01153     if (parentItem == NULL) {
01154         kError() << msgPrefix
01155                   << "parent item in listview is not a UMLListViewItem (?)" << endl;
01156         return false;
01157     }
01158     const Uml::ListView_Type lvt = parentItem->getType();
01159     if (! Model_Utils::typeIsFolder(lvt))
01160         return false;
01161     UMLFolder *modelFolder = dynamic_cast<UMLFolder*>(parentItem->getUMLObject());
01162     if (modelFolder == NULL) {
01163         kError() << msgPrefix
01164                   << "parent model object is not a UMLFolder (?)" << endl;
01165         return false;
01166     }
01167     QString folderFile = modelFolder->getFolderFile();
01168     return !folderFile.isEmpty();
01169 }
01170 
01171 void UMLView::contentsMousePressEvent(QMouseEvent* ome) {
01172     m_pToolBarState->mousePress(ome);
01173     //TODO should be managed by widgets when are selected. Right now also has some
01174     //problems, such as clicking on a widget, and clicking to move that widget shows
01175     //documentation of the diagram instead of keeping the widget documentation.
01176     //When should diagram documentation be shown? When clicking on an empty
01177     //space in the diagram with arrow tool?
01178     if (!m_bChildDisplayedDoc) {
01179       UMLApp::app() -> getDocWindow() -> showDocumentation( this, true );
01180     }
01181     m_bChildDisplayedDoc = false;
01182 }
01183 
01184 void UMLView::makeSelected (UMLWidget * uw) {
01185     if (uw == NULL)
01186         return;
01187     uw -> setSelected(true);
01188     m_SelectedList.remove(uw);  // make sure not in there
01189     m_SelectedList.append(uw);
01190 }
01191 
01192 void UMLView::selectWidgetsOfAssoc (AssociationWidget * a) {
01193     if (!a)
01194         return;
01195     a -> setSelected(true);
01196     //select the two widgets
01197     makeSelected( a->getWidget(A) );
01198     makeSelected( a->getWidget(B) );
01199     //select all the text
01200     makeSelected( a->getMultiWidget(A) );
01201     makeSelected( a->getMultiWidget(B) );
01202     makeSelected( a->getRoleWidget(A) );
01203     makeSelected( a->getRoleWidget(B) );
01204     makeSelected( a->getChangeWidget(A) );
01205     makeSelected( a->getChangeWidget(B) );
01206 }
01207 
01208 void UMLView::selectWidgets(int px, int py, int qx, int qy) {
01209     clearSelected();
01210 
01211     QRect rect;
01212     if(px <= qx) {
01213         rect.setLeft(px);
01214         rect.setRight(qx);
01215     } else {
01216         rect.setLeft(qx);
01217         rect.setRight(px);
01218     }
01219     if(py <= qy) {
01220         rect.setTop(py);
01221         rect.setBottom(qy);
01222     } else {
01223         rect.setTop(qy);
01224         rect.setBottom(py);
01225     }
01226     UMLWidgetListIt it(m_WidgetList);
01227     UMLWidget * temp = NULL;
01228     while ( (temp = it.current()) != 0 ) {
01229         int x = temp -> getX();
01230         int y = temp -> getY();
01231         int w = temp -> getWidth();
01232         int h = temp -> getHeight();
01233         QRect rect2(x, y, w, h);
01234         ++it;
01235         //see if any part of widget is in the rectangle
01236         if( !rect.intersects(rect2) )
01237             continue;
01238         //if it is text that is part of an association then select the association
01239         //and the objects that are connected to it.
01240         if (temp -> getBaseType() == wt_Text) {
01241             FloatingTextWidget *ft = static_cast<FloatingTextWidget*>(temp);
01242             Text_Role t = ft -> getRole();
01243             LinkWidget *lw = ft->getLink();
01244             MessageWidget * mw = dynamic_cast<MessageWidget*>(lw);
01245             if (mw) {
01246                 makeSelected( mw );
01247                 makeSelected( mw->getWidget(A) );
01248                 makeSelected( mw->getWidget(B) );
01249             } else if (t != tr_Floating) {
01250                 AssociationWidget * a = dynamic_cast<AssociationWidget*>(lw);
01251                 if (a)
01252                     selectWidgetsOfAssoc( a );
01253             }
01254         } else if(temp -> getBaseType() == wt_Message) {
01255             MessageWidget *mw = static_cast<MessageWidget*>(temp);
01256             makeSelected( mw -> getWidget(A) );
01257             makeSelected( mw -> getWidget(B) );
01258         }
01259         if(temp -> isVisible()) {
01260             makeSelected( temp );
01261         }
01262     }
01263     selectAssociations( true );
01264 
01265     //now do the same for the messagewidgets
01266     MessageWidgetListIt itw( m_MessageList );
01267     MessageWidget *w = 0;
01268     while ( (w = itw.current()) != 0 ) {
01269         ++itw;
01270         if ( w -> getWidget(A) -> getSelected() &&
01271                 w -> getWidget(B) -> getSelected() ) {
01272             makeSelected( w );
01273         }//end if
01274     }//end while
01275 }
01276 
01277 void  UMLView::getDiagram(const QRect &rect, QPixmap & diagram) {
01278     QPixmap pixmap(rect.x() + rect.width(), rect.y() + rect.height());
01279     QPainter painter(&pixmap);
01280     getDiagram(canvas()->rect(),painter);
01281     bitBlt(&diagram, QPoint(0, 0), &pixmap, rect);
01282 }
01283 
01284 void  UMLView::getDiagram(const QRect &area, QPainter & painter) {
01285     //TODO unselecting and selecting later doesn't work now as the selection is
01286     //cleared in UMLViewImageExporter. Check if the anything else than the
01287     //following is needed and, if it works, remove the clearSelected in
01288     //UMLViewImageExporter and UMLViewImageExporterModel
01289     UMLWidget* widget = 0;
01290     for (widget=(UMLWidget*)m_SelectedList.first(); widget; widget=(UMLWidget*)m_SelectedList.next()) {
01291         widget->setSelected(false);
01292     }
01293     AssociationWidgetList selectedAssociationsList = getSelectedAssocs();
01294     AssociationWidget* association = 0;
01295     for (association=selectedAssociationsList.first(); association;
01296                                 association=selectedAssociationsList.next()) {
01297         association->setSelected(false);
01298     }
01299 
01300     // we don't want to get the grid
01301     bool showSnapGrid = getShowSnapGrid();
01302     setShowSnapGrid(false);
01303 
01304     canvas()->drawArea(area, &painter);
01305 
01306     setShowSnapGrid(showSnapGrid);
01307 
01308     canvas()->setAllChanged();
01309     //select again
01310     for (widget=(UMLWidget *)m_SelectedList.first(); widget; widget=(UMLWidget *)m_SelectedList.next()) {
01311         widget->setSelected( true );
01312     }
01313     for (association=selectedAssociationsList.first(); association;
01314                                 association=selectedAssociationsList.next()) {
01315         association->setSelected(true);
01316     }
01317 
01318     return;
01319 }
01320 
01321 UMLViewImageExporter* UMLView::getImageExporter() {
01322     return m_pImageExporter;
01323 }
01324 
01325 void UMLView::slotActivate() {
01326     m_pDoc->changeCurrentView(getID());
01327 }
01328 
01329 UMLObjectList UMLView::getUMLObjects() {
01330     UMLObjectList list;
01331     for (UMLWidgetListIt it(m_WidgetList); it.current(); ++it) {
01332         UMLWidget *w = it.current();
01333         switch (w->getBaseType()) //use switch for easy future expansion
01334         {
01335         case wt_Actor:
01336         case wt_Class:
01337         case wt_Interface:
01338         case wt_Package:
01339         case wt_Component:
01340         case wt_Node:
01341         case wt_Artifact:
01342         case wt_UseCase:
01343         case wt_Object:
01344             list.append( w->getUMLObject() );
01345             break;
01346         default:
01347             break;
01348         }
01349     }
01350     return list;
01351 }
01352 
01353 void UMLView::activate() {
01354     UMLWidgetListIt it( m_WidgetList );
01355     UMLWidget *obj;
01356 
01357     //Activate Regular widgets then activate  messages
01358     while ( (obj = it.current()) != 0 ) {
01359         ++it;
01360         //If this UMLWidget is already activated or is a MessageWidget then skip it
01361         if(obj->isActivated() || obj->getBaseType() == wt_Message)
01362             continue;
01363 
01364         if (obj->activate()) {
01365             obj->setVisible(true);
01366         } else {
01367             m_WidgetList.remove(obj);
01368             delete obj;
01369         }
01370     }//end while
01371 
01372     MessageWidgetListIt it2( m_MessageList );
01373     //Activate Message widgets
01374     while ( (obj = (UMLWidget*)it2.current()) != 0 ) {
01375         ++it2;
01376         //If this MessageWidget is already activated then skip it
01377         if(obj->isActivated())
01378             continue;
01379 
01380         obj->activate(m_pDoc->getChangeLog());
01381         obj->setVisible( true );
01382 
01383     }//end while
01384 
01385     // Activate all association widgets
01386     AssociationWidget *aw;
01387     for (AssociationWidgetListIt ait(m_AssociationList);
01388             (aw = ait.current()); ++ait) {
01389         if (aw->activate()) {
01390             if (m_PastePoint.x() != 0) {
01391                 int x = m_PastePoint.x() - m_Pos.x();
01392                 int y = m_PastePoint.y() - m_Pos.y();
01393                 aw->moveEntireAssoc(x, y);
01394             }
01395         } else {
01396             m_AssociationList.remove(aw);
01397         }
01398     }
01399 }
01400 
01401 int UMLView::getSelectCount(bool filterText) const {
01402     if (!filterText)
01403         return m_SelectedList.count();
01404     int counter = 0;
01405     const UMLWidget * temp = 0;
01406     for (UMLWidgetListIt iter(m_SelectedList); (temp = iter.current()) != 0; ++iter) {
01407         if (temp->getBaseType() == wt_Text) {
01408             const FloatingTextWidget *ft = static_cast<const FloatingTextWidget*>(temp);
01409             if (ft->getRole() == tr_Floating)
01410                 counter++;
01411         } else {
01412             counter++;
01413         }
01414     }
01415     return counter;
01416 }
01417 
01418 
01419 bool UMLView::getSelectedWidgets(UMLWidgetList &WidgetList, bool filterText /*= true*/) {
01420     const UMLWidget * temp = 0;
01421     for (UMLWidgetListIt it(m_SelectedList); (temp = it.current()) != NULL; ++it) {
01422         if (filterText && temp->getBaseType() == wt_Text) {
01423             const FloatingTextWidget *ft = static_cast<const FloatingTextWidget*>(temp);
01424             if (ft->getRole() == tr_Floating)
01425                 WidgetList.append(temp);
01426         } else {
01427             WidgetList.append(temp);
01428         }
01429     }//end for
01430     return true;
01431 }
01432 
01433 AssociationWidgetList UMLView::getSelectedAssocs() {
01434     AssociationWidgetList assocWidgetList;
01435     AssociationWidgetListIt assoc_it( m_AssociationList );
01436     AssociationWidget* assocwidget = 0;
01437     while((assocwidget=assoc_it.current())) {
01438         ++assoc_it;
01439         if( assocwidget -> getSelected() )
01440             assocWidgetList.append(assocwidget);
01441     }
01442     return assocWidgetList;
01443 }
01444 
01445 bool UMLView::addWidget( UMLWidget * pWidget , bool isPasteOperation ) {
01446     if( !pWidget ) {
01447         return false;
01448     }
01449     Widget_Type type = pWidget->getBaseType();
01450     if (isPasteOperation) {
01451         if (type == Uml::wt_Message)
01452             m_MessageList.append(static_cast<MessageWidget*>(pWidget));
01453         else
01454             m_WidgetList.append(pWidget);
01455         return true;
01456     }
01457     if (!isPasteOperation && findWidget(pWidget->getID())) {
01458         kError() << "UMLView::addWidget: Not adding "
01459                   << "(id=" << ID2STR(pWidget->getID())
01460                   << "/type=" << type << "/name=" << pWidget->getName()
01461                   << ") because it's already there" << endl;
01462         return false;
01463     }
01464     //kDebug() << "UMLView::addWidget called for basetype " << type << endl;
01465     IDChangeLog * log = m_pDoc -> getChangeLog();
01466     if( isPasteOperation && (!log || !m_pIDChangesLog)) {
01467         kError()<<" Cant addWidget to view in paste op because a log is not open"<<endl;
01468         return false;
01469     }
01470     int wX = pWidget -> getX();
01471     int wY = pWidget -> getY();
01472     bool xIsOutOfRange = (wX <= 0 || wX >= FloatingTextWidget::restrictPositionMax);
01473     bool yIsOutOfRange = (wY <= 0 || wY >= FloatingTextWidget::restrictPositionMax);
01474     if (xIsOutOfRange || yIsOutOfRange) {
01475         QString name = pWidget->getName();
01476         if (name.isEmpty()) {
01477             FloatingTextWidget *ft = dynamic_cast<FloatingTextWidget*>(pWidget);
01478             if (ft)
01479                 name = ft->getDisplayText();
01480         }
01481         kDebug() << "UMLView::addWidget (" << name << " type="
01482                   << pWidget->getBaseType() << "): position (" << wX << ","
01483                   << wY << ") is out of range" << endl;
01484         if (xIsOutOfRange) {
01485             pWidget->setX(0);
01486             wX = 0;
01487         }
01488         if (yIsOutOfRange) {
01489             pWidget->setY(0);
01490             wY = 0;
01491         }
01492     }
01493     if( wX < m_Pos.x() )
01494         m_Pos.setX( wX );
01495     if( wY < m_Pos.y() )
01496         m_Pos.setY( wY );
01497 
01498     //see if we need a new id to match object
01499     switch( type ) {
01500 
01501     case wt_Class:
01502     case wt_Package:
01503     case wt_Component:
01504     case wt_Node:
01505     case wt_Artifact:
01506     case wt_Interface:
01507     case wt_Enum:
01508     case wt_Entity:
01509     case wt_Datatype:
01510     case wt_Actor:
01511     case wt_UseCase:
01512         {
01513             Uml::IDType id = pWidget -> getID();
01514             Uml::IDType newID = log->findNewID( id );
01515             if( newID == Uml::id_None ) {  // happens after a cut
01516                 if (id == Uml::id_None)
01517                     return false;
01518                 newID = id; //don't stop paste
01519             } else
01520                 pWidget -> setID( newID );
01521             UMLObject * pObject = m_pDoc -> findObjectById( newID );
01522             if( !pObject ) {
01523                 kDebug() << "addWidget: Can't find UMLObject for id "
01524                           << ID2STR(newID) << endl;
01525                 return false;
01526             }
01527             pWidget -> setUMLObject( pObject );
01528             //make sure it doesn't already exist.
01529             if (findWidget(newID)) {
01530                 kDebug() << "UMLView::addWidget: Not adding "
01531                           << "(id=" << ID2STR(pWidget->getID())
01532                           << "/type=" << pWidget->getBaseType()
01533                           << "/name=" << pWidget->getName()
01534                           << ") because it's already there" << endl;
01535                 delete pWidget; // Not nice but if _we_ don't do it nobody else will
01536                 return true;//don't stop paste just because widget found.
01537             }
01538             m_WidgetList.append( pWidget );
01539         }
01540         break;
01541 
01542     case wt_Message:
01543     case wt_Note:
01544     case wt_Box:
01545     case wt_Text:
01546     case wt_State:
01547     case wt_Activity:
01548         {
01549             Uml::IDType newID = m_pDoc->assignNewID( pWidget->getID() );
01550             pWidget->setID(newID);
01551             if (type != wt_Message) {
01552                 m_WidgetList.append( pWidget );
01553                 return true;
01554             }
01555             // CHECK
01556             // Handling of wt_Message:
01557             MessageWidget *pMessage = static_cast<MessageWidget *>( pWidget );
01558             if (pMessage == NULL) {
01559                 kDebug() << "UMLView::addWidget(): pMessage is NULL" << endl;
01560                 return false;
01561             }
01562             ObjectWidget *objWidgetA = pMessage -> getWidget(A);
01563             ObjectWidget *objWidgetB = pMessage -> getWidget(B);
01564             Uml::IDType waID = objWidgetA -> getLocalID();
01565             Uml::IDType wbID = objWidgetB -> getLocalID();
01566             Uml::IDType newWAID = m_pIDChangesLog ->findNewID( waID );
01567             Uml::IDType newWBID = m_pIDChangesLog ->findNewID( wbID );
01568             if( newWAID == Uml::id_None || newWBID == Uml::id_None ) {
01569                 kDebug() << "Error with ids : " << ID2STR(newWAID)
01570                           << " " << ID2STR(newWBID) << endl;
01571                 return false;
01572             }
01573             // Assumption here is that the A/B objectwidgets and the textwidget
01574             // are pristine in the sense that we may freely change their local IDs.
01575             objWidgetA -> setLocalID( newWAID );
01576             objWidgetB -> setLocalID( newWBID );
01577             FloatingTextWidget *ft = pMessage->getFloatingTextWidget();
01578             if (ft == NULL)
01579                 kDebug() << "UMLView::addWidget: FloatingTextWidget of Message is NULL" << endl;
01580             else if (ft->getID() == Uml::id_None)
01581                 ft->setID( UniqueID::gen() );
01582             else {
01583                 Uml::IDType newTextID = m_pDoc->assignNewID( ft->getID() );
01584                 ft->setID( newTextID );
01585             }
01586             m_MessageList.append( pMessage );
01587         }
01588         break;
01589 
01590     case wt_Object:
01591         {
01592             ObjectWidget* pObjectWidget = static_cast<ObjectWidget*>(pWidget);
01593             if (pObjectWidget == NULL) {
01594                 kDebug() << "UMLView::addWidget(): pObjectWidget is NULL" << endl;
01595                 return false;
01596             }
01597             Uml::IDType nNewLocalID = getLocalID();
01598             Uml::IDType nOldLocalID = pObjectWidget -> getLocalID();
01599             m_pIDChangesLog->addIDChange( nOldLocalID, nNewLocalID );
01600             pObjectWidget -> setLocalID( nNewLocalID );
01601             UMLObject *pObject = m_pDoc->findObjectById(pWidget->getID());
01602             if( !pObject ) {
01603                 kDebug() << "addWidget::Can't find UMLObject" << endl;
01604                 return false;
01605             }
01606             pWidget -> setUMLObject( pObject );
01607             m_WidgetList.append( pWidget );
01608         }
01609         break;
01610 
01611     default:
01612         kDebug() << "Trying to add an invalid widget type" << endl;
01613         return false;
01614         break;
01615     }
01616 
01617     return true;
01618 }
01619 
01620 // Add the association, and its child widgets to this view
01621 bool UMLView::addAssociation(AssociationWidget* pAssoc , bool isPasteOperation) {
01622 
01623     if (!pAssoc) {
01624         return false;
01625     }
01626     const Association_Type type = pAssoc->getAssocType();
01627 
01628     if( isPasteOperation )
01629     {
01630         IDChangeLog * log = m_pDoc -> getChangeLog();
01631 
01632         if(!log )
01633             return false;
01634 
01635         Uml::IDType ida = Uml::id_None, idb = Uml::id_None;
01636         if( getType() == dt_Collaboration || getType() == dt_Sequence ) {
01637             //check local log first
01638             ida = m_pIDChangesLog->findNewID( pAssoc->getWidgetID(A) );
01639             idb = m_pIDChangesLog->findNewID( pAssoc->getWidgetID(B) );
01640             //if either is still not found and assoc type is anchor
01641             //we are probably linking to a notewidet - else an error
01642             if( ida == Uml::id_None && type == at_Anchor )
01643                 ida = log->findNewID(pAssoc->getWidgetID(A));
01644             if( idb == Uml::id_None && type == at_Anchor )
01645                 idb = log->findNewID(pAssoc->getWidgetID(B));
01646         } else {
01647             Uml::IDType oldIdA = pAssoc->getWidgetID(A);
01648             Uml::IDType oldIdB = pAssoc->getWidgetID(B);
01649             ida = log->findNewID( oldIdA );
01650             if (ida == Uml::id_None) {  // happens after a cut
01651                 if (oldIdA == Uml::id_None)
01652                     return false;
01653                 ida = oldIdA;
01654             }
01655             idb = log->findNewID( oldIdB );
01656             if (idb == Uml::id_None) {  // happens after a cut
01657                 if (oldIdB == Uml::id_None)
01658                     return false;
01659                 idb = oldIdB;
01660             }
01661         }
01662         if(ida == Uml::id_None || idb == Uml::id_None) {
01663             return false;
01664         }
01665         // cant do this anymore.. may cause problem for pasting
01666         //      pAssoc->setWidgetID(ida, A);
01667         //      pAssoc->setWidgetID(idb, B);
01668         pAssoc->setWidget(findWidget(ida), A);
01669         pAssoc->setWidget(findWidget(idb), B);
01670     }
01671 
01672     UMLWidget * pWidgetA = findWidget(pAssoc->getWidgetID(A));
01673     UMLWidget * pWidgetB = findWidget(pAssoc->getWidgetID(B));
01674     //make sure valid widget ids
01675     if (!pWidgetA || !pWidgetB) {
01676         return false;
01677     }
01678 
01679     //make sure valid
01680     if (!isPasteOperation && !m_pDoc->loading() &&
01681         !AssocRules::allowAssociation(type, pWidgetA, pWidgetB, false)) {
01682         kWarning() << "UMLView::addAssociation: allowAssociation returns false "
01683                    << "for AssocType " << type << endl;
01684         return false;
01685     }
01686 
01687     //make sure there isn't already the same assoc
01688     AssociationWidgetListIt assoc_it( m_AssociationList );
01689     AssociationWidget* assocwidget = 0;
01690     while((assocwidget=assoc_it.current())) {
01691         ++assoc_it;
01692         if( *pAssoc == *assocwidget )
01693             // this is nuts. Paste operation wants to know if 'true'
01694             // for duplicate, but loadFromXMI needs 'false' value
01695             return (isPasteOperation? true: false);
01696     }
01697 
01698     m_AssociationList.append(pAssoc);
01699 
01700     FloatingTextWidget *ft[5] = { pAssoc->getNameWidget(),
01701                             pAssoc->getRoleWidget(A),
01702                             pAssoc->getRoleWidget(B),
01703                             pAssoc->getMultiWidget(A),
01704                             pAssoc->getMultiWidget(B) };
01705     for (int i = 0; i < 5; i++) {
01706         FloatingTextWidget *flotxt = ft[i];
01707         if (flotxt) {
01708             flotxt->updateComponentSize();
01709             addWidget(flotxt);
01710         }
01711     }
01712 
01713     return true;
01714 }
01715 
01716 void UMLView::activateAfterLoad(bool bUseLog) {
01717     if (m_bActivated)
01718         return;
01719     if( bUseLog ) {
01720         beginPartialWidgetPaste();
01721     }
01722 
01723     //now activate them all
01724     activate();
01725 
01726     if( bUseLog ) {
01727         endPartialWidgetPaste();
01728     }
01729     resizeCanvasToItems();
01730     setZoom( getZoom() );
01731     m_bActivated = true;
01732 }
01733 
01734 void UMLView::beginPartialWidgetPaste() {
01735     delete m_pIDChangesLog;
01736     m_pIDChangesLog = 0;
01737 
01738     m_pIDChangesLog = new IDChangeLog();
01739     m_bPaste = true;
01740 }
01741 
01742 void UMLView::endPartialWidgetPaste() {
01743     delete    m_pIDChangesLog;
01744     m_pIDChangesLog = 0;
01745 
01746     m_bPaste = false;
01747 }
01748 
01749 void UMLView::removeAssoc(AssociationWidget* pAssoc) {
01750     if(!pAssoc)
01751         return;
01752 
01753     emit sigAssociationRemoved(pAssoc);
01754 
01755     pAssoc->cleanup();
01756     m_AssociationList.remove(pAssoc); // will delete our association
01757     m_pDoc->setModified();
01758 }
01759 
01760 void UMLView::removeAssocInViewAndDoc(AssociationWidget* a) {
01761     // For umbrello 1.2, UMLAssociations can only be removed in two ways:
01762     // 1. Right click on the assocwidget in the view and select Delete
01763     // 2. Go to the Class Properties page, select Associations, right click
01764     //    on the association and select Delete
01765     if(!a)
01766         return;
01767     if (a->getAssocType() == at_Containment) {
01768         UMLObject *objToBeMoved = a->getWidget(B)->getUMLObject();
01769         if (objToBeMoved != NULL) {
01770             UMLListView *lv = UMLApp::app()->getListView();
01771             lv->moveObject( objToBeMoved->getID(),
01772                             Model_Utils::convert_OT_LVT(objToBeMoved),
01773                             lv->theLogicalView() );
01774             // UMLListView::moveObject() will delete the containment
01775             // AssociationWidget via UMLView::updateContainment().
01776         } else {
01777             kDebug() << "removeAssocInViewAndDoc(containment): "
01778                       << "objB is NULL" << endl;
01779         }
01780     } else {
01781         // Remove assoc in doc.
01782         m_pDoc->removeAssociation(a->getAssociation());
01783         // Remove assoc in view.
01784         removeAssoc(a);
01785     }
01786 }
01787 
01789 void UMLView::removeAssociations(UMLWidget* Widget) {
01790     AssociationWidgetListIt assoc_it(m_AssociationList);
01791     AssociationWidget* assocwidget = 0;
01792     while((assocwidget=assoc_it.current())) {
01793         ++assoc_it;
01794         if(assocwidget->contains(Widget)) {
01795             removeAssoc(assocwidget);
01796         }
01797     }
01798 }
01799 
01800 void UMLView::selectAssociations(bool bSelect) {
01801     AssociationWidgetListIt assoc_it(m_AssociationList);
01802     AssociationWidget* assocwidget = 0;
01803     while((assocwidget=assoc_it.current())) {
01804         ++assoc_it;
01805         if(bSelect &&
01806                 assocwidget->getWidget(A) && assocwidget->getWidget(A)->getSelected() &&
01807                 assocwidget->getWidget(B) && assocwidget->getWidget(B)->getSelected() ) {
01808             assocwidget->setSelected(true);
01809         } else {
01810             assocwidget->setSelected(false);
01811         }
01812     }//end while
01813 }
01814 
01815 void UMLView::getWidgetAssocs(UMLObject* Obj, AssociationWidgetList & Associations) {
01816     if( ! Obj )
01817         return;
01818 
01819     AssociationWidgetListIt assoc_it(m_AssociationList);
01820     AssociationWidget * assocwidget;
01821     while((assocwidget = assoc_it.current())) {
01822         if (assocwidget->getWidget(A)->getUMLObject() == Obj ||
01823                 assocwidget->getWidget(B)->getUMLObject() == Obj)
01824             Associations.append(assocwidget);
01825         ++assoc_it;
01826     }//end while
01827 }
01828 
01829 void UMLView::closeEvent ( QCloseEvent * e ) {
01830     QWidget::closeEvent(e);
01831 }
01832 
01833 void UMLView::removeAllAssociations() {
01834     //Remove All association widgets
01835     AssociationWidgetListIt assoc_it(m_AssociationList);
01836     AssociationWidget* assocwidget = 0;
01837     while((assocwidget=assoc_it.current()))
01838     {
01839         ++assoc_it;
01840         removeAssoc(assocwidget);
01841     }
01842     m_AssociationList.clear();
01843 }
01844 
01845 
01846 void UMLView::removeAllWidgets() {
01847     // Remove widgets.
01848     UMLWidgetListIt it( m_WidgetList );
01849     UMLWidget * temp = 0;
01850     while ( (temp = it.current()) != 0 ) {
01851         ++it;
01852         // I had to take this condition back in, else umbrello
01853         // crashes on exit. Still to be analyzed.  --okellogg
01854         if( !( temp -> getBaseType() == wt_Text &&
01855                 ((FloatingTextWidget *)temp)-> getRole() != tr_Floating ) ) {
01856             removeWidget( temp );
01857         }
01858     }
01859     m_WidgetList.clear();
01860 }
01861 
01862 void UMLView::showDocumentation( UMLObject * object, bool overwrite ) {
01863     UMLApp::app() -> getDocWindow() -> showDocumentation( object, overwrite );
01864     m_bChildDisplayedDoc = true;
01865 }
01866 
01867 void UMLView::showDocumentation( UMLWidget * widget, bool overwrite ) {
01868     UMLApp::app() -> getDocWindow() -> showDocumentation( widget, overwrite );
01869     m_bChildDisplayedDoc = true;
01870 }
01871 
01872 void UMLView::showDocumentation( AssociationWidget * widget, bool overwrite ) {
01873     UMLApp::app() -> getDocWindow() -> showDocumentation( widget, overwrite );
01874     m_bChildDisplayedDoc = true;
01875 }
01876 
01877 void UMLView::updateDocumentation( bool clear ) {
01878     UMLApp::app() -> getDocWindow() -> updateDocumentation( clear );
01879 }
01880 
01881 void UMLView::updateContainment(UMLCanvasObject *self) {
01882     if (self == NULL)
01883         return;
01884     // See if the object has a widget representation in this view.
01885     // While we're at it, also see if the new parent has a widget here.
01886     UMLWidget *selfWidget = NULL, *newParentWidget = NULL;
01887     UMLPackage *newParent = self->getUMLPackage();
01888     for (UMLWidgetListIt wit(m_WidgetList); wit.current(); ++wit) {
01889         UMLWidget *w = wit.current();
01890         UMLObject *o = w->getUMLObject();
01891         if (o == self)
01892             selfWidget = w;
01893         else if (newParent != NULL && o == newParent)
01894             newParentWidget = w;
01895     }
01896     if (selfWidget == NULL)
01897         return;
01898     // Remove possibly obsoleted containment association.
01899     for (AssociationWidgetListIt it(m_AssociationList); it.current(); ++it) {
01900         AssociationWidget *a = it.current();
01901         if (a->getAssocType() != Uml::at_Containment)
01902             continue;
01903         // Container is at role A, containee at B.
01904         // We only look at association for which we are B.
01905         UMLWidget *wB = a->getWidget(B);
01906         UMLObject *roleBObj = wB->getUMLObject();
01907         if (roleBObj != self)
01908             continue;
01909         UMLWidget *wA = a->getWidget(A);
01910         UMLObject *roleAObj = wA->getUMLObject();
01911         if (roleAObj == newParent) {
01912             // Wow, all done. Great!
01913             return;
01914         }
01915         removeAssoc(a);  // AutoDelete is true
01916         // It's okay to break out because there can only be a single
01917         // containing object.
01918         break;
01919     }
01920     if (newParentWidget == NULL)
01921         return;
01922     // Create the new containment association.
01923     AssociationWidget *a = new AssociationWidget(this, newParentWidget,
01924                            Uml::at_Containment, selfWidget);
01925     a->calculateEndingPoints();
01926     a->setActivated(true);
01927     m_AssociationList.append(a);
01928 }
01929 
01930 void UMLView::createAutoAssociations( UMLWidget * widget ) {
01931     if (widget == NULL ||
01932         (m_Type != Uml::dt_Class &&
01933          m_Type != Uml::dt_Component &&
01934          m_Type != Uml::dt_Deployment &&
01935          m_Type != Uml::dt_EntityRelationship))
01936         return;
01937     // Recipe:
01938     // If this widget has an underlying UMLCanvasObject then
01939     //   for each of the UMLCanvasObject's UMLAssociations
01940     //     if umlassoc's "other" role has a widget representation on this view then
01941     //       if the AssocWidget does not already exist then
01942     //         if the assoc type is permitted in the current diagram type then
01943     //           create the AssocWidget
01944     //         end if
01945     //       end if
01946     //     end if
01947     //   end loop
01948     //   Do createAutoAttributeAssociations()
01949     //   if this object is capable of containing nested objects then
01950     //     for each of the object's containedObjects
01951     //       if the containedObject has a widget representation on this view then
01952     //         if the containedWidget is not physically located inside this widget
01953     //           create the containment AssocWidget
01954     //         end if
01955     //       end if
01956     //     end loop
01957     //   end if
01958     //   if the UMLCanvasObject has a parentPackage then
01959     //     if the parentPackage has a widget representation on this view then
01960     //       create the containment AssocWidget
01961     //     end if
01962     //   end if
01963     // end if
01964     UMLObject *tmpUmlObj = widget->getUMLObject();
01965     if (tmpUmlObj == NULL)
01966         return;
01967     UMLCanvasObject *umlObj = dynamic_cast<UMLCanvasObject*>(tmpUmlObj);
01968     if (umlObj == NULL)
01969         return;
01970     const UMLAssociationList& umlAssocs = umlObj->getAssociations();
01971     UMLAssociationListIt it(umlAssocs);
01972     UMLAssociation *assoc = NULL;
01973     Uml::IDType myID = umlObj->getID();
01974     while ((assoc = it.current()) != NULL) {
01975         ++it;
01976         UMLCanvasObject *other = NULL;
01977         UMLObject *roleAObj = assoc->getObject(A);
01978         if (roleAObj == NULL) {
01979             kDebug() << "createAutoAssociations: roleA object is NULL at UMLAssoc "
01980                       << ID2STR(assoc->getID()) << endl;
01981             continue;
01982         }
01983         UMLObject *roleBObj = assoc->getObject(B);
01984         if (roleBObj == NULL) {
01985             kDebug() << "createAutoAssociations: roleB object is NULL at UMLAssoc "
01986                       << ID2STR(assoc->getID()) << endl;
01987             continue;
01988         }
01989         if (roleAObj->getID() == myID) {
01990             other = static_cast<UMLCanvasObject*>(roleBObj);
01991         } else if (roleBObj->getID() == myID) {
01992             other = static_cast<UMLCanvasObject*>(roleAObj);
01993         } else {
01994             kDebug() << "createAutoAssociations: Can't find own object "
01995                       << ID2STR(myID) << " in UMLAssoc "
01996                       << ID2STR(assoc->getID()) << endl;
01997             continue;
01998         }
01999         // Now that we have determined the "other" UMLObject, seek it in
02000         // this view's UMLWidgets.
02001         Uml::IDType otherID = other->getID();
02002         UMLWidget *pOtherWidget;
02003         UMLWidgetListIt wit(m_WidgetList);
02004         while ((pOtherWidget = wit.current()) != NULL) {
02005             ++wit;
02006             if (pOtherWidget->getID() == otherID)
02007                 break;
02008         }
02009         if (pOtherWidget == NULL)
02010             continue;
02011         // Both objects are represented in this view:
02012         // Assign widget roles as indicated by the UMLAssociation.
02013         UMLWidget *widgetA, *widgetB;
02014         if (myID == roleAObj->getID()) {
02015             widgetA = widget;
02016             widgetB = pOtherWidget;
02017         } else {
02018             widgetA = pOtherWidget;
02019             widgetB = widget;
02020         }
02021         // Check that the assocwidget does not already exist.
02022         Uml::Association_Type assocType = assoc->getAssocType();
02023         AssociationWidget * assocwidget = findAssocWidget(assocType, widgetA, widgetB);
02024         if (assocwidget) {
02025             assocwidget->calculateEndingPoints();  // recompute assoc lines
02026             continue;
02027         }
02028         // Check that the assoc is allowed.
02029         if (!AssocRules::allowAssociation(assocType, widgetA, widgetB, false)) {
02030             kDebug() << "createAutoAssociations: not transferring assoc "
02031                       << "of type " << assocType << endl;
02032             continue;
02033         }
02034         // Create the AssociationWidget.
02035         assocwidget = new AssociationWidget( this );
02036         assocwidget->setWidget(widgetA, A);
02037         assocwidget->setWidget(widgetB, B);
02038         assocwidget->setAssocType(assocType);
02039         assocwidget->setUMLObject(assoc);
02040         // Call calculateEndingPoints() before setting the FloatingTexts
02041         // because their positions are computed according to the
02042         // assocwidget line positions.
02043         assocwidget->calculateEndingPoints();
02044         assocwidget->syncToModel();
02045         assocwidget->setActivated(true);
02046         if (! addAssociation(assocwidget))
02047             delete assocwidget;
02048     }
02049     createAutoAttributeAssociations(widget);
02050     // if this object is capable of containing nested objects then
02051     Uml::Object_Type t = umlObj->getBaseType();
02052     if (t == ot_Package || t == ot_Class || t == ot_Interface || t == ot_Component) {
02053         // for each of the object's containedObjects
02054         UMLPackage *umlPkg = static_cast<UMLPackage*>(umlObj);
02055         UMLObjectList lst = umlPkg->containedObjects();
02056         for (UMLObject *obj = lst.first(); obj; obj = lst.next()) {
02057             // if the containedObject has a widget representation on this view then
02058             Uml::IDType id = obj->getID();
02059             for (UMLWidget *w = m_WidgetList.first(); w; w = m_WidgetList.next()) {
02060                 if (w->getID() != id)
02061                     continue;
02062                 // if the containedWidget is not physically located inside this widget
02063                 if (widget->rect().contains(w->rect()))
02064                     continue;
02065                 // create the containment AssocWidget
02066                 AssociationWidget *a = new AssociationWidget(this, widget,
02067                                        at_Containment, w);
02068                 a->calculateEndingPoints();
02069                 a->setActivated(true);
02070                 if (! addAssociation(a))
02071                     delete a;
02072             }
02073         }
02074     }
02075     // if the UMLCanvasObject has a parentPackage then
02076     UMLPackage *parent = umlObj->getUMLPackage();
02077     if (parent == NULL)
02078         return;
02079     // if the parentPackage has a widget representation on this view then
02080     Uml::IDType pkgID = parent->getID();
02081     UMLWidget *pWidget;
02082     UMLWidgetListIt wit(m_WidgetList);
02083     while ((pWidget = wit.current()) != NULL) {
02084         ++wit;
02085         if (pWidget->getID() == pkgID)
02086             break;
02087     }
02088     if (pWidget == NULL || pWidget->rect().contains(widget->rect()))
02089         return;
02090     // create the containment AssocWidget
02091     AssociationWidget *a = new AssociationWidget(this, pWidget, at_Containment, widget);
02092     a->calculateEndingPoints();
02093     a->setActivated(true);
02094     if (! addAssociation(a))
02095         delete a;
02096 }
02097 
02098 void UMLView::createAutoAttributeAssociations(UMLWidget *widget) {
02099     if (widget == NULL || m_Type != Uml::dt_Class)
02100         return;
02101 
02102     // Pseudocode:
02103     //   if the underlying model object is really a UMLClassifier then
02104     //     for each of the UMLClassifier's UMLAttributes
02105     //       if the attribute type has a widget representation on this view then
02106     //         if the AssocWidget does not already exist then
02107     //           if the current diagram type permits compositions then
02108     //             create a composition AssocWidget
02109     //           end if
02110     //         end if
02111     //       end if
02112     //       if the attribute type is a Datatype then
02113     //         if the Datatype is a reference (pointer) type then
02114     //           if the referenced type has a widget representation on this view then
02115     //             if the AssocWidget does not already exist then
02116     //               if the current diagram type permits aggregations then
02117     //                 create an aggregation AssocWidget from the ClassifierWidget to the
02118     //                                                 widget of the referenced type
02119     //               end if
02120     //             end if
02121     //           end if
02122     //         end if
02123     //       end if
02124     //     end loop
02125     //   end if
02126     //
02127     // Implementation:
02128     UMLObject *tmpUmlObj = widget->getUMLObject();
02129     if (tmpUmlObj == NULL)
02130         return;
02131     // if the underlying model object is really a UMLClassifier then
02132     if (tmpUmlObj->getBaseType() == Uml::ot_Datatype) {
02133         UMLClassifier *dt = static_cast<UMLClassifier*>(tmpUmlObj);
02134         while (dt->originType() != NULL) {
02135             tmpUmlObj = dt->originType();
02136             if (tmpUmlObj->getBaseType() != Uml::ot_Datatype)
02137                 break;
02138             dt = static_cast<UMLClassifier*>(tmpUmlObj);
02139         }
02140     }
02141     if (tmpUmlObj->getBaseType() != Uml::ot_Class)
02142         return;
02143     UMLClassifier * klass = static_cast<UMLClassifier*>(tmpUmlObj);
02144     // for each of the UMLClassifier's UMLAttributes
02145     UMLAttributeList attrList = klass->getAttributeList();
02146     for (UMLAttributeListIt ait(attrList); ait.current(); ++ait) {
02147         UMLAttribute *attr = ait.current();
02148         createAutoAttributeAssociation(attr->getType(), attr, widget);
02149         /*
02150          * The following code from attachment 19935 of http://bugs.kde.org/140669
02151          * creates Aggregation/Composition to the template parameters.
02152          * The current solution uses Dependency instead, see handling of template
02153          * instantiation at Import_Utils::createUMLObject().
02154         UMLClassifierList templateList = attr->getTemplateParams();
02155         for (UMLClassifierListIt it(templateList); it.current(); ++it) {
02156             createAutoAttributeAssociation(it,attr,widget);
02157         }
02158          */
02159     }
02160 }
02161 
02162 void UMLView::createAutoAttributeAssociation(UMLClassifier *type, UMLAttribute *attr,
02163                                              UMLWidget *widget /*, UMLClassifier * klass*/) {
02164     if (type == NULL) {
02165         // kDebug() << "UMLView::createAutoAttributeAssociations("
02166         //     << klass->getName() << "): type is NULL for "
02167         //     << "attribute " << attr->getName() << endl;
02168         return;
02169     }
02170     Uml::Association_Type assocType = Uml::at_Composition;
02171     UMLWidget *w = findWidget( type->getID() );
02172     AssociationWidget *aw = NULL;
02173     // if the attribute type has a widget representation on this view
02174     if (w) {
02175         aw = findAssocWidget(widget, w, attr->getName());
02176         if ( aw == NULL &&
02177                // if the current diagram type permits compositions
02178                AssocRules::allowAssociation(assocType, widget, w, false) ) {
02179             // Create a composition AssocWidget, or, if the attribute type is
02180             // stereotyped <<CORBAInterface>>, create a UniAssociation widget.
02181             if (type->getStereotype() == "CORBAInterface")
02182                 assocType = at_UniAssociation;
02183             AssociationWidget *a = new AssociationWidget (this, widget, assocType, w);
02184             a->setUMLObject(attr);
02185             a->calculateEndingPoints();
02186             a->setVisibility(attr->getVisibility(), B);
02187             /*
02188             if (assocType == at_Aggregation || assocType == at_UniAssociation)
02189             a->setMulti("0..1", B);
02190             */
02191             a->setRoleName(attr->getName(), B);
02192             a->setActivated(true);
02193             if (! addAssociation(a))
02194                 delete a;
02195         }
02196     }
02197     // if the attribute type is a Datatype then
02198     if (type->getBaseType() == ot_Datatype) {
02199         UMLClassifier *dt = static_cast<UMLClassifier*>(type);
02200         // if the Datatype is a reference (pointer) type
02201         if (dt->isReference()) {
02202             //Uml::Association_Type assocType = Uml::at_Composition;
02203             UMLClassifier *c = dt->originType();
02204             UMLWidget *w = c ? findWidget( c->getID() ) : 0;
02205             // if the referenced type has a widget representation on this view
02206             if (w) {
02207                 aw = findAssocWidget(widget, w, attr->getName());
02208                 if (aw == NULL &&
02209                     // if the current diagram type permits aggregations
02210                     AssocRules::allowAssociation(at_Aggregation, widget, w, false)) {
02211                     // create an aggregation AssocWidget from the ClassifierWidget
02212                     // to the widget of the referenced type
02213                     AssociationWidget *a = new AssociationWidget
02214                             (this, widget, at_Aggregation, w);
02215                     a->setUMLObject(attr);
02216                     a->calculateEndingPoints();
02217                     a->setVisibility(attr->getVisibility(), B);
02218                     //a->setChangeability(true, B);
02219                     a->setMulti("0..1", B);
02220                     a->setRoleName(attr->getName(), B);
02221                     a->setActivated(true);
02222                     if (! addAssociation(a))
02223                         delete a;
02224                 }
02225             }
02226         }
02227     }
02228 }
02229 
02230 void UMLView::findMaxBoundingRectangle(const FloatingTextWidget* ft, int& px, int& py, int& qx, int& qy)
02231 {
02232     if (ft == NULL || !ft->isVisible())
02233         return;
02234 
02235     int x = ft -> getX();
02236     int y = ft -> getY();
02237     int x1 = x + ft -> getWidth() - 1;
02238     int y1 = y + ft -> getHeight() - 1;
02239 
02240     if (px == -1 || x < px)
02241         px = x;
02242     if (py == -1 || y < py)
02243         py = y;
02244     if (qx == -1 || x1 > qx)
02245         qx = x1;
02246     if (qy == -1 || y1 > qy)
02247         qy = y1;
02248 }
02249 
02250 void UMLView::copyAsImage(QPixmap*& pix) {
02251     //get the smallest rect holding the diagram
02252     QRect rect = getDiagramRect();
02253     QPixmap diagram( rect.width(), rect.height() );
02254 
02255     //only draw what is selected
02256     m_bDrawSelectedOnly = true;
02257     selectAssociations(true);
02258     getDiagram(rect, diagram);
02259 
02260     //now get the selection cut
02261     int px = -1, py = -1, qx = -1, qy = -1;
02262 
02263     //first get the smallest rect holding the widgets
02264     for (UMLWidget* temp = m_SelectedList.first(); temp; temp = m_SelectedList.next()) {
02265         int x = temp -> getX();
02266         int y = temp -> getY();
02267         int x1 = x + temp -> width() - 1;
02268         int y1 = y + temp -> height() - 1;
02269         if(px == -1 || x < px) {
02270             px = x;
02271         }
02272         if(py == -1 || y < py) {
02273             py = y;
02274         }
02275         if(qx == -1 || x1 > qx) {
02276             qx = x1;
02277         }
02278         if(qy == -1 || y1 > qy) {
02279             qy = y1;
02280         }
02281     }
02282 
02283     //also take into account any text lines in assocs or messages
02284     AssociationWidget *a;
02285     AssociationWidgetListIt assoc_it(m_AssociationList);
02286 
02287     //get each type of associations
02288     //This needs to be reimplemented to increase the rectangle
02289     //if a part of any association is not included
02290     while ((a = assoc_it.current()) != NULL) {
02291         ++assoc_it;
02292         if (! a->getSelected())
02293             continue;
02294         const FloatingTextWidget* multiA = const_cast<FloatingTextWidget*>(a->getMultiWidget(A));
02295         const FloatingTextWidget* multiB = const_cast<FloatingTextWidget*>(a->getMultiWidget(B));
02296         const FloatingTextWidget* roleA = const_cast<FloatingTextWidget*>(a->getRoleWidget(A));
02297         const FloatingTextWidget* roleB = const_cast<FloatingTextWidget*>(a->getRoleWidget(B));
02298         const FloatingTextWidget* changeA = const_cast<FloatingTextWidget*>(a->getChangeWidget(A));
02299         const FloatingTextWidget* changeB = const_cast<FloatingTextWidget*>(a->getChangeWidget(B));
02300         findMaxBoundingRectangle(multiA, px, py, qx, qy);
02301         findMaxBoundingRectangle(multiB, px, py, qx, qy);
02302         findMaxBoundingRectangle(roleA, px, py, qx, qy);
02303         findMaxBoundingRectangle(roleB, px, py, qx, qy);
02304         findMaxBoundingRectangle(changeA, px, py, qx, qy);
02305         findMaxBoundingRectangle(changeB, px, py, qx, qy);
02306     }//end while
02307 
02308     QRect imageRect;  //area with respect to getDiagramRect()
02309     //i.e. all widgets on the canvas.  Was previously with
02310     //respect to whole canvas
02311 
02312     imageRect.setLeft( px - rect.left() );
02313     imageRect.setTop( py - rect.top() );
02314     imageRect.setRight( qx - rect.left() );
02315     imageRect.setBottom( qy - rect.top() );
02316 
02317     pix = new QPixmap(imageRect.width(), imageRect.height());
02318     bitBlt(pix, QPoint(0, 0), &diagram, imageRect);
02319     m_bDrawSelectedOnly = false;
02320 }
02321 
02322 void UMLView::setMenu() {
02323     slotRemovePopupMenu();
02324     ListPopupMenu::Menu_Type menu = ListPopupMenu::mt_Undefined;
02325     switch( getType() ) {
02326     case dt_Class:
02327         menu = ListPopupMenu::mt_On_Class_Diagram;
02328         break;
02329 
02330     case dt_UseCase:
02331         menu = ListPopupMenu::mt_On_UseCase_Diagram;
02332         break;
02333 
02334     case dt_Sequence:
02335         menu = ListPopupMenu::mt_On_Sequence_Diagram;
02336         break;
02337 
02338     case dt_Collaboration:
02339         menu = ListPopupMenu::mt_On_Collaboration_Diagram;
02340         break;
02341 
02342     case dt_State:
02343         menu = ListPopupMenu::mt_On_State_Diagram;
02344         break;
02345 
02346     case dt_Activity:
02347         menu = ListPopupMenu::mt_On_Activity_Diagram;
02348         break;
02349 
02350     case dt_Component:
02351         menu = ListPopupMenu::mt_On_Component_Diagram;
02352         break;
02353 
02354     case dt_Deployment:
02355         menu = ListPopupMenu::mt_On_Deployment_Diagram;
02356         break;
02357 
02358     case dt_EntityRelationship:
02359         menu = ListPopupMenu::mt_On_EntityRelationship_Diagram;
02360         break;
02361 
02362     default:
02363         kWarning() << "setMenu() called on unknown diagram type" << endl;
02364         menu = ListPopupMenu::mt_Undefined;
02365         break;
02366     }//end switch
02367     if( menu != ListPopupMenu::mt_Undefined ) {
02368         m_pMenu = new ListPopupMenu(this, menu, this);
02369         connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
02370         m_pMenu->popup( mapToGlobal( contentsToViewport(worldMatrix().map(m_Pos)) ) );
02371     }
02372 }
02373 
02374 void UMLView::slotRemovePopupMenu() {
02375     if(m_pMenu) {
02376         disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
02377         delete m_pMenu;
02378         m_pMenu = 0;
02379     }
02380 }
02381 
02382 void UMLView::slotMenuSelection(int sel) {
02383     switch( (ListPopupMenu::Menu_Type)sel ) {
02384     case ListPopupMenu::mt_Undo:
02385         m_pDoc->loadUndoData();
02386         break;
02387 
02388     case ListPopupMenu::mt_Redo:
02389         m_pDoc->loadRedoData();
02390         break;
02391 
02392     case ListPopupMenu::mt_Clear:
02393         clearDiagram();
02394         break;
02395 
02396     case ListPopupMenu::mt_Export_Image:
02397         m_pImageExporter->exportView();
02398         break;
02399 
02400     case ListPopupMenu::mt_FloatText:
02401         {
02402             FloatingTextWidget* ft = new FloatingTextWidget(this);
02403             ft->changeTextDlg();
02404             //if no text entered delete
02405             if(!FloatingTextWidget::isTextValid(ft->getText())) {
02406                 delete ft;
02407             } else {
02408                 ft->setID(UniqueID::gen());
02409                 setupNewWidget(ft);
02410             }
02411         }
02412         break;
02413 
02414     case ListPopupMenu::mt_UseCase:
02415         m_bCreateObject = true;
02416         Object_Factory::createUMLObject( ot_UseCase );
02417         break;
02418 
02419     case ListPopupMenu::mt_Actor:
02420         m_bCreateObject = true;
02421         Object_Factory::createUMLObject( ot_Actor );
02422         break;
02423 
02424     case ListPopupMenu::mt_Class:
02425     case ListPopupMenu::mt_Object:
02426         m_bCreateObject = true;
02427         Object_Factory::createUMLObject( ot_Class);
02428         break;
02429 
02430     case ListPopupMenu::mt_Package:
02431         m_bCreateObject = true;
02432         Object_Factory::createUMLObject(ot_Package);
02433         break;
02434 
02435     case ListPopupMenu::mt_Component:
02436         m_bCreateObject = true;
02437         Object_Factory::createUMLObject(ot_Component);
02438         break;
02439 
02440     case ListPopupMenu::mt_Node:
02441         m_bCreateObject = true;
02442         Object_Factory::createUMLObject(ot_Node);
02443         break;
02444 
02445     case ListPopupMenu::mt_Artifact:
02446         m_bCreateObject = true;
02447         Object_Factory::createUMLObject(ot_Artifact);
02448         break;
02449 
02450     case ListPopupMenu::mt_Interface:
02451         m_bCreateObject = true;
02452         Object_Factory::createUMLObject(ot_Interface);
02453         break;
02454 
02455     case ListPopupMenu::mt_Enum:
02456         m_bCreateObject = true;
02457         Object_Factory::createUMLObject(ot_Enum);
02458         break;
02459 
02460     case ListPopupMenu::mt_Entity:
02461         m_bCreateObject = true;
02462         Object_Factory::createUMLObject(ot_Entity);
02463         break;
02464 
02465     case ListPopupMenu::mt_Datatype:
02466         m_bCreateObject = true;
02467         Object_Factory::createUMLObject(ot_Datatype);
02468         break;
02469 
02470     case ListPopupMenu::mt_Cut:
02471         //FIXME make this work for diagram's right click menu
02472         if ( m_SelectedList.count() &&
02473                 UMLApp::app()->editCutCopy(true) ) {
02474             deleteSelection();
02475             m_pDoc->setModified(true);
02476         }
02477         break;
02478 
02479     case ListPopupMenu::mt_Copy:
02480         //FIXME make this work for diagram's right click menu
02481         m_SelectedList.count() && UMLApp::app()->editCutCopy(true);
02482         break;
02483 
02484     case ListPopupMenu::mt_Paste:
02485         m_PastePoint = m_Pos;
02486         m_Pos.setX( 2000 );
02487         m_Pos.setY( 2000 );
02488         UMLApp::app()->slotEditPaste();
02489 
02490         m_PastePoint.setX( 0 );
02491         m_PastePoint.setY( 0 );
02492         break;
02493 
02494     case ListPopupMenu::mt_Initial_State:
02495         {
02496             StateWidget* state = new StateWidget( this, StateWidget::Initial );
02497             setupNewWidget( state );
02498         }
02499         break;
02500 
02501     case ListPopupMenu::mt_End_State:
02502         {
02503             StateWidget* state = new StateWidget( this, StateWidget::End );
02504             setupNewWidget( state );
02505         }
02506         break;
02507 
02508     case ListPopupMenu::mt_State:
02509         {
02510             bool ok = false;
02511             QString name = KInputDialog::getText( i18n("Enter State Name"),
02512                                                   i18n("Enter the name of the new state:"),
02513                                                   i18n("new state"), &ok, UMLApp::app() );
02514             if ( ok ) {
02515                 StateWidget* state = new StateWidget( this );
02516                 state->setName( name );
02517                 setupNewWidget( state );
02518             }
02519         }
02520         break;
02521 
02522     case ListPopupMenu::mt_Initial_Activity:
02523         {
02524             ActivityWidget* activity = new ActivityWidget( this, ActivityWidget::Initial );
02525             setupNewWidget(activity);
02526         }
02527         break;
02528 
02529 
02530     case ListPopupMenu::mt_End_Activity:
02531         {
02532             ActivityWidget* activity = new ActivityWidget( this, ActivityWidget::End );
02533             setupNewWidget(activity);
02534         }
02535         break;
02536 
02537     case ListPopupMenu::mt_Branch:
02538         {
02539             ActivityWidget* activity = new ActivityWidget( this, ActivityWidget::Branch );
02540             setupNewWidget(activity);
02541         }
02542         break;
02543 
02544     case ListPopupMenu::mt_Activity:
02545         {
02546             bool ok = false;
02547             QString name = KInputDialog::getText( i18n("Enter Activity Name"),
02548                                                   i18n("Enter the name of the new activity:"),
02549                                                   i18n("new activity"), &ok, UMLApp::app() );
02550             if ( ok ) {
02551                 ActivityWidget* activity = new ActivityWidget( this, ActivityWidget::Normal );
02552                 activity->setName( name );
02553                 setupNewWidget(activity);
02554             }
02555         }
02556         break;
02557 
02558     case ListPopupMenu::mt_SnapToGrid:
02559         toggleSnapToGrid();
02560         m_pDoc->setModified();
02561         break;
02562 
02563     case ListPopupMenu::mt_ShowSnapGrid:
02564         toggleShowGrid();
02565         m_pDoc->setModified();
02566         break;
02567 
02568     case ListPopupMenu::mt_Properties:
02569         if (showPropDialog() == true)
02570             m_pDoc->setModified();
02571         break;
02572 
02573     case ListPopupMenu::mt_Delete:
02574         m_pDoc->removeDiagram( getID() );
02575         break;
02576 
02577     case ListPopupMenu::mt_Rename:
02578         {
02579             bool ok = false;
02580             QString name = KInputDialog::getText( i18n("Enter Diagram Name"),
02581                                                   i18n("Enter the new name of the diagram:"),
02582                                                   getName(), &ok, UMLApp::app() );
02583             if (ok) {
02584                 setName(name);
02585                 m_pDoc->signalDiagramRenamed(this);
02586             }
02587         }
02588         break;
02589 
02590     default:
02591         break;
02592     }
02593 }
02594 
02595 void UMLView::slotCutSuccessful() {
02596     if( m_bStartedCut ) {
02597         deleteSelection();
02598         m_bStartedCut = false;
02599     }
02600 }
02601 
02602 void UMLView::slotShowView() {
02603     m_pDoc -> changeCurrentView( getID() );
02604 }
02605 
02606 QPoint UMLView::getPastePoint() {
02607     QPoint point = m_PastePoint;
02608     point.setX( point.x() - m_Pos.x() );
02609     point.setY( point.y() - m_Pos.y() );
02610     return point;
02611 }
02612 
02613 void UMLView::resetPastePoint() {
02614     m_PastePoint = m_Pos;
02615 }
02616 
02617 int UMLView::snappedX (int x) {
02618     if (getSnapToGrid()) {
02619         int gridX = getSnapX();
02620         int modX = x % gridX;
02621         x -= modX;
02622         if (modX >= gridX / 2)
02623             x += gridX;
02624     }
02625     return x;
02626 }
02627 
02628 int UMLView::snappedY (int y) {
02629     if (getSnapToGrid()) {
02630         int gridY = getSnapY();
02631         int modY = y % gridY;
02632         y -= modY;
02633         if (modY >= gridY / 2)
02634             y += gridY;
02635     }
02636     return y;
02637 }
02638 
02639 bool UMLView::showPropDialog() {
02640     UMLViewDialog dlg( this, this );
02641     if( dlg.exec() ) {
02642         return true;
02643     }
02644     return false;
02645 }
02646 
02647 
02648 QFont UMLView::getFont() const {
02649     return m_Options.uiState.font;
02650 }
02651 
02652 void UMLView::setFont(QFont font, bool changeAllWidgets /* = false */) {
02653     m_Options.uiState.font = font;
02654     if (!changeAllWidgets)
02655         return;
02656     for (UMLWidgetListIt wit(m_WidgetList); wit.current(); ++wit) {
02657         UMLWidget *w = wit.current();
02658         w->setFont(font);
02659     }
02660 }
02661 
02662 void UMLView::setClassWidgetOptions( ClassOptionsPage * page ) {
02663     UMLWidget * pWidget = 0;
02664     UMLWidgetListIt wit( m_WidgetList );
02665     while ( (pWidget = wit.current()) != 0 ) {
02666         ++wit;
02667         Uml::Widget_Type wt = pWidget->getBaseType();
02668         if (wt == Uml::wt_Class || wt == Uml::wt_Interface) {
02669             page -> setWidget( static_cast<ClassifierWidget *>(pWidget) );
02670             page -> updateUMLWidget();
02671         }
02672     }
02673 }
02674 
02675 
02676 void UMLView::checkSelections() {
02677     UMLWidget * pWA = 0, * pWB = 0, * pTemp = 0;
02678     //check messages
02679     for(pTemp=(UMLWidget *)m_SelectedList.first();pTemp;pTemp=(UMLWidget *)m_SelectedList.next()) {
02680         if( pTemp->getBaseType() == wt_Message && pTemp -> getSelected() ) {
02681             MessageWidget * pMessage = static_cast<MessageWidget *>( pTemp );
02682             pWA = pMessage -> getWidget(A);
02683             pWB = pMessage -> getWidget(B);
02684             if( !pWA -> getSelected() ) {
02685                 pWA -> setSelectedFlag( true );
02686                 m_SelectedList.append( pWA );
02687             }
02688             if( !pWB -> getSelected() ) {
02689                 pWB -> setSelectedFlag( true );
02690                 m_SelectedList.append( pWB );
02691             }
02692         }//end if
02693     }//end for
02694     //check Associations
02695     AssociationWidgetListIt it(m_AssociationList);
02696     AssociationWidget * pAssoc = 0;
02697     while((pAssoc = it.current())) {
02698         ++it;
02699         if( pAssoc -> getSelected() ) {
02700             pWA = pAssoc -> getWidget(A);
02701             pWB = pAssoc -> getWidget(B);
02702             if( !pWA -> getSelected() ) {
02703                 pWA -> setSelectedFlag( true );
02704                 m_SelectedList.append( pWA );
02705             }
02706             if( !pWB -> getSelected() ) {
02707                 pWB -> setSelectedFlag( true );
02708                 m_SelectedList.append( pWB );
02709             }
02710         }//end if
02711     }//end while
02712 }
02713 
02714 bool UMLView::checkUniqueSelection()
02715 {
02716     // if there are no selected items, we return true
02717     if (m_SelectedList.count() <= 0)
02718         return true;
02719 
02720     // get the first item and its base type
02721     UMLWidget * pTemp = (UMLWidget *) m_SelectedList.first();
02722     Widget_Type tmpType = pTemp -> getBaseType();
02723 
02724     // check all selected items, if they have the same BaseType
02725     for ( pTemp = (UMLWidget *) m_SelectedList.first();
02726             pTemp;
02727             pTemp = (UMLWidget *) m_SelectedList.next() ) {
02728         if( pTemp->getBaseType() != tmpType)
02729         {
02730             return false; // the base types are different, the list is not unique
02731         }
02732     } // for ( through all selected items )
02733 
02734     return true; // selected items are unique
02735 }
02736 
02737 void UMLView::clearDiagram() {
02738     if( KMessageBox::Continue == KMessageBox::warningContinueCancel( this, i18n("You are about to delete "
02739             "the entire diagram.\nAre you sure?"),
02740             i18n("Delete Diagram?"),KGuiItem( i18n("&Delete"), "editdelete") ) ) {
02741         removeAllWidgets();
02742     }
02743 }
02744 
02745 void UMLView::toggleSnapToGrid() {
02746     setSnapToGrid( !getSnapToGrid() );
02747 }
02748 
02749 void UMLView::toggleSnapComponentSizeToGrid() {
02750     setSnapComponentSizeToGrid( !getSnapComponentSizeToGrid() );
02751 }
02752 
02753 void UMLView::toggleShowGrid() {
02754     setShowSnapGrid( !getShowSnapGrid() );
02755 }
02756 
02757 void UMLView::setSnapToGrid(bool bSnap) {
02758     m_bUseSnapToGrid = bSnap;
02759     emit sigSnapToGridToggled( getSnapToGrid() );
02760 }
02761 
02762 void UMLView::setSnapComponentSizeToGrid(bool bSnap) {
02763     m_bUseSnapComponentSizeToGrid = bSnap;
02764     updateComponentSizes();
02765     emit sigSnapComponentSizeToGridToggled( getSnapComponentSizeToGrid() );
02766 }
02767 
02768 bool UMLView::getShowSnapGrid() const {
02769     return m_bShowSnapGrid;
02770 }
02771 
02772 void UMLView::setShowSnapGrid(bool bShow) {
02773     m_bShowSnapGrid = bShow;
02774     canvas()->setAllChanged();
02775     emit sigShowGridToggled( getShowSnapGrid() );
02776 }
02777 
02778 bool UMLView::getShowOpSig() const {
02779     return m_Options.classState.showOpSig;
02780 }
02781 
02782 void UMLView::setShowOpSig(bool bShowOpSig) {
02783     m_Options.classState.showOpSig = bShowOpSig;
02784 }
02785 
02786 void UMLView::setZoom(int zoom) {
02787     if (zoom < 10) {
02788         zoom = 10;
02789     } else if (zoom > 500) {
02790         zoom = 500;
02791     }
02792 
02793     QWMatrix wm;
02794     wm.scale(zoom/100.0,zoom/100.0);
02795     setWorldMatrix(wm);
02796 
02797     m_nZoom = currentZoom();
02798     resizeCanvasToItems();
02799 }
02800 
02801 int UMLView::currentZoom() {
02802     return (int)(worldMatrix().m11()*100.0);
02803 }
02804 
02805 void UMLView::zoomIn() {
02806     QWMatrix wm = worldMatrix();
02807     wm.scale(1.5,1.5); // adjust zooming step here
02808     setZoom( (int)(wm.m11()*100.0) );
02809 }
02810 
02811 void UMLView::zoomOut() {
02812     QWMatrix wm = worldMatrix();
02813     wm.scale(2.0/3.0, 2.0/3.0); //adjust zooming step here
02814     setZoom( (int)(wm.m11()*100.0) );
02815 }
02816 
02817 void UMLView::fileLoaded() {
02818     setZoom( getZoom() );
02819     resizeCanvasToItems();
02820 }
02821 
02822 void UMLView::setCanvasSize(int width, int height) {
02823     setCanvasWidth(width);
02824     setCanvasHeight(height);
02825     canvas()->resize(width, height);
02826 }
02827 
02828 void UMLView::resizeCanvasToItems() {
02829     QRect canvasSize = getDiagramRect();
02830     int canvasWidth = canvasSize.right() + 5;
02831     int canvasHeight = canvasSize.bottom() + 5;
02832 
02833     //Find out the bottom right visible pixel and size to at least that
02834     int contentsX, contentsY;
02835     int contentsWMX, contentsWMY;
02836     viewportToContents(viewport()->width(), viewport()->height(), contentsX, contentsY);
02837     inverseWorldMatrix().map(contentsX, contentsY, &contentsWMX, &contentsWMY);
02838 
02839     if (canvasWidth < contentsWMX) {
02840         canvasWidth = contentsWMX;
02841     }
02842 
02843     if (canvasHeight < contentsWMY) {
02844         canvasHeight = contentsWMY;
02845     }
02846 
02847     setCanvasSize(canvasWidth, canvasHeight);
02848 }
02849 
02850 void UMLView::show() {
02851     QWidget::show();
02852     resizeCanvasToItems();
02853 }
02854 
02855 void UMLView::updateComponentSizes() {
02856     // update sizes of all components
02857     UMLWidgetListIt it( m_WidgetList );
02858     UMLWidget *obj;
02859     while ( (obj=(UMLWidget*)it.current()) != 0 ) {
02860         ++it;
02861         obj->updateComponentSize();
02862     }
02863 }
02864 
02874 void UMLView::forceUpdateWidgetFontMetrics(QPainter * painter) {
02875     UMLWidgetListIt it( m_WidgetList );
02876     UMLWidget *obj;
02877 
02878     while ((obj = it.current()) != 0 ) {
02879         ++it;
02880         obj->forceUpdateFontMetrics(painter);
02881     }
02882 }
02883 
02884 void UMLView::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
02885     QDomElement viewElement = qDoc.createElement( "diagram" );
02886     viewElement.setAttribute( "xmi.id", ID2STR(m_nID) );
02887     viewElement.setAttribute( "name", getName() );
02888     viewElement.setAttribute( "type", m_Type );
02889     viewElement.setAttribute( "documentation", m_Documentation );
02890     //optionstate uistate
02891     viewElement.setAttribute( "fillcolor", m_Options.uiState.fillColor.name() );
02892     viewElement.setAttribute( "linecolor", m_Options.uiState.lineColor.name() );
02893     viewElement.setAttribute( "linewidth", m_Options.uiState.lineWidth );
02894     viewElement.setAttribute( "usefillcolor", m_Options.uiState.useFillColor );
02895     viewElement.setAttribute( "font", m_Options.uiState.font.toString() );
02896     //optionstate classstate
02897     viewElement.setAttribute( "showattsig", m_Options.classState.showAttSig );
02898     viewElement.setAttribute( "showatts", m_Options.classState.showAtts);
02899     viewElement.setAttribute( "showopsig", m_Options.classState.showOpSig );
02900     viewElement.setAttribute( "showops", m_Options.classState.showOps );
02901     viewElement.setAttribute( "showpackage", m_Options.classState.showPackage );
02902     viewElement.setAttribute( "showscope", m_Options.classState.showVisibility );
02903     viewElement.setAttribute( "showstereotype", m_Options.classState.showStereoType );
02904     //misc
02905     viewElement.setAttribute( "localid", ID2STR(m_nLocalID) );
02906     viewElement.setAttribute( "showgrid", m_bShowSnapGrid );
02907     viewElement.setAttribute( "snapgrid", m_bUseSnapToGrid );
02908     viewElement.setAttribute( "snapcsgrid", m_bUseSnapComponentSizeToGrid );
02909     viewElement.setAttribute( "snapx", m_nSnapX );
02910     viewElement.setAttribute( "snapy", m_nSnapY );
02911     viewElement.setAttribute( "zoom", m_nZoom );
02912     viewElement.setAttribute( "canvasheight", m_nCanvasHeight );
02913     viewElement.setAttribute( "canvaswidth", m_nCanvasWidth );
02914     //now save all the widgets
02915     UMLWidget * widget = 0;
02916     UMLWidgetListIt w_it( m_WidgetList );
02917     QDomElement widgetElement = qDoc.createElement( "widgets" );
02918     while( ( widget = w_it.current() ) ) {
02919         ++w_it;
02920         // Having an exception is bad I know, but gotta work with
02921         // system we are given.
02922         // We DONT want to record any text widgets which are belonging
02923         // to associations as they are recorded later in the "associations"
02924         // section when each owning association is dumped. -b.t.
02925         if (widget->getBaseType() != wt_Text ||
02926                 static_cast<FloatingTextWidget*>(widget)->getLink() == NULL)
02927             widget->saveToXMI( qDoc, widgetElement );
02928     }
02929     viewElement.appendChild( widgetElement );
02930     //now save the message widgets
02931     MessageWidgetListIt m_it( m_MessageList );
02932     QDomElement messageElement = qDoc.createElement( "messages" );
02933     while( ( widget = m_it.current() ) ) {
02934         ++m_it;
02935         widget -> saveToXMI( qDoc, messageElement );
02936     }
02937     viewElement.appendChild( messageElement );
02938     //now save the associations
02939     QDomElement assocElement = qDoc.createElement( "associations" );
02940     if ( m_AssociationList.count() ) {
02941         // We guard against ( m_AssociationList.count() == 0 ) because
02942         // this code could be reached as follows:
02943         //  ^  UMLView::saveToXMI()
02944         //  ^  UMLDoc::saveToXMI()
02945         //  ^  UMLDoc::addToUndoStack()
02946         //  ^  UMLDoc::setModified()
02947         //  ^  UMLDoc::createDiagram()
02948         //  ^  UMLDoc::newDocument()
02949         //  ^  UMLApp::newDocument()
02950         //  ^  main()
02951         //
02952         AssociationWidgetListIt a_it( m_AssociationList );
02953         AssociationWidget * assoc = 0;
02954         while( ( assoc = a_it.current() ) ) {
02955             ++a_it;
02956             assoc -> saveToXMI( qDoc, assocElement );
02957         }
02958         // kDebug() << "UMLView::saveToXMI() saved "
02959         //   << m_AssociationList.count() << " assocData." << endl;
02960     }
02961     viewElement.appendChild( assocElement );
02962     qElement.appendChild( viewElement );
02963 }
02964 
02965 bool UMLView::loadFromXMI( QDomElement & qElement ) {
02966     QString id = qElement.attribute( "xmi.id", "-1" );
02967     m_nID = STR2ID(id);
02968     if( m_nID == Uml::id_None )
02969         return false;
02970     setName( qElement.attribute( "name", "" ) );
02971     QString type = qElement.attribute( "type", "0" );
02972     m_Documentation = qElement.attribute( "documentation", "" );
02973     QString localid = qElement.attribute( "localid", "0" );
02974     //optionstate uistate
02975     QString font = qElement.attribute( "font", "" );
02976     if (!font.isEmpty()) {
02977         m_Options.uiState.font.fromString( font );
02978         m_Options.uiState.font.setUnderline(false);
02979     }
02980     QString fillcolor = qElement.attribute( "fillcolor", "" );
02981     QString linecolor = qElement.attribute( "linecolor", "" );
02982     QString linewidth = qElement.attribute( "linewidth", "" );
02983     QString usefillcolor = qElement.attribute( "usefillcolor", "0" );
02984     m_Options.uiState.useFillColor = (bool)usefillcolor.toInt();
02985     //optionstate classstate
02986     QString temp = qElement.attribute( "showattsig", "0" );
02987     m_Options.classState.showAttSig = (bool)temp.toInt();
02988     temp = qElement.attribute( "showatts", "0" );
02989     m_Options.classState.showAtts = (bool)temp.toInt();
02990     temp = qElement.attribute( "showopsig", "0" );
02991     m_Options.classState.showOpSig = (bool)temp.toInt();
02992     temp = qElement.attribute( "showops", "0" );
02993     m_Options.classState.showOps = (bool)temp.toInt();
02994     temp = qElement.attribute( "showpackage", "0" );
02995     m_Options.classState.showPackage = (bool)temp.toInt();
02996     temp = qElement.attribute( "showscope", "0" );
02997     m_Options.classState.showVisibility = (bool)temp.toInt();
02998     temp = qElement.attribute( "showstereotype", "0" );
02999     m_Options.classState.showStereoType = (bool)temp.toInt();
03000     //misc
03001     QString showgrid = qElement.attribute( "showgrid", "0" );
03002     m_bShowSnapGrid = (bool)showgrid.toInt();
03003 
03004     QString snapgrid = qElement.attribute( "snapgrid", "0" );
03005     m_bUseSnapToGrid = (bool)snapgrid.toInt();
03006 
03007     QString snapcsgrid = qElement.attribute( "snapcsgrid", "0" );
03008     m_bUseSnapComponentSizeToGrid = (bool)snapcsgrid.toInt();
03009 
03010     QString snapx = qElement.attribute( "snapx", "10" );
03011     m_nSnapX = snapx.toInt();
03012 
03013     QString snapy = qElement.attribute( "snapy", "10" );
03014     m_nSnapY = snapy.toInt();
03015 
03016     QString zoom = qElement.attribute( "zoom", "100" );
03017     m_nZoom = zoom.toInt();
03018 
03019     QString height = qElement.attribute( "canvasheight", QString("%1").arg(UMLView::defaultCanvasSize) );
03020     m_nCanvasHeight = height.toInt();
03021 
03022     QString width = qElement.attribute( "canvaswidth", QString("%1").arg(UMLView::defaultCanvasSize) );
03023     m_nCanvasWidth = width.toInt();
03024 
03025     int nType = type.toInt();
03026     if (nType == -1 || nType >= 400) {
03027         // Pre 1.5.5 numeric values
03028         // Values of "type" were changed in 1.5.5 to merge with Settings::Diagram
03029         switch (nType) {
03030             case 400:
03031                 m_Type = Uml::dt_UseCase;
03032                 break;
03033             case 401:
03034                 m_Type = Uml::dt_Collaboration;
03035                 break;
03036             case 402:
03037                 m_Type = Uml::dt_Class;
03038                 break;
03039             case 403:
03040                 m_Type = Uml::dt_Sequence;
03041                 break;
03042             case 404:
03043                 m_Type = Uml::dt_State;
03044                 break;
03045             case 405:
03046                 m_Type = Uml::dt_Activity;
03047                 break;
03048             case 406:
03049                 m_Type = Uml::dt_Component;
03050                 break;
03051             case 407:
03052                 m_Type = Uml::dt_Deployment;
03053                 break;
03054             case 408:
03055                 m_Type = Uml::dt_EntityRelationship;
03056                 break;
03057             default:
03058                 m_Type = Uml::dt_Undefined;
03059                 break;
03060         }
03061     } else {
03062         m_Type = (Uml::Diagram_Type)nType;
03063     }
03064     if( !fillcolor.isEmpty() )
03065         m_Options.uiState.fillColor = QColor( fillcolor );
03066     if( !linecolor.isEmpty() )
03067         m_Options.uiState.lineColor = QColor( linecolor );
03068     if( !linewidth.isEmpty() )
03069         m_Options.uiState.lineWidth = linewidth.toInt();
03070     m_nLocalID = STR2ID(localid);
03071 
03072     QDomNode node = qElement.firstChild();
03073     bool widgetsLoaded = false, messagesLoaded = false, associationsLoaded = false;
03074     while (!node.isNull()) {
03075         QDomElement element = node.toElement();
03076         if (!element.isNull()) {
03077             if (element.tagName() == "widgets")
03078                 widgetsLoaded = loadWidgetsFromXMI( element );
03079             else if (element.tagName() == "messages")
03080                 messagesLoaded = loadMessagesFromXMI( element );
03081             else if (element.tagName() == "associations")
03082                 associationsLoaded = loadAssociationsFromXMI( element );
03083         }
03084         node = node.nextSibling();
03085     }
03086 
03087     if (!widgetsLoaded) {
03088         kWarning() << "failed umlview load on widgets" << endl;
03089         return false;
03090     }
03091     if (!messagesLoaded) {
03092         kWarning() << "failed umlview load on messages" << endl;
03093         return false;
03094     }
03095     if (!associationsLoaded) {
03096         kWarning() << "failed umlview load on associations" << endl;
03097         return false;
03098     }
03099     return true;
03100 }
03101 
03102 bool UMLView::loadWidgetsFromXMI( QDomElement & qElement ) {
03103     UMLWidget* widget = 0;
03104     QDomNode node = qElement.firstChild();
03105     QDomElement widgetElement = node.toElement();
03106     while( !widgetElement.isNull() ) {
03107         widget = loadWidgetFromXMI(widgetElement);
03108         if (widget) {
03109             m_WidgetList.append( widget );
03110             // In the interest of best-effort loading, in case of a
03111             // (widget == NULL) we still go on.
03112             // The individual widget's loadFromXMI method should
03113             // already have generated an error message to tell the
03114             // user that something went wrong.
03115         }
03116         node = widgetElement.nextSibling();
03117         widgetElement = node.toElement();
03118     }
03119 
03120     return true;
03121 }
03122 
03123 UMLWidget* UMLView::loadWidgetFromXMI(QDomElement& widgetElement) {
03124 
03125     if ( !m_pDoc ) {
03126         kWarning() << "UMLView::loadWidgetFromXMI(): m_pDoc is NULL" << endl;
03127         return 0L;
03128     }
03129 
03130     QString tag  = widgetElement.tagName();
03131     QString idstr  = widgetElement.attribute( "xmi.id", "-1" );
03132     UMLWidget* widget = Widget_Factory::makeWidgetFromXMI(tag, idstr, this);
03133     if (widget == NULL)
03134         return NULL;
03135     if (!widget->loadFromXMI(widgetElement)) {
03136         widget->cleanup();
03137         delete widget;
03138         return 0;
03139     }
03140     return widget;
03141 }
03142 
03143 bool UMLView::loadMessagesFromXMI( QDomElement & qElement ) {
03144     MessageWidget * message = 0;
03145     QDomNode node = qElement.firstChild();
03146     QDomElement messageElement = node.toElement();
03147     while( !messageElement.isNull() ) {
03148         QString tag = messageElement.tagName();
03149         if (tag == "messagewidget" ||
03150                 tag == "UML:MessageWidget" ) {  // for bkwd compatibility
03151             message = new MessageWidget(this, sequence_message_asynchronous,
03152                                         Uml::id_Reserved);
03153             if( !message -> loadFromXMI( messageElement ) ) {
03154                 delete message;
03155                 return false;
03156             }
03157             m_MessageList.append( message );
03158             FloatingTextWidget *ft = message->getFloatingTextWidget();
03159             if (ft)
03160                 m_WidgetList.append( ft );
03161             else if (message->getSequenceMessageType() != sequence_message_creation)
03162                 kDebug() << "UMLView::loadMessagesFromXMI: ft is NULL"
03163                           << " for message " << ID2STR(message->getID()) << endl;
03164         }
03165         node = messageElement.nextSibling();
03166         messageElement = node.toElement();
03167     }
03168     return true;
03169 }
03170 
03171 bool UMLView::loadAssociationsFromXMI( QDomElement & qElement ) {
03172     QDomNode node = qElement.firstChild();
03173     QDomElement assocElement = node.toElement();
03174     int countr = 0;
03175     while( !assocElement.isNull() ) {
03176         QString tag = assocElement.tagName();
03177         if (tag == "assocwidget" ||
03178                 tag == "UML:AssocWidget") {  // for bkwd compatibility
03179             countr++;
03180             AssociationWidget *assoc = new AssociationWidget(this);
03181             if( !assoc->loadFromXMI( assocElement ) ) {
03182                 kError() << "couldn't loadFromXMI association widget:"
03183                           << assoc << ", bad XMI file? Deleting from umlview."
03184                           << endl;
03185                 delete assoc;
03186                 /* return false;
03187                    Returning false here is a little harsh when the
03188                    rest of the diagram might load okay.
03189                  */
03190             } else {
03191                 if(!addAssociation(assoc, false))
03192                 {
03193                     kError()<<"Couldnt addAssociation("<<assoc<<") to umlview, deleting."<<endl;
03194                     //               assoc->cleanup();
03195                     delete assoc;
03196                     //return false; // soften error.. may not be that bad
03197                 }
03198             }
03199         }
03200         node = assocElement.nextSibling();
03201         assocElement = node.toElement();
03202     }
03203     return true;
03204 }
03205 
03206 void UMLView::addObject(UMLObject *object)
03207 {
03208     m_bCreateObject = true;
03209     if (m_pDoc->addUMLObject(object))
03210         m_pDoc->signalUMLObjectCreated(object);  // m_bCreateObject is reset by slotObjectCreated()
03211     else
03212         m_bCreateObject = false;
03213 }
03214 
03215 bool UMLView::loadUisDiagramPresentation(QDomElement & qElement) {
03216     for (QDomNode node = qElement.firstChild(); !node.isNull(); node = node.nextSibling()) {
03217         QDomElement elem = node.toElement();
03218         QString tag = elem.tagName();
03219         if (! Uml::tagEq(tag, "Presentation")) {
03220             kError() << "ignoring unknown UisDiagramPresentation tag "
03221                       << tag << endl;
03222             continue;
03223         }
03224         QDomNode n = elem.firstChild();
03225         QDomElement e = n.toElement();
03226         QString idStr;
03227         int x = 0, y = 0, w = 0, h = 0;
03228         while (!e.isNull()) {
03229             tag = e.tagName();
03230             kDebug() << "Presentation: tag = " << tag << endl;
03231             if (Uml::tagEq(tag, "Presentation.geometry")) {
03232                 QDomNode gnode = e.firstChild();
03233                 QDomElement gelem = gnode.toElement();
03234                 QString csv = gelem.text();
03235                 QStringList dim = QStringList::split(",", csv);
03236                 x = dim[0].toInt();
03237                 y = dim[1].toInt();
03238                 w = dim[2].toInt();
03239                 h = dim[3].toInt();
03240             } else if (Uml::tagEq(tag, "Presentation.style")) {
03241                 // TBD
03242             } else if (Uml::tagEq(tag, "Presentation.model")) {
03243                 QDomNode mnode = e.firstChild();
03244                 QDomElement melem = mnode.toElement();
03245                 idStr = melem.attribute("xmi.idref", "");
03246             } else {
03247                 kDebug() << "UMLView::uisLoadFromXMI: ignoring tag "
03248                           << tag << endl;
03249             }
03250             n = n.nextSibling();
03251             e = n.toElement();
03252         }
03253         Uml::IDType id = STR2ID(idStr);
03254         UMLObject *o = m_pDoc->findObjectById(id);
03255         if (o == NULL) {
03256             kError() << "UMLView::uisLoadFromXMI: Cannot find object for id "
03257                       << idStr << endl;
03258         } else {
03259             Uml::Object_Type ot = o->getBaseType();
03260             kDebug() << "Create widget for model object of type " << ot << endl;
03261             UMLWidget *widget = NULL;
03262             switch (ot) {
03263             case Uml::ot_Class:
03264                 widget = new ClassifierWidget(this, static_cast<UMLClassifier*>(o));
03265                 break;
03266             case Uml::ot_Association:
03267                 {
03268                     UMLAssociation *umla = static_cast<UMLAssociation*>(o);
03269                     Uml::Association_Type at = umla->getAssocType();
03270                     UMLObject* objA = umla->getObject(Uml::A);
03271                     UMLObject* objB = umla->getObject(Uml::B);
03272                     if (objA == NULL || objB == NULL) {
03273                         kError() << "intern err 1" << endl;
03274                         return false;
03275                     }
03276                     UMLWidget *wA = findWidget(objA->getID());
03277                     UMLWidget *wB = findWidget(objB->getID());
03278                     if (wA != NULL && wB != NULL) {
03279                         AssociationWidget *aw =
03280                             new AssociationWidget(this, wA, at, wB, umla);
03281                         aw->syncToModel();
03282                         m_AssociationList.append(aw);
03283                     } else {
03284                         kError() << "cannot create assocwidget from ("
03285                                   << wA << ", " << wB << ")" << endl;
03286                     }
03287                     break;
03288                 }
03289             case Uml::ot_Role:
03290                 {
03291                     UMLRole *robj = static_cast<UMLRole*>(o);
03292                     UMLAssociation *umla = robj->getParentAssociation();
03293                     // @todo properly display role names.
03294                     //       For now, in order to get the role names displayed
03295                     //       simply delete the participating diagram objects
03296                     //       and drag them from the list view to the diagram.
03297                     break;
03298                 }
03299             default:
03300                 kError() << "UMLView::uisLoadFromXMI: "
03301                           << "Cannot create widget of type "
03302                           << ot << endl;
03303             }
03304             if (widget) {
03305                 kDebug() << "Widget: x=" << x << ", y=" << y
03306                           << ", w=" << w << ", h=" << h << endl;
03307                 widget->setX(x);
03308                 widget->setY(y);
03309                 widget->setSize(w, h);
03310                 m_WidgetList.append(widget);
03311             }
03312         }
03313     }
03314     return true;
03315 }
03316 
03317 bool UMLView::loadUISDiagram(QDomElement & qElement) {
03318     QString idStr = qElement.attribute( "xmi.id", "" );
03319     if (idStr.isEmpty())
03320         return false;
03321     m_nID = STR2ID(idStr);
03322     UMLListViewItem *ulvi = NULL;
03323     for (QDomNode node = qElement.firstChild(); !node.isNull(); node = node.nextSibling()) {
03324         if (node.isComment())
03325             continue;
03326         QDomElement elem = node.toElement();
03327         QString tag = elem.tagName();
03328         if (tag == "uisDiagramName") {
03329             setName( elem.text() );
03330             if (ulvi)
03331                 ulvi->setText( getName() );
03332         } else if (tag == "uisDiagramStyle") {
03333             QString diagramStyle = elem.text();
03334             if (diagramStyle != "ClassDiagram") {
03335                 kError() << "UMLView::uisLoadFromXMI: diagram style " << diagramStyle
03336                           << " is not yet implemented" << endl;
03337                 continue;
03338             }
03339             m_pDoc->setMainViewID(m_nID);
03340             m_Type = Uml::dt_Class;
03341             UMLListView *lv = UMLApp::app()->getListView();
03342             ulvi = new UMLListViewItem( lv->theLogicalView(), getName(),
03343                                         Uml::lvt_Class_Diagram, m_nID );
03344         } else if (tag == "uisDiagramPresentation") {
03345             loadUisDiagramPresentation(elem);
03346         } else if (tag != "uisToolName") {
03347             kDebug() << "UMLView::uisLoadFromXMI: ignoring tag " << tag << endl;
03348         }
03349     }
03350     return true;
03351 }
03352 
03353 
03354 #include "umlview.moc"
KDE Logo
This file is part of the documentation for umbrello Version 3.1.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 26 08:08:01 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003