itemitem.cpp 10.2 KB
Newer Older
1
/****************************************************************************
Jochen Becher's avatar
Jochen Becher committed
2
**
3
4
** Copyright (C) 2016 Jochen Becher
** Contact: https://www.qt.io/licensing/
Jochen Becher's avatar
Jochen Becher committed
5
6
7
8
9
10
11
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
12
13
14
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
Jochen Becher's avatar
Jochen Becher committed
15
**
16
17
18
19
20
21
22
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
Jochen Becher's avatar
Jochen Becher committed
23
24
25
26
27
28
29
30
31
32
33
**
****************************************************************************/

#include "itemitem.h"

#include "qmt/diagram_controller/diagramcontroller.h"
#include "qmt/diagram/ditem.h"
#include "qmt/diagram_scene/diagramsceneconstants.h"
#include "qmt/diagram_scene/diagramscenemodel.h"
#include "qmt/diagram_scene/parts/contextlabelitem.h"
#include "qmt/diagram_scene/parts/customiconitem.h"
34
#include "qmt/diagram_scene/parts/editabletextitem.h"
Jochen Becher's avatar
Jochen Becher committed
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include "qmt/diagram_scene/parts/relationstarter.h"
#include "qmt/diagram_scene/parts/stereotypesitem.h"
#include "qmt/infrastructure/geometryutilities.h"
#include "qmt/infrastructure/qmtassert.h"
#include "qmt/stereotype/stereotypecontroller.h"
#include "qmt/stereotype/stereotypeicon.h"
#include "qmt/style/style.h"
#include "qmt/tasks/diagramscenecontroller.h"

#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QGraphicsSimpleTextItem>
#include <QBrush>
#include <QPen>
#include <QFont>

#include <algorithm>

namespace qmt {

static const qreal BODY_VERT_BORDER = 4.0;
static const qreal BODY_HORIZ_BORDER = 4.0;

58
ItemItem::ItemItem(DItem *item, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent)
59
    : ObjectItem(item, diagramSceneModel, parent)
Jochen Becher's avatar
Jochen Becher committed
60
61
62
63
64
65
66
67
68
69
70
71
{
}

ItemItem::~ItemItem()
{
}

void ItemItem::update()
{
    prepareGeometryChange();
    updateStereotypeIconDisplay();

Jochen Becher's avatar
Jochen Becher committed
72
    auto diagramItem = dynamic_cast<DItem *>(object());
73
74
    Q_UNUSED(diagramItem); // avoid warning about unsed variable
    QMT_CHECK(diagramItem);
Jochen Becher's avatar
Jochen Becher committed
75

76
    const Style *style = adaptedStyle(shapeIconId());
Jochen Becher's avatar
Jochen Becher committed
77

78
    if (!shapeIconId().isEmpty()) {
79
        if (!m_customIcon)
80
81
82
83
84
            m_customIcon = new CustomIconItem(diagramSceneModel(), this);
        m_customIcon->setStereotypeIconId(shapeIconId());
        m_customIcon->setBaseSize(stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(), CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT));
        m_customIcon->setBrush(style->fillBrush());
        m_customIcon->setPen(style->outerLinePen());
85
86
87
88
89
        m_customIcon->setZValue(SHAPE_ZVALUE);
    } else if (m_customIcon) {
        m_customIcon->scene()->removeItem(m_customIcon);
        delete m_customIcon;
        m_customIcon = 0;
Jochen Becher's avatar
Jochen Becher committed
90
91
92
    }

    // shape
93
    if (!m_customIcon) {
94
        if (!m_shape)
95
            m_shape = new QGraphicsRectItem(this);
96
97
        m_shape->setBrush(style->fillBrush());
        m_shape->setPen(style->outerLinePen());
98
        m_shape->setZValue(SHAPE_ZVALUE);
Jochen Becher's avatar
Jochen Becher committed
99
    } else {
100
101
102
103
        if (m_shape) {
            m_shape->scene()->removeItem(m_shape);
            delete m_shape;
            m_shape = 0;
Jochen Becher's avatar
Jochen Becher committed
104
105
106
107
        }
    }

    // stereotypes
108
    updateStereotypes(stereotypeIconId(), stereotypeIconDisplay(), adaptedStyle(stereotypeIconId()));
Jochen Becher's avatar
Jochen Becher committed
109
110

    // component name
111
    updateNameItem(style);
Jochen Becher's avatar
Jochen Becher committed
112
113
114

