umbrello API Documentation

umlwidget.cpp

00001 /***************************************************************************
00002  *                                                                         *
00003  *   This program is free software; you can redistribute it and/or modify  *
00004  *   it under the terms of the GNU General Public License as published by  *
00005  *   the Free Software Foundation; either version 2 of the License, or     *
00006  *   (at your option) any later version.                                   *
00007  *                                                                         *
00008  *   copyright (C) 2002-2007                                               *
00009  *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
00010  ***************************************************************************/
00011 
00012 // own header file
00013 #include "umlwidget.h"
00014 // system includes
00015 #include <qpainter.h>
00016 #include <qcolor.h>
00017 #include <kdebug.h>
00018 #include <kcolordialog.h>
00019 #include <kfontdialog.h>
00020 #include <kmessagebox.h>
00021 // local includes
00022 #include "umlwidgetcontroller.h"
00023 #include "umlobject.h"
00024 #include "classifier.h"
00025 #include "uniqueid.h"
00026 #include "uml.h"
00027 #include "umldoc.h"
00028 #include "umlview.h"
00029 #include "umlclassifierlistitemlist.h"
00030 #include "codegenerator.h"
00031 #include "codegenerators/simplecodegenerator.h"
00032 #include "listpopupmenu.h"
00033 #include "associationwidget.h"
00034 #include "dialogs/settingsdlg.h"
00035 #include "codedocument.h"
00036 #include "floatingtextwidget.h"
00037 #include "docwindow.h"
00038 #include "dialogs/classpropdlg.h"
00039 #include "clipboard/idchangelog.h"
00040 
00041 using namespace Uml;
00042 
00043 
00044 UMLWidget::UMLWidget( UMLView * view, UMLObject * o, UMLWidgetController *widgetController /* = 0*/ )
00045         : WidgetBase(view), QCanvasRectangle( view->canvas() ),
00046         m_pMenu(0)
00047 {
00048     if (widgetController) {
00049         m_widgetController = widgetController;
00050     } else {
00051         m_widgetController = new UMLWidgetController(this);
00052     }
00053     init();
00054     m_pObject = o;
00055     if(m_pObject) {
00056         connect( m_pObject, SIGNAL(modified()), this, SLOT(updateWidget()) );
00057         m_nId = m_pObject->getID();
00058     }
00059 }
00060 
00061 UMLWidget::UMLWidget(UMLView * view, Uml::IDType id /* = Uml::id_None */, UMLWidgetController *widgetController /* = 0*/)
00062         : WidgetBase(view), QCanvasRectangle( view->canvas() ),
00063         m_pMenu(0)
00064 {
00065     if (widgetController) {
00066         m_widgetController = widgetController;
00067     } else {
00068         m_widgetController = new UMLWidgetController(this);
00069     }
00070     init();
00071     if (id == Uml::id_None)
00072         m_nId = UniqueID::gen();
00073     else
00074         m_nId = id;
00075 }
00076 
00077 UMLWidget::~UMLWidget() {
00078     //slotRemovePopupMenu();
00079     delete m_widgetController;
00080     cleanup();
00081 }
00082 
00083 UMLWidget& UMLWidget::operator=(const UMLWidget& other) {
00084     if (this == &other)
00085         return *this;
00086 
00087     // assign members loaded/saved
00088     m_bUseFillColour = other.m_bUseFillColour;
00089     m_nId = other.m_nId;
00090     m_Type = other.m_Type;
00091     setX( other.getX() );
00092     setY( other.getY() );
00093     m_Assocs = other.m_Assocs;
00094     m_Font = other.m_Font;
00095     QCanvasRectangle::setSize( other.width(), other.height() );
00096     m_bUsesDiagramFillColour = other.m_bUsesDiagramFillColour;
00097     m_bUsesDiagramLineColour = other.m_bUsesDiagramLineColour;
00098     m_bUsesDiagramLineWidth  = other.m_bUsesDiagramLineWidth;
00099     m_bUsesDiagramUseFillColour = other.m_bUsesDiagramUseFillColour;
00100     m_LineColour = other.m_LineColour;
00101     m_LineWidth  = other.m_LineWidth;
00102     m_FillColour = other.m_FillColour;
00103     m_bIsInstance = other.m_bIsInstance;
00104     m_instanceName = other.m_instanceName;
00105 
00106     // assign volatile (non-saved) members
00107     m_bSelected = other.m_bSelected;
00108     m_bStartMove = other.m_bStartMove;
00109     m_nPosX = other.m_nPosX;
00110     m_pObject = other.m_pObject;
00111     m_pView = other.m_pView;
00112     m_pMenu = other.m_pMenu;
00113     m_bResizable = other.m_bResizable;
00114     for (unsigned i = 0; i < FT_INVALID; i++)
00115         m_pFontMetrics[i] = other.m_pFontMetrics[i];
00116     m_bActivated = other.m_bActivated;
00117     m_bIgnoreSnapToGrid = other.m_bIgnoreSnapToGrid;
00118     m_bIgnoreSnapComponentSizeToGrid = other.m_bIgnoreSnapComponentSizeToGrid;
00119     return *this;
00120 }
00121 
00122 bool UMLWidget::operator==(const UMLWidget& other) {
00123     if( this == &other )
00124         return true;
00125 
00126     if(m_Type != other.m_Type) {
00127         return false;
00128     }
00129 
00130     if (getID() != other.getID())
00131         return false;
00132 
00133     /* Testing the associations is already an exaggeration, no?
00134        The type and ID should uniquely identify an UMLWidget.
00135      */
00136     if (m_Assocs.count() != other.m_Assocs.count()) {
00137         return false;
00138     }
00139 
00140     // if(getBaseType() != wt_Text) // DON'T do this for floatingtext widgets, an infinite loop will result
00141     // {
00142     AssociationWidgetListIt assoc_it( m_Assocs );
00143     AssociationWidgetListIt assoc_it2( other.m_Assocs );
00144     AssociationWidget * assoc = 0, *assoc2 = 0;
00145     while ( ((assoc=assoc_it.current()) != 0) &&  ((assoc2=assoc_it2.current()) != 0)) {
00146         ++assoc_it;
00147         ++assoc_it2;
00148         if(!(*assoc == *assoc2)) {
00149             return false;
00150         }
00151     }
00152     // }
00153     return true;
00154     // NOTE:  In the comparison tests we are going to do, we don't need these values.
00155     // They will actually stop things functioning correctly so if you change these, be aware of that.
00156     /*
00157     if(m_bUseFillColour != other.m_bUseFillColour)
00158         return false;
00159     if(m_nId != other.m_nId)
00160         return false;
00161     if( m_Font != other.m_Font )
00162         return false;
00163     if(m_nX  != other.m_nX)
00164         return false;
00165     if(m_nY != other.m_nY)
00166         return false;
00167      */
00168 }
00169 
00170 void UMLWidget::mouseMoveEvent(QMouseEvent* me) {
00171     m_widgetController->mouseMoveEvent(me);
00172 }
00173 
00174 void UMLWidget::mousePressEvent(QMouseEvent *me) {
00175     m_widgetController->mousePressEvent(me);
00176 }
00177 
00178 void UMLWidget::updateWidget()
00179 {
00180     updateComponentSize();
00181     adjustAssocs( getX(), getY() ); //adjust assoc lines.
00182     if (m_Type == Uml::wt_Class) {
00183         m_pView->createAutoAttributeAssociations(this);
00184     }
00185     if(isVisible())
00186         update();
00187 }
00188 
00189 QSize UMLWidget::calculateSize() {
00190     return QSize(20, 20);
00191 }
00192 
00193 void UMLWidget::constrain(int& width, int& height) {
00194     const QSize minSize = calculateSize();
00195     if (width < minSize.width())
00196         width = minSize.width();
00197     if (height < minSize.height())
00198         height = minSize.height();
00199 }
00200 
00201 void UMLWidget::mouseReleaseEvent(QMouseEvent *me) {
00202     m_widgetController->mouseReleaseEvent(me);
00203 }
00204 
00205 void UMLWidget::init() {
00206     m_nId = Uml::id_None;
00207     m_bIsInstance = false;
00208     if (m_pView) {
00209         m_bUseFillColour = true;
00210         m_bUsesDiagramFillColour = true;
00211         m_bUsesDiagramUseFillColour = true;
00212         const Settings::OptionState& optionState = m_pView->getOptionState();
00213         m_FillColour = optionState.uiState.fillColor;
00214         m_Font       = optionState.uiState.font;
00215         m_bShowStereotype = optionState.classState.showStereoType;
00216     } else {
00217         kError() << "UMLWidget::init: SERIOUS PROBLEM - m_pView is NULL" << endl;
00218         m_bUseFillColour = false;
00219         m_bUsesDiagramFillColour = false;
00220         m_bUsesDiagramUseFillColour = false;
00221         m_bShowStereotype = false;
00222     }
00223 
00224     for (int i = 0; i < (int)FT_INVALID; ++i)
00225         m_pFontMetrics[(UMLWidget::FontType)i] = 0;
00226 
00227     m_bResizable = true;
00228 
00229     m_bSelected = false;
00230     m_bStartMove = false;
00231     m_bActivated = false;
00232     m_bIgnoreSnapToGrid = false;
00233     m_bIgnoreSnapComponentSizeToGrid = false;
00234     m_pMenu = 0;
00235     m_pDoc = UMLApp::app()->getDocument();
00236     m_nPosX = 0;
00237     connect( m_pView, SIGNAL( sigRemovePopupMenu() ), this, SLOT( slotRemovePopupMenu() ) );
00238     connect( m_pView, SIGNAL( sigClearAllSelected() ), this, SLOT( slotClearAllSelected() ) );
00239 
00240     connect( m_pView, SIGNAL(sigColorChanged(Uml::IDType)), this, SLOT(slotColorChanged(Uml::IDType)));
00241     connect( m_pView, SIGNAL(sigLineWidthChanged(Uml::IDType)), this, SLOT(slotLineWidthChanged(Uml::IDType)));
00242 
00243 
00244     // connect( m_pView, SIGNAL(sigColorChanged(int)), this, SLOT(slotColorChanged(int)));
00245     m_pObject = NULL;
00246     setZ(m_origZ = 2);  // default for most widgets
00247 }
00248 
00249 void UMLWidget::slotMenuSelection(int sel) {
00250     QFont font;
00251     QColor newColour;
00252     const Uml::Widget_Type wt = m_Type;
00253     UMLWidget* widget = 0; // use for select the first object properties (fill, line color)
00254 
00255     switch(sel) {
00256     case ListPopupMenu::mt_Rename:
00257         m_pDoc -> renameUMLObject(m_pObject);
00258         // adjustAssocs( getX(), getY() );//adjust assoc lines
00259         break;
00260 
00261     case ListPopupMenu::mt_Delete:
00262         //remove self from diagram
00263         m_pView -> removeWidget(this);
00264         break;
00265 
00266     //UMLWidgetController::doMouseDoubleClick relies on this implementation
00267     case ListPopupMenu::mt_Properties:
00268         if (wt == wt_Actor || wt == wt_UseCase ||
00269                 wt == wt_Package || wt == wt_Interface || wt == wt_Datatype ||
00270                 wt == wt_Component || wt == wt_Artifact ||
00271                 wt == wt_Node || wt == wt_Enum || wt == wt_Entity ||
00272                 (wt == wt_Class && m_pView -> getType() == dt_Class)) {
00273             showProperties();
00274         } else if (wt == wt_Object) {
00275             m_pObject->showProperties();
00276         } else {
00277             kWarning() << "making properties dialog for unknown widget type" << endl;
00278         }
00279         // adjustAssocs( getX(), getY() );//adjust assoc lines
00280         break;
00281 
00282     case ListPopupMenu::mt_Line_Color:
00283     case ListPopupMenu::mt_Line_Color_Selection:
00284         widget = m_pView->getFirstMultiSelectedWidget();
00285         if (widget) { newColour = widget->getLineColor(); }
00286         if( KColorDialog::getColor(newColour) ) {
00287             m_pView -> selectionSetLineColor( newColour );
00288             m_pDoc -> setModified(true);
00289         }
00290         break;
00291 
00292     case ListPopupMenu::mt_Fill_Color:
00293     case ListPopupMenu::mt_Fill_Color_Selection:
00294         widget = m_pView->getFirstMultiSelectedWidget();
00295         if (widget) { newColour = widget->getFillColour(); }
00296         if ( KColorDialog::getColor(newColour) ) {
00297             m_pView -> selectionSetFillColor( newColour );
00298             m_pDoc -> setModified(true);
00299         }
00300         break;
00301 
00302     case ListPopupMenu::mt_Use_Fill_Color:
00303         m_bUseFillColour = !m_bUseFillColour;
00304         m_bUsesDiagramUseFillColour = false;
00305         m_pView->selectionUseFillColor( m_bUseFillColour );
00306         break;
00307     case ListPopupMenu::mt_Show_Attributes_Selection:
00308     case ListPopupMenu::mt_Show_Operations_Selection:
00309     case ListPopupMenu::mt_Visibility_Selection:
00310     case ListPopupMenu::mt_DrawAsCircle_Selection:
00311     case ListPopupMenu::mt_Show_Operation_Signature_Selection:
00312     case ListPopupMenu::mt_Show_Attribute_Signature_Selection:
00313     case ListPopupMenu::mt_Show_Packages_Selection:
00314     case ListPopupMenu::mt_Show_Stereotypes_Selection:
00315     case ListPopupMenu::mt_Show_Public_Only_Selection:
00316         m_pView->selectionToggleShow(sel);
00317         m_pDoc->setModified(true);
00318         break;
00319 
00320     case ListPopupMenu::mt_ViewCode: {
00321             UMLClassifier *c = dynamic_cast<UMLClassifier*>(m_pObject);
00322             if(c)
00323             {
00324                 UMLApp::app()->viewCodeDocument(c);
00325             }
00326             break;
00327         }
00328 
00329     case ListPopupMenu::mt_Delete_Selection:
00330         m_pView -> deleteSelection();
00331         break;
00332 
00333     case ListPopupMenu::mt_Change_Font:
00334         font = getFont();
00335         if( KFontDialog::getFont( font, false, m_pView ) )
00336         {
00337             setFont( font );
00338             m_pDoc->setModified(true);
00339         }
00340         break;
00341 
00342     case ListPopupMenu::mt_Change_Font_Selection:
00343         font = getFont();
00344         if( KFontDialog::getFont( font, false, m_pView ) )
00345         {
00346             m_pView -> selectionSetFont( font );
00347             m_pDoc->setModified(true);
00348         }
00349         break;
00350 
00351     case ListPopupMenu::mt_Cut:
00352         m_pView -> setStartedCut();
00353         UMLApp::app() -> slotEditCut();
00354         break;
00355 
00356     case ListPopupMenu::mt_Copy:
00357         UMLApp::app() -> slotEditCopy();
00358         break;
00359 
00360     case ListPopupMenu::mt_Paste:
00361         UMLApp::app() -> slotEditPaste();
00362         break;
00363 
00364     case ListPopupMenu::mt_Refactoring:
00365         //check if we are operating on a classifier, or some other kind of UMLObject
00366         if(dynamic_cast<UMLClassifier*>(m_pObject))
00367         {
00368             UMLApp::app()->refactor(static_cast<UMLClassifier*>(m_pObject));
00369         }
00370         break;
00371 
00372     case ListPopupMenu::mt_Clone:
00373         // In principle we clone all the uml objects.
00374         {
00375             UMLObject *pClone = m_pObject->clone();
00376             m_pView->addObject(pClone);
00377         }
00378         break;
00379 
00380     case ListPopupMenu::mt_Rename_MultiA:
00381     case ListPopupMenu::mt_Rename_MultiB:
00382     case ListPopupMenu::mt_Rename_Name:
00383     case ListPopupMenu::mt_Rename_RoleAName:
00384     case ListPopupMenu::mt_Rename_RoleBName:
00385         {
00386             FloatingTextWidget *ft = static_cast<FloatingTextWidget*>(this);
00387             ft->handleRename();
00388             break;
00389         }
00390     }
00391 }
00392 
00393 void UMLWidget::slotWidgetMoved(Uml::IDType /*id*/) {}
00394 
00395 void UMLWidget::slotColorChanged(Uml::IDType viewID) {
00396     //only change if on the diagram concerned
00397     if(m_pView->getID() != viewID) {
00398         return;
00399     }
00400     if ( m_bUsesDiagramFillColour ) {
00401         m_FillColour = m_pView->getFillColor();
00402     }
00403     if ( m_bUsesDiagramLineColour ) {
00404         m_LineColour = m_pView->getLineColor();
00405     }
00406     if ( m_bUsesDiagramUseFillColour ) {
00407         m_bUseFillColour = m_pView->getUseFillColor();
00408     }
00409     update();
00410 }
00411 
00412 void UMLWidget::slotLineWidthChanged(Uml::IDType viewID) {
00413     //only change if on the diagram concerned
00414     if(m_pView->getID() != viewID) {
00415         return;
00416     }
00417     if ( m_bUsesDiagramLineWidth ) {
00418         m_LineWidth = m_pView->getLineWidth();
00419     }
00420     update();
00421 }
00422 
00423 void UMLWidget::mouseDoubleClickEvent( QMouseEvent * me ) {
00424     m_widgetController->mouseDoubleClickEvent(me);
00425 }
00426 
00427 void UMLWidget::setUseFillColour(bool fc) {
00428     m_bUseFillColour = fc;
00429     m_bUsesDiagramUseFillColour = false;
00430     update();
00431 }
00432 
00433 void UMLWidget::setLineColor(const QColor &colour) {
00434     WidgetBase::setLineColor(colour);
00435     update();
00436 }
00437 
00438 void UMLWidget::setLineWidth(uint width) {
00439     WidgetBase::setLineWidth(width);
00440     update();
00441 }
00442 
00443 void UMLWidget::setFillColour(const QColor &colour) {
00444     m_FillColour = colour;
00445     m_bUsesDiagramFillColour = false;
00446     update();
00447 }
00448 
00449 void UMLWidget::drawSelected(QPainter * p, int offsetX, int offsetY) {
00450     int w = width();
00451     int h = height();
00452     int s = 4;
00453     QBrush brush(blue);
00454     p -> fillRect(offsetX, offsetY, s,  s, brush);
00455     p -> fillRect(offsetX, offsetY + h - s, s, s, brush);
00456     p -> fillRect(offsetX + w - s, offsetY, s, s, brush);
00457 
00458     // Draw the resize anchor in the lower right corner.
00459     if (m_bResizable) {
00460         brush.setColor(Qt::red);
00461         const int right = offsetX + w;
00462         const int bottom = offsetY + h;
00463         p->drawLine(right - s, offsetY + h - 1, offsetX + w - 1, offsetY + h - s);
00464         p->drawLine(right - (s*2), bottom - 1, right - 1, bottom - (s*2) );
00465         p->drawLine(right - (s*3), bottom - 1, right - 1, bottom - (s*3) );
00466      } else {
00467          p->fillRect(offsetX + w - s, offsetY + h - s, s, s, brush);
00468      }
00469 }
00470 
00471 bool UMLWidget::activate(IDChangeLog* /*ChangeLog  = 0 */) {
00472     if (widgetHasUMLObject(m_Type) && m_pObject == NULL) {
00473         m_pObject = m_pDoc->findObjectById(m_nId);
00474         if (m_pObject == NULL) {
00475             kError() << "UMLWidget::activate: cannot find UMLObject with id="
00476                 << ID2STR(m_nId) << endl;
00477             return false;
00478         }
00479     }
00480     setFont(m_Font);
00481     setSize(getWidth(), getHeight());
00482     m_bActivated = true;
00483     updateComponentSize();
00484     if (m_pView->getPaste()) {
00485         FloatingTextWidget * ft = 0;
00486         QPoint point = m_pView -> getPastePoint();
00487         int x = point.x() + getX();
00488         int y = point.y() + getY();
00489         x = x < 0?0:x;
00490         y = y < 0?0:y;
00491         if( m_pView -> getType() == dt_Sequence ) {
00492             switch( getBaseType() ) {
00493             case wt_Object:
00494             case wt_Message:
00495                 setY( getY() );
00496                 setX( x );
00497                 break;
00498 
00499             case wt_Text:
00500                 ft = static_cast<FloatingTextWidget *>( this );
00501                 if (ft->getRole() == tr_Seq_Message) {
00502                     setX( x );
00503                     setY( getY() );
00504                 } else {
00505                     setX( getX() );
00506                     setY( getY() );
00507                 }
00508                 break;
00509 
00510             default:
00511                 setY( y );
00512                 break;
00513             }//end switch base type
00514         }//end if sequence
00515         else {
00516             setX( x );
00517             setY( y );
00518         }
00519     }//end if pastepoint
00520     else {
00521         setX( getX() );
00522         setY( getY() );
00523     }
00524     if ( m_pView -> getPaste() )
00525         m_pView -> createAutoAssociations( this );
00526     updateComponentSize();
00527     return true;
00528 }
00529 
00531 bool UMLWidget::isActivated() {
00532     return m_bActivated;
00533 }
00534 
00535 void UMLWidget::setActivated(bool Active /*=true*/) {
00536     m_bActivated = Active;
00537 }
00538 
00539 void UMLWidget::addAssoc(AssociationWidget* pAssoc) {
00540     if (pAssoc && !m_Assocs.contains(pAssoc)) {
00541         m_Assocs.append(pAssoc);
00542     }
00543 }
00544 
00545 void UMLWidget::removeAssoc(AssociationWidget* pAssoc) {
00546     if(pAssoc) {
00547         m_Assocs.remove(pAssoc);
00548     }
00549 }
00550 
00551 void UMLWidget::adjustAssocs(int x, int y)
00552 {
00553     // 2004-04-30: Achim Spangler
00554     // don't adjust Assocs on file load, as
00555     // the original positions, which are stored in XMI
00556     // should be reproduced exactly
00557     // ( don't try to reposition assocs as long
00558     //   as file is only partly loaded -> reposition
00559     //   could be misguided )
00561     if ( m_pDoc->loading() ) {
00562         // don't recalculate the assocs during load of XMI
00563         // -> return immediately without action
00564         return;
00565     }
00566     AssociationWidgetListIt assoc_it(m_Assocs);
00567     AssociationWidget* assocwidget = 0;
00568     while ((assocwidget = assoc_it.current())) {
00569         ++assoc_it;
00570         assocwidget->saveIdealTextPositions();
00571     }
00572     assoc_it.toFirst();
00573     while ((assocwidget = assoc_it.current())) {
00574         ++assoc_it;
00575         assocwidget->widgetMoved(this, x, y);
00576     }
00577 }
00578 
00579 void UMLWidget::adjustUnselectedAssocs(int x, int y)
00580 {
00581     AssociationWidgetListIt assoc_it(m_Assocs);
00582     AssociationWidget* assocwidget = 0;
00583     while ((assocwidget = assoc_it.current())) {
00584         ++assoc_it;
00585         if(!assocwidget->getSelected())
00586             assocwidget->saveIdealTextPositions();
00587     }
00588     assoc_it.toFirst();
00589     while ((assocwidget = assoc_it.current())) {
00590         ++assoc_it;
00591         if(!assocwidget->getSelected())
00592             assocwidget->widgetMoved(this, x, y);
00593     }
00594 }
00595 
00596 void UMLWidget::showProperties() {
00597     // will already be selected so make sure docWindow updates the doc
00598     // back it the widget
00599     DocWindow *docwindow = UMLApp::app()->getDocWindow();
00600     docwindow->updateDocumentation( false );
00601     ClassPropDlg *dlg = new ClassPropDlg((QWidget*)UMLApp::app(), this);
00602 
00603     if (dlg->exec()) {
00604         docwindow->showDocumentation( getUMLObject() , true );
00605         m_pDoc->setModified(true);
00606     }
00607     dlg->close(true); //wipe from memory
00608 }
00609 
00610 void UMLWidget::startPopupMenu( const QPoint &At) {
00611     slotRemovePopupMenu();
00612 
00613     //if in a multi- selection to a specific m_pMenu for that
00614     // NEW: ask UMLView to count ONLY the widgets and not their floatingtextwidgets
00615     int count = m_pView->getSelectCount(true);
00616     //a MessageWidget when selected will select its text widget and vice versa
00617     //so take that into account for popup menu.
00618 
00619     // determine multi state
00620     bool multi = (m_bSelected && count > 1);
00621 
00622     // if multiple selected items have the same type
00623     bool unique = false;
00624 
00625     // if multiple items are selected, we have to check if they all have the same
00626     // base type
00627     if (multi == true)
00628         unique = m_pView -> checkUniqueSelection();
00629 
00630     // create the right click context menu
00631     m_pMenu = new ListPopupMenu(m_pView, this, multi, unique);
00632 
00633     // disable the "view code" menu for simple code generators
00634     CodeGenerator * currentCG = UMLApp::app()->getGenerator();
00635     if(currentCG && dynamic_cast<SimpleCodeGenerator*>(currentCG))
00636         m_pMenu->setItemEnabled(ListPopupMenu::mt_ViewCode, false);
00637 
00638     m_pMenu->popup(At);
00639 
00640     connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
00641 }
00642 
00643 void UMLWidget::slotRemovePopupMenu() {
00644     if(m_pMenu) {
00645         disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
00646         delete m_pMenu;
00647         m_pMenu = 0;
00648     }
00649 }
00650 
00651 int UMLWidget::onWidget(const QPoint & p) {
00652     const int w = width();
00653     const int h = height();
00654     const int left = getX();
00655     const int right = left + w;
00656     const int top = getY();
00657     const int bottom = top + h;
00658     if (p.x() < left || p.x() > right ||
00659         p.y() < top || p.y() > bottom)   // Qt coord.sys. origin in top left corner
00660         return 0;
00661     return (w + h) / 2;
00662 }
00663 
00664 void UMLWidget::moveBy(int dx, int dy) {
00665     int newX = getX() + dx;
00666     int newY = getY() + dy;
00667     setX(newX);
00668     setY(newY);
00669     adjustAssocs(newX, newY);
00670 }
00671 
00672 void UMLWidget::setPen(QPainter & p) {
00673     p.setPen( QPen(m_LineColour, m_LineWidth) );
00674 }
00675 
00676 void UMLWidget::drawShape(QPainter &p ) {
00677     draw( p, getX(), getY() );
00678 }
00679 
00680 void UMLWidget::setSelected(bool _select) {
00681     const Uml::Widget_Type wt = m_Type;
00682     if( _select ) {
00683         if( m_pView -> getSelectCount() == 0 ) {
00684             if ( widgetHasUMLObject(wt) ) {
00685                 m_pView->showDocumentation(m_pObject, false);
00686             } else {
00687                 m_pView->showDocumentation(this, false);
00688             }
00689         }//end if
00690         /* if (wt != wt_Text && wt != wt_Box) {
00691             setZ(9);//keep text on top and boxes behind so don't touch Z value
00692         } */
00693     } else {
00694         /* if (wt != wt_Text && wt != wt_Box) {
00695             setZ(m_origZ);
00696         } */
00697         if( m_bSelected )
00698             m_pView -> updateDocumentation( true );
00699     }
00700     m_bSelected = _select;
00701 
00702     const QPoint pos(getX(), getY());
00703     UMLWidget *bkgnd = m_pView->getWidgetAt(pos);
00704     if (bkgnd && bkgnd != this && _select) {
00705         kDebug() << "UMLWidget::setSelected: setting Z to "
00706             << bkgnd->getZ() + 1 << ", SelectState: " << _select << endl;
00707         setZ( bkgnd->getZ() + 1 );
00708     } else {
00709         setZ( m_origZ );
00710     }
00711 
00712     update();
00713 
00714     /* selection changed, we have to make sure the copy and paste items
00715      * are correctly enabled/disabled */
00716     UMLApp::app()->slotCopyChanged();
00717 }
00718 
00719 void UMLWidget::slotClearAllSelected()
00720 {
00721     setSelected( false );
00722 }
00723 
00724 void UMLWidget::setView(UMLView * v) {
00725     //remove signals from old view - was probably 0 anyway
00726     disconnect( m_pView, SIGNAL( sigRemovePopupMenu() ), this, SLOT( slotRemovePopupMenu() ) );
00727     disconnect( m_pView, SIGNAL( sigClearAllSelected() ), this, SLOT( slotClearAllSelected() ) );
00728     disconnect( m_pView, SIGNAL(sigColorChanged(Uml::IDType)), this, SLOT(slotColorChanged(Uml::IDType)));
00729     disconnect( m_pView, SIGNAL(sigLineWidthChanged(Uml::IDType)), this, SLOT(slotLineWidthChanged(Uml::IDType)));
00730     m_pView = v;
00731     connect( m_pView, SIGNAL( sigRemovePopupMenu() ), this, SLOT( slotRemovePopupMenu() ) );
00732     connect( m_pView, SIGNAL( sigClearAllSelected() ), this, SLOT( slotClearAllSelected() ) );
00733     connect( m_pView, SIGNAL(sigColorChanged(Uml::IDType)), this, SLOT(slotColorChanged(Uml::IDType)));
00734     connect( m_pView, SIGNAL(sigLineWidthChanged(Uml::IDType)), this, SLOT(slotLineWidthChanged(Uml::IDType)));
00735 }
00736 
00737 void UMLWidget::setX( int x ) {
00738     if (!m_bIgnoreSnapToGrid) {
00739         x = m_pView->snappedX(x);
00740     }
00741     QCanvasItem::setX( (double)x );
00742 }
00743 
00744 void UMLWidget::setY( int y ) {
00745     if (!m_bIgnoreSnapToGrid){
00746         y = m_pView->snappedX(y);
00747     }
00748     QCanvasItem::setY( (double)y );
00749 }
00750 
00751 void UMLWidget::setZ(int z) {
00752     m_origZ = getZ();
00753     QCanvasItem::setZ(z);
00754 }
00755 
00756 void UMLWidget::setName(const QString &strName) {
00757     if (m_pObject)
00758         m_pObject->setName(strName);
00759     else
00760         m_Text = strName;
00761     updateComponentSize();
00762     adjustAssocs( getX(), getY() );
00763 }
00764 
00765 QString UMLWidget::getName() const {
00766     if (m_pObject)
00767         return m_pObject->getName();
00768     return m_Text;
00769 }
00770 
00771 void UMLWidget::cleanup() {
00772 }
00773 
00774 void UMLWidget::slotSnapToGrid( ) {
00775     setX( getX() );
00776     setY( getY() );
00777 }
00778 
00779 bool UMLWidget::widgetHasUMLObject(Uml::Widget_Type type) {
00780     if (type == wt_Actor ||
00781             type == wt_UseCase ||
00782             type == wt_Class ||
00783             type == wt_Interface ||
00784             type == wt_Enum ||
00785             type == wt_Datatype ||
00786             type == wt_Package ||
00787             type == wt_Component ||
00788             type == wt_Node ||
00789             type == wt_Artifact ||
00790             type == wt_Object) {
00791         return true;
00792     } else {
00793         return false;
00794     }
00795 }
00796 
00797 void UMLWidget::setIgnoreSnapToGrid(bool to) {
00798     m_bIgnoreSnapToGrid = to;
00799 }
00800 
00801 bool UMLWidget::getIgnoreSnapToGrid() const {
00802     return m_bIgnoreSnapToGrid;
00803 }
00804 
00805 void UMLWidget::setSize(int width,int height) {
00806     // snap to the next larger size that is a multiple of the grid
00807     if (!m_bIgnoreSnapComponentSizeToGrid
00808             && m_pView -> getSnapComponentSizeToGrid() )
00809     {
00810         // integer divisions
00811         int numX = width / m_pView->getSnapX();
00812         int numY = height / m_pView->getSnapY();
00813         // snap to the next larger valid value
00814         if (width > numX * m_pView->getSnapX())
00815             width = (numX + 1) * m_pView->getSnapX();
00816         if (height > numY * m_pView->getSnapY())
00817             height = (numY + 1) * m_pView->getSnapY();
00818     }
00819 
00820     QCanvasRectangle::setSize(width,height);
00821 }
00822 
00823 void UMLWidget::updateComponentSize() {
00824     if (m_pDoc->loading())
00825         return;
00826     const QSize minSize = calculateSize();
00827     const int w = minSize.width();
00828     const int h = minSize.height();
00829     setSize(w, h);
00830     adjustAssocs( getX(), getY() );  // adjust assoc lines
00831 }
00832 
00833 void UMLWidget::setDefaultFontMetrics(UMLWidget::FontType fontType) {
00834     setupFontType(m_Font, fontType);
00835     setFontMetrics(fontType, QFontMetrics(m_Font));
00836 }
00837 
00838 void UMLWidget::setupFontType(QFont &font, UMLWidget::FontType fontType) {
00839     switch(fontType){
00840     case FT_NORMAL:
00841         font.setBold(false);
00842         font.setItalic(false);
00843         font.setUnderline(false);
00844         break;
00845     case FT_BOLD:
00846         font.setBold(true);
00847         font.setItalic(false);
00848         font.setUnderline(false);
00849         break;
00850     case FT_ITALIC:
00851         font.setBold(false);
00852         font.setItalic(true);
00853         font.setUnderline(false);
00854         break;
00855     case FT_UNDERLINE:
00856         font.setBold(false);
00857         font.setItalic(false);
00858         font.setUnderline(true);
00859         break;
00860     case FT_BOLD_ITALIC:
00861         font.setBold(true);
00862         font.setItalic(true);
00863         font.setUnderline(false);
00864         break;
00865     case FT_BOLD_UNDERLINE:
00866         font.setBold(true);
00867         font.setItalic(false);
00868         font.setUnderline(true);
00869         break;
00870     case FT_ITALIC_UNDERLINE:
00871         font.setBold(false);
00872         font.setItalic(true);
00873         font.setUnderline(true);
00874         break;
00875     case FT_BOLD_ITALIC_UNDERLINE:
00876         font.setBold(true);
00877         font.setItalic(true);
00878         font.setUnderline(true);
00879         break;
00880     default: return;
00881     }
00882 }
00883 
00884 void UMLWidget::setDefaultFontMetrics(UMLWidget::FontType fontType, QPainter &painter) {
00885     setupFontType(m_Font, fontType);
00886     painter.setFont(m_Font);
00887     setFontMetrics(fontType, painter.fontMetrics());
00888 }
00889 
00890 //FIXME this is probably the source of problems with widgets not being wide enough
00891 QFontMetrics &UMLWidget::getFontMetrics(UMLWidget::FontType fontType) {
00892     if (m_pFontMetrics[fontType] == 0) {
00893         setDefaultFontMetrics(fontType);
00894     }
00895     return *m_pFontMetrics[fontType];
00896 }
00897 
00898 void UMLWidget::setFontMetrics(UMLWidget::FontType fontType, QFontMetrics fm) {
00899     delete m_pFontMetrics[fontType];
00900     m_pFontMetrics[fontType] = new QFontMetrics(fm);
00901 }
00902 
00903 QFont UMLWidget::getFont() const {
00904     return m_Font;
00905 }
00906 
00907 void UMLWidget::setFont( QFont font ) {
00908     m_Font = font;
00909     forceUpdateFontMetrics(0);
00910     if (m_pDoc->loading())
00911         return;
00912     update();
00913 }
00914 
00915 void UMLWidget::forceUpdateFontMetrics(QPainter *painter) {
00916     if (painter == 0) {
00917         for (int i = 0; i < (int)UMLWidget::FT_INVALID; ++i) {
00918             if (m_pFontMetrics[(UMLWidget::FontType)i]!=0)
00919                 setDefaultFontMetrics((UMLWidget::FontType)i);
00920         }
00921     } else {
00922         for (int i2 = 0; i2 < (int)UMLWidget::FT_INVALID; ++i2) {
00923             if (m_pFontMetrics[(UMLWidget::FontType)i2]!=0)
00924                 setDefaultFontMetrics((UMLWidget::FontType)i2,*painter);
00925         }
00926     }
00927     // calculate the size, based on the new font metric
00928     updateComponentSize();
00929 }
00930 
00931 void UMLWidget::setShowStereotype(bool _status) {
00932     m_bShowStereotype = _status;
00933     updateComponentSize();
00934     update();
00935 }
00936 
00937 bool UMLWidget::getShowStereotype() const {
00938     return m_bShowStereotype;
00939 }
00940 
00941 void UMLWidget::moveEvent(QMoveEvent *me) {
00942 }
00943 
00944 void UMLWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
00945     /*
00946       Call after required actions in child class.
00947       Type must be set in the child class.
00948     */
00949     WidgetBase::saveToXMI(qDoc, qElement);
00950     qElement.setAttribute( "xmi.id", ID2STR(getID()) );
00951     qElement.setAttribute( "font", m_Font.toString() );
00952     qElement.setAttribute( "usefillcolor", m_bUseFillColour );
00953     qElement.setAttribute( "x", getX() );
00954     qElement.setAttribute( "y", getY() );
00955     qElement.setAttribute( "width", getWidth() );
00956     qElement.setAttribute( "height", getHeight() );
00957     // for consistency the following attributes now use american spelling for "color"
00958     qElement.setAttribute( "usesdiagramfillcolor", m_bUsesDiagramFillColour );
00959     qElement.setAttribute( "usesdiagramusefillcolor", m_bUsesDiagramUseFillColour );
00960     if (m_bUsesDiagramFillColour) {
00961         qElement.setAttribute( "fillcolor", "none" );
00962     } else {
00963         qElement.setAttribute( "fillcolor", m_FillColour.name() );
00964     }
00965     qElement.setAttribute("isinstance", m_bIsInstance);
00966     if (!m_instanceName.isEmpty())
00967         qElement.setAttribute("instancename", m_instanceName);
00968     if (m_bShowStereotype)
00969         qElement.setAttribute("showstereotype", m_bShowStereotype);
00970 }
00971 
00972 bool UMLWidget::loadFromXMI( QDomElement & qElement ) {
00973     WidgetBase::loadFromXMI(qElement);
00974     QString id = qElement.attribute( "xmi.id", "-1" );
00975     QString font = qElement.attribute( "font", "" );
00976     QString usefillcolor = qElement.attribute( "usefillcolor", "1" );
00977     QString x = qElement.attribute( "x", "0" );
00978     QString y = qElement.attribute( "y", "0" );
00979     QString h = qElement.attribute( "height", "0" );
00980     QString w = qElement.attribute( "width", "0" );
00981     /*
00982       For the next three *color attributes, there was a mixup of american and english spelling for "color".
00983       So first we need to keep backward compatibility and try to retrieve the *colour attribute.
00984       Next we overwrite this value if we find a *color, otherwise the former *colour is kept.
00985     */
00986     QString fillColour = qElement.attribute( "fillcolour", "none" );
00987     fillColour = qElement.attribute( "fillcolor", fillColour );
00988     QString usesDiagramFillColour = qElement.attribute( "usesdiagramfillcolour", "1" );
00989     usesDiagramFillColour = qElement.attribute( "usesdiagramfillcolor", usesDiagramFillColour );
00990     QString usesDiagramUseFillColour = qElement.attribute( "usesdiagramusefillcolour", "1" );
00991     usesDiagramUseFillColour = qElement.attribute( "usesdiagramusefillcolor", usesDiagramUseFillColour );
00992 
00993     m_nId = STR2ID(id);
00994 
00995     if( !font.isEmpty() ) {
00996         //QFont newFont;
00997         m_Font.fromString(font);
00998         //setFont(newFont);
00999     } else {
01000         kWarning() << "Using default font " << m_Font.toString()
01001         << " for widget with xmi.id " << ID2STR(m_nId) << endl;
01002         //setFont( m_Font );
01003     }
01004     m_bUseFillColour = (bool)usefillcolor.toInt();
01005     m_bUsesDiagramFillColour = (bool)usesDiagramFillColour.toInt();
01006     m_bUsesDiagramUseFillColour = (bool)usesDiagramUseFillColour.toInt();
01007     setSize( w.toInt(), h.toInt() );
01008     setX( x.toInt() );
01009     setY( y.toInt() );
01010     if (fillColour != "none") {
01011         m_FillColour = QColor(fillColour);
01012     }
01013     QString isinstance = qElement.attribute("isinstance", "0");
01014     m_bIsInstance = (bool)isinstance.toInt();
01015     m_instanceName = qElement.attribute("instancename", "");
01016     QString showstereo = qElement.attribute("showstereotype", "0");
01017     m_bShowStereotype = (bool)showstereo.toInt();
01018     return true;
01019 }
01020 
01021 UMLWidgetController* UMLWidget::getWidgetController() {
01022     return m_widgetController;
01023 }
01024 
01025 #include "umlwidget.moc"
KDE Logo
This file is part of the documentation for umbrello Version 3.1.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 26 08:08:02 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003