You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdesdk/umbrello/umbrello/umlview.cpp

3353 lines
113 KiB

/***************************************************************************
* *
* 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 <uml-devel@uml.sf.net> *
***************************************************************************/
// own header
#include "umlview.h"
// system includes
#include <climits>
#include <math.h>
// include files for TQt
#include <tqpixmap.h>
#include <tqpicture.h>
#include <tqprinter.h>
#include <tqpainter.h>
#include <tqstring.h>
#include <tqstringlist.h>
#include <tqobjectlist.h>
#include <tqobjectdict.h>
#include <tqdragobject.h>
#include <tqpaintdevicemetrics.h>
#include <tqfileinfo.h>
#include <tqptrlist.h>
#include <tqcolor.h>
#include <tqwmatrix.h>
#include <tqregexp.h>
//kde include files
#include <ktempfile.h>
#include <kio/netaccess.h>
#include <kmessagebox.h>
#include <kprinter.h>
#include <kcursor.h>
#include <kfiledialog.h>
#include <kinputdialog.h>
#include <klocale.h>
#include <kdebug.h>
// 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<ObjectWidget*>(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<NoteWidget*>(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<ObjectWidget*>(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<ObjectWidget *>( 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<ObjectWidget*>(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<MessageWidget*>(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<ObjectWidget*>(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<ClassifierWidget*>(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<UMLListViewItem*>( 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<UMLFolder*>(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<FloatingTextWidget*>(temp);
Text_Role t = ft -> getRole();
LinkWidget *lw = ft->getLink();
MessageWidget * mw = dynamic_cast<MessageWidget*>(lw);
if (mw) {
makeSelected( mw );
makeSelected( mw->getWidget(A) );
makeSelected( mw->getWidget(B) );
} else if (t != tr_Floating) {
AssociationWidget * a = dynamic_cast<AssociationWidget*>(lw);
if (a)
selectWidgetsOfAssoc( a );
}
} else if(temp -> getBaseType() == wt_Message) {
MessageWidget *mw = static_cast<MessageWidget*>(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<const FloatingTextWidget*>(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<const FloatingTextWidget*>(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<MessageWidget*>(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"<<endl;
return false;
}
int wX = pWidget -> 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<FloatingTextWidget*>(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<MessageWidget *>( 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<ObjectWidget*>(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<UMLCanvasObject*>(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<UMLCanvasObject*>(roleBObj);
} else if (roleBObj->getID() == myID) {
other = static_cast<UMLCanvasObject*>(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<UMLPackage*>(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<UMLClassifier*>(tmpUmlObj);
while (dt->originType() != NULL) {
tmpUmlObj = dt->originType();
if (tmpUmlObj->getBaseType() != Uml::ot_Datatype)
break;
dt = static_cast<UMLClassifier*>(tmpUmlObj);
}
}
if (tmpUmlObj->getBaseType() != Uml::ot_Class)
return;
UMLClassifier * klass = static_cast<UMLClassifier*>(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 <<CORBAInterface>>, 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<UMLClassifier*>(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<FloatingTextWidget*>(a->getMultiWidget(A));
const FloatingTextWidget* multiB = const_cast<FloatingTextWidget*>(a->getMultiWidget(B));
const FloatingTextWidget* roleA = const_cast<FloatingTextWidget*>(a->getRoleWidget(A));
const FloatingTextWidget* roleB = const_cast<FloatingTextWidget*>(a->getRoleWidget(B));
const FloatingTextWidget* changeA = const_cast<FloatingTextWidget*>(a->getChangeWidget(A));
const FloatingTextWidget* changeB = const_cast<FloatingTextWidget*>(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<ClassifierWidget *>(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<MessageWidget *>( 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"), "editdelete") ) ) {
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<FloatingTextWidget*>(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("<<assoc<<") to umlview, deleting."<<endl;
// assoc->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<UMLClassifier*>(o));
break;
case Uml::ot_Association:
{
UMLAssociation *umla = static_cast<UMLAssociation*>(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<UMLRole*>(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"