    // context
    if (showContext()) {
115
        if (!m_contextLabel)
116
            m_contextLabel = new ContextLabelItem(this);
117
118
119
        m_contextLabel->setFont(style->smallFont());
        m_contextLabel->setBrush(style->textBrush());
        m_contextLabel->setContext(object()->context());
120
121
122
123
    } else if (m_contextLabel) {
        m_contextLabel->scene()->removeItem(m_contextLabel);
        delete m_contextLabel;
        m_contextLabel = 0;
Jochen Becher's avatar
Jochen Becher committed
124
125
    }

126
    updateSelectionMarker(m_customIcon);
Jochen Becher's avatar
Jochen Becher committed
127
128
129

    // relation starters
    if (isFocusSelected()) {
130
        if (!m_relationStarter && scene()) {
131
            m_relationStarter = new RelationStarter(this, diagramSceneModel(), 0);
132
133
            scene()->addItem(m_relationStarter);
            m_relationStarter->setZValue(RELATION_STARTER_ZVALUE);
134
            m_relationStarter->addArrow(QStringLiteral("dependency"), ArrowItem::ShaftDashed, ArrowItem::HeadOpen);
Jochen Becher's avatar
Jochen Becher committed
135
        }
136
    } else if (m_relationStarter) {
137
        if (m_relationStarter->scene())
138
139
140
            m_relationStarter->scene()->removeItem(m_relationStarter);
        delete m_relationStarter;
        m_relationStarter = 0;
Jochen Becher's avatar
Jochen Becher committed
141
142
143
144
145
146
    }

    updateAlignmentButtons();
    updateGeometry();
}

147
bool ItemItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
Jochen Becher's avatar
Jochen Becher committed
148
149
{
    QPolygonF polygon;
150
    if (m_customIcon) {
151
        // TODO use customIcon path as shape
152
153
        QRectF rect = object()->rect();
        rect.translate(object()->pos());
Jochen Becher's avatar
Jochen Becher committed
154
155
        polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
    } else {
156
157
        QRectF rect = object()->rect();
        rect.translate(object()->pos());
Jochen Becher's avatar
Jochen Becher committed
158
159
        polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
    }
160
    return GeometryUtilities::intersect(polygon, line, intersectionPoint, intersectionLine);
Jochen Becher's avatar
Jochen Becher committed
161
162
}

163
QSizeF ItemItem::minimumSize() const
Jochen Becher's avatar
Jochen Becher committed
164
165
166
167
{
    return calcMinimumGeometry();
}

168
QList<ILatchable::Latch> ItemItem::horizontalLatches(ILatchable::Action action, bool grabbedItem) const
Jochen Becher's avatar
Jochen Becher committed
169
{
170
    return ObjectItem::horizontalLatches(action, grabbedItem);
Jochen Becher's avatar
Jochen Becher committed
171
172
}

173
QList<ILatchable::Latch> ItemItem::verticalLatches(ILatchable::Action action, bool grabbedItem) const
Jochen Becher's avatar
Jochen Becher committed
174
{
175
    return ObjectItem::verticalLatches(action, grabbedItem);
Jochen Becher's avatar
Jochen Becher committed
176
177
}

178
QPointF ItemItem::relationStartPos() const
Jochen Becher's avatar
Jochen Becher committed
179
180
181
182
{
    return pos();
}

183
void ItemItem::relationDrawn(const QString &id, const QPointF &toScenePos, const QList<QPointF> &intermediatePoints)
Jochen Becher's avatar
Jochen Becher committed
184
{
185
    DElement *targetElement = diagramSceneModel()->findTopmostElement(toScenePos);
186
    if (targetElement) {
Jochen Becher's avatar
Jochen Becher committed
187
       if (id == QStringLiteral("dependency")) {
Jochen Becher's avatar
Jochen Becher committed
188
            auto dependantObject = dynamic_cast<DObject *>(targetElement);
189
            if (dependantObject)
190
                diagramSceneModel()->diagramSceneController()->createDependency(object(), dependantObject, intermediatePoints, diagramSceneModel()->diagram());
Jochen Becher's avatar
Jochen Becher committed
191
192
193
194
195
196
197
198
199
        }
    }
}

QSizeF ItemItem::calcMinimumGeometry() const
{
    double width = 0.0;
    double height = 0.0;

200
201
202
203
    if (m_customIcon) {
        return stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(),
                                         CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT);
    }
Jochen Becher's avatar
Jochen Becher committed
204
205

    height += BODY_VERT_BORDER;
206
    if (CustomIconItem *stereotypeIconItem = this->stereotypeIconItem()) {
207
208
        width = std::max(width, stereotypeIconItem->boundingRect().width());
        height += stereotypeIconItem->boundingRect().height();
Jochen Becher's avatar
Jochen Becher committed
209
    }
