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/umlwidgetcontroller.cpp

541 lines
17 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) 2006-2007 *
* Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
***************************************************************************/
// own header
#include "umlwidgetcontroller.h"
// qt includes
#include <tqevent.h>
#include <tqpoint.h>
// kde includes
#include <kcursor.h>
#include <kdebug.h>
#include <tdelocale.h>
// 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();
}