umbrello API Documentation

umlwidgetcontroller.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) 2006-2007                                               *
00009  *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
00010  ***************************************************************************/
00011 
00012 // own header
00013 #include "umlwidgetcontroller.h"
00014 
00015 // qt includes
00016 #include <qevent.h>
00017 #include <qpoint.h>
00018 
00019 // kde includes
00020 #include <kcursor.h>
00021 #include <kdebug.h>
00022 #include <klocale.h>
00023 
00024 // app includes
00025 #include "umlwidget.h"
00026 #include "umlwidgetlist.h"
00027 #include "umlnamespace.h"
00028 #include "uml.h"
00029 #include "umldoc.h"
00030 #include "umlview.h"
00031 #include "umlobject.h"
00032 #include "listpopupmenu.h"
00033 #include "classifierwidget.h"
00034 #include "associationwidget.h"
00035 #include "messagewidget.h"
00036 
00037 using namespace Uml;
00038 
00039 UMLWidgetController::UMLWidgetController(UMLWidget *widget) {
00040     m_widget = widget;
00041 
00042     m_pressOffsetX = m_pressOffsetY = 0;
00043     m_oldX = m_oldY = 0;
00044     m_oldW = m_oldH = 0;
00045     m_minSelectedX = m_minSelectedY = m_maxSelectedX = m_maxSelectedY = 0;
00046 
00047     m_shiftPressed = false;
00048     m_leftButtonDown = m_middleButtonDown = m_rightButtonDown = false;
00049     m_inMoveArea = m_inResizeArea = 0;
00050     m_wasSelected = m_moved = m_resized = 0;
00051 }
00052 
00053 UMLWidgetController::~UMLWidgetController() {
00054 }
00055 
00056 void UMLWidgetController::mousePressEvent(QMouseEvent *me) {
00057     // If there is a button pressed already ignore other press events
00058     if (m_leftButtonDown || m_middleButtonDown || m_rightButtonDown) {
00059         return;
00060     }
00061 
00062     if (me->button() == Qt::LeftButton) {
00063         m_leftButtonDown = true;
00064     } else if (me->button() == Qt::RightButton) {
00065         m_rightButtonDown = true;
00066     } else {
00067         m_middleButtonDown = true;
00068         return;
00069     }
00070 
00071     //There is no harm in saving all the values of the widget even when
00072     //they aren't going to be used
00073     saveWidgetValues(me);
00074 
00075     m_oldStatusBarMsg = UMLApp::app()->getStatusBarMsg();
00076 
00077     if (me->state() == Qt::ShiftButton || me->state() == Qt::ControlButton) {
00078         m_shiftPressed = true;
00079 
00080         if (me->button() == Qt::LeftButton) {
00081             m_inMoveArea = true;
00082         }
00083 
00084         if (!m_widget->m_bSelected) {
00085             selectMultiple(me);
00086         } else if (!m_rightButtonDown) {
00087             m_wasSelected = false;
00088         }
00089         return;
00090     }
00091 
00092     m_shiftPressed = false;
00093 
00094     int count = m_widget->m_pView->getSelectCount(true);
00095     if (me->button() == Qt::LeftButton) {
00096         if (m_widget->m_bSelected && count > 1) {
00097             //Single selection is made in release event if the widget wasn't moved
00098             m_inMoveArea = true;
00099             lastUpdate.start();
00100             return;
00101         }
00102 
00103         if (isInResizeArea(me)) {
00104             m_inResizeArea = true;
00105         } else {
00106             m_inMoveArea = true;
00107         }
00108     }
00109 
00110     //If widget wasn't selected, or it was selected but with other widgets also selected
00111     if (!m_widget->m_bSelected || count > 1) {
00112         selectSingle(me);
00113     } else if (!m_rightButtonDown) {
00114         m_wasSelected = false;
00115     }
00116 }
00117 
00118 void UMLWidgetController::mouseMoveEvent(QMouseEvent* me) {
00119     if (!m_leftButtonDown)
00120         return;
00121 
00122     if (m_inResizeArea) {
00123         resize(me);
00124         return;
00125     }
00126 
00127     if (!m_moved) {
00128         UMLApp::app()->getDocument()->writeToStatusBar(i18n("Hold shift or ctrl to move in X axis. Hold shift and control to move in Y axis. Right button click to cancel move."));
00129 
00130         m_moved = true;
00131         //Maybe needed by AssociationWidget
00132         m_widget->m_bStartMove = true;
00133 
00134         setSelectionBounds();
00135     }
00136 
00137     QPoint positionDifference = getPositionDifference(me);
00138     int diffX = positionDifference.x();
00139     int diffY = positionDifference.y();
00140 
00141     if ((me->state() & Qt::ShiftButton) && (me->state() & Qt::ControlButton)) {
00142         //Move in Y axis
00143         diffX = 0;
00144     } else if ((me->state() & Qt::ShiftButton) || (me->state() & Qt::ControlButton)) {
00145         //Move in X axis
00146         diffY = 0;
00147     }
00148 
00149     // kDebug() << "UMLWidgetController::mouseMoveEvent before constrainMovementForAllWidgets:"
00150     //     << " diffX=" << diffX << ", diffY=" << diffY << endl;
00151     constrainMovementForAllWidgets(diffX, diffY);
00152     // kDebug() << "UMLWidgetController::mouseMoveEvent after constrainMovementForAllWidgets:"
00153     //     << " diffX=" << diffX << ", diffY=" << diffY << endl;
00154 
00155     //Nothing to move
00156     if (diffX == 0 && diffY == 0) {
00157         return;
00158     }
00159 
00160     UMLWidgetListIt it(m_selectedWidgetsList);
00161     UMLWidget* widget;
00162     it.toFirst();
00163 
00164     bool update = false;
00165     if (lastUpdate.elapsed() > 25) {
00166         update = true;
00167         lastUpdate.restart();
00168 
00169         // CHECK: UMLWidget::adjustUnselectedAssocs(x,y) appears to take absolute
00170         //      values for x and y. Surprisingly, supplying diffX and diffY seems
00171         //      to work all the same ?!?
00172         m_widget->adjustUnselectedAssocs(diffX, diffY);
00173     }
00174 
00175     while ((widget = it.current()) != 0) {
00176         ++it;
00177         widget->getWidgetController()->moveWidgetBy(diffX, diffY);
00178     }
00179     // kDebug() << endl;
00180 
00181     // Move any selected associations.
00182     AssociationWidgetList awl = m_widget->m_pView->getSelectedAssocs();
00183     AssociationWidget *aw = NULL;
00184     for (AssociationWidgetListIt ai(awl); (aw = ai.current()) != NULL; ++ai) {
00185         if (aw->getSelected()) {
00186             aw->moveEntireAssoc(diffX, diffY);
00187         }
00188     }
00189 
00190     m_widget->m_pView->resizeCanvasToItems();
00191     updateSelectionBounds(diffX, diffY);
00192 }
00193 
00194 void UMLWidgetController::mouseReleaseEvent(QMouseEvent *me) {
00195     if (me->button() != Qt::LeftButton && me->button() != Qt::RightButton) {
00196         if (m_middleButtonDown) {
00197             m_middleButtonDown = false;
00198             resetSelection();
00199         }
00200     } else if (me->button() == Qt::LeftButton) {
00201         if (m_leftButtonDown) {
00202             m_leftButtonDown = false;
00203 
00204             if (!m_moved && !m_resized) {
00205                 if (!m_shiftPressed && (m_widget->m_pView->getSelectCount(true) > 1)) {
00206                     selectSingle(me);
00207                 } else if (!m_wasSelected) {
00208                     deselect(me);
00209                 }
00210             } else {
00211                 if (m_moved) {
00212                     m_moved = false;
00213 
00214                     //Ensure associations are updated (the timer could prevent the
00215                     //adjustment in the last move event before the release)
00216                     UMLWidgetListIt it(m_selectedWidgetsList);
00217                     UMLWidget* widget;
00218                     it.toFirst();
00219                     while ((widget = it.current()) != 0) {
00220                         ++it;
00221                         widget->adjustAssocs(widget->getX(), widget->getY());
00222                     }
00223 
00224                     m_widget->m_bStartMove = false;
00225                 } else {
00226                     m_resized = false;
00227                 }
00228 
00229                 if ((m_inMoveArea && wasPositionChanged()) ||
00230                             (m_inResizeArea && wasSizeChanged())) {
00231                     m_widget->m_pDoc->setModified(true);
00232                 }
00233 
00234                 UMLApp::app()->getDocument()->writeToStatusBar(m_oldStatusBarMsg);
00235             }
00236 
00237             if (m_inResizeArea) {
00238                 m_inResizeArea = false;
00239                 m_widget->m_pView->setCursor(KCursor::arrowCursor());
00240             } else {
00241                 m_inMoveArea = false;
00242             }
00243         }
00244     } else if (me->button() == Qt::RightButton) {
00245         if (m_rightButtonDown) {
00246             m_rightButtonDown = false;
00247             showPopupMenu(me);
00248         } else if (m_leftButtonDown) {
00249             //Cancel move/edit
00250             QMouseEvent move(QMouseEvent::MouseMove,
00251                                 QPoint(m_oldX + m_pressOffsetX, m_oldY + m_pressOffsetY),
00252                                 Qt::LeftButton, Qt::NoButton);
00253             mouseMoveEvent(&move);
00254             QMouseEvent release(QMouseEvent::MouseButtonRelease,
00255                                 QPoint(m_oldX + m_pressOffsetX, m_oldY + m_pressOffsetY),
00256                                 Qt::LeftButton, Qt::NoButton);
00257             mouseReleaseEvent(&release);
00258         }
00259     }
00260 
00261     //TODO Copied from old code. Does it really work as intended?
00262     UMLWidget *bkgnd = m_widget->m_pView->getWidgetAt(me->pos());
00263     if (bkgnd) {
00264         //kDebug() << "UMLWidgetController::mouseReleaseEvent: setting Z to "
00265         //    << bkgnd->getZ() + 1 << endl;
00266         m_widget->setZ(bkgnd->getZ() + 1);
00267     } else {
00268         m_widget->setZ(0);
00269     }
00270 }
00271 
00272 void UMLWidgetController::mouseDoubleClickEvent(QMouseEvent *me) {
00273     if (me->button() != Qt::LeftButton) {
00274         return;
00275     }
00276 
00277     selectSingle(me);
00278 
00279     doMouseDoubleClick(me);
00280 }
00281 
00282 bool UMLWidgetController::isInResizeArea(QMouseEvent *me) {
00283     const int m = 10;
00284 
00285     if (m_widget->m_bResizable &&
00286                 me->x() >= (m_widget->getX() + m_widget->width() - m) &&
00287                 me->y() >= (m_widget->getY() + m_widget->height() - m)) {
00288         m_widget->m_pView->setCursor(getResizeCursor());
00289         return true;
00290     } else {
00291         m_widget->m_pView->setCursor(KCursor::arrowCursor());
00292         return false;
00293     }
00294 }
00295 
00296 QCursor UMLWidgetController::getResizeCursor() {
00297     return KCursor::sizeFDiagCursor();
00298 }
00299 
00300 void UMLWidgetController::resizeWidget(int newW, int newH) {
00301     m_widget->setSize(newW, newH);
00302 }
00303 
00304 void UMLWidgetController::moveWidgetBy(int diffX, int diffY) {
00305     m_widget->setX(m_widget->getX() + diffX);
00306     m_widget->setY(m_widget->getY() + diffY);
00307 }
00308 
00309 void UMLWidgetController::constrainMovementForAllWidgets(int &/*diffX*/, int &/*diffY*/) {
00310 }
00311 
00312 void UMLWidgetController::doMouseDoubleClick(QMouseEvent *) {
00313     m_widget->slotMenuSelection(ListPopupMenu::mt_Properties);
00314 }
00315 
00316 void UMLWidgetController::resetSelection() {
00317     m_widget->m_pView->clearSelected();
00318     m_widget->m_pView->resetToolbar();
00319     m_widget->setSelected(false);
00320 
00321     m_wasSelected = false;
00322 }
00323 
00324 void UMLWidgetController::selectSingle(QMouseEvent *me) {
00325     m_widget->m_pView->clearSelected();
00326 
00327     //Adds the widget to the selected widgets list, but as it has been cleared
00328     //only the current widget is selected
00329     selectMultiple(me);
00330 }
00331 
00332 void UMLWidgetController::selectMultiple(QMouseEvent *me) {
00333     m_widget->m_bSelected = true;
00334     m_widget->setSelected(m_widget->m_bSelected);
00335     m_widget->m_pView->setSelected(m_widget, me);
00336 
00337     m_wasSelected = true;
00338 }
00339 
00340 void UMLWidgetController::deselect(QMouseEvent *me) {
00341     m_widget->m_bSelected = false;
00342     m_widget->setSelected(m_widget->m_bSelected);
00343     m_widget->m_pView->setSelected(m_widget, me);
00344     //m_wasSelected is false implicitly, no need to set it again
00345 }
00346 
00347 void UMLWidgetController::saveWidgetValues(QMouseEvent *me) {
00348     m_pressOffsetX = me->x() - m_widget->getX();
00349     m_pressOffsetY = me->y() - m_widget->getY();
00350 
00351     m_oldX = m_widget->getX();
00352     m_oldY = m_widget->getY();
00353 
00354     m_oldW = m_widget->width();
00355     m_oldH = m_widget->height();
00356 }
00357 
00358 void UMLWidgetController::setSelectionBounds() {
00359     if (m_widget->m_pView->getSelectCount() > 0) {
00360         m_selectedWidgetsList.clear();
00361         m_widget->m_pView->getSelectedWidgets(m_selectedWidgetsList, false);
00362 
00363         updateSelectionBounds(1, 1);
00364     }
00365 }
00366 
00367 //TODO optimize it
00368 void UMLWidgetController::updateSelectionBounds(int diffX, int diffY) {
00369     if (diffX != 0) {
00370         m_minSelectedX = getSmallestX(m_selectedWidgetsList);
00371         m_maxSelectedX = getBiggestX(m_selectedWidgetsList);
00372     }
00373     if (diffY != 0) {
00374         m_minSelectedY = getSmallestY(m_selectedWidgetsList);
00375         m_maxSelectedY = getBiggestY(m_selectedWidgetsList);
00376     }
00377 }
00378 
00379 void UMLWidgetController::resize(QMouseEvent *me) {
00380     UMLApp::app()->getDocument()->writeToStatusBar(i18n("Hold shift or ctrl to move in X axis. Hold shift and control to move in Y axis. Right button click to cancel resize."));
00381 
00382     m_resized = true;
00383 
00384     int newW = m_oldW + me->x() - m_widget->getX() - m_pressOffsetX;
00385     int newH = m_oldH + me->y() - m_widget->getY() - m_pressOffsetY;
00386 
00387     if ((me->state() & Qt::ShiftButton) && (me->state() & Qt::ControlButton)) {
00388         //Move in Y axis
00389         newW = m_oldW;
00390     } else if ((me->state() & Qt::ShiftButton) || (me->state() & Qt::ControlButton)) {
00391         //Move in X axis
00392         newH = m_oldH;
00393     }
00394 
00395     m_widget->constrain(newW, newH);
00396     resizeWidget(newW, newH);
00397     m_widget->adjustAssocs(m_widget->getX(), m_widget->getY());
00398 
00399     m_widget->m_pView->resizeCanvasToItems();
00400 }
00401 
00402 //TODO refactor with AlignToolbar method.
00403 int UMLWidgetController::getSmallestX(const UMLWidgetList &widgetList) {
00404     UMLWidgetListIt it(widgetList);
00405     UMLWidget* widget;
00406 
00407     widget = it.toFirst();
00408     // leave function upon empty widget list
00409     if (NULL == widget) return 0;
00410     int smallestX = widget->getX();
00411     ++it;
00412 
00413     while ((widget = it.current()) != 0) {
00414         ++it;
00415         if (smallestX > widget->getX())
00416             smallestX = widget->getX();
00417     }
00418 
00419     return smallestX;
00420 }
00421 
00422 //TODO refactor with AlignToolbar method.
00423 int UMLWidgetController::getSmallestY(const UMLWidgetList &widgetList) {
00424     UMLWidgetListIt it(widgetList);
00425     UMLWidget* widget;
00426 
00427     widget = it.toFirst();
00428     // leave function upon empty widget list
00429     if (NULL == widget) return 0;
00430     int smallestY = widget->getY();
00431     ++it;
00432 
00433     while ((widget = it.current()) != 0) {
00434         ++it;
00435         if (smallestY > widget->getY())
00436             smallestY = widget->getY();
00437     }
00438 
00439     return smallestY;
00440 }
00441 
00442 //TODO refactor with AlignToolbar method.
00443 int UMLWidgetController::getBiggestX(const UMLWidgetList &widgetList) {
00444     UMLWidgetListIt it(widgetList);
00445     UMLWidget* widget;
00446 
00447     widget = it.toFirst();
00448     // leave function upon empty widget list
00449     if (NULL == widget) return 0;
00450     int biggestX = widget->getX();
00451     biggestX += it.current()->getWidth();
00452     ++it;
00453 
00454     while ((widget = it.current()) != 0) {
00455         ++it;
00456         if (biggestX < widget->getX() + widget->getWidth())
00457             biggestX = widget->getX() + widget->getWidth();
00458     }
00459 
00460     return biggestX;
00461 }
00462 
00463 //TODO refactor with AlignToolbar method.
00464 int UMLWidgetController::getBiggestY(const UMLWidgetList &widgetList) {
00465     UMLWidgetListIt it(widgetList);
00466     UMLWidget* widget;
00467 
00468     widget = it.toFirst();
00469     // leave function upon empty widget list
00470     if (NULL == widget) return 0;
00471     int biggestY = widget->getY();
00472     biggestY += it.current()->getHeight();
00473     ++it;
00474 
00475     while ((widget = it.current()) != 0) {
00476         ++it;
00477         if (biggestY < widget->getY() + widget->getHeight())
00478             biggestY = widget->getY() + widget->getHeight();
00479     }
00480 
00481     return biggestY;
00482 }
00483 
00484 QPoint UMLWidgetController::getPositionDifference(QMouseEvent* me) {
00485     /*
00486     kDebug() << "UMLWidgetController::getPositionDifference: me->x=" << me->x()
00487         << " m_widget->getX=" << m_widget->getX() << ", m_oldX=" << m_oldX
00488         << ", m_pressOffsetX=" << m_pressOffsetX << endl;
00489     kDebug() << "UMLWidgetController::getPositionDifference: me->y=" << me->y()
00490         << " m_widget->getY=" << m_widget->getY() << ", m_oldY=" << m_oldY
00491         << ", m_pressOffsetY=" << m_pressOffsetY << endl;
00492      */
00493     int newX = me->x() + m_widget->getX() - m_oldX - m_pressOffsetX;
00494     int newY = me->y() + m_widget->getY() - m_oldY - m_pressOffsetY;
00495     int maxX = m_widget->m_pView->canvas()->width();
00496     int maxY = m_widget->m_pView->canvas()->height();
00497 
00498     m_oldX = newX;
00499     m_oldY = newY;
00500 
00501     if (newX + (m_minSelectedX - m_widget->getX()) < 0) {
00502         //kDebug() << "UMLWidgetController::getPositionDifference: got into cond.1" << endl;
00503         newX = m_widget->getX() - m_minSelectedX;
00504     }
00505     if (newY + (m_minSelectedY - m_widget->getY()) < 0) {
00506         //kDebug() << "UMLWidgetController::getPositionDifference: got into cond.2" << endl;
00507         newY = m_widget->getY() - m_minSelectedY;
00508     }
00509     if (newX + (m_maxSelectedX - m_widget->getX()) > maxX) {
00510         //kDebug() << "UMLWidgetController::getPositionDifference: got into cond.3" << endl;
00511         newX = maxX - (m_maxSelectedX - m_widget->getX());
00512     }
00513     if (newY + (m_maxSelectedY - m_widget->getY()) > maxY) {
00514         //kDebug() << "UMLWidgetController::getPositionDifference: got into cond.4" << endl;
00515         newY = maxY - (m_maxSelectedY - m_widget->getY());
00516     }
00517 
00518     newX -= m_widget->getX();
00519     newY -= m_widget->getY();
00520 
00521     return QPoint(newX, newY);
00522 }
00523 
00524 void UMLWidgetController::showPopupMenu(QMouseEvent *me) {
00525     //TODO why this condition?
00526     if (m_widget->m_pMenu) {
00527         return;
00528     }
00529     m_widget->startPopupMenu(me->globalPos());
00530 }
00531 
00532 bool UMLWidgetController::wasSizeChanged() {
00533     return m_oldW != m_widget->getWidth() || m_oldH != m_widget->getHeight();
00534 }
00535 
00536 bool UMLWidgetController::wasPositionChanged() {
00537     return m_oldX != m_widget->getX() || m_oldY != m_widget->getY();
00538 }
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