210
    if (StereotypesItem *stereotypesItem = this->stereotypesItem()) {
211
212
        width = std::max(width, stereotypesItem->boundingRect().width());
        height += stereotypesItem->boundingRect().height();
Jochen Becher's avatar
Jochen Becher committed
213
    }
214
215
216
    if (nameItem()) {
        width = std::max(width, nameItem()->boundingRect().width());
        height += nameItem()->boundingRect().height();
Jochen Becher's avatar
Jochen Becher committed
217
    }
218
    if (m_contextLabel)
219
        height += m_contextLabel->height();
Jochen Becher's avatar
Jochen Becher committed
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
    height += BODY_VERT_BORDER;

    width = BODY_HORIZ_BORDER + width + BODY_HORIZ_BORDER;

    return GeometryUtilities::ensureMinimumRasterSize(QSizeF(width, height), 2 * RASTER_WIDTH, 2 * RASTER_HEIGHT);
}

void ItemItem::updateGeometry()
{
    prepareGeometryChange();

    // calc width and height
    double width = 0.0;
    double height = 0.0;

    QSizeF geometry = calcMinimumGeometry();
    width = geometry.width();
    height = geometry.height();

239
    if (object()->isAutoSized()) {
Jochen Becher's avatar
Jochen Becher committed
240
241
        // nothing
    } else {
242
        QRectF rect = object()->rect();
243
        if (rect.width() > width)
Jochen Becher's avatar
Jochen Becher committed
244
            width = rect.width();
245
        if (rect.height() > height)
Jochen Becher's avatar
Jochen Becher committed
246
247
248
249
250
251
252
253
254
            height = rect.height();
    }

    // update sizes and positions
    double left = -width / 2.0;
    double right = width / 2.0;
    double top = -height / 2.0;
    double y = top;

255
    setPos(object()->pos());
Jochen Becher's avatar
Jochen Becher committed
256
257
258
259
260
261

    QRectF rect(left, top, width, height);

    // the object is updated without calling DiagramController intentionally.
    // attribute rect is not a real attribute stored on DObject but
    // a backup for the graphics item used for manual resized and persistency.
262
    object()->setRect(rect);
Jochen Becher's avatar
Jochen Becher committed
263

264
265
266
    if (m_customIcon) {
        m_customIcon->setPos(left, top);
        m_customIcon->setActualSize(QSizeF(width, height));
Jochen Becher's avatar
Jochen Becher committed
267
268
269
        y += height;
    }

270
    if (m_shape)
271
        m_shape->setRect(rect);
Jochen Becher's avatar
Jochen Becher committed
272
273

    y += BODY_VERT_BORDER;
274
    if (CustomIconItem *stereotypeIconItem = this->stereotypeIconItem()) {
275
276
        stereotypeIconItem->setPos(right - stereotypeIconItem->boundingRect().width() - BODY_HORIZ_BORDER, y);
        y += stereotypeIconItem->boundingRect().height();
Jochen Becher's avatar
Jochen Becher committed
277
    }
278
    if (StereotypesItem *stereotypesItem = this->stereotypesItem()) {
279
280
        stereotypesItem->setPos(-stereotypesItem->boundingRect().width() / 2.0, y);
        y += stereotypesItem->boundingRect().height();
Jochen Becher's avatar
Jochen Becher committed
281
    }
282
283
284
    if (nameItem()) {
        nameItem()->setPos(-nameItem()->boundingRect().width() / 2.0, y);
        y += nameItem()->boundingRect().height();
Jochen Becher's avatar
Jochen Becher committed
285
    }
286
287
288
    if (m_contextLabel) {
        if (m_customIcon) {
            m_contextLabel->resetMaxWidth();
Jochen Becher's avatar
Jochen Becher committed
289
        } else {
290
291
            double maxContextWidth = width - 2 * BODY_HORIZ_BORDER;
            m_contextLabel->setMaxWidth(maxContextWidth);
Jochen Becher's avatar
Jochen Becher committed
292
        }
293
        m_contextLabel->setPos(-m_contextLabel->boundingRect().width() / 2.0, y);
Jochen Becher's avatar
Jochen Becher committed
294
295
296
297
    }

    updateSelectionMarkerGeometry(rect);

298
    if (m_relationStarter)
299
        m_relationStarter->setPos(mapToScene(QPointF(right + 8.0, top)));
Jochen Becher's avatar
Jochen Becher committed
300
301
302
303
304
305

    updateAlignmentButtonsGeometry(rect);
    updateDepth();
}

} // namespace qmt