Commit 50797b59 authored by Ralf Habacker's avatar Ralf Habacker
Browse files

Fix 'On sequence diagrams no display of a selected object widget on the corresponding line'

If an object widget is selected, the corresponding sequence line is
displayed with a larger line width.

It was necessary to fix a problem with QGraphicsItem::setSelected() to
implement the requested behavior. Details can be found in the
documentation of the class QGraphicsObjectWrapper.

BUG:418249
FIXED-IN:2.30.80 (KDE releases 20.03.80)
parent 6dfd45fa
......@@ -101,6 +101,19 @@ bool ObjectWidget::multipleInstance() const
return m_multipleInstance;
}
void ObjectWidget::setSelected(bool state)
{
UMLWidget::setSelected(state);
if (m_pLine) {
QPen pen = m_pLine->pen();
int lineWidth = (int)UMLWidget::lineWidth();
if (state)
lineWidth = lineWidth ? lineWidth * 2 : 2;
pen.setWidth(lineWidth);
m_pLine->setPen(pen);
}
}
/**
* Overridden from UMLWidget.
* Moves the widget to a new position using the difference between the
......
......@@ -44,6 +44,8 @@ public:
void setMultipleInstance(bool multiple);
bool multipleInstance() const;
void setSelected(bool state);
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
bool activate(IDChangeLog* ChangeLog = 0);
......
......@@ -1668,7 +1668,7 @@ void UMLWidget::setScene(UMLScene *scene)
*/
void UMLWidget::setX(qreal x)
{
QGraphicsObject::setX(x);
QGraphicsObjectWrapper::setX(x);
}
/**
......@@ -1680,7 +1680,7 @@ void UMLWidget::setX(qreal x)
*/
void UMLWidget::setY(qreal y)
{
QGraphicsObject::setY(y);
QGraphicsObjectWrapper::setY(y);
}
/**
......
......@@ -35,6 +35,23 @@
#endif
#include <QPointer>
void QGraphicsObjectWrapper::setSelected(bool state)
{
if (!m_calledFromItemChange)
QGraphicsObject::setSelected(state);
m_calledFromItemChange = false;
}
QVariant QGraphicsObjectWrapper::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == ItemSelectedChange && scene()) {
bool state = value.toBool();
m_calledFromItemChange = true;
setSelected(state);
}
return QGraphicsItem::itemChange(change, value);
}
/**
* Creates a WidgetBase object.
*
......@@ -43,7 +60,7 @@
* value by the constructors of inheriting classes.
*/
WidgetBase::WidgetBase(UMLScene *scene, WidgetType type, Uml::ID::Type id)
: QGraphicsObject(),
: QGraphicsObjectWrapper(),
m_baseType(type),
m_scene(scene),
m_umlObject(0),
......@@ -135,7 +152,7 @@ QString WidgetBase::baseTypeStrWithoutPrefix() const
*/
void WidgetBase::setSelected(bool select)
{
QGraphicsObject::setSelected(select);
QGraphicsObjectWrapper::setSelected(select);
}
/**
......
......@@ -61,12 +61,47 @@ class UMLObject;
class UMLScene;
class UMLWidget; // required by function onWidget()
/**
* Provides a wrapper that bypasses the restriction that
* QGraphicsItem::setSelected() is not virtual
*
* The selection management of umbrello uses a virtual method
* setSelected() for selection to achieve the desired behavior
* in the different derivation levels regarding selection and
* deselection.
*
* Within QGraphicsScene, QGraphicsItem::setSelected() is called
* to manage the selection state, e.g. with clearSelection(), but
* unfortunately cannot be directly overwritten by umbrello because
* this method is not virtual (I consider this a design flaw).
*
* Fortunately there is a workaround for the problem by using
* QGraphicsItem::itemChange(), which is overridden in this class
* and calls the (now) virtual method setSelected() when the selection
* state changes. This calls derived implementations of this method
* and realizes the desired behavior.
*
* Within setSelected() you have to take care that
* QGraphicsObject::setSelected() is not called if the call came
* from itemChange() to avoid an endless loop.
*
* @author Ralf Habacker <ralf.habacker@freenet.de>
*/
class QGraphicsObjectWrapper: public QGraphicsObject
{
public:
virtual void setSelected(bool state);
protected:
bool m_calledFromItemChange{false};
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
};
/**
* @short Common base class for UMLWidget and AssociationWidget
* @author Oliver Kellogg <okellogg@users.sourceforge.net>
* Bugs and comments to umbrello-devel@kde.org or https://bugs.kde.org
*/
class WidgetBase : public QGraphicsObject
class WidgetBase : public QGraphicsObjectWrapper
{
Q_OBJECT
Q_ENUMS(WidgetType)
......
......@@ -138,6 +138,13 @@ ecm_add_test(
TEST_NAME testpreconditionwidget
)
ecm_add_test(
testwidgetbase.cpp
testbase.cpp
LINK_LIBRARIES ${LIBS}
TEST_NAME testwidgetbase
)
set(testumlroledialog_SRCS
testumlroledialog.cpp
)
......
/*
Copyright 2015 Ralf Habacker <ralf.habacker@freenet.de>
Copyright 2015-2020 Ralf Habacker <ralf.habacker@freenet.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
......
/*
Copyright 2020 Ralf Habacker <ralf.habacker@freenet.de>
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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "testwidgetbase.h"
#include "folder.h"
#include "widgetbase.h"
#include "umlscene.h"
#include "umlview.h"
#include "umlwidget.h"
void TestWidgetBase::test_setSelected()
{
UMLFolder folder("folder");
UMLView view(&folder);
UMLScene scene(&folder, &view);
WidgetBase widget1(&scene, WidgetBase::wt_UMLWidget);
scene.addItem(&widget1);
// simple widget
widget1.setSelected(true);
QVERIFY(widget1.isSelected());
widget1.setSelected(false);
QVERIFY(!widget1.isSelected());
widget1.setSelected(true);
scene.clearSelected();
QVERIFY(!widget1.isSelected());
}
void TestWidgetBase::test_clearSelected()
{
UMLFolder folder("folder");
UMLView view(&folder);
UMLScene scene(&folder, &view);
UMLWidget widget1(&scene, WidgetBase::wt_Text, nullptr);
scene.addItem(&widget1);
UMLWidget widget2(&scene, WidgetBase::wt_Box, nullptr);
scene.addItem(&widget2);
widget2.setSelected(true);
widget1.setSelected(true);
QVERIFY(widget1.isSelected());
QVERIFY(widget2.isSelected());
scene.clearSelected();
QVERIFY(!widget1.isSelected());
QVERIFY(!widget2.isSelected());
widget2.setSelected(true);
widget1.setSelected(true);
QVERIFY(widget1.isSelected());
QVERIFY(widget2.isSelected());
scene.clearSelection();
}
QTEST_MAIN(TestWidgetBase)
/*
Copyright 2020 Ralf Habacker <ralf.habacker@freenet.de>
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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TESTWIDGETBASE_H
#define TESTWIDGETBASE_H
#include "testbase.h"
class TestWidgetBase : public TestBase
{
Q_OBJECT
private slots:
void test_setSelected();
void test_clearSelected();
};
#endif // TESTWIDGETBASE_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment