ModelEditor: Improve custom items

The default name for a new custom item can be set. The display of any
text of a custom icon can be suppressed (e.g. start element in activity
diagrams).

Change-Id: Iaaefda3a6795e0b2a63d96fd001948d302906b7a
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Jochen Becher
2017-08-02 09:44:21 +02:00
parent 75b77fea33
commit 56be6cc2c8
17 changed files with 131 additions and 66 deletions

View File

@@ -15,6 +15,7 @@
// display: <default display of element.
// One of: none, label, decoration, icon, smart.
// Default is smart.>
// name: <Name of new element. Defaults to "New <Toolbar entry title>".>
// width: <width of icon in pixels. The width defines the width of the icon as decoration.>
// height: <height of icon in pixels. The height defines the height of the icon as decoration.>
// minwidth: <minimum width of custom icon in pixels.>
@@ -22,9 +23,9 @@
// lockSize: <lock resizing.
// One of: none, width, height, size, ratio.
// Default is none.>
// textAlignment: <alignment of text.
// One of: top, center, below.
// Defaults to center.>
// textAlignment: <alignment of text (stereotype label, name and context).
// One of: top, center, below, none.
// Defaults to below. None means no text will be displayed>
// baseColor: <color #rrggbb>
// Shape {
// Line { x1: <x1>; y1: <y1>; x2:<x2>; y2: <y2> }
@@ -345,6 +346,8 @@ Icon {
elements: item
stereotype: 'start'
display: icon
name: ""
textAlignment: none
width: 20
height: 20
lockSize: ratio
@@ -391,6 +394,8 @@ Icon {
elements: item
stereotype: 'horizontalbar'
display: icon
name: ""
textAlignment: none
width: 20
height: 5
minWidth: 20
@@ -408,6 +413,8 @@ Icon {
elements: item
stereotype: 'verticalbar'
display: icon
name: ""
textAlignment: none
width: 5
height: 20
minWidth: 5
@@ -424,6 +431,8 @@ Icon {
elements: item
stereotype: 'termination'
display: icon
name: ""
textAlignment: none
width: 20
height: 20
lockSize: ratio

View File

@@ -424,7 +424,8 @@ void StereotypeDefinitionParser::parseIcon()
const static QHash<QString, StereotypeIcon::TextAlignment> alignNames = QHash<QString, StereotypeIcon::TextAlignment>()
<< qMakePair(QString("below"), StereotypeIcon::TextalignBelow)
<< qMakePair(QString("center"), StereotypeIcon::TextalignCenter)
<< qMakePair(QString("none"), StereotypeIcon::TextalignNone);
<< qMakePair(QString("none"), StereotypeIcon::TextalignNone)
<< qMakePair(QString("top"), StereotypeIcon::TextalignTop);
parseEnum<StereotypeIcon::TextAlignment>(
parseIdentifierProperty(), alignNames, token.sourcePos(),
[&](StereotypeIcon::TextAlignment align) { stereotypeIcon.setTextAlignment(align); });
@@ -436,6 +437,10 @@ void StereotypeDefinitionParser::parseIcon()
case KEYWORD_SHAPE:
stereotypeIcon.setIconShape(parseIconShape());
break;
case KEYWORD_NAME:
stereotypeIcon.setName(parseStringProperty());
stereotypeIcon.setHasName(true);
break;
default:
throwUnknownPropertyError(token);
}

View File

@@ -131,7 +131,7 @@ void ClassItem::update()
updateStereotypes(stereotypeIconId(), stereotypeIconDisplay(), style);
// namespace
if (!diagramClass->umlNamespace().isEmpty()) {
if (!suppressTextDisplay() && !diagramClass->umlNamespace().isEmpty()) {
if (!m_namespace)
m_namespace = new QGraphicsSimpleTextItem(this);
m_namespace->setFont(style->smallFont());
@@ -147,7 +147,7 @@ void ClassItem::update()
updateNameItem(style);
// context
if (showContext()) {
if (!suppressTextDisplay() && showContext()) {
if (!m_contextLabel)
m_contextLabel = new ContextLabelItem(this);
m_contextLabel->setFont(style->smallFont());
@@ -160,7 +160,7 @@ void ClassItem::update()
}
// attributes separator
if (m_shape || !m_attributesText.isEmpty() || !m_methodsText.isEmpty()) {
if (m_shape || (!suppressTextDisplay() && (!m_attributesText.isEmpty() || !m_methodsText.isEmpty()))) {
if (!m_attributesSeparator)
m_attributesSeparator = new QGraphicsLineItem(this);
m_attributesSeparator->setPen(style->innerLinePen());
@@ -172,7 +172,7 @@ void ClassItem::update()
}
// attributes
if (!m_attributesText.isEmpty()) {
if (!suppressTextDisplay() && !m_attributesText.isEmpty()) {
if (!m_attributes)
m_attributes = new QGraphicsTextItem(this);
m_attributes->setFont(style->normalFont());
@@ -186,7 +186,7 @@ void ClassItem::update()
}
// methods separator
if (m_shape || !m_attributesText.isEmpty() || !m_methodsText.isEmpty()) {
if (m_shape || (!suppressTextDisplay() && (!m_attributesText.isEmpty() || !m_methodsText.isEmpty()))) {
if (!m_methodsSeparator)
m_methodsSeparator = new QGraphicsLineItem(this);
m_methodsSeparator->setPen(style->innerLinePen());
@@ -198,7 +198,7 @@ void ClassItem::update()
}
// methods
if (!m_methodsText.isEmpty()) {
if (!suppressTextDisplay() && !m_methodsText.isEmpty()) {
if (!m_methods)
m_methods = new QGraphicsTextItem(this);
m_methods->setFont(style->normalFont());

View File

@@ -140,7 +140,7 @@ void ComponentItem::update()
updateNameItem(style);
// context
if (showContext()) {
if (!suppressTextDisplay() && showContext()) {
if (!m_contextLabel)
m_contextLabel = new ContextLabelItem(this);
m_contextLabel->setFont(style->smallFont());

View File

@@ -110,7 +110,7 @@ void ItemItem::update()
updateNameItem(style);
// context
if (showContext()) {
if (!suppressTextDisplay() && showContext()) {
if (!m_contextLabel)
m_contextLabel = new ContextLabelItem(this);
m_contextLabel->setFont(style->smallFont());

View File

@@ -470,6 +470,7 @@ void ObjectItem::updateStereotypeIconDisplay()
m_object->accept(&stereotypeDisplayVisitor);
m_stereotypeIconId = stereotypeDisplayVisitor.stereotypeIconId();
m_shapeIconId = stereotypeDisplayVisitor.shapeIconId();
m_shapeIcon = stereotypeDisplayVisitor.shapeIcon();
m_stereotypeIconDisplay = stereotypeDisplayVisitor.stereotypeIconDisplay();
}
@@ -493,16 +494,16 @@ void ObjectItem::updateStereotypes(const QString &stereotypeIconId, StereotypeIc
delete m_stereotypeIcon;
m_stereotypeIcon = nullptr;
}
if (stereotypeDisplay != StereotypeIcon::DisplayNone && !stereotypes.isEmpty()) {
if (!m_stereotypes)
m_stereotypes = new StereotypesItem(this);
m_stereotypes->setFont(style->smallFont());
m_stereotypes->setBrush(style->textBrush());
m_stereotypes->setStereotypes(stereotypes);
} else if (m_stereotypes) {
m_stereotypes->scene()->removeItem(m_stereotypes);
delete m_stereotypes;
m_stereotypes = nullptr;
if (stereotypeDisplay != StereotypeIcon::DisplayNone && !suppressTextDisplay() && !stereotypes.isEmpty()) {
if (!m_stereotypesItem)
m_stereotypesItem = new StereotypesItem(this);
m_stereotypesItem->setFont(style->smallFont());
m_stereotypesItem->setBrush(style->textBrush());
m_stereotypesItem->setStereotypes(stereotypes);
} else if (m_stereotypesItem) {
m_stereotypesItem->scene()->removeItem(m_stereotypesItem);
delete m_stereotypesItem;
m_stereotypesItem = nullptr;
}
}
@@ -545,8 +546,14 @@ QSizeF ObjectItem::stereotypeIconMinimumSize(const StereotypeIcon &stereotypeIco
return QSizeF(width, height);
}
bool ObjectItem::suppressTextDisplay() const
{
return m_shapeIcon.textAlignment() == StereotypeIcon::TextalignNone;
}
void ObjectItem::updateNameItem(const Style *style)
{
if (!suppressTextDisplay()) {
if (!m_nameItem) {
m_nameItem = new EditableTextItem(this);
m_nameItem->setShowFocus(true);
@@ -566,6 +573,11 @@ void ObjectItem::updateNameItem(const Style *style)
if (name != m_nameItem->toPlainText())
m_nameItem->setPlainText(name);
}
} else if (m_nameItem ){
m_nameItem->scene()->removeItem(m_nameItem);
delete m_nameItem;
m_nameItem = nullptr;
}
}
QString ObjectItem::buildDisplayName() const

View File

@@ -136,13 +136,15 @@ protected:
void updateStereotypeIconDisplay();
QString stereotypeIconId() const { return m_stereotypeIconId; }
QString shapeIconId() const { return m_shapeIconId; }
StereotypeIcon shapeIcon() const { return m_shapeIcon; }
StereotypeIcon::Display stereotypeIconDisplay() const { return m_stereotypeIconDisplay; }
void updateStereotypes(const QString &stereotypeIconId,
StereotypeIcon::Display stereotypeDisplay, const Style *style);
StereotypesItem *stereotypesItem() const { return m_stereotypes; }
StereotypesItem *stereotypesItem() const { return m_stereotypesItem; }
CustomIconItem *stereotypeIconItem() const { return m_stereotypeIcon; }
QSizeF stereotypeIconMinimumSize(const StereotypeIcon &stereotypeIcon, qreal minimumWidth,
qreal minimumHeight) const;
bool suppressTextDisplay() const;
void updateNameItem(const Style *style);
EditableTextItem *nameItem() const { return m_nameItem; }
virtual QString buildDisplayName() const;
@@ -185,8 +187,9 @@ private:
bool m_isFocusSelected = false;
QString m_stereotypeIconId;
QString m_shapeIconId;
StereotypeIcon m_shapeIcon;
StereotypeIcon::Display m_stereotypeIconDisplay = StereotypeIcon::DisplayLabel;
StereotypesItem *m_stereotypes = nullptr;
StereotypesItem *m_stereotypesItem = nullptr;
CustomIconItem *m_stereotypeIcon = nullptr;
EditableTextItem *m_nameItem = nullptr;
RectangularSelectionItem *m_selectionMarker = nullptr;

View File

@@ -121,7 +121,7 @@ void PackageItem::update()
updateNameItem(style);
// context
if (showContext()) {
if (!suppressTextDisplay() && showContext()) {
if (!m_contextLabel)
m_contextLabel = new ContextLabelItem(this);
m_contextLabel->setFont(style->smallFont());

View File

@@ -80,7 +80,7 @@ public:
stereotypeDisplayVisitor.setModelController(m_diagramSceneModel->diagramSceneController()->modelController());
stereotypeDisplayVisitor.setStereotypeController(m_diagramSceneModel->stereotypeController());
baseObject->accept(&stereotypeDisplayVisitor);
lollipopDisplay = stereotypeDisplayVisitor.stereotypeDisplay() == DObject::StereotypeIcon;
lollipopDisplay = stereotypeDisplayVisitor.stereotypeIconDisplay() == StereotypeIcon::DisplayIcon;
}
}
if (lollipopDisplay) {

View File

@@ -114,6 +114,7 @@ void StereotypeDisplayVisitor::visitDPackage(const DPackage *package)
m_stereotypeIconElement = StereotypeIcon::ElementPackage;
m_stereotypeSmartDisplay = DObject::StereotypeDecoration;
visitDObject(package);
updateShapeIcon();
}
void StereotypeDisplayVisitor::visitDClass(const DClass *klass)
@@ -125,6 +126,7 @@ void StereotypeDisplayVisitor::visitDClass(const DClass *klass)
hasMembers = true;
m_stereotypeSmartDisplay = hasMembers ? DObject::StereotypeDecoration : DObject::StereotypeIcon;
visitDObject(klass);
updateShapeIcon();
}
void StereotypeDisplayVisitor::visitDComponent(const DComponent *component)
@@ -132,6 +134,7 @@ void StereotypeDisplayVisitor::visitDComponent(const DComponent *component)
m_stereotypeIconElement = StereotypeIcon::ElementComponent;
m_stereotypeSmartDisplay = DObject::StereotypeIcon;
visitDObject(component);
updateShapeIcon();
}
void StereotypeDisplayVisitor::visitDDiagram(const DDiagram *diagram)
@@ -139,6 +142,7 @@ void StereotypeDisplayVisitor::visitDDiagram(const DDiagram *diagram)
m_stereotypeIconElement = StereotypeIcon::ElementDiagram;
m_stereotypeSmartDisplay = DObject::StereotypeDecoration;
visitDObject(diagram);
updateShapeIcon();
}
void StereotypeDisplayVisitor::visitDItem(const DItem *item)
@@ -150,6 +154,15 @@ void StereotypeDisplayVisitor::visitDItem(const DItem *item)
m_stereotypeIconId = m_stereotypeController->findStereotypeIconId(StereotypeIcon::ElementItem, QStringList(item->shape()));
if (m_shapeIconId.isEmpty() && !item->variety().isEmpty())
m_shapeIconId = m_stereotypeController->findStereotypeIconId(StereotypeIcon::ElementItem, QStringList(item->variety()));
updateShapeIcon();
}
void StereotypeDisplayVisitor::updateShapeIcon()
{
if (!m_shapeIconId.isEmpty())
m_shapeIcon = m_stereotypeController->findStereotypeIcon(m_shapeIconId);
else if (!m_stereotypeIconId.isEmpty())
m_shapeIcon = m_stereotypeController->findStereotypeIcon(m_stereotypeIconId);
}
} // namespace qmt

View File

@@ -43,10 +43,10 @@ public:
void setModelController(ModelController *modelController);
void setStereotypeController(StereotypeController *stereotypeController);
DObject::StereotypeDisplay stereotypeDisplay() const { return m_stereotypeDisplay; }
StereotypeIcon::Display stereotypeIconDisplay() const;
QString stereotypeIconId() const { return m_stereotypeIconId; }
QString shapeIconId() const { return m_shapeIconId; }
StereotypeIcon shapeIcon() const { return m_shapeIcon; }
void visitDObject(const DObject *object) override;
void visitDPackage(const DPackage *package) override;
@@ -56,11 +56,14 @@ public:
void visitDItem(const DItem *item) override;
private:
void updateShapeIcon();
ModelController *m_modelController = nullptr;
StereotypeController *m_stereotypeController = nullptr;
DObject::StereotypeDisplay m_stereotypeDisplay = DObject::StereotypeNone;
QString m_stereotypeIconId;
QString m_shapeIconId;
StereotypeIcon m_shapeIcon;
StereotypeIcon::Element m_stereotypeIconElement = StereotypeIcon::ElementAny;
DObject::StereotypeDisplay m_stereotypeSmartDisplay = DObject::StereotypeDecoration;
};

View File

@@ -54,6 +54,16 @@ void StereotypeIcon::setStereotypes(const QSet<QString> &stereotypes)
m_stereotypes = stereotypes;
}
void StereotypeIcon::setHasName(bool hasName)
{
m_hasName = hasName;
}
void StereotypeIcon::setName(const QString &name)
{
m_name = name;
}
void StereotypeIcon::setWidth(qreal width)
{
m_width = width;

View File

@@ -64,7 +64,8 @@ public:
enum TextAlignment {
TextalignBelow,
TextalignCenter,
TextalignNone
TextalignNone,
TextalignTop
};
QString id() const { return m_id; }
@@ -75,6 +76,10 @@ public:
void setElements(const QSet<Element> &elements);
QSet<QString> stereotypes() const { return m_stereotypes; }
void setStereotypes(const QSet<QString> &stereotypes);
bool hasName() const { return m_hasName; }
void setHasName(bool hasName);
QString name() const { return m_name; }
void setName(const QString &name);
qreal width() const { return m_width; }
void setWidth(qreal width);
qreal height() const { return m_height; }
@@ -101,6 +106,8 @@ private:
QString m_title;
QSet<Element> m_elements;
QSet<QString> m_stereotypes;
bool m_hasName = false;
QString m_name;
qreal m_width = 100.0;
qreal m_height = 100.0;
qreal m_minWidth = -1;

View File

@@ -397,28 +397,23 @@ void DiagramSceneController::dropNewElement(const QString &newElementId, const Q
} else {
MPackage *parentPackage = findSuitableParentPackage(topMostElementAtPos, diagram);
MObject *newObject = nullptr;
QString newName;
if (newElementId == QLatin1String(ELEMENT_TYPE_PACKAGE)) {
auto package = new MPackage();
newName = tr("New Package");
if (!stereotype.isEmpty())
package->setStereotypes({stereotype});
newObject = package;
} else if (newElementId == QLatin1String(ELEMENT_TYPE_COMPONENT)) {
auto component = new MComponent();
newName = tr("New Component");
if (!stereotype.isEmpty())
component->setStereotypes({stereotype});
newObject = component;
} else if (newElementId == QLatin1String(ELEMENT_TYPE_CLASS)) {
auto klass = new MClass();
newName = tr("New Class");
if (!stereotype.isEmpty())
klass->setStereotypes({stereotype});
newObject = klass;
} else if (newElementId == QLatin1String(ELEMENT_TYPE_ITEM)) {
auto item = new MItem();
newName = tr("New Item");
if (!stereotype.isEmpty()) {
item->setVariety(stereotype);
item->setVarietyEditable(false);
@@ -426,9 +421,7 @@ void DiagramSceneController::dropNewElement(const QString &newElementId, const Q
newObject = item;
}
if (newObject) {
if (!name.isEmpty())
newName = tr("New %1").arg(name);
newObject->setName(newName);
newObject->setName(name);
dropNewModelElement(newObject, parentPackage, pos, diagram);
}
}

View File

@@ -41,13 +41,14 @@ public:
QIcon icon;
QSize iconSize;
QString title;
QString newElementName;
QString newElementId;
QString stereotype;
bool disableFrame = false;
bool framePainted = false;
};
DragTool::DragTool(const QIcon &icon, const QString &title, const QString &newElementId,
DragTool::DragTool(const QIcon &icon, const QString &title, const QString &newElementName, const QString &newElementId,
const QString &stereotype, QWidget *parent)
: QWidget(parent),
d(new DragToolPrivate)
@@ -55,6 +56,7 @@ DragTool::DragTool(const QIcon &icon, const QString &title, const QString &newEl
d->icon = icon;
d->iconSize = QSize(32, 32);
d->title = title;
d->newElementName = newElementName;
d->newElementId = newElementId;
d->stereotype = stereotype;
QMargins margins = contentsMargins();
@@ -144,7 +146,7 @@ void DragTool::mousePressEvent(QMouseEvent *event)
auto mimeData = new QMimeData;
QByteArray data;
QDataStream dataStream(&data, QIODevice::WriteOnly);
dataStream << d->newElementId << d->title << d->stereotype;
dataStream << d->newElementId << d->newElementName << d->stereotype;
mimeData->setData(QLatin1String(qmt::MIME_TYPE_NEW_MODEL_ELEMENTS), data);
drag->setMimeData(mimeData);

View File

@@ -38,8 +38,8 @@ class DragTool :
class DragToolPrivate;
public:
DragTool(const QIcon &icon, const QString &title, const QString &newElementId,
const QString &stereotype, QWidget *parent = nullptr);
DragTool(const QIcon &icon, const QString &title, const QString &newElementName,
const QString &newElementId, const QString &stereotype, QWidget *parent = nullptr);
~DragTool();
QSize sizeHint() const override;

View File

@@ -1051,16 +1051,24 @@ void ModelEditor::initToolbars()
styleEngineElementType = qmt::StyleEngine::TypeSwimlane;
}
QIcon icon;
QString newElementName = tr("New %1").arg(tool.m_name);
if (!tool.m_stereotype.isEmpty() && stereotypeIconElement != qmt::StereotypeIcon::ElementAny) {
const qmt::Style *style = documentController->styleController()->adaptStyle(styleEngineElementType);
icon = stereotypeController->createIcon(
stereotypeIconElement, QStringList() << tool.m_stereotype,
QString(), style, QSize(48, 48), QMarginsF(3.0, 2.0, 3.0, 4.0));
if (!icon.isNull()) {
QString stereotypeIconId = stereotypeController->findStereotypeIconId(
stereotypeIconElement, QStringList() << tool.m_stereotype);
qmt::StereotypeIcon stereotypeIcon = stereotypeController->findStereotypeIcon(stereotypeIconId);
if (stereotypeIcon.hasName())
newElementName = stereotypeIcon.name();
}
}
if (icon.isNull())
icon = QIcon(iconPath);
if (!icon.isNull()) {
toolBarLayout->addWidget(new DragTool(icon, tool.m_name, tool.m_elementType,
toolBarLayout->addWidget(new DragTool(icon, tool.m_name, newElementName, tool.m_elementType,
tool.m_stereotype, toolBar));
}
break;
@@ -1088,34 +1096,34 @@ void ModelEditor::initToolbars()
toolBars.insert(generalId, toolBar);
toolBarLayout->addWidget(
new DragTool(QIcon(":/modelinglib/48x48/package.png"),
tr("Package"), QLatin1String(qmt::ELEMENT_TYPE_PACKAGE),
tr("Package"), tr("New Package"), QLatin1String(qmt::ELEMENT_TYPE_PACKAGE),
QString(), toolBar));
toolBarLayout->addWidget(
new DragTool(QIcon(":/modelinglib/48x48/component.png"),
tr("Component"), QLatin1String(qmt::ELEMENT_TYPE_COMPONENT),
tr("Component"), tr("New Component"), QLatin1String(qmt::ELEMENT_TYPE_COMPONENT),
QString(), toolBar));
toolBarLayout->addWidget(
new DragTool(QIcon(":/modelinglib/48x48/class.png"),
tr("Class"), QLatin1String(qmt::ELEMENT_TYPE_CLASS),
tr("Class"), tr("New Class"), QLatin1String(qmt::ELEMENT_TYPE_CLASS),
QString(), toolBar));
toolBarLayout->addWidget(
new DragTool(QIcon(":/modelinglib/48x48/item.png"),
tr("Item"), QLatin1String(qmt::ELEMENT_TYPE_ITEM),
tr("Item"), tr("New Item"), QLatin1String(qmt::ELEMENT_TYPE_ITEM),
QString(), toolBar));
auto horizLine1 = new QFrame(d->leftToolBox);
horizLine1->setFrameShape(QFrame::HLine);
toolBarLayout->addWidget(horizLine1);
toolBarLayout->addWidget(
new DragTool(QIcon(":/modelinglib/48x48/annotation.png"),
tr("Annotation"), QLatin1String(qmt::ELEMENT_TYPE_ANNOTATION),
tr("Annotation"), QString(), QLatin1String(qmt::ELEMENT_TYPE_ANNOTATION),
QString(), toolBar));
toolBarLayout->addWidget(
new DragTool(QIcon(":/modelinglib/48x48/boundary.png"),
tr("Boundary"), QLatin1String(qmt::ELEMENT_TYPE_BOUNDARY),
tr("Boundary"), QString(), QLatin1String(qmt::ELEMENT_TYPE_BOUNDARY),
QString(), toolBar));
toolBarLayout->addWidget(
new DragTool(QIcon(":/modelinglib/48x48/swimlane.png"),
tr("Swimlane"), QLatin1String(qmt::ELEMENT_TYPE_SWIMLANE),
tr("Swimlane"), QString(), QLatin1String(qmt::ELEMENT_TYPE_SWIMLANE),
QString(), toolBar));
}