/*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * copyright (C) 2002-2007 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "umlview.h" // system includes #include #include // include files for TQt #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //kde include files #include #include #include #include #include #include #include #include #include // application specific includes #include "umlviewimageexporter.h" #include "listpopupmenu.h" #include "uml.h" #include "umldoc.h" #include "umlobject.h" #include "docwindow.h" #include "assocrules.h" #include "umlrole.h" #include "umlviewcanvas.h" #include "dialogs/classoptionspage.h" #include "dialogs/umlviewdialog.h" #include "clipboard/idchangelog.h" #include "clipboard/umldrag.h" #include "widget_factory.h" #include "floatingtextwidget.h" #include "classifierwidget.h" #include "classifier.h" #include "packagewidget.h" #include "package.h" #include "folder.h" #include "componentwidget.h" #include "nodewidget.h" #include "artifactwidget.h" #include "datatypewidget.h" #include "enumwidget.h" #include "entitywidget.h" #include "actorwidget.h" #include "usecasewidget.h" #include "notewidget.h" #include "boxwidget.h" #include "associationwidget.h" #include "objectwidget.h" #include "messagewidget.h" #include "statewidget.h" #include "forkjoinwidget.h" #include "activitywidget.h" #include "seqlinewidget.h" #include "uniqueid.h" #include "umllistviewitemlist.h" #include "umllistviewitem.h" #include "umllistview.h" #include "umlobjectlist.h" #include "association.h" #include "attribute.h" #include "model_utils.h" #include "object_factory.h" #include "umlwidget.h" #include "toolbarstatefactory.h" // control the manual DoubleBuffering of TQCanvas // with a define, so that this memory X11 effect can // be tested more easily #define MANUAL_CONTROL_DOUBLE_BUFFERING // static members const int UMLView::defaultCanvasSize = 1300; using namespace Uml; // constructor UMLView::UMLView(UMLFolder *parentFolder) : TQCanvasView(UMLApp::app()->getMainViewWidget()) { init(); m_pDoc = UMLApp::app()->getDocument(); m_pFolder = parentFolder; } void UMLView::init() { // Initialize loaded/saved data m_nID = Uml::id_None; m_pDoc = NULL; m_Documentation = ""; m_Type = dt_Undefined; m_bUseSnapToGrid = false; m_bUseSnapComponentSizeToGrid = false; m_bShowSnapGrid = false; m_nSnapX = 10; m_nSnapY = 10; m_nZoom = 100; m_nCanvasWidth = UMLView::defaultCanvasSize; m_nCanvasHeight = UMLView::defaultCanvasSize; m_nCollaborationId = 0; // Initialize other data m_AssociationList.setAutoDelete( true ); //Setup up booleans m_bChildDisplayedDoc = false; m_bPaste = false; m_bActivated = false; m_bCreateObject = false; m_bDrawSelectedOnly = false; m_bPopupShowing = false; m_bStartedCut = false; //clear pointers m_PastePoint = TQPoint(0, 0); m_pIDChangesLog = 0; m_pMenu = 0; m_pImageExporter = new UMLViewImageExporter(this); //setup graphical items viewport() -> setBackgroundMode( TQt::NoBackground ); setCanvas( new UMLViewCanvas( this ) ); // don't set the quite frequent update rate for each // diagram, as that causes also an update of invisible // diagrams, which can cost high CPU load for many // diagrams. // Instead: set the updatePeriod to 20 on Show event, // and switch update back off on Hide event canvas() -> setUpdatePeriod( -1 ); resizeContents(defaultCanvasSize, defaultCanvasSize); canvas() -> resize(defaultCanvasSize, defaultCanvasSize); setAcceptDrops(true); viewport() -> setAcceptDrops(true); setDragAutoScroll(false); viewport() -> setMouseTracking(false); //setup signals connect( this, TQT_SIGNAL(sigRemovePopupMenu()), this, TQT_SLOT(slotRemovePopupMenu() ) ); connect( UMLApp::app(), TQT_SIGNAL( sigCutSuccessful() ), this, TQT_SLOT( slotCutSuccessful() ) ); // Create the ToolBarState factory. This class is not a singleton, because it // needs a pointer to this object. m_pToolBarStateFactory = new ToolBarStateFactory(this); m_pToolBarState = m_pToolBarStateFactory->getState(WorkToolBar::tbb_Arrow); } UMLView::~UMLView() { delete m_pImageExporter; if(m_pIDChangesLog) { delete m_pIDChangesLog; m_pIDChangesLog = 0; } // before we can delete the TQCanvas, all widgets must be explicitly // removed // otherwise the implicit remove of the contained widgets will cause // events which would demand a valid connected TQCanvas // ==> this causes umbrello to crash for some - larger?? - projects // first avoid all events, which would cause some update actions // on deletion of each removed widget blockSignals( true ); removeAllWidgets(); delete m_pToolBarStateFactory; m_pToolBarStateFactory = NULL; // TQt Doc for TQCanvasView::~TQCanvasView () states: // "Destroys the canvas view. The associated canvas is not deleted." // we should do it now delete canvas(); } TQString UMLView::getName() const { return m_Name; } void UMLView::setName(const TQString &name) { m_Name = name; } int UMLView::generateCollaborationId() { return ++m_nCollaborationId; } void UMLView::print(KPrinter *pPrinter, TQPainter & pPainter) { int height, width; //get the size of the page pPrinter->setFullPage( true ); TQPaintDeviceMetrics metrics(pPrinter); TQFontMetrics fm = pPainter.fontMetrics(); // use the painter font metrics, not the screen fm! int fontHeight = fm.lineSpacing(); uint left, right, top, bottom; // fetch printer margins individual for all four page sides, as at least top and bottom are not the same pPrinter->margins ( &top, &left, &bottom, &right ); // give a little extra space at each side left += 2; right += 2; top += 2; bottom += 2; if(pPrinter->orientation() == KPrinter::Landscape) { // we are printing in LANDSCAPE --> swap marginX and marginY uint right_old = right; // the DiagramRight side is printed at PrintersTop right = top; // the DiagramTop side is printed at PrintersLeft top = left; // the DiagramLeft side is printed at PrintersBottom left = bottom; // the DiagramBottom side is printed at PrintersRight bottom = right_old; } // The printer will probably use a different font with different font metrics, // force the widgets to update accordingly on paint forceUpdateWidgetFontMetrics(&pPainter); width = metrics.width() - left - right; height = metrics.height() - top - bottom; //get the smallest rect holding the diagram TQRect rect = getDiagramRect(); //now draw to printer #if 0 int offsetX = 0, offsetY = 0, widthX = 0, heightY = 0; // respect the margin pPainter.translate(marginX, marginY); // clip away everything outside of the margin pPainter.setClipRect(marginX, marginY, width, metrics.height() - marginY * 2); //loop until all of the picture is printed int numPagesX = (int)ceil((double)rect.width()/(double)width); int numPagesY = (int)ceil((double)rect.height()/(double)height); int page = 0; // print the canvas to multiple pages for (int pageY = 0; pageY < numPagesY; ++pageY) { // tile vertically offsetY = pageY * height + rect.y(); heightY = (pageY + 1) * height > rect.height() ? rect.height() - pageY * height : height; for (int pageX = 0; pageX < numPagesX; ++pageX) { // tile horizontally offsetX = pageX * width + rect.x(); widthX = (pageX + 1) * width > rect.width() ? rect.width() - pageX * width : width; // make sure the part of the diagram is painted at the correct // place in the printout pPainter.translate(-offsetX,-offsetY); getDiagram(TQRect(offsetX, offsetY,widthX, heightY), pPainter); // undo the translation so the coordinates for the painter // correspond to the page again pPainter.translate(offsetX,offsetY); //draw foot note TQString string = i18n("Diagram: %2 Page %1").arg(page + 1).arg(getName()); TQColor textColor(50, 50, 50); pPainter.setPen(textColor); pPainter.drawLine(0, height + 2, width, height + 2); pPainter.drawText(0, height + 4, width, fontHeight, TQt::AlignLeft, string); if(pageX+1 < numPagesX || pageY+1 < numPagesY) { pPrinter -> newPage(); page++; } } } #else // be gentle - as described in TQt-Doc "The Coordinate System" pPainter.save(); int diagramHeight = rect.height(); // + 4+fontHeight between diagram and footline as space-buffer // + 2 between line and foot-text // + 1 for foot-line // + fontHeight for foot-text // ============== // (2*fontHeight) + 7 int footHeight = (2*fontHeight) + 7; int footTop = rect.y() + diagramHeight + 4+fontHeight; int drawHeight = diagramHeight + footHeight; // set window of painter to dimensions of diagram // set window to viewport relation so that x:y isn't changed double dScaleX = (double)rect.width()/ (double)width; double dScaleY = (double)drawHeight/ (double)height; // select the scaling factor so that the larger dimension // fits on the printer page -> use the larger scaling factor // -> the virtual diagram window has some additional space at the // shorter dimension double dScaleUse = ( dScaleX > dScaleY )?dScaleX:dScaleY; int windowWidth = (int)ceil(dScaleUse*width); int windowHeight = (int)ceil(dScaleUse*height); #ifdef DEBUG_PRINTING kDebug() << "drawHeight: " << drawHeight << ", width: " << rect.width() << "\nPageHeight: " << height << ", PageWidht: " << width << "\nScaleY: " << dScaleY << ", ScaleX: " << dScaleX << "\ndScaleUse: " << dScaleUse << "\nVirtualSize: Width: " << windowWidth << ", Height: " << windowHeight << "\nFoot Top: " << footTop << endl; #endif // set virtual drawing area window - where diagram fits 100% in pPainter.setWindow( rect.x(), rect.y(), windowWidth, windowHeight ); // set viewport - the physical mapping // --> TQt's TQPainter will map all drawed elements from diagram area ( window ) // to printer area ( viewport ) pPainter.setViewport( left, top, width, height ); // get Diagram getDiagram(TQRect(rect.x(), rect.y(), windowWidth, diagramHeight), pPainter); //draw foot note TQString string = i18n("Diagram: %2 Page %1").arg( 1).arg(getName()); TQColor textColor(50, 50, 50); pPainter.setPen(textColor); pPainter.drawLine(rect.x(), footTop , windowWidth, footTop); pPainter.drawText(rect.x(), footTop + 3, windowWidth, fontHeight, TQt::AlignLeft, string); // now restore scaling pPainter.restore(); #endif // next painting will most probably be to a different device (i.e. the screen) forceUpdateWidgetFontMetrics(0); } void UMLView::setupNewWidget(UMLWidget *w) { w->setX( m_Pos.x() ); w->setY( m_Pos.y() ); w->setVisible( true ); w->setActivated(); w->setFont( getFont() ); w->slotColorChanged( getID() ); w->slotLineWidthChanged( getID() ); resizeCanvasToItems(); m_WidgetList.append( w ); m_pDoc->setModified(); } void UMLView::contentsMouseReleaseEvent(TQMouseEvent* ome) { m_pToolBarState->mouseRelease(ome); } void UMLView::slotToolBarChanged(int c) { m_pToolBarState->cleanBeforeChange(); m_pToolBarState = m_pToolBarStateFactory->getState((WorkToolBar::ToolBar_Buttons)c); m_pToolBarState->init(); m_bPaste = false; } void UMLView::showEvent(TQShowEvent* /*se*/) { # ifdef MANUAL_CONTROL_DOUBLE_BUFFERING //kWarning() << "Show Event for " << getName() << endl; canvas()->setDoubleBuffering( true ); // as the diagram gets now visible again, // the update of the diagram elements shall be // at the normal value of 20 canvas()-> setUpdatePeriod( 20 ); # endif UMLApp* theApp = UMLApp::app(); WorkToolBar* tb = theApp->getWorkToolBar(); connect(tb,TQT_SIGNAL(sigButtonChanged(int)), this, TQT_SLOT(slotToolBarChanged(int))); connect(this,TQT_SIGNAL(sigResetToolBar()), tb, TQT_SLOT(slotResetToolBar())); connect(m_pDoc, TQT_SIGNAL(sigObjectCreated(UMLObject *)), this, TQT_SLOT(slotObjectCreated(UMLObject *))); connect(this, TQT_SIGNAL(sigAssociationRemoved(AssociationWidget*)), UMLApp::app()->getDocWindow(), TQT_SLOT(slotAssociationRemoved(AssociationWidget*))); connect(this, TQT_SIGNAL(sigWidgetRemoved(UMLWidget*)), UMLApp::app()->getDocWindow(), TQT_SLOT(slotWidgetRemoved(UMLWidget*))); resetToolbar(); } void UMLView::hideEvent(TQHideEvent* /*he*/) { UMLApp* theApp = UMLApp::app(); WorkToolBar* tb = theApp->getWorkToolBar(); disconnect(tb,TQT_SIGNAL(sigButtonChanged(int)), this, TQT_SLOT(slotToolBarChanged(int))); disconnect(this,TQT_SIGNAL(sigResetToolBar()), tb, TQT_SLOT(slotResetToolBar())); disconnect(m_pDoc, TQT_SIGNAL(sigObjectCreated(UMLObject *)), this, TQT_SLOT(slotObjectCreated(UMLObject *))); disconnect(this, TQT_SIGNAL(sigAssociationRemoved(AssociationWidget*)), UMLApp::app()->getDocWindow(), TQT_SLOT(slotAssociationRemoved(AssociationWidget*))); disconnect(this, TQT_SIGNAL(sigWidgetRemoved(UMLWidget*)), UMLApp::app()->getDocWindow(), TQT_SLOT(slotWidgetRemoved(UMLWidget*))); # ifdef MANUAL_CONTROL_DOUBLE_BUFFERING //kWarning() << "Hide Event for " << getName() << endl; canvas()->setDoubleBuffering( false ); // a periodic update of all - also invisible - diagrams // can cause a very high CPU load if more than 100diagrams // are inside a project - and this without any need // => switch the update off for hidden diagrams canvas()-> setUpdatePeriod( -1 ); # endif } void UMLView::slotObjectCreated(UMLObject* o) { m_bPaste = false; //check to see if we want the message //may be wanted by someone else e.g. list view if (!m_bCreateObject) { return; } UMLWidget* newWidget = Widget_Factory::createWidget(this, o); if (newWidget == NULL) return; newWidget->setVisible( true ); newWidget->setActivated(); newWidget->setFont( getFont() ); newWidget->slotColorChanged( getID() ); newWidget->slotLineWidthChanged( getID() ); newWidget->updateComponentSize(); if (m_Type == Uml::dt_Sequence) { // Set proper position on the sequence line widget which is // attached to the object widget. ObjectWidget *ow = dynamic_cast(newWidget); if (ow) ow->moveEvent(NULL); } m_bCreateObject = false; m_WidgetList.append(newWidget); switch (o->getBaseType()) { case ot_Actor: case ot_UseCase: case ot_Class: case ot_Package: case ot_Component: case ot_Node: case ot_Artifact: case ot_Interface: case ot_Enum: case ot_Entity: case ot_Datatype: createAutoAssociations(newWidget); // We need to invoke createAutoAttributeAssociations() // on all other widgets again because the newly created // widget might saturate some latent attribute assocs. for (UMLWidgetListIt it(m_WidgetList); it.current(); ++it) { UMLWidget *w = it.current(); if (w != newWidget) createAutoAttributeAssociations(w); } break; default: break; } resizeCanvasToItems(); } void UMLView::slotObjectRemoved(UMLObject * o) { m_bPaste = false; Uml::IDType id = o->getID(); UMLWidgetListIt it( m_WidgetList ); UMLWidget *obj; while ((obj = it.current()) != 0 ) { ++it; if(obj -> getID() != id) continue; removeWidget(obj); } } void UMLView::contentsDragEnterEvent(TQDragEnterEvent *e) { UMLDrag::LvTypeAndID_List tidList; if(!UMLDrag::getClip3TypeAndID(e, tidList)) { return; } UMLDrag::LvTypeAndID_It tidIt(tidList); UMLDrag::LvTypeAndID * tid = tidIt.current(); if (!tid) { kDebug() << "UMLView::contentsDragEnterEvent: " << "UMLDrag::getClip3TypeAndID returned empty list" << endl; return; } ListView_Type lvtype = tid->type; Uml::IDType id = tid->id; Diagram_Type diagramType = getType(); UMLObject* temp = 0; //if dragging diagram - might be a drag-to-note if (Model_Utils::typeIsDiagram(lvtype)) { e->accept(true); return; } //can't drag anything onto state/activity diagrams if( diagramType == dt_State || diagramType == dt_Activity) { e->accept(false); return; } //make sure can find UMLObject if( !(temp = m_pDoc->findObjectById(id) ) ) { kDebug() << "object " << ID2STR(id) << " not found" << endl; e->accept(false); return; } //make sure dragging item onto correct diagram // concept - class,seq,coll diagram // actor,usecase - usecase diagram Object_Type ot = temp->getBaseType(); bool bAccept = true; switch (diagramType) { case dt_UseCase: if ((widgetOnDiagram(id) && ot == ot_Actor) || (ot != ot_Actor && ot != ot_UseCase)) bAccept = false; break; case dt_Class: if (widgetOnDiagram(id) || (ot != ot_Class && ot != ot_Package && ot != ot_Interface && ot != ot_Enum && ot != ot_Datatype)) { bAccept = false; } break; case dt_Sequence: case dt_Collaboration: if (ot != ot_Class && ot != ot_Interface && ot != ot_Actor) bAccept = false; break; case dt_Deployment: if (widgetOnDiagram(id)) bAccept = false; else if (ot != ot_Interface && ot != ot_Package && ot != ot_Component && ot != ot_Class && ot != ot_Node) bAccept = false; else if (ot == ot_Package && temp->getStereotype() != "subsystem") bAccept = false; break; case dt_Component: if (widgetOnDiagram(id) || (ot != ot_Interface && ot != ot_Package && ot != ot_Component && ot != ot_Artifact && ot != ot_Class)) bAccept = false; if (ot == ot_Class && !temp->getAbstract()) bAccept = false; break; case dt_EntityRelationship: if (ot != ot_Entity) bAccept = false; break; default: break; } e->accept(bAccept); } void UMLView::contentsDropEvent(TQDropEvent *e) { UMLDrag::LvTypeAndID_List tidList; if( !UMLDrag::getClip3TypeAndID(e, tidList) ) { return; } UMLDrag::LvTypeAndID_It tidIt(tidList); UMLDrag::LvTypeAndID * tid = tidIt.current(); if (!tid) { kDebug() << "UMLView::contentsDropEvent: " << "UMLDrag::getClip3TypeAndID returned empty list" << endl; return; } ListView_Type lvtype = tid->type; Uml::IDType id = tid->id; if (Model_Utils::typeIsDiagram(lvtype)) { UMLWidget *w = NULL; for (w = m_WidgetList.first(); w; w = m_WidgetList.next()) { if (w->getBaseType() == Uml::wt_Note && w->onWidget(e->pos())) break; } if (w) { NoteWidget *note = static_cast(w); note->setDiagramLink(id); } return; } UMLObject* o = m_pDoc->findObjectById(id); if( !o ) { kDebug() << "UMLView::contentsDropEvent: object id=" << ID2STR(id) << " not found" << endl; return; } m_bCreateObject = true; m_Pos = (e->pos() * 100 ) / m_nZoom; slotObjectCreated(o); m_pDoc -> setModified(true); } ObjectWidget * UMLView::onWidgetLine( const TQPoint &point ) { UMLWidget *obj; for (UMLWidgetListIt it(m_WidgetList); (obj = it.current()) != NULL; ++it) { ObjectWidget *ow = dynamic_cast(obj); if (ow == NULL) continue; SeqLineWidget *pLine = ow->getSeqLine(); if (pLine == NULL) { kError() << "UMLView::onWidgetLine: SeqLineWidget of " << ow->getName() << " (id=" << ID2STR(ow->getLocalID()) << ") is NULL" << endl; continue; } if (pLine->onWidget(point)) return ow; } return 0; } UMLWidget *UMLView::getWidgetAt(const TQPoint& p) { int relativeSize = 10000; // start with an arbitrary large number UMLWidget *obj, *retObj = NULL; UMLWidgetListIt it(m_WidgetList); for (UMLWidgetListIt it(m_WidgetList); (obj = it.current()) != NULL; ++it) { const int s = obj->onWidget(p); if (!s) continue; if (s < relativeSize) { relativeSize = s; retObj = obj; } } return retObj; } void UMLView::checkMessages(ObjectWidget * w) { if(getType() != dt_Sequence) return; MessageWidgetListIt it( m_MessageList ); MessageWidget *obj; while ( (obj = it.current()) != 0 ) { ++it; if(! obj -> contains(w)) continue; //make sure message doesn't have any associations removeAssociations(obj); obj -> cleanup(); //make sure not in selected list m_SelectedList.remove(obj); m_MessageList.remove(obj); delete obj; } } bool UMLView::widgetOnDiagram(Uml::IDType id) { UMLWidget *obj; UMLWidgetListIt it( m_WidgetList ); while ( (obj = it.current()) != 0 ) { ++it; if(id == obj -> getID()) return true; } MessageWidgetListIt mit( m_MessageList ); while ( (obj = (UMLWidget*)mit.current()) != 0 ) { ++mit; if(id == obj -> getID()) return true; } return false; } void UMLView::contentsMouseMoveEvent(TQMouseEvent* ome) { m_pToolBarState->mouseMove(ome); } // search both our UMLWidget AND MessageWidget lists UMLWidget * UMLView::findWidget( Uml::IDType id ) { UMLWidgetListIt it( m_WidgetList ); UMLWidget * obj = NULL; while ( (obj = it.current()) != 0 ) { ++it; // object widgets are special..the widget id is held by 'localId' attribute (crappy!) if( obj -> getBaseType() == wt_Object ) { if( static_cast( obj ) -> getLocalID() == id ) return obj; } else if( obj -> getID() == id ) { return obj; } } MessageWidgetListIt mit( m_MessageList ); while ( (obj = (UMLWidget*)mit.current()) != 0 ) { ++mit; if( obj -> getID() == id ) return obj; } return 0; } AssociationWidget * UMLView::findAssocWidget( Uml::IDType id ) { AssociationWidget *obj; AssociationWidgetListIt it( m_AssociationList ); while ( (obj = it.current()) != 0 ) { ++it; UMLAssociation* umlassoc = obj -> getAssociation(); if ( umlassoc && umlassoc->getID() == id ) { return obj; } } return 0; } AssociationWidget * UMLView::findAssocWidget(UMLWidget *pWidgetA, UMLWidget *pWidgetB, const TQString& roleNameB) { AssociationWidget *assoc; AssociationWidgetListIt it(m_AssociationList); while ((assoc = it.current()) != 0) { ++it; const Association_Type testType = assoc->getAssocType(); if (testType != Uml::at_Association && testType != Uml::at_UniAssociation && testType != Uml::at_Composition && testType != Uml::at_Aggregation) continue; if (pWidgetA->getID() == assoc->getWidgetID(A) && pWidgetB->getID() == assoc->getWidgetID(B) && assoc->getRoleName(Uml::B) == roleNameB) return assoc; } return 0; } AssociationWidget * UMLView::findAssocWidget(Uml::Association_Type at, UMLWidget *pWidgetA, UMLWidget *pWidgetB) { AssociationWidget *assoc; AssociationWidgetListIt it(m_AssociationList); while ((assoc = it.current()) != 0) { ++it; Association_Type testType = assoc->getAssocType(); if (testType != at) continue; if (pWidgetA->getID() == assoc->getWidgetID(A) && pWidgetB->getID() == assoc->getWidgetID(B)) return assoc; } return 0; } void UMLView::removeWidget(UMLWidget * o) { if(!o) return; emit sigWidgetRemoved(o); removeAssociations(o); Widget_Type t = o->getBaseType(); if(getType() == dt_Sequence && t == wt_Object) checkMessages( static_cast(o) ); o -> cleanup(); m_SelectedList.remove(o); disconnect( this, TQT_SIGNAL( sigRemovePopupMenu() ), o, TQT_SLOT( slotRemovePopupMenu() ) ); disconnect( this, TQT_SIGNAL( sigClearAllSelected() ), o, TQT_SLOT( slotClearAllSelected() ) ); disconnect( this, TQT_SIGNAL(sigColorChanged(Uml::IDType)), o, TQT_SLOT(slotColorChanged(Uml::IDType))); if (t == wt_Message) m_MessageList.remove(static_cast(o)); else m_WidgetList.remove(o); m_pDoc->setModified(); delete o; } bool UMLView::getUseFillColor() const { return m_Options.uiState.useFillColor; } void UMLView::setUseFillColor(bool ufc) { m_Options.uiState.useFillColor = ufc; } TQColor UMLView::getFillColor() const { return m_Options.uiState.fillColor; } void UMLView::setFillColor(const TQColor &color) { m_Options.uiState.fillColor = color; emit sigColorChanged( getID() ); canvas()->setAllChanged(); } TQColor UMLView::getLineColor() const { return m_Options.uiState.lineColor; } void UMLView::setLineColor(const TQColor &color) { m_Options.uiState.lineColor = color; emit sigColorChanged( getID() ); canvas() -> setAllChanged(); } uint UMLView::getLineWidth() const { return m_Options.uiState.lineWidth; } void UMLView::setLineWidth(uint width) { m_Options.uiState.lineWidth = width; emit sigLineWidthChanged( getID() ); canvas() -> setAllChanged(); } void UMLView::contentsMouseDoubleClickEvent(TQMouseEvent* ome) { m_pToolBarState->mouseDoubleClick(ome); } TQRect UMLView::getDiagramRect() { int startx, starty, endx, endy; startx = starty = INT_MAX; endx = endy = 0; UMLWidgetListIt it( m_WidgetList ); UMLWidget *obj; while ( (obj = it.current()) != 0 ) { ++it; if (! obj->isVisible()) continue; int objEndX = obj -> getX() + obj -> getWidth(); int objEndY = obj -> getY() + obj -> getHeight(); int objStartX = obj -> getX(); int objStartY = obj -> getY(); if (startx >= objStartX) startx = objStartX; if (starty >= objStartY) starty = objStartY; if(endx <= objEndX) endx = objEndX; if(endy <= objEndY) endy = objEndY; } //if seq. diagram, make sure print all of the lines if (getType() == dt_Sequence ) { for (UMLWidgetListIt it(m_WidgetList); (obj = it.current()) != NULL; ++it) { ObjectWidget *ow = dynamic_cast(obj); if (ow == NULL) continue; int y = ow->getEndLineY(); if (endy < y) endy = y; } } /* now we need another look at the associations, because they are no * UMLWidgets */ AssociationWidgetListIt assoc_it (m_AssociationList); AssociationWidget * assoc_obj; TQRect rect; while ((assoc_obj = assoc_it.current()) != 0) { /* get the rectangle around all segments of the assoc */ rect = assoc_obj->getAssocLineRectangle(); if (startx >= rect.x()) startx = rect.x(); if (starty >= rect.y()) starty = rect.y(); if (endx <= rect.x() + rect.width()) endx = rect.x() + rect.width(); if (endy <= rect.y() + rect.height()) endy = rect.y() + rect.height(); ++assoc_it; // next assoc } /* Margin causes problems of black border around the edge // Margin: startx -= 24; starty -= 20; endx += 24; endy += 20; */ return TQRect(startx, starty, endx - startx, endy - starty); } void UMLView::setSelected(UMLWidget * w, TQMouseEvent * /*me*/) { //only add if wasn't in list if(!m_SelectedList.remove(w)) m_SelectedList.append(w); int count = m_SelectedList.count(); //only call once - if we select more, no need to keep clearing window // if count == 1, widget will update the doc window with their data when selected if( count == 2 ) updateDocumentation( true );//clear doc window /* selection changed, we have to make sure the copy and paste items * are correctly enabled/disabled */ UMLApp::app()->slotCopyChanged(); } void UMLView::clearSelected() { m_SelectedList.clear(); emit sigClearAllSelected(); //m_pDoc -> enableCutCopy(false); } //TODO Only used in MLApp::handleCursorKeyReleaseEvent void UMLView::moveSelectedBy(int dX, int dY) { for (UMLWidget *w = m_SelectedList.first(); w; w = m_SelectedList.next()) w->moveBy(dX, dY); } void UMLView::selectionUseFillColor(bool useFC) { UMLWidget * temp = 0; for(temp=(UMLWidget *)m_SelectedList.first();temp;temp=(UMLWidget *)m_SelectedList.next()) temp -> setUseFillColour(useFC); } void UMLView::selectionSetFont( const TQFont &font ) { UMLWidget * temp = 0; for(temp=(UMLWidget *)m_SelectedList.first();temp;temp=(UMLWidget *)m_SelectedList.next()) temp -> setFont( font ); } void UMLView::selectionSetLineColor( const TQColor &color ) { UMLWidget * temp = 0; for (temp = m_SelectedList.first(); temp; temp = m_SelectedList.next()) { temp->setLineColor(color); temp->setUsesDiagramLineColour(false); } AssociationWidgetList assoclist = getSelectedAssocs(); for (AssociationWidget *aw = assoclist.first(); aw; aw = assoclist.next()) { aw->setLineColor(color); aw->setUsesDiagramLineColour(false); } } void UMLView::selectionSetLineWidth( uint width ) { UMLWidget * temp = 0; for (temp = m_SelectedList.first(); temp; temp = m_SelectedList.next()) { temp->setLineWidth(width); temp->setUsesDiagramLineWidth(false); } AssociationWidgetList assoclist = getSelectedAssocs(); for (AssociationWidget *aw = assoclist.first(); aw; aw = assoclist.next()) { aw->setLineWidth(width); aw->setUsesDiagramLineWidth(false); } } void UMLView::selectionSetFillColor( const TQColor &color ) { UMLWidget * temp = 0; for(temp=(UMLWidget *) m_SelectedList.first(); temp; temp=(UMLWidget *)m_SelectedList.next()) { temp -> setFillColour( color ); temp -> setUsesDiagramFillColour(false); } } void UMLView::selectionToggleShow(int sel) { // loop through all selected items for(UMLWidget *temp = (UMLWidget *)m_SelectedList.first(); temp; temp=(UMLWidget *)m_SelectedList.next()) { Widget_Type type = temp->getBaseType(); ClassifierWidget *cw = dynamic_cast(temp); // toggle the show setting sel switch (sel) { // some setting are only available for class, some for interface and some // for both case ListPopupMenu::mt_Show_Attributes_Selection: if (type == wt_Class) cw -> toggleShowAtts(); break; case ListPopupMenu::mt_Show_Operations_Selection: if (cw) cw -> toggleShowOps(); break; case ListPopupMenu::mt_Visibility_Selection: if (cw) cw -> toggleShowVisibility(); break; case ListPopupMenu::mt_DrawAsCircle_Selection: if (type == wt_Interface) cw -> toggleDrawAsCircle(); break; case ListPopupMenu::mt_Show_Operation_Signature_Selection: if (cw) cw -> toggleShowOpSigs(); break; case ListPopupMenu::mt_Show_Attribute_Signature_Selection: if (type == wt_Class) cw -> toggleShowAttSigs(); break; case ListPopupMenu::mt_Show_Packages_Selection: if (cw) cw -> toggleShowPackage(); break; case ListPopupMenu::mt_Show_Stereotypes_Selection: if (type == wt_Class) cw -> toggleShowStereotype(); break; case ListPopupMenu::mt_Show_Public_Only_Selection: if (cw) cw -> toggleShowPublicOnly(); break; default: break; } // switch (sel) } } void UMLView::deleteSelection() { /* Don't delete text widget that are connect to associations as these will be cleaned up by the associations. */ UMLWidget * temp = 0; for(temp=(UMLWidget *) m_SelectedList.first(); temp; temp=(UMLWidget *)m_SelectedList.next()) { if( temp -> getBaseType() == wt_Text && ((FloatingTextWidget *)temp) -> getRole() != tr_Floating ) { m_SelectedList.remove(); // remove advances the iterator to the next position, m_SelectedList.prev(); // let's allow for statement do the advancing temp -> hide(); } else { removeWidget(temp); } } // Delete any selected associations. AssociationWidgetListIt assoc_it( m_AssociationList ); AssociationWidget* assocwidget = 0; while((assocwidget=assoc_it.current())) { ++assoc_it; if( assocwidget-> getSelected() ) removeAssoc(assocwidget); // MARK } /* we also have to remove selected messages from sequence diagrams */ MessageWidget * cur_msgWgt; /* loop through all messages and check the selection state */ for (cur_msgWgt = m_MessageList.first(); cur_msgWgt; cur_msgWgt = m_MessageList.next()) { if (cur_msgWgt->getSelected() == true) { removeWidget(cur_msgWgt); // Remove message - it is selected. } } // sometimes we miss one widget, so call this function again to remove it as // well if (m_SelectedList.count() != 0) deleteSelection(); //make sure list empty - it should be anyway, just a check. m_SelectedList.clear(); } void UMLView::selectAll() { selectWidgets(0, 0, canvas()->width(), canvas()->height()); } Uml::IDType UMLView::getLocalID() { m_nLocalID = UniqueID::gen(); return m_nLocalID; } bool UMLView::isSavedInSeparateFile() { if (getOptionState().generalState.tabdiagrams) { // Umbrello currently does not support external folders // when tabbed diagrams are enabled. return false; } const TQString msgPrefix("UMLView::isSavedInSeparateFile(" + getName() + "): "); UMLListView *listView = UMLApp::app()->getListView(); UMLListViewItem *lvItem = listView->findItem(m_nID); if (lvItem == NULL) { kError() << msgPrefix << "listView->findUMLObject(this) returns false" << endl; return false; } UMLListViewItem *parentItem = dynamic_cast( lvItem->parent() ); if (parentItem == NULL) { kError() << msgPrefix << "parent item in listview is not a UMLListViewItem (?)" << endl; return false; } const Uml::ListView_Type lvt = parentItem->getType(); if (! Model_Utils::typeIsFolder(lvt)) return false; UMLFolder *modelFolder = dynamic_cast(parentItem->getUMLObject()); if (modelFolder == NULL) { kError() << msgPrefix << "parent model object is not a UMLFolder (?)" << endl; return false; } TQString folderFile = modelFolder->getFolderFile(); return !folderFile.isEmpty(); } void UMLView::contentsMousePressEvent(TQMouseEvent* ome) { m_pToolBarState->mousePress(ome); //TODO should be managed by widgets when are selected. Right now also has some //problems, such as clicking on a widget, and clicking to move that widget shows //documentation of the diagram instead of keeping the widget documentation. //When should diagram documentation be shown? When clicking on an empty //space in the diagram with arrow tool? if (!m_bChildDisplayedDoc) { UMLApp::app() -> getDocWindow() -> showDocumentation( this, true ); } m_bChildDisplayedDoc = false; } void UMLView::makeSelected (UMLWidget * uw) { if (uw == NULL) return; uw -> setSelected(true); m_SelectedList.remove(uw); // make sure not in there m_SelectedList.append(uw); } void UMLView::selectWidgetsOfAssoc (AssociationWidget * a) { if (!a) return; a -> setSelected(true); //select the two widgets makeSelected( a->getWidget(A) ); makeSelected( a->getWidget(B) ); //select all the text makeSelected( a->getMultiWidget(A) ); makeSelected( a->getMultiWidget(B) ); makeSelected( a->getRoleWidget(A) ); makeSelected( a->getRoleWidget(B) ); makeSelected( a->getChangeWidget(A) ); makeSelected( a->getChangeWidget(B) ); } void UMLView::selectWidgets(int px, int py, int qx, int qy) { clearSelected(); TQRect rect; if(px <= qx) { rect.setLeft(px); rect.setRight(qx); } else { rect.setLeft(qx); rect.setRight(px); } if(py <= qy) { rect.setTop(py); rect.setBottom(qy); } else { rect.setTop(qy); rect.setBottom(py); } UMLWidgetListIt it(m_WidgetList); UMLWidget * temp = NULL; while ( (temp = it.current()) != 0 ) { int x = temp -> getX(); int y = temp -> getY(); int w = temp -> getWidth(); int h = temp -> getHeight(); TQRect rect2(x, y, w, h); ++it; //see if any part of widget is in the rectangle if( !rect.intersects(rect2) ) continue; //if it is text that is part of an association then select the association //and the objects that are connected to it. if (temp -> getBaseType() == wt_Text) { FloatingTextWidget *ft = static_cast(temp); Text_Role t = ft -> getRole(); LinkWidget *lw = ft->getLink(); MessageWidget * mw = dynamic_cast(lw); if (mw) { makeSelected( mw ); makeSelected( mw->getWidget(A) ); makeSelected( mw->getWidget(B) ); } else if (t != tr_Floating) { AssociationWidget * a = dynamic_cast(lw); if (a) selectWidgetsOfAssoc( a ); } } else if(temp -> getBaseType() == wt_Message) { MessageWidget *mw = static_cast(temp); makeSelected( mw -> getWidget(A) ); makeSelected( mw -> getWidget(B) ); } if(temp -> isVisible()) { makeSelected( temp ); } } selectAssociations( true ); //now do the same for the messagewidgets MessageWidgetListIt itw( m_MessageList ); MessageWidget *w = 0; while ( (w = itw.current()) != 0 ) { ++itw; if ( w -> getWidget(A) -> getSelected() && w -> getWidget(B) -> getSelected() ) { makeSelected( w ); }//end if }//end while } void UMLView::getDiagram(const TQRect &rect, TQPixmap & diagram) { TQPixmap pixmap(rect.x() + rect.width(), rect.y() + rect.height()); TQPainter painter(&pixmap); getDiagram(canvas()->rect(),painter); bitBlt(&diagram, TQPoint(0, 0), &pixmap, rect); } void UMLView::getDiagram(const TQRect &area, TQPainter & painter) { //TODO unselecting and selecting later doesn't work now as the selection is //cleared in UMLViewImageExporter. Check if the anything else than the //following is needed and, if it works, remove the clearSelected in //UMLViewImageExporter and UMLViewImageExporterModel UMLWidget* widget = 0; for (widget=(UMLWidget*)m_SelectedList.first(); widget; widget=(UMLWidget*)m_SelectedList.next()) { widget->setSelected(false); } AssociationWidgetList selectedAssociationsList = getSelectedAssocs(); AssociationWidget* association = 0; for (association=selectedAssociationsList.first(); association; association=selectedAssociationsList.next()) { association->setSelected(false); } // we don't want to get the grid bool showSnapGrid = getShowSnapGrid(); setShowSnapGrid(false); canvas()->drawArea(area, &painter); setShowSnapGrid(showSnapGrid); canvas()->setAllChanged(); //select again for (widget=(UMLWidget *)m_SelectedList.first(); widget; widget=(UMLWidget *)m_SelectedList.next()) { widget->setSelected( true ); } for (association=selectedAssociationsList.first(); association; association=selectedAssociationsList.next()) { association->setSelected(true); } return; } UMLViewImageExporter* UMLView::getImageExporter() { return m_pImageExporter; } void UMLView::slotActivate() { m_pDoc->changeCurrentView(getID()); } UMLObjectList UMLView::getUMLObjects() { UMLObjectList list; for (UMLWidgetListIt it(m_WidgetList); it.current(); ++it) { UMLWidget *w = it.current(); switch (w->getBaseType()) //use switch for easy future expansion { case wt_Actor: case wt_Class: case wt_Interface: case wt_Package: case wt_Component: case wt_Node: case wt_Artifact: case wt_UseCase: case wt_Object: list.append( w->getUMLObject() ); break; default: break; } } return list; } void UMLView::activate() { UMLWidgetListIt it( m_WidgetList ); UMLWidget *obj; //Activate Regular widgets then activate messages while ( (obj = it.current()) != 0 ) { ++it; //If this UMLWidget is already activated or is a MessageWidget then skip it if(obj->isActivated() || obj->getBaseType() == wt_Message) continue; if (obj->activate()) { obj->setVisible(true); } else { m_WidgetList.remove(obj); delete obj; } }//end while MessageWidgetListIt it2( m_MessageList ); //Activate Message widgets while ( (obj = (UMLWidget*)it2.current()) != 0 ) { ++it2; //If this MessageWidget is already activated then skip it if(obj->isActivated()) continue; obj->activate(m_pDoc->getChangeLog()); obj->setVisible( true ); }//end while // Activate all association widgets AssociationWidget *aw; for (AssociationWidgetListIt ait(m_AssociationList); (aw = ait.current()); ++ait) { if (aw->activate()) { if (m_PastePoint.x() != 0) { int x = m_PastePoint.x() - m_Pos.x(); int y = m_PastePoint.y() - m_Pos.y(); aw->moveEntireAssoc(x, y); } } else { m_AssociationList.remove(aw); } } } int UMLView::getSelectCount(bool filterText) const { if (!filterText) return m_SelectedList.count(); int counter = 0; const UMLWidget * temp = 0; for (UMLWidgetListIt iter(m_SelectedList); (temp = iter.current()) != 0; ++iter) { if (temp->getBaseType() == wt_Text) { const FloatingTextWidget *ft = static_cast(temp); if (ft->getRole() == tr_Floating) counter++; } else { counter++; } } return counter; } bool UMLView::getSelectedWidgets(UMLWidgetList &WidgetList, bool filterText /*= true*/) { const UMLWidget * temp = 0; for (UMLWidgetListIt it(m_SelectedList); (temp = it.current()) != NULL; ++it) { if (filterText && temp->getBaseType() == wt_Text) { const FloatingTextWidget *ft = static_cast(temp); if (ft->getRole() == tr_Floating) WidgetList.append(temp); } else { WidgetList.append(temp); } }//end for return true; } AssociationWidgetList UMLView::getSelectedAssocs() { AssociationWidgetList assocWidgetList; AssociationWidgetListIt assoc_it( m_AssociationList ); AssociationWidget* assocwidget = 0; while((assocwidget=assoc_it.current())) { ++assoc_it; if( assocwidget -> getSelected() ) assocWidgetList.append(assocwidget); } return assocWidgetList; } bool UMLView::addWidget( UMLWidget * pWidget , bool isPasteOperation ) { if( !pWidget ) { return false; } Widget_Type type = pWidget->getBaseType(); if (isPasteOperation) { if (type == Uml::wt_Message) m_MessageList.append(static_cast(pWidget)); else m_WidgetList.append(pWidget); return true; } if (!isPasteOperation && findWidget(pWidget->getID())) { kError() << "UMLView::addWidget: Not adding " << "(id=" << ID2STR(pWidget->getID()) << "/type=" << type << "/name=" << pWidget->getName() << ") because it's already there" << endl; return false; } //kDebug() << "UMLView::addWidget called for basetype " << type << endl; IDChangeLog * log = m_pDoc -> getChangeLog(); if( isPasteOperation && (!log || !m_pIDChangesLog)) { kError()<<" Cant addWidget to view in paste op because a log is not open"< getX(); int wY = pWidget -> getY(); bool xIsOutOfRange = (wX <= 0 || wX >= FloatingTextWidget::restrictPositionMax); bool yIsOutOfRange = (wY <= 0 || wY >= FloatingTextWidget::restrictPositionMax); if (xIsOutOfRange || yIsOutOfRange) { TQString name = pWidget->getName(); if (name.isEmpty()) { FloatingTextWidget *ft = dynamic_cast(pWidget); if (ft) name = ft->getDisplayText(); } kDebug() << "UMLView::addWidget (" << name << " type=" << pWidget->getBaseType() << "): position (" << wX << "," << wY << ") is out of range" << endl; if (xIsOutOfRange) { pWidget->setX(0); wX = 0; } if (yIsOutOfRange) { pWidget->setY(0); wY = 0; } } if( wX < m_Pos.x() ) m_Pos.setX( wX ); if( wY < m_Pos.y() ) m_Pos.setY( wY ); //see if we need a new id to match object switch( type ) { case wt_Class: case wt_Package: case wt_Component: case wt_Node: case wt_Artifact: case wt_Interface: case wt_Enum: case wt_Entity: case wt_Datatype: case wt_Actor: case wt_UseCase: { Uml::IDType id = pWidget -> getID(); Uml::IDType newID = log->findNewID( id ); if( newID == Uml::id_None ) { // happens after a cut if (id == Uml::id_None) return false; newID = id; //don't stop paste } else pWidget -> setID( newID ); UMLObject * pObject = m_pDoc -> findObjectById( newID ); if( !pObject ) { kDebug() << "addWidget: Can't find UMLObject for id " << ID2STR(newID) << endl; return false; } pWidget -> setUMLObject( pObject ); //make sure it doesn't already exist. if (findWidget(newID)) { kDebug() << "UMLView::addWidget: Not adding " << "(id=" << ID2STR(pWidget->getID()) << "/type=" << pWidget->getBaseType() << "/name=" << pWidget->getName() << ") because it's already there" << endl; delete pWidget; // Not nice but if _we_ don't do it nobody else will return true;//don't stop paste just because widget found. } m_WidgetList.append( pWidget ); } break; case wt_Message: case wt_Note: case wt_Box: case wt_Text: case wt_State: case wt_Activity: { Uml::IDType newID = m_pDoc->assignNewID( pWidget->getID() ); pWidget->setID(newID); if (type != wt_Message) { m_WidgetList.append( pWidget ); return true; } // CHECK // Handling of wt_Message: MessageWidget *pMessage = static_cast( pWidget ); if (pMessage == NULL) { kDebug() << "UMLView::addWidget(): pMessage is NULL" << endl; return false; } ObjectWidget *objWidgetA = pMessage -> getWidget(A); ObjectWidget *objWidgetB = pMessage -> getWidget(B); Uml::IDType waID = objWidgetA -> getLocalID(); Uml::IDType wbID = objWidgetB -> getLocalID(); Uml::IDType newWAID = m_pIDChangesLog ->findNewID( waID ); Uml::IDType newWBID = m_pIDChangesLog ->findNewID( wbID ); if( newWAID == Uml::id_None || newWBID == Uml::id_None ) { kDebug() << "Error with ids : " << ID2STR(newWAID) << " " << ID2STR(newWBID) << endl; return false; } // Assumption here is that the A/B objectwidgets and the textwidget // are pristine in the sense that we may freely change their local IDs. objWidgetA -> setLocalID( newWAID ); objWidgetB -> setLocalID( newWBID ); FloatingTextWidget *ft = pMessage->getFloatingTextWidget(); if (ft == NULL) kDebug() << "UMLView::addWidget: FloatingTextWidget of Message is NULL" << endl; else if (ft->getID() == Uml::id_None) ft->setID( UniqueID::gen() ); else { Uml::IDType newTextID = m_pDoc->assignNewID( ft->getID() ); ft->setID( newTextID ); } m_MessageList.append( pMessage ); } break; case wt_Object: { ObjectWidget* pObjectWidget = static_cast(pWidget); if (pObjectWidget == NULL) { kDebug() << "UMLView::addWidget(): pObjectWidget is NULL" << endl; return false; } Uml::IDType nNewLocalID = getLocalID(); Uml::IDType nOldLocalID = pObjectWidget -> getLocalID(); m_pIDChangesLog->addIDChange( nOldLocalID, nNewLocalID ); pObjectWidget -> setLocalID( nNewLocalID ); UMLObject *pObject = m_pDoc->findObjectById(pWidget->getID()); if( !pObject ) { kDebug() << "addWidget::Can't find UMLObject" << endl; return false; } pWidget -> setUMLObject( pObject ); m_WidgetList.append( pWidget ); } break; default: kDebug() << "Trying to add an invalid widget type" << endl; return false; break; } return true; } // Add the association, and its child widgets to this view bool UMLView::addAssociation(AssociationWidget* pAssoc , bool isPasteOperation) { if (!pAssoc) { return false; } const Association_Type type = pAssoc->getAssocType(); if( isPasteOperation ) { IDChangeLog * log = m_pDoc -> getChangeLog(); if(!log ) return false; Uml::IDType ida = Uml::id_None, idb = Uml::id_None; if( getType() == dt_Collaboration || getType() == dt_Sequence ) { //check local log first ida = m_pIDChangesLog->findNewID( pAssoc->getWidgetID(A) ); idb = m_pIDChangesLog->findNewID( pAssoc->getWidgetID(B) ); //if either is still not found and assoc type is anchor //we are probably linking to a notewidet - else an error if( ida == Uml::id_None && type == at_Anchor ) ida = log->findNewID(pAssoc->getWidgetID(A)); if( idb == Uml::id_None && type == at_Anchor ) idb = log->findNewID(pAssoc->getWidgetID(B)); } else { Uml::IDType oldIdA = pAssoc->getWidgetID(A); Uml::IDType oldIdB = pAssoc->getWidgetID(B); ida = log->findNewID( oldIdA ); if (ida == Uml::id_None) { // happens after a cut if (oldIdA == Uml::id_None) return false; ida = oldIdA; } idb = log->findNewID( oldIdB ); if (idb == Uml::id_None) { // happens after a cut if (oldIdB == Uml::id_None) return false; idb = oldIdB; } } if(ida == Uml::id_None || idb == Uml::id_None) { return false; } // cant do this anymore.. may cause problem for pasting // pAssoc->setWidgetID(ida, A); // pAssoc->setWidgetID(idb, B); pAssoc->setWidget(findWidget(ida), A); pAssoc->setWidget(findWidget(idb), B); } UMLWidget * pWidgetA = findWidget(pAssoc->getWidgetID(A)); UMLWidget * pWidgetB = findWidget(pAssoc->getWidgetID(B)); //make sure valid widget ids if (!pWidgetA || !pWidgetB) { return false; } //make sure valid if (!isPasteOperation && !m_pDoc->loading() && !AssocRules::allowAssociation(type, pWidgetA, pWidgetB, false)) { kWarning() << "UMLView::addAssociation: allowAssociation returns false " << "for AssocType " << type << endl; return false; } //make sure there isn't already the same assoc AssociationWidgetListIt assoc_it( m_AssociationList ); AssociationWidget* assocwidget = 0; while((assocwidget=assoc_it.current())) { ++assoc_it; if( *pAssoc == *assocwidget ) // this is nuts. Paste operation wants to know if 'true' // for duplicate, but loadFromXMI needs 'false' value return (isPasteOperation? true: false); } m_AssociationList.append(pAssoc); FloatingTextWidget *ft[5] = { pAssoc->getNameWidget(), pAssoc->getRoleWidget(A), pAssoc->getRoleWidget(B), pAssoc->getMultiWidget(A), pAssoc->getMultiWidget(B) }; for (int i = 0; i < 5; i++) { FloatingTextWidget *flotxt = ft[i]; if (flotxt) { flotxt->updateComponentSize(); addWidget(flotxt); } } return true; } void UMLView::activateAfterLoad(bool bUseLog) { if (m_bActivated) return; if( bUseLog ) { beginPartialWidgetPaste(); } //now activate them all activate(); if( bUseLog ) { endPartialWidgetPaste(); } resizeCanvasToItems(); setZoom( getZoom() ); m_bActivated = true; } void UMLView::beginPartialWidgetPaste() { delete m_pIDChangesLog; m_pIDChangesLog = 0; m_pIDChangesLog = new IDChangeLog(); m_bPaste = true; } void UMLView::endPartialWidgetPaste() { delete m_pIDChangesLog; m_pIDChangesLog = 0; m_bPaste = false; } void UMLView::removeAssoc(AssociationWidget* pAssoc) { if(!pAssoc) return; emit sigAssociationRemoved(pAssoc); pAssoc->cleanup(); m_AssociationList.remove(pAssoc); // will delete our association m_pDoc->setModified(); } void UMLView::removeAssocInViewAndDoc(AssociationWidget* a) { // For umbrello 1.2, UMLAssociations can only be removed in two ways: // 1. Right click on the assocwidget in the view and select Delete // 2. Go to the Class Properties page, select Associations, right click // on the association and select Delete if(!a) return; if (a->getAssocType() == at_Containment) { UMLObject *objToBeMoved = a->getWidget(B)->getUMLObject(); if (objToBeMoved != NULL) { UMLListView *lv = UMLApp::app()->getListView(); lv->moveObject( objToBeMoved->getID(), Model_Utils::convert_OT_LVT(objToBeMoved), lv->theLogicalView() ); // UMLListView::moveObject() will delete the containment // AssociationWidget via UMLView::updateContainment(). } else { kDebug() << "removeAssocInViewAndDoc(containment): " << "objB is NULL" << endl; } } else { // Remove assoc in doc. m_pDoc->removeAssociation(a->getAssociation()); // Remove assoc in view. removeAssoc(a); } } /** Removes all the associations related to Widget */ void UMLView::removeAssociations(UMLWidget* Widget) { AssociationWidgetListIt assoc_it(m_AssociationList); AssociationWidget* assocwidget = 0; while((assocwidget=assoc_it.current())) { ++assoc_it; if(assocwidget->contains(Widget)) { removeAssoc(assocwidget); } } } void UMLView::selectAssociations(bool bSelect) { AssociationWidgetListIt assoc_it(m_AssociationList); AssociationWidget* assocwidget = 0; while((assocwidget=assoc_it.current())) { ++assoc_it; if(bSelect && assocwidget->getWidget(A) && assocwidget->getWidget(A)->getSelected() && assocwidget->getWidget(B) && assocwidget->getWidget(B)->getSelected() ) { assocwidget->setSelected(true); } else { assocwidget->setSelected(false); } }//end while } void UMLView::getWidgetAssocs(UMLObject* Obj, AssociationWidgetList & Associations) { if( ! Obj ) return; AssociationWidgetListIt assoc_it(m_AssociationList); AssociationWidget * assocwidget; while((assocwidget = assoc_it.current())) { if (assocwidget->getWidget(A)->getUMLObject() == Obj || assocwidget->getWidget(B)->getUMLObject() == Obj) Associations.append(assocwidget); ++assoc_it; }//end while } void UMLView::closeEvent ( TQCloseEvent * e ) { TQWidget::closeEvent(e); } void UMLView::removeAllAssociations() { //Remove All association widgets AssociationWidgetListIt assoc_it(m_AssociationList); AssociationWidget* assocwidget = 0; while((assocwidget=assoc_it.current())) { ++assoc_it; removeAssoc(assocwidget); } m_AssociationList.clear(); } void UMLView::removeAllWidgets() { // Remove widgets. UMLWidgetListIt it( m_WidgetList ); UMLWidget * temp = 0; while ( (temp = it.current()) != 0 ) { ++it; // I had to take this condition back in, else umbrello // crashes on exit. Still to be analyzed. --okellogg if( !( temp -> getBaseType() == wt_Text && ((FloatingTextWidget *)temp)-> getRole() != tr_Floating ) ) { removeWidget( temp ); } } m_WidgetList.clear(); } void UMLView::showDocumentation( UMLObject * object, bool overwrite ) { UMLApp::app() -> getDocWindow() -> showDocumentation( object, overwrite ); m_bChildDisplayedDoc = true; } void UMLView::showDocumentation( UMLWidget * widget, bool overwrite ) { UMLApp::app() -> getDocWindow() -> showDocumentation( widget, overwrite ); m_bChildDisplayedDoc = true; } void UMLView::showDocumentation( AssociationWidget * widget, bool overwrite ) { UMLApp::app() -> getDocWindow() -> showDocumentation( widget, overwrite ); m_bChildDisplayedDoc = true; } void UMLView::updateDocumentation( bool clear ) { UMLApp::app() -> getDocWindow() -> updateDocumentation( clear ); } void UMLView::updateContainment(UMLCanvasObject *self) { if (self == NULL) return; // See if the object has a widget representation in this view. // While we're at it, also see if the new parent has a widget here. UMLWidget *selfWidget = NULL, *newParentWidget = NULL; UMLPackage *newParent = self->getUMLPackage(); for (UMLWidgetListIt wit(m_WidgetList); wit.current(); ++wit) { UMLWidget *w = wit.current(); UMLObject *o = w->getUMLObject(); if (o == self) selfWidget = w; else if (newParent != NULL && o == newParent) newParentWidget = w; } if (selfWidget == NULL) return; // Remove possibly obsoleted containment association. for (AssociationWidgetListIt it(m_AssociationList); it.current(); ++it) { AssociationWidget *a = it.current(); if (a->getAssocType() != Uml::at_Containment) continue; // Container is at role A, containee at B. // We only look at association for which we are B. UMLWidget *wB = a->getWidget(B); UMLObject *roleBObj = wB->getUMLObject(); if (roleBObj != self) continue; UMLWidget *wA = a->getWidget(A); UMLObject *roleAObj = wA->getUMLObject(); if (roleAObj == newParent) { // Wow, all done. Great! return; } removeAssoc(a); // AutoDelete is true // It's okay to break out because there can only be a single // containing object. break; } if (newParentWidget == NULL) return; // Create the new containment association. AssociationWidget *a = new AssociationWidget(this, newParentWidget, Uml::at_Containment, selfWidget); a->calculateEndingPoints(); a->setActivated(true); m_AssociationList.append(a); } void UMLView::createAutoAssociations( UMLWidget * widget ) { if (widget == NULL || (m_Type != Uml::dt_Class && m_Type != Uml::dt_Component && m_Type != Uml::dt_Deployment && m_Type != Uml::dt_EntityRelationship)) return; // Recipe: // If this widget has an underlying UMLCanvasObject then // for each of the UMLCanvasObject's UMLAssociations // if umlassoc's "other" role has a widget representation on this view then // if the AssocWidget does not already exist then // if the assoc type is permitted in the current diagram type then // create the AssocWidget // end if // end if // end if // end loop // Do createAutoAttributeAssociations() // if this object is capable of containing nested objects then // for each of the object's containedObjects // if the containedObject has a widget representation on this view then // if the containedWidget is not physically located inside this widget // create the containment AssocWidget // end if // end if // end loop // end if // if the UMLCanvasObject has a parentPackage then // if the parentPackage has a widget representation on this view then // create the containment AssocWidget // end if // end if // end if UMLObject *tmpUmlObj = widget->getUMLObject(); if (tmpUmlObj == NULL) return; UMLCanvasObject *umlObj = dynamic_cast(tmpUmlObj); if (umlObj == NULL) return; const UMLAssociationList& umlAssocs = umlObj->getAssociations(); UMLAssociationListIt it(umlAssocs); UMLAssociation *assoc = NULL; Uml::IDType myID = umlObj->getID(); while ((assoc = it.current()) != NULL) { ++it; UMLCanvasObject *other = NULL; UMLObject *roleAObj = assoc->getObject(A); if (roleAObj == NULL) { kDebug() << "createAutoAssociations: roleA object is NULL at UMLAssoc " << ID2STR(assoc->getID()) << endl; continue; } UMLObject *roleBObj = assoc->getObject(B); if (roleBObj == NULL) { kDebug() << "createAutoAssociations: roleB object is NULL at UMLAssoc " << ID2STR(assoc->getID()) << endl; continue; } if (roleAObj->getID() == myID) { other = static_cast(roleBObj); } else if (roleBObj->getID() == myID) { other = static_cast(roleAObj); } else { kDebug() << "createAutoAssociations: Can't find own object " << ID2STR(myID) << " in UMLAssoc " << ID2STR(assoc->getID()) << endl; continue; } // Now that we have determined the "other" UMLObject, seek it in // this view's UMLWidgets. Uml::IDType otherID = other->getID(); UMLWidget *pOtherWidget; UMLWidgetListIt wit(m_WidgetList); while ((pOtherWidget = wit.current()) != NULL) { ++wit; if (pOtherWidget->getID() == otherID) break; } if (pOtherWidget == NULL) continue; // Both objects are represented in this view: // Assign widget roles as indicated by the UMLAssociation. UMLWidget *widgetA, *widgetB; if (myID == roleAObj->getID()) { widgetA = widget; widgetB = pOtherWidget; } else { widgetA = pOtherWidget; widgetB = widget; } // Check that the assocwidget does not already exist. Uml::Association_Type assocType = assoc->getAssocType(); AssociationWidget * assocwidget = findAssocWidget(assocType, widgetA, widgetB); if (assocwidget) { assocwidget->calculateEndingPoints(); // recompute assoc lines continue; } // Check that the assoc is allowed. if (!AssocRules::allowAssociation(assocType, widgetA, widgetB, false)) { kDebug() << "createAutoAssociations: not transferring assoc " << "of type " << assocType << endl; continue; } // Create the AssociationWidget. assocwidget = new AssociationWidget( this ); assocwidget->setWidget(widgetA, A); assocwidget->setWidget(widgetB, B); assocwidget->setAssocType(assocType); assocwidget->setUMLObject(assoc); // Call calculateEndingPoints() before setting the FloatingTexts // because their positions are computed according to the // assocwidget line positions. assocwidget->calculateEndingPoints(); assocwidget->syncToModel(); assocwidget->setActivated(true); if (! addAssociation(assocwidget)) delete assocwidget; } createAutoAttributeAssociations(widget); // if this object is capable of containing nested objects then Uml::Object_Type t = umlObj->getBaseType(); if (t == ot_Package || t == ot_Class || t == ot_Interface || t == ot_Component) { // for each of the object's containedObjects UMLPackage *umlPkg = static_cast(umlObj); UMLObjectList lst = umlPkg->containedObjects(); for (UMLObject *obj = lst.first(); obj; obj = lst.next()) { // if the containedObject has a widget representation on this view then Uml::IDType id = obj->getID(); for (UMLWidget *w = m_WidgetList.first(); w; w = m_WidgetList.next()) { if (w->getID() != id) continue; // if the containedWidget is not physically located inside this widget if (widget->rect().contains(w->rect())) continue; // create the containment AssocWidget AssociationWidget *a = new AssociationWidget(this, widget, at_Containment, w); a->calculateEndingPoints(); a->setActivated(true); if (! addAssociation(a)) delete a; } } } // if the UMLCanvasObject has a parentPackage then UMLPackage *parent = umlObj->getUMLPackage(); if (parent == NULL) return; // if the parentPackage has a widget representation on this view then Uml::IDType pkgID = parent->getID(); UMLWidget *pWidget; UMLWidgetListIt wit(m_WidgetList); while ((pWidget = wit.current()) != NULL) { ++wit; if (pWidget->getID() == pkgID) break; } if (pWidget == NULL || pWidget->rect().contains(widget->rect())) return; // create the containment AssocWidget AssociationWidget *a = new AssociationWidget(this, pWidget, at_Containment, widget); a->calculateEndingPoints(); a->setActivated(true); if (! addAssociation(a)) delete a; } void UMLView::createAutoAttributeAssociations(UMLWidget *widget) { if (widget == NULL || m_Type != Uml::dt_Class) return; // Pseudocode: // if the underlying model object is really a UMLClassifier then // for each of the UMLClassifier's UMLAttributes // if the attribute type has a widget representation on this view then // if the AssocWidget does not already exist then // if the current diagram type permits compositions then // create a composition AssocWidget // end if // end if // end if // if the attribute type is a Datatype then // if the Datatype is a reference (pointer) type then // if the referenced type has a widget representation on this view then // if the AssocWidget does not already exist then // if the current diagram type permits aggregations then // create an aggregation AssocWidget from the ClassifierWidget to the // widget of the referenced type // end if // end if // end if // end if // end if // end loop // end if // // Implementation: UMLObject *tmpUmlObj = widget->getUMLObject(); if (tmpUmlObj == NULL) return; // if the underlying model object is really a UMLClassifier then if (tmpUmlObj->getBaseType() == Uml::ot_Datatype) { UMLClassifier *dt = static_cast(tmpUmlObj); while (dt->originType() != NULL) { tmpUmlObj = dt->originType(); if (tmpUmlObj->getBaseType() != Uml::ot_Datatype) break; dt = static_cast(tmpUmlObj); } } if (tmpUmlObj->getBaseType() != Uml::ot_Class) return; UMLClassifier * klass = static_cast(tmpUmlObj); // for each of the UMLClassifier's UMLAttributes UMLAttributeList attrList = klass->getAttributeList(); for (UMLAttributeListIt ait(attrList); ait.current(); ++ait) { UMLAttribute *attr = ait.current(); createAutoAttributeAssociation(attr->getType(), attr, widget); /* * The following code from attachment 19935 of http://bugs.kde.org/140669 * creates Aggregation/Composition to the template parameters. * The current solution uses Dependency instead, see handling of template * instantiation at Import_Utils::createUMLObject(). UMLClassifierList templateList = attr->getTemplateParams(); for (UMLClassifierListIt it(templateList); it.current(); ++it) { createAutoAttributeAssociation(it,attr,widget); } */ } } void UMLView::createAutoAttributeAssociation(UMLClassifier *type, UMLAttribute *attr, UMLWidget *widget /*, UMLClassifier * klass*/) { if (type == NULL) { // kDebug() << "UMLView::createAutoAttributeAssociations(" // << klass->getName() << "): type is NULL for " // << "attribute " << attr->getName() << endl; return; } Uml::Association_Type assocType = Uml::at_Composition; UMLWidget *w = findWidget( type->getID() ); AssociationWidget *aw = NULL; // if the attribute type has a widget representation on this view if (w) { aw = findAssocWidget(widget, w, attr->getName()); if ( aw == NULL && // if the current diagram type permits compositions AssocRules::allowAssociation(assocType, widget, w, false) ) { // Create a composition AssocWidget, or, if the attribute type is // stereotyped <>, create a UniAssociation widget. if (type->getStereotype() == "CORBAInterface") assocType = at_UniAssociation; AssociationWidget *a = new AssociationWidget (this, widget, assocType, w, attr); a->calculateEndingPoints(); a->setVisibility(attr->getVisibility(), B); /* if (assocType == at_Aggregation || assocType == at_UniAssociation) a->setMulti("0..1", B); */ a->setRoleName(attr->getName(), B); a->setActivated(true); if (! addAssociation(a)) delete a; } } // if the attribute type is a Datatype then if (type->getBaseType() == ot_Datatype) { UMLClassifier *dt = static_cast(type); // if the Datatype is a reference (pointer) type if (dt->isReference()) { //Uml::Association_Type assocType = Uml::at_Composition; UMLClassifier *c = dt->originType(); UMLWidget *w = c ? findWidget( c->getID() ) : 0; // if the referenced type has a widget representation on this view if (w) { aw = findAssocWidget(widget, w, attr->getName()); if (aw == NULL && // if the current diagram type permits aggregations AssocRules::allowAssociation(at_Aggregation, widget, w, false)) { // create an aggregation AssocWidget from the ClassifierWidget // to the widget of the referenced type AssociationWidget *a = new AssociationWidget (this, widget, at_Aggregation, w, attr); a->calculateEndingPoints(); a->setVisibility(attr->getVisibility(), B); //a->setChangeability(true, B); a->setMulti("0..1", B); a->setRoleName(attr->getName(), B); a->setActivated(true); if (! addAssociation(a)) delete a; } } } } } void UMLView::findMaxBoundingRectangle(const FloatingTextWidget* ft, int& px, int& py, int& qx, int& qy) { if (ft == NULL || !ft->isVisible()) return; int x = ft -> getX(); int y = ft -> getY(); int x1 = x + ft -> getWidth() - 1; int y1 = y + ft -> getHeight() - 1; if (px == -1 || x < px) px = x; if (py == -1 || y < py) py = y; if (qx == -1 || x1 > qx) qx = x1; if (qy == -1 || y1 > qy) qy = y1; } void UMLView::copyAsImage(TQPixmap*& pix) { //get the smallest rect holding the diagram TQRect rect = getDiagramRect(); TQPixmap diagram( rect.width(), rect.height() ); //only draw what is selected m_bDrawSelectedOnly = true; selectAssociations(true); getDiagram(rect, diagram); //now get the selection cut int px = -1, py = -1, qx = -1, qy = -1; //first get the smallest rect holding the widgets for (UMLWidget* temp = m_SelectedList.first(); temp; temp = m_SelectedList.next()) { int x = temp -> getX(); int y = temp -> getY(); int x1 = x + temp -> width() - 1; int y1 = y + temp -> height() - 1; if(px == -1 || x < px) { px = x; } if(py == -1 || y < py) { py = y; } if(qx == -1 || x1 > qx) { qx = x1; } if(qy == -1 || y1 > qy) { qy = y1; } } //also take into account any text lines in assocs or messages AssociationWidget *a; AssociationWidgetListIt assoc_it(m_AssociationList); //get each type of associations //This needs to be reimplemented to increase the rectangle //if a part of any association is not included while ((a = assoc_it.current()) != NULL) { ++assoc_it; if (! a->getSelected()) continue; const FloatingTextWidget* multiA = const_cast(a->getMultiWidget(A)); const FloatingTextWidget* multiB = const_cast(a->getMultiWidget(B)); const FloatingTextWidget* roleA = const_cast(a->getRoleWidget(A)); const FloatingTextWidget* roleB = const_cast(a->getRoleWidget(B)); const FloatingTextWidget* changeA = const_cast(a->getChangeWidget(A)); const FloatingTextWidget* changeB = const_cast(a->getChangeWidget(B)); findMaxBoundingRectangle(multiA, px, py, qx, qy); findMaxBoundingRectangle(multiB, px, py, qx, qy); findMaxBoundingRectangle(roleA, px, py, qx, qy); findMaxBoundingRectangle(roleB, px, py, qx, qy); findMaxBoundingRectangle(changeA, px, py, qx, qy); findMaxBoundingRectangle(changeB, px, py, qx, qy); }//end while TQRect imageRect; //area with respect to getDiagramRect() //i.e. all widgets on the canvas. Was previously with //respect to whole canvas imageRect.setLeft( px - rect.left() ); imageRect.setTop( py - rect.top() ); imageRect.setRight( qx - rect.left() ); imageRect.setBottom( qy - rect.top() ); pix = new TQPixmap(imageRect.width(), imageRect.height()); bitBlt(pix, TQPoint(0, 0), &diagram, imageRect); m_bDrawSelectedOnly = false; } void UMLView::setMenu() { slotRemovePopupMenu(); ListPopupMenu::Menu_Type menu = ListPopupMenu::mt_Undefined; switch( getType() ) { case dt_Class: menu = ListPopupMenu::mt_On_Class_Diagram; break; case dt_UseCase: menu = ListPopupMenu::mt_On_UseCase_Diagram; break; case dt_Sequence: menu = ListPopupMenu::mt_On_Sequence_Diagram; break; case dt_Collaboration: menu = ListPopupMenu::mt_On_Collaboration_Diagram; break; case dt_State: menu = ListPopupMenu::mt_On_State_Diagram; break; case dt_Activity: menu = ListPopupMenu::mt_On_Activity_Diagram; break; case dt_Component: menu = ListPopupMenu::mt_On_Component_Diagram; break; case dt_Deployment: menu = ListPopupMenu::mt_On_Deployment_Diagram; break; case dt_EntityRelationship: menu = ListPopupMenu::mt_On_EntityRelationship_Diagram; break; default: kWarning() << "setMenu() called on unknown diagram type" << endl; menu = ListPopupMenu::mt_Undefined; break; }//end switch if( menu != ListPopupMenu::mt_Undefined ) { m_pMenu = new ListPopupMenu(this, menu, this); connect(m_pMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotMenuSelection(int))); m_pMenu->popup( mapToGlobal( contentsToViewport(worldMatrix().map(m_Pos)) ) ); } } void UMLView::slotRemovePopupMenu() { if(m_pMenu) { disconnect(m_pMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotMenuSelection(int))); delete m_pMenu; m_pMenu = 0; } } void UMLView::slotMenuSelection(int sel) { switch( (ListPopupMenu::Menu_Type)sel ) { case ListPopupMenu::mt_Undo: m_pDoc->loadUndoData(); break; case ListPopupMenu::mt_Redo: m_pDoc->loadRedoData(); break; case ListPopupMenu::mt_Clear: clearDiagram(); break; case ListPopupMenu::mt_Export_Image: m_pImageExporter->exportView(); break; case ListPopupMenu::mt_FloatText: { FloatingTextWidget* ft = new FloatingTextWidget(this); ft->changeTextDlg(); //if no text entered delete if(!FloatingTextWidget::isTextValid(ft->getText())) { delete ft; } else { ft->setID(UniqueID::gen()); setupNewWidget(ft); } } break; case ListPopupMenu::mt_UseCase: m_bCreateObject = true; Object_Factory::createUMLObject( ot_UseCase ); break; case ListPopupMenu::mt_Actor: m_bCreateObject = true; Object_Factory::createUMLObject( ot_Actor ); break; case ListPopupMenu::mt_Class: case ListPopupMenu::mt_Object: m_bCreateObject = true; Object_Factory::createUMLObject( ot_Class); break; case ListPopupMenu::mt_Package: m_bCreateObject = true; Object_Factory::createUMLObject(ot_Package); break; case ListPopupMenu::mt_Component: m_bCreateObject = true; Object_Factory::createUMLObject(ot_Component); break; case ListPopupMenu::mt_Node: m_bCreateObject = true; Object_Factory::createUMLObject(ot_Node); break; case ListPopupMenu::mt_Artifact: m_bCreateObject = true; Object_Factory::createUMLObject(ot_Artifact); break; case ListPopupMenu::mt_Interface: m_bCreateObject = true; Object_Factory::createUMLObject(ot_Interface); break; case ListPopupMenu::mt_Enum: m_bCreateObject = true; Object_Factory::createUMLObject(ot_Enum); break; case ListPopupMenu::mt_Entity: m_bCreateObject = true; Object_Factory::createUMLObject(ot_Entity); break; case ListPopupMenu::mt_Datatype: m_bCreateObject = true; Object_Factory::createUMLObject(ot_Datatype); break; case ListPopupMenu::mt_Cut: //FIXME make this work for diagram's right click menu if ( m_SelectedList.count() && UMLApp::app()->editCutCopy(true) ) { deleteSelection(); m_pDoc->setModified(true); } break; case ListPopupMenu::mt_Copy: //FIXME make this work for diagram's right click menu m_SelectedList.count() && UMLApp::app()->editCutCopy(true); break; case ListPopupMenu::mt_Paste: m_PastePoint = m_Pos; m_Pos.setX( 2000 ); m_Pos.setY( 2000 ); UMLApp::app()->slotEditPaste(); m_PastePoint.setX( 0 ); m_PastePoint.setY( 0 ); break; case ListPopupMenu::mt_Initial_State: { StateWidget* state = new StateWidget( this, StateWidget::Initial ); setupNewWidget( state ); } break; case ListPopupMenu::mt_End_State: { StateWidget* state = new StateWidget( this, StateWidget::End ); setupNewWidget( state ); } break; case ListPopupMenu::mt_State: { bool ok = false; TQString name = KInputDialog::getText( i18n("Enter State Name"), i18n("Enter the name of the new state:"), i18n("new state"), &ok, UMLApp::app() ); if ( ok ) { StateWidget* state = new StateWidget( this ); state->setName( name ); setupNewWidget( state ); } } break; case ListPopupMenu::mt_Initial_Activity: { ActivityWidget* activity = new ActivityWidget( this, ActivityWidget::Initial ); setupNewWidget(activity); } break; case ListPopupMenu::mt_End_Activity: { ActivityWidget* activity = new ActivityWidget( this, ActivityWidget::End ); setupNewWidget(activity); } break; case ListPopupMenu::mt_Branch: { ActivityWidget* activity = new ActivityWidget( this, ActivityWidget::Branch ); setupNewWidget(activity); } break; case ListPopupMenu::mt_Activity: { bool ok = false; TQString name = KInputDialog::getText( i18n("Enter Activity Name"), i18n("Enter the name of the new activity:"), i18n("new activity"), &ok, UMLApp::app() ); if ( ok ) { ActivityWidget* activity = new ActivityWidget( this, ActivityWidget::Normal ); activity->setName( name ); setupNewWidget(activity); } } break; case ListPopupMenu::mt_SnapToGrid: toggleSnapToGrid(); m_pDoc->setModified(); break; case ListPopupMenu::mt_ShowSnapGrid: toggleShowGrid(); m_pDoc->setModified(); break; case ListPopupMenu::mt_Properties: if (showPropDialog() == true) m_pDoc->setModified(); break; case ListPopupMenu::mt_Delete: m_pDoc->removeDiagram( getID() ); break; case ListPopupMenu::mt_Rename: { bool ok = false; TQString name = KInputDialog::getText( i18n("Enter Diagram Name"), i18n("Enter the new name of the diagram:"), getName(), &ok, UMLApp::app() ); if (ok) { setName(name); m_pDoc->signalDiagramRenamed(this); } } break; default: break; } } void UMLView::slotCutSuccessful() { if( m_bStartedCut ) { deleteSelection(); m_bStartedCut = false; } } void UMLView::slotShowView() { m_pDoc -> changeCurrentView( getID() ); } TQPoint UMLView::getPastePoint() { TQPoint point = m_PastePoint; point.setX( point.x() - m_Pos.x() ); point.setY( point.y() - m_Pos.y() ); return point; } void UMLView::resetPastePoint() { m_PastePoint = m_Pos; } int UMLView::snappedX (int x) { if (getSnapToGrid()) { int gridX = getSnapX(); int modX = x % gridX; x -= modX; if (modX >= gridX / 2) x += gridX; } return x; } int UMLView::snappedY (int y) { if (getSnapToGrid()) { int gridY = getSnapY(); int modY = y % gridY; y -= modY; if (modY >= gridY / 2) y += gridY; } return y; } bool UMLView::showPropDialog() { UMLViewDialog dlg( this, this ); if( dlg.exec() ) { return true; } return false; } TQFont UMLView::getFont() const { return m_Options.uiState.font; } void UMLView::setFont(TQFont font, bool changeAllWidgets /* = false */) { m_Options.uiState.font = font; if (!changeAllWidgets) return; for (UMLWidgetListIt wit(m_WidgetList); wit.current(); ++wit) { UMLWidget *w = wit.current(); w->setFont(font); } } void UMLView::setClassWidgetOptions( ClassOptionsPage * page ) { UMLWidget * pWidget = 0; UMLWidgetListIt wit( m_WidgetList ); while ( (pWidget = wit.current()) != 0 ) { ++wit; Uml::Widget_Type wt = pWidget->getBaseType(); if (wt == Uml::wt_Class || wt == Uml::wt_Interface) { page -> setWidget( static_cast(pWidget) ); page -> updateUMLWidget(); } } } void UMLView::checkSelections() { UMLWidget * pWA = 0, * pWB = 0, * pTemp = 0; //check messages for(pTemp=(UMLWidget *)m_SelectedList.first();pTemp;pTemp=(UMLWidget *)m_SelectedList.next()) { if( pTemp->getBaseType() == wt_Message && pTemp -> getSelected() ) { MessageWidget * pMessage = static_cast( pTemp ); pWA = pMessage -> getWidget(A); pWB = pMessage -> getWidget(B); if( !pWA -> getSelected() ) { pWA -> setSelectedFlag( true ); m_SelectedList.append( pWA ); } if( !pWB -> getSelected() ) { pWB -> setSelectedFlag( true ); m_SelectedList.append( pWB ); } }//end if }//end for //check Associations AssociationWidgetListIt it(m_AssociationList); AssociationWidget * pAssoc = 0; while((pAssoc = it.current())) { ++it; if( pAssoc -> getSelected() ) { pWA = pAssoc -> getWidget(A); pWB = pAssoc -> getWidget(B); if( !pWA -> getSelected() ) { pWA -> setSelectedFlag( true ); m_SelectedList.append( pWA ); } if( !pWB -> getSelected() ) { pWB -> setSelectedFlag( true ); m_SelectedList.append( pWB ); } }//end if }//end while } bool UMLView::checkUniqueSelection() { // if there are no selected items, we return true if (m_SelectedList.count() <= 0) return true; // get the first item and its base type UMLWidget * pTemp = (UMLWidget *) m_SelectedList.first(); Widget_Type tmpType = pTemp -> getBaseType(); // check all selected items, if they have the same BaseType for ( pTemp = (UMLWidget *) m_SelectedList.first(); pTemp; pTemp = (UMLWidget *) m_SelectedList.next() ) { if( pTemp->getBaseType() != tmpType) { return false; // the base types are different, the list is not unique } } // for ( through all selected items ) return true; // selected items are unique } void UMLView::clearDiagram() { if( KMessageBox::Continue == KMessageBox::warningContinueCancel( this, i18n("You are about to delete " "the entire diagram.\nAre you sure?"), i18n("Delete Diagram?"),KGuiItem( i18n("&Delete"), "edit-delete") ) ) { removeAllWidgets(); } } void UMLView::toggleSnapToGrid() { setSnapToGrid( !getSnapToGrid() ); } void UMLView::toggleSnapComponentSizeToGrid() { setSnapComponentSizeToGrid( !getSnapComponentSizeToGrid() ); } void UMLView::toggleShowGrid() { setShowSnapGrid( !getShowSnapGrid() ); } void UMLView::setSnapToGrid(bool bSnap) { m_bUseSnapToGrid = bSnap; emit sigSnapToGridToggled( getSnapToGrid() ); } void UMLView::setSnapComponentSizeToGrid(bool bSnap) { m_bUseSnapComponentSizeToGrid = bSnap; updateComponentSizes(); emit sigSnapComponentSizeToGridToggled( getSnapComponentSizeToGrid() ); } bool UMLView::getShowSnapGrid() const { return m_bShowSnapGrid; } void UMLView::setShowSnapGrid(bool bShow) { m_bShowSnapGrid = bShow; canvas()->setAllChanged(); emit sigShowGridToggled( getShowSnapGrid() ); } bool UMLView::getShowOpSig() const { return m_Options.classState.showOpSig; } void UMLView::setShowOpSig(bool bShowOpSig) { m_Options.classState.showOpSig = bShowOpSig; } void UMLView::setZoom(int zoom) { if (zoom < 10) { zoom = 10; } else if (zoom > 500) { zoom = 500; } TQWMatrix wm; wm.scale(zoom/100.0,zoom/100.0); setWorldMatrix(wm); m_nZoom = currentZoom(); resizeCanvasToItems(); } int UMLView::currentZoom() { return (int)(worldMatrix().m11()*100.0); } void UMLView::zoomIn() { TQWMatrix wm = worldMatrix(); wm.scale(1.5,1.5); // adjust zooming step here setZoom( (int)(wm.m11()*100.0) ); } void UMLView::zoomOut() { TQWMatrix wm = worldMatrix(); wm.scale(2.0/3.0, 2.0/3.0); //adjust zooming step here setZoom( (int)(wm.m11()*100.0) ); } void UMLView::fileLoaded() { setZoom( getZoom() ); resizeCanvasToItems(); } void UMLView::setCanvasSize(int width, int height) { setCanvasWidth(width); setCanvasHeight(height); canvas()->resize(width, height); } void UMLView::resizeCanvasToItems() { TQRect canvasSize = getDiagramRect(); int canvasWidth = canvasSize.right() + 5; int canvasHeight = canvasSize.bottom() + 5; //Find out the bottom right visible pixel and size to at least that int contentsX, contentsY; int contentsWMX, contentsWMY; viewportToContents(viewport()->width(), viewport()->height(), contentsX, contentsY); inverseWorldMatrix().map(contentsX, contentsY, &contentsWMX, &contentsWMY); if (canvasWidth < contentsWMX) { canvasWidth = contentsWMX; } if (canvasHeight < contentsWMY) { canvasHeight = contentsWMY; } setCanvasSize(canvasWidth, canvasHeight); } void UMLView::show() { TQWidget::show(); resizeCanvasToItems(); } void UMLView::updateComponentSizes() { // update sizes of all components UMLWidgetListIt it( m_WidgetList ); UMLWidget *obj; while ( (obj=(UMLWidget*)it.current()) != 0 ) { ++it; obj->updateComponentSize(); } } /** * Force the widget font metrics to be updated next time * the widgets are drawn. * This is necessary because the widget size might depend on the * font metrics and the font metrics might change for different * TQPainter, i.e. font metrics for Display font and Printer font are * usually different. * Call this when you change the TQPainter. */ void UMLView::forceUpdateWidgetFontMetrics(TQPainter * painter) { UMLWidgetListIt it( m_WidgetList ); UMLWidget *obj; while ((obj = it.current()) != 0 ) { ++it; obj->forceUpdateFontMetrics(painter); } } void UMLView::saveToXMI( TQDomDocument & qDoc, TQDomElement & qElement ) { TQDomElement viewElement = qDoc.createElement( "diagram" ); viewElement.setAttribute( "xmi.id", ID2STR(m_nID) ); viewElement.setAttribute( "name", getName() ); viewElement.setAttribute( "type", m_Type ); viewElement.setAttribute( "documentation", m_Documentation ); //optionstate uistate viewElement.setAttribute( "fillcolor", m_Options.uiState.fillColor.name() ); viewElement.setAttribute( "linecolor", m_Options.uiState.lineColor.name() ); viewElement.setAttribute( "linewidth", m_Options.uiState.lineWidth ); viewElement.setAttribute( "usefillcolor", m_Options.uiState.useFillColor ); viewElement.setAttribute( "font", m_Options.uiState.font.toString() ); //optionstate classstate viewElement.setAttribute( "showattsig", m_Options.classState.showAttSig ); viewElement.setAttribute( "showatts", m_Options.classState.showAtts); viewElement.setAttribute( "showopsig", m_Options.classState.showOpSig ); viewElement.setAttribute( "showops", m_Options.classState.showOps ); viewElement.setAttribute( "showpackage", m_Options.classState.showPackage ); viewElement.setAttribute( "showscope", m_Options.classState.showVisibility ); viewElement.setAttribute( "showstereotype", m_Options.classState.showStereoType ); //misc viewElement.setAttribute( "localid", ID2STR(m_nLocalID) ); viewElement.setAttribute( "showgrid", m_bShowSnapGrid ); viewElement.setAttribute( "snapgrid", m_bUseSnapToGrid ); viewElement.setAttribute( "snapcsgrid", m_bUseSnapComponentSizeToGrid ); viewElement.setAttribute( "snapx", m_nSnapX ); viewElement.setAttribute( "snapy", m_nSnapY ); viewElement.setAttribute( "zoom", m_nZoom ); viewElement.setAttribute( "canvasheight", m_nCanvasHeight ); viewElement.setAttribute( "canvaswidth", m_nCanvasWidth ); //now save all the widgets UMLWidget * widget = 0; UMLWidgetListIt w_it( m_WidgetList ); TQDomElement widgetElement = qDoc.createElement( "widgets" ); while( ( widget = w_it.current() ) ) { ++w_it; // Having an exception is bad I know, but gotta work with // system we are given. // We DONT want to record any text widgets which are belonging // to associations as they are recorded later in the "associations" // section when each owning association is dumped. -b.t. if (widget->getBaseType() != wt_Text || static_cast(widget)->getLink() == NULL) widget->saveToXMI( qDoc, widgetElement ); } viewElement.appendChild( widgetElement ); //now save the message widgets MessageWidgetListIt m_it( m_MessageList ); TQDomElement messageElement = qDoc.createElement( "messages" ); while( ( widget = m_it.current() ) ) { ++m_it; widget -> saveToXMI( qDoc, messageElement ); } viewElement.appendChild( messageElement ); //now save the associations TQDomElement assocElement = qDoc.createElement( "associations" ); if ( m_AssociationList.count() ) { // We guard against ( m_AssociationList.count() == 0 ) because // this code could be reached as follows: // ^ UMLView::saveToXMI() // ^ UMLDoc::saveToXMI() // ^ UMLDoc::addToUndoStack() // ^ UMLDoc::setModified() // ^ UMLDoc::createDiagram() // ^ UMLDoc::newDocument() // ^ UMLApp::newDocument() // ^ main() // AssociationWidgetListIt a_it( m_AssociationList ); AssociationWidget * assoc = 0; while( ( assoc = a_it.current() ) ) { ++a_it; assoc -> saveToXMI( qDoc, assocElement ); } // kDebug() << "UMLView::saveToXMI() saved " // << m_AssociationList.count() << " assocData." << endl; } viewElement.appendChild( assocElement ); qElement.appendChild( viewElement ); } bool UMLView::loadFromXMI( TQDomElement & qElement ) { TQString id = qElement.attribute( "xmi.id", "-1" ); m_nID = STR2ID(id); if( m_nID == Uml::id_None ) return false; setName( qElement.attribute( "name", "" ) ); TQString type = qElement.attribute( "type", "0" ); m_Documentation = qElement.attribute( "documentation", "" ); TQString localid = qElement.attribute( "localid", "0" ); //optionstate uistate TQString font = qElement.attribute( "font", "" ); if (!font.isEmpty()) { m_Options.uiState.font.fromString( font ); m_Options.uiState.font.setUnderline(false); } TQString fillcolor = qElement.attribute( "fillcolor", "" ); TQString linecolor = qElement.attribute( "linecolor", "" ); TQString linewidth = qElement.attribute( "linewidth", "" ); TQString usefillcolor = qElement.attribute( "usefillcolor", "0" ); m_Options.uiState.useFillColor = (bool)usefillcolor.toInt(); //optionstate classstate TQString temp = qElement.attribute( "showattsig", "0" ); m_Options.classState.showAttSig = (bool)temp.toInt(); temp = qElement.attribute( "showatts", "0" ); m_Options.classState.showAtts = (bool)temp.toInt(); temp = qElement.attribute( "showopsig", "0" ); m_Options.classState.showOpSig = (bool)temp.toInt(); temp = qElement.attribute( "showops", "0" ); m_Options.classState.showOps = (bool)temp.toInt(); temp = qElement.attribute( "showpackage", "0" ); m_Options.classState.showPackage = (bool)temp.toInt(); temp = qElement.attribute( "showscope", "0" ); m_Options.classState.showVisibility = (bool)temp.toInt(); temp = qElement.attribute( "showstereotype", "0" ); m_Options.classState.showStereoType = (bool)temp.toInt(); //misc TQString showgrid = qElement.attribute( "showgrid", "0" ); m_bShowSnapGrid = (bool)showgrid.toInt(); TQString snapgrid = qElement.attribute( "snapgrid", "0" ); m_bUseSnapToGrid = (bool)snapgrid.toInt(); TQString snapcsgrid = qElement.attribute( "snapcsgrid", "0" ); m_bUseSnapComponentSizeToGrid = (bool)snapcsgrid.toInt(); TQString snapx = qElement.attribute( "snapx", "10" ); m_nSnapX = snapx.toInt(); TQString snapy = qElement.attribute( "snapy", "10" ); m_nSnapY = snapy.toInt(); TQString zoom = qElement.attribute( "zoom", "100" ); m_nZoom = zoom.toInt(); TQString height = qElement.attribute( "canvasheight", TQString("%1").arg(UMLView::defaultCanvasSize) ); m_nCanvasHeight = height.toInt(); TQString width = qElement.attribute( "canvaswidth", TQString("%1").arg(UMLView::defaultCanvasSize) ); m_nCanvasWidth = width.toInt(); int nType = type.toInt(); if (nType == -1 || nType >= 400) { // Pre 1.5.5 numeric values // Values of "type" were changed in 1.5.5 to merge with Settings::Diagram switch (nType) { case 400: m_Type = Uml::dt_UseCase; break; case 401: m_Type = Uml::dt_Collaboration; break; case 402: m_Type = Uml::dt_Class; break; case 403: m_Type = Uml::dt_Sequence; break; case 404: m_Type = Uml::dt_State; break; case 405: m_Type = Uml::dt_Activity; break; case 406: m_Type = Uml::dt_Component; break; case 407: m_Type = Uml::dt_Deployment; break; case 408: m_Type = Uml::dt_EntityRelationship; break; default: m_Type = Uml::dt_Undefined; break; } } else { m_Type = (Uml::Diagram_Type)nType; } if( !fillcolor.isEmpty() ) m_Options.uiState.fillColor = TQColor( fillcolor ); if( !linecolor.isEmpty() ) m_Options.uiState.lineColor = TQColor( linecolor ); if( !linewidth.isEmpty() ) m_Options.uiState.lineWidth = linewidth.toInt(); m_nLocalID = STR2ID(localid); TQDomNode node = qElement.firstChild(); bool widgetsLoaded = false, messagesLoaded = false, associationsLoaded = false; while (!node.isNull()) { TQDomElement element = node.toElement(); if (!element.isNull()) { if (element.tagName() == "widgets") widgetsLoaded = loadWidgetsFromXMI( element ); else if (element.tagName() == "messages") messagesLoaded = loadMessagesFromXMI( element ); else if (element.tagName() == "associations") associationsLoaded = loadAssociationsFromXMI( element ); } node = node.nextSibling(); } if (!widgetsLoaded) { kWarning() << "failed umlview load on widgets" << endl; return false; } if (!messagesLoaded) { kWarning() << "failed umlview load on messages" << endl; return false; } if (!associationsLoaded) { kWarning() << "failed umlview load on associations" << endl; return false; } return true; } bool UMLView::loadWidgetsFromXMI( TQDomElement & qElement ) { UMLWidget* widget = 0; TQDomNode node = qElement.firstChild(); TQDomElement widgetElement = node.toElement(); while( !widgetElement.isNull() ) { widget = loadWidgetFromXMI(widgetElement); if (widget) { m_WidgetList.append( widget ); // In the interest of best-effort loading, in case of a // (widget == NULL) we still go on. // The individual widget's loadFromXMI method should // already have generated an error message to tell the // user that something went wrong. } node = widgetElement.nextSibling(); widgetElement = node.toElement(); } return true; } UMLWidget* UMLView::loadWidgetFromXMI(TQDomElement& widgetElement) { if ( !m_pDoc ) { kWarning() << "UMLView::loadWidgetFromXMI(): m_pDoc is NULL" << endl; return 0L; } TQString tag = widgetElement.tagName(); TQString idstr = widgetElement.attribute( "xmi.id", "-1" ); UMLWidget* widget = Widget_Factory::makeWidgetFromXMI(tag, idstr, this); if (widget == NULL) return NULL; if (!widget->loadFromXMI(widgetElement)) { widget->cleanup(); delete widget; return 0; } return widget; } bool UMLView::loadMessagesFromXMI( TQDomElement & qElement ) { MessageWidget * message = 0; TQDomNode node = qElement.firstChild(); TQDomElement messageElement = node.toElement(); while( !messageElement.isNull() ) { TQString tag = messageElement.tagName(); if (tag == "messagewidget" || tag == "UML:MessageWidget" ) { // for bkwd compatibility message = new MessageWidget(this, sequence_message_asynchronous, Uml::id_Reserved); if( !message -> loadFromXMI( messageElement ) ) { delete message; return false; } m_MessageList.append( message ); FloatingTextWidget *ft = message->getFloatingTextWidget(); if (ft) m_WidgetList.append( ft ); else if (message->getSequenceMessageType() != sequence_message_creation) kDebug() << "UMLView::loadMessagesFromXMI: ft is NULL" << " for message " << ID2STR(message->getID()) << endl; } node = messageElement.nextSibling(); messageElement = node.toElement(); } return true; } bool UMLView::loadAssociationsFromXMI( TQDomElement & qElement ) { TQDomNode node = qElement.firstChild(); TQDomElement assocElement = node.toElement(); int countr = 0; while( !assocElement.isNull() ) { TQString tag = assocElement.tagName(); if (tag == "assocwidget" || tag == "UML:AssocWidget") { // for bkwd compatibility countr++; AssociationWidget *assoc = new AssociationWidget(this); if( !assoc->loadFromXMI( assocElement ) ) { kError() << "couldn't loadFromXMI association widget:" << assoc << ", bad XMI file? Deleting from umlview." << endl; delete assoc; /* return false; Returning false here is a little harsh when the rest of the diagram might load okay. */ } else { if(!addAssociation(assoc, false)) { kError()<<"Couldnt addAssociation("<cleanup(); delete assoc; //return false; // soften error.. may not be that bad } } } node = assocElement.nextSibling(); assocElement = node.toElement(); } return true; } void UMLView::addObject(UMLObject *object) { m_bCreateObject = true; if (m_pDoc->addUMLObject(object)) m_pDoc->signalUMLObjectCreated(object); // m_bCreateObject is reset by slotObjectCreated() else m_bCreateObject = false; } bool UMLView::loadUisDiagramPresentation(TQDomElement & qElement) { for (TQDomNode node = qElement.firstChild(); !node.isNull(); node = node.nextSibling()) { TQDomElement elem = node.toElement(); TQString tag = elem.tagName(); if (! Uml::tagEq(tag, "Presentation")) { kError() << "ignoring unknown UisDiagramPresentation tag " << tag << endl; continue; } TQDomNode n = elem.firstChild(); TQDomElement e = n.toElement(); TQString idStr; int x = 0, y = 0, w = 0, h = 0; while (!e.isNull()) { tag = e.tagName(); kDebug() << "Presentation: tag = " << tag << endl; if (Uml::tagEq(tag, "Presentation.geometry")) { TQDomNode gnode = e.firstChild(); TQDomElement gelem = gnode.toElement(); TQString csv = gelem.text(); TQStringList dim = TQStringList::split(",", csv); x = dim[0].toInt(); y = dim[1].toInt(); w = dim[2].toInt(); h = dim[3].toInt(); } else if (Uml::tagEq(tag, "Presentation.style")) { // TBD } else if (Uml::tagEq(tag, "Presentation.model")) { TQDomNode mnode = e.firstChild(); TQDomElement melem = mnode.toElement(); idStr = melem.attribute("xmi.idref", ""); } else { kDebug() << "UMLView::uisLoadFromXMI: ignoring tag " << tag << endl; } n = n.nextSibling(); e = n.toElement(); } Uml::IDType id = STR2ID(idStr); UMLObject *o = m_pDoc->findObjectById(id); if (o == NULL) { kError() << "UMLView::uisLoadFromXMI: Cannot find object for id " << idStr << endl; } else { Uml::Object_Type ot = o->getBaseType(); kDebug() << "Create widget for model object of type " << ot << endl; UMLWidget *widget = NULL; switch (ot) { case Uml::ot_Class: widget = new ClassifierWidget(this, static_cast(o)); break; case Uml::ot_Association: { UMLAssociation *umla = static_cast(o); Uml::Association_Type at = umla->getAssocType(); UMLObject* objA = umla->getObject(Uml::A); UMLObject* objB = umla->getObject(Uml::B); if (objA == NULL || objB == NULL) { kError() << "intern err 1" << endl; return false; } UMLWidget *wA = findWidget(objA->getID()); UMLWidget *wB = findWidget(objB->getID()); if (wA != NULL && wB != NULL) { AssociationWidget *aw = new AssociationWidget(this, wA, at, wB, umla); aw->syncToModel(); m_AssociationList.append(aw); } else { kError() << "cannot create assocwidget from (" << wA << ", " << wB << ")" << endl; } break; } case Uml::ot_Role: { UMLRole *robj = static_cast(o); UMLAssociation *umla = robj->getParentAssociation(); // @todo properly display role names. // For now, in order to get the role names displayed // simply delete the participating diagram objects // and drag them from the list view to the diagram. break; } default: kError() << "UMLView::uisLoadFromXMI: " << "Cannot create widget of type " << ot << endl; } if (widget) { kDebug() << "Widget: x=" << x << ", y=" << y << ", w=" << w << ", h=" << h << endl; widget->setX(x); widget->setY(y); widget->setSize(w, h); m_WidgetList.append(widget); } } } return true; } bool UMLView::loadUISDiagram(TQDomElement & qElement) { TQString idStr = qElement.attribute( "xmi.id", "" ); if (idStr.isEmpty()) return false; m_nID = STR2ID(idStr); UMLListViewItem *ulvi = NULL; for (TQDomNode node = qElement.firstChild(); !node.isNull(); node = node.nextSibling()) { if (node.isComment()) continue; TQDomElement elem = node.toElement(); TQString tag = elem.tagName(); if (tag == "uisDiagramName") { setName( elem.text() ); if (ulvi) ulvi->setText( getName() ); } else if (tag == "uisDiagramStyle") { TQString diagramStyle = elem.text(); if (diagramStyle != "ClassDiagram") { kError() << "UMLView::uisLoadFromXMI: diagram style " << diagramStyle << " is not yet implemented" << endl; continue; } m_pDoc->setMainViewID(m_nID); m_Type = Uml::dt_Class; UMLListView *lv = UMLApp::app()->getListView(); ulvi = new UMLListViewItem( lv->theLogicalView(), getName(), Uml::lvt_Class_Diagram, m_nID ); } else if (tag == "uisDiagramPresentation") { loadUisDiagramPresentation(elem); } else if (tag != "uisToolName") { kDebug() << "UMLView::uisLoadFromXMI: ignoring tag " << tag << endl; } } return true; } #include "umlview.moc"