/*************************************************************************** * * * 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) 2006-2007 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "umlwidgetcontroller.h" // qt includes #include #include // kde includes #include #include #include // app includes #include "umlwidget.h" #include "umlwidgetlist.h" #include "umlnamespace.h" #include "uml.h" #include "umldoc.h" #include "umlview.h" #include "umlobject.h" #include "listpopupmenu.h" #include "classifierwidget.h" #include "associationwidget.h" #include "messagewidget.h" using namespace Uml; UMLWidgetController::UMLWidgetController(UMLWidget *widget) { m_widget = widget; m_pressOffsetX = m_pressOffsetY = 0; m_oldX = m_oldY = 0; m_oldW = m_oldH = 0; m_minSelectedX = m_minSelectedY = m_maxSelectedX = m_maxSelectedY = 0; m_shiftPressed = false; m_leftButtonDown = m_middleButtonDown = m_rightButtonDown = false; m_inMoveArea = m_inResizeArea = 0; m_wasSelected = m_moved = m_resized = 0; } UMLWidgetController::~UMLWidgetController() { } void UMLWidgetController::mousePressEvent(TQMouseEvent *me) { // If there is a button pressed already ignore other press events if (m_leftButtonDown || m_middleButtonDown || m_rightButtonDown) { return; } if (me->button() == TQt::LeftButton) { m_leftButtonDown = true; } else if (me->button() == TQt::RightButton) { m_rightButtonDown = true; } else { m_middleButtonDown = true; return; } //There is no harm in saving all the values of the widget even when //they aren't going to be used saveWidgetValues(me); m_oldStatusBarMsg = UMLApp::app()->getStatusBarMsg(); if (me->state() == TQt::ShiftButton || me->state() == TQt::ControlButton) { m_shiftPressed = true; if (me->button() == TQt::LeftButton) { m_inMoveArea = true; } if (!m_widget->m_bSelected) { selectMultiple(me); } else if (!m_rightButtonDown) { m_wasSelected = false; } return; } m_shiftPressed = false; int count = m_widget->m_pView->getSelectCount(true); if (me->button() == TQt::LeftButton) { if (m_widget->m_bSelected && count > 1) { //Single selection is made in release event if the widget wasn't moved m_inMoveArea = true; lastUpdate.start(); return; } if (isInResizeArea(me)) { m_inResizeArea = true; } else { m_inMoveArea = true; } } //If widget wasn't selected, or it was selected but with other widgets also selected if (!m_widget->m_bSelected || count > 1) { selectSingle(me); } else if (!m_rightButtonDown) { m_wasSelected = false; } } void UMLWidgetController::mouseMoveEvent(TQMouseEvent* me) { if (!m_leftButtonDown) return; if (m_inResizeArea) { resize(me); return; } if (!m_moved) { 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.")); m_moved = true; //Maybe needed by AssociationWidget m_widget->m_bStartMove = true; setSelectionBounds(); } TQPoint position = getPosition(me); int diffX = position.x() - m_widget->getX(); int diffY = position.y() - m_widget->getY(); if ((me->state() & TQt::ShiftButton) && (me->state() & TQt::ControlButton)) { //Move in Y axis diffX = 0; } else if ((me->state() & TQt::ShiftButton) || (me->state() & TQt::ControlButton)) { //Move in X axis diffY = 0; } // kDebug() << "UMLWidgetController::mouseMoveEvent before constrainMovementForAllWidgets:" // << " diffX=" << diffX << ", diffY=" << diffY << endl; constrainMovementForAllWidgets(diffX, diffY); // kDebug() << "UMLWidgetController::mouseMoveEvent after constrainMovementForAllWidgets:" // << " diffX=" << diffX << ", diffY=" << diffY << endl; //Nothing to move if (diffX == 0 && diffY == 0) { return; } UMLWidgetListIt it(m_selectedWidgetsList); UMLWidget* widget; it.toFirst(); bool update = false; if (lastUpdate.elapsed() > 25) { update = true; lastUpdate.restart(); m_widget->adjustUnselectedAssocs(m_widget->getX(), m_widget->getY()); } while ((widget = it.current()) != 0) { ++it; widget->getWidgetController()->moveWidgetBy(diffX, diffY); } // kDebug() << endl; // Move any selected associations. AssociationWidgetList awl = m_widget->m_pView->getSelectedAssocs(); AssociationWidget *aw = NULL; for (AssociationWidgetListIt ai(awl); (aw = ai.current()) != NULL; ++ai) { if (aw->getSelected()) { aw->moveEntireAssoc(diffX, diffY); } } m_widget->m_pView->resizeCanvasToItems(); updateSelectionBounds(diffX, diffY); } void UMLWidgetController::mouseReleaseEvent(TQMouseEvent *me) { if (me->button() != TQt::LeftButton && me->button() != TQt::RightButton) { if (m_middleButtonDown) { m_middleButtonDown = false; resetSelection(); } } else if (me->button() == TQt::LeftButton) { if (m_leftButtonDown) { m_leftButtonDown = false; if (!m_moved && !m_resized) { if (!m_shiftPressed && (m_widget->m_pView->getSelectCount(true) > 1)) { selectSingle(me); } else if (!m_wasSelected) { deselect(me); } } else { if (m_moved) { m_moved = false; //Ensure associations are updated (the timer could prevent the //adjustment in the last move event before the release) UMLWidgetListIt it(m_selectedWidgetsList); UMLWidget* widget; it.toFirst(); while ((widget = it.current()) != 0) { ++it; widget->adjustAssocs(widget->getX(), widget->getY()); } m_widget->m_bStartMove = false; } else { m_resized = false; } if ((m_inMoveArea && wasPositionChanged()) || (m_inResizeArea && wasSizeChanged())) { m_widget->m_pDoc->setModified(true); } UMLApp::app()->getDocument()->writeToStatusBar(m_oldStatusBarMsg); } if (m_inResizeArea) { m_inResizeArea = false; m_widget->m_pView->setCursor(KCursor::arrowCursor()); } else { m_inMoveArea = false; } } } else if (me->button() == TQt::RightButton) { if (m_rightButtonDown) { m_rightButtonDown = false; showPopupMenu(me); } else if (m_leftButtonDown) { //Cancel move/edit TQMouseEvent move(TQMouseEvent::MouseMove, TQPoint(m_oldX + m_pressOffsetX, m_oldY + m_pressOffsetY), TQt::LeftButton, TQt::NoButton); mouseMoveEvent(&move); TQMouseEvent release(TQMouseEvent::MouseButtonRelease, TQPoint(m_oldX + m_pressOffsetX, m_oldY + m_pressOffsetY), TQt::LeftButton, TQt::NoButton); mouseReleaseEvent(&release); } } //TODO Copied from old code. Does it really work as intended? UMLWidget *bkgnd = m_widget->m_pView->getWidgetAt(me->pos()); if (bkgnd) { //kDebug() << "UMLWidgetController::mouseReleaseEvent: setting Z to " // << bkgnd->getZ() + 1 << endl; m_widget->setZ(bkgnd->getZ() + 1); } else { m_widget->setZ(0); } } void UMLWidgetController::mouseDoubleClickEvent(TQMouseEvent *me) { if (me->button() != TQt::LeftButton) { return; } selectSingle(me); doMouseDoubleClick(me); } bool UMLWidgetController::isInResizeArea(TQMouseEvent *me) { const int m = 10; if (m_widget->m_bResizable && me->x() >= (m_widget->getX() + m_widget->width() - m) && me->y() >= (m_widget->getY() + m_widget->height() - m)) { m_widget->m_pView->setCursor(getResizeCursor()); return true; } else { m_widget->m_pView->setCursor(KCursor::arrowCursor()); return false; } } TQCursor UMLWidgetController::getResizeCursor() { return KCursor::sizeFDiagCursor(); } void UMLWidgetController::resizeWidget(int newW, int newH) { m_widget->setSize(newW, newH); } void UMLWidgetController::moveWidgetBy(int diffX, int diffY) { m_widget->setX(m_widget->getX() + diffX); m_widget->setY(m_widget->getY() + diffY); } void UMLWidgetController::constrainMovementForAllWidgets(int &/*diffX*/, int &/*diffY*/) { } void UMLWidgetController::doMouseDoubleClick(TQMouseEvent *) { if (!m_widget || !m_widget->m_pMenu) return; m_widget->slotMenuSelection(ListPopupMenu::mt_Properties); } void UMLWidgetController::resetSelection() { m_widget->m_pView->clearSelected(); m_widget->m_pView->resetToolbar(); m_widget->setSelected(false); m_wasSelected = false; } void UMLWidgetController::selectSingle(TQMouseEvent *me) { m_widget->m_pView->clearSelected(); //Adds the widget to the selected widgets list, but as it has been cleared //only the current widget is selected selectMultiple(me); } void UMLWidgetController::selectMultiple(TQMouseEvent *me) { m_widget->m_bSelected = true; m_widget->setSelected(m_widget->m_bSelected); m_widget->m_pView->setSelected(m_widget, me); m_wasSelected = true; } void UMLWidgetController::deselect(TQMouseEvent *me) { m_widget->m_bSelected = false; m_widget->setSelected(m_widget->m_bSelected); m_widget->m_pView->setSelected(m_widget, me); //m_wasSelected is false implicitly, no need to set it again } void UMLWidgetController::saveWidgetValues(TQMouseEvent *me) { m_pressOffsetX = me->x() - m_widget->getX(); m_pressOffsetY = me->y() - m_widget->getY(); m_oldX = m_widget->getX(); m_oldY = m_widget->getY(); m_oldW = m_widget->width(); m_oldH = m_widget->height(); } void UMLWidgetController::setSelectionBounds() { if (m_widget->m_pView->getSelectCount() > 0) { m_selectedWidgetsList.clear(); m_widget->m_pView->getSelectedWidgets(m_selectedWidgetsList, false); updateSelectionBounds(1, 1); } } //TODO optimize it void UMLWidgetController::updateSelectionBounds(int diffX, int diffY) { if (diffX != 0) { m_minSelectedX = getSmallestX(m_selectedWidgetsList); m_maxSelectedX = getBiggestX(m_selectedWidgetsList); } if (diffY != 0) { m_minSelectedY = getSmallestY(m_selectedWidgetsList); m_maxSelectedY = getBiggestY(m_selectedWidgetsList); } } void UMLWidgetController::resize(TQMouseEvent *me) { 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.")); m_resized = true; int newW = m_oldW + me->x() - m_widget->getX() - m_pressOffsetX; int newH = m_oldH + me->y() - m_widget->getY() - m_pressOffsetY; if ((me->state() & TQt::ShiftButton) && (me->state() & TQt::ControlButton)) { //Move in Y axis newW = m_oldW; } else if ((me->state() & TQt::ShiftButton) || (me->state() & TQt::ControlButton)) { //Move in X axis newH = m_oldH; } m_widget->constrain(newW, newH); resizeWidget(newW, newH); m_widget->adjustAssocs(m_widget->getX(), m_widget->getY()); m_widget->m_pView->resizeCanvasToItems(); } //TODO refactor with AlignToolbar method. int UMLWidgetController::getSmallestX(const UMLWidgetList &widgetList) { UMLWidgetListIt it(widgetList); UMLWidget* widget; widget = it.toFirst(); // leave function upon empty widget list if (NULL == widget) return 0; int smallestX = widget->getX(); ++it; while ((widget = it.current()) != 0) { ++it; if (smallestX > widget->getX()) smallestX = widget->getX(); } return smallestX; } //TODO refactor with AlignToolbar method. int UMLWidgetController::getSmallestY(const UMLWidgetList &widgetList) { UMLWidgetListIt it(widgetList); UMLWidget* widget; widget = it.toFirst(); // leave function upon empty widget list if (NULL == widget) return 0; int smallestY = widget->getY(); ++it; while ((widget = it.current()) != 0) { ++it; if (smallestY > widget->getY()) smallestY = widget->getY(); } return smallestY; } //TODO refactor with AlignToolbar method. int UMLWidgetController::getBiggestX(const UMLWidgetList &widgetList) { UMLWidgetListIt it(widgetList); UMLWidget* widget; widget = it.toFirst(); // leave function upon empty widget list if (NULL == widget) return 0; int biggestX = widget->getX(); biggestX += it.current()->getWidth(); ++it; while ((widget = it.current()) != 0) { ++it; if (biggestX < widget->getX() + widget->getWidth()) biggestX = widget->getX() + widget->getWidth(); } return biggestX; } //TODO refactor with AlignToolbar method. int UMLWidgetController::getBiggestY(const UMLWidgetList &widgetList) { UMLWidgetListIt it(widgetList); UMLWidget* widget; widget = it.toFirst(); // leave function upon empty widget list if (NULL == widget) return 0; int biggestY = widget->getY(); biggestY += it.current()->getHeight(); ++it; while ((widget = it.current()) != 0) { ++it; if (biggestY < widget->getY() + widget->getHeight()) biggestY = widget->getY() + widget->getHeight(); } return biggestY; } TQPoint UMLWidgetController::getPosition(TQMouseEvent* me) { /* kDebug() << "UMLWidgetController::getPosition: me->x=" << me->x() << " m_widget->getX=" << m_widget->getX() << ", m_oldX=" << m_oldX << ", m_pressOffsetX=" << m_pressOffsetX << endl; kDebug() << "UMLWidgetController::getPosition: me->y=" << me->y() << " m_widget->getY=" << m_widget->getY() << ", m_oldY=" << m_oldY << ", m_pressOffsetY=" << m_pressOffsetY << endl; */ int newX = me->x() + m_widget->getX() - m_oldX - m_pressOffsetX; int newY = me->y() + m_widget->getY() - m_oldY - m_pressOffsetY; int maxX = m_widget->m_pView->canvas()->width(); int maxY = m_widget->m_pView->canvas()->height(); m_oldX = newX; m_oldY = newY; if (newX + (m_minSelectedX - m_widget->getX()) < 0) { //kDebug() << "UMLWidgetController::getPosition: got into cond.1" << endl; newX = m_widget->getX() - m_minSelectedX; } if (newY + (m_minSelectedY - m_widget->getY()) < 0) { //kDebug() << "UMLWidgetController::getPosition: got into cond.2" << endl; newY = m_widget->getY() - m_minSelectedY; } if (newX + (m_maxSelectedX - m_widget->getX()) > maxX) { //kDebug() << "UMLWidgetController::getPosition: got into cond.3" << endl; newX = maxX - (m_maxSelectedX - m_widget->getX()); } if (newY + (m_maxSelectedY - m_widget->getY()) > maxY) { //kDebug() << "UMLWidgetController::getPosition: got into cond.4" << endl; newY = maxY - (m_maxSelectedY - m_widget->getY()); } return TQPoint(newX, newY); } TQPoint UMLWidgetController::getPositionDifference(TQMouseEvent* me) { TQPoint newPoint = getPosition(me); const int diffX = newPoint.x() - m_widget->getX(); const int diffY = newPoint.y() - m_widget->getY(); return TQPoint(diffX, diffY); } void UMLWidgetController::showPopupMenu(TQMouseEvent *me) { //TODO why this condition? if (m_widget->m_pMenu) { return; } m_widget->startPopupMenu(me->globalPos()); } bool UMLWidgetController::wasSizeChanged() { return m_oldW != m_widget->getWidth() || m_oldH != m_widget->getHeight(); } bool UMLWidgetController::wasPositionChanged() { return m_oldX != m_widget->getX() || m_oldY != m_widget->getY(); }