Commit 81008125 authored by Jochen Becher's avatar Jochen Becher

ModelEditor: Support custom relations in configuration files

Change-Id: I87338f290bd1ea729682236df8b017516a18e7bb
Reviewed-by: Tobias Hunger's avatarTobias Hunger <tobias.hunger@qt.io>
parent 42844215
......@@ -2,6 +2,9 @@
//
// Language syntax and commands:
//
//
// An Icon defines an icon of an element selected by stereotype.
//
// Icon {
// id: <id>
// title: <a UI title. Defaults to the id of the icon.>
......@@ -29,6 +32,8 @@
// RoundedRect { x: <x>; y: <y>; width: <width>; height: <height>; radius: <radius> }
// Circle { x: <center_x>; y: <center_y>; radius: <radius> }
// Ellipse { x: <center_x>; y: <center_y>; radiusX: <radius_x>; radiusY: <radius_y> }
// Diamond { x: <center_x>; y: <center_y>; width: <width>; height: <height; filled: <yes or no or true or false> }
// Triangle { x: <center_x>; y: <center_y>; width: <width>; height: <height; filled: <yes or no or true or false> }
// Arc { x: <center_x>; y: <center_y>; radiusX: <radius_x>; radiusY: <radius_y>; start: <start_angle>; span: <span_angle> }
// MoveTo { x: <x>; y: <y> }
// LineTo { x: <x>; y: <y> }
......@@ -38,6 +43,79 @@
// }
// }
//
//
// A Relation defines a new relation between to items:
//
// Relation {
// id: <id>
// title: <a UI title. Defaults to the id of the icon.>
// elements: <A list of elements that may be the start or end element of the relation. Can be one of
// class, component, package, diagram, item or any id of an Icon definition. Must be given.>
// stereotype: <Stereotype as a string. Defaults to nothing.>
// name: <Name of the relation. Defaults to nothing.>
// direction: <One of AtoB, BtoA or Bi. Defaults to nothing.>
// pattern: <The pattern used for the relation shaft.
// One of solid, dash, dot, dashdot, dashdotdot. Defaults to solid>
// color: <The color of the relation. One of A or B (uses the color of the respective end element) or
// any valid color (#rrggbb or a color name). Defaults to A.>
// End {
// end: <One of A or B. Defines the settings of the relations end.>
// elements: <Overrides the elements property of parent.>
// role: <The role of the end. A string that defaults to nothing.>
// cardinality: <An integer or a string defining the cardinality of the end. Defaults to nothing.>
// navigable: <If the end is navigable. One of Yes, No, True, False. Defaults to nothing.>
// Shape {
// }
// }
// }
//
//
// A Dependency defines a number of settings of a dependency specialization:
//
// Dependency {
// id: <id>
// title: <a UI title. Defaults to the id of the icon.>
// elements: <A list of elements that provides this specialization in its menu. Can be one of
// class, component, package, diagram, item or any id of an Icon definition. Must be given.>
// stereotype: <Stereotype as a string. Defaults to nothing.>
// name: <Name of the relation. Defaults to nothing.>
// direction: <One of AtoB, BtoA or Bi. Defaults to nothing.>
// }
//
//
// An Inheritance defines settings of an inheritance specialization:
//
// Inheritance {
// id: <id>
// title: <a UI title. Defaults to the id of the icon.>
// elements: <A list of elements that provides this specialization in its menu. Can be one of
// class or any id of an Icon definition for classes. Defaults to class.>
// stereotype: <Stereotype as a string. Defaults to nothing.>
// name: <Name of the relation. Defaults to nothing.>
// }
//
//
// An Association defines settings of an association specialization:
//
// Association {
// id: <id>
// title: <a UI title. Defaults to the id of the icon.>
// elements: <A list of elements that provides this specialization in its menu. Can be one of
// class or any id of an Icon definition for classes. Defaults to class.>
// stereotype: <Stereotype as a string. Defaults to nothing.>
// name: <Name of the relation. Defaults to nothing.>
// End {
// end: <One of A or B. Defines the settings of the relations end.>
// role: <The role of the end. A string that defaults to nothing.>
// cardinality: <An integer or a string defining the cardinality of the end. Defaults to nothing.>
// navigable: <If the end is navigable. One of Yes, No, True, False. Defaults to nothing.>
// relationship: <One of Association, Aggregation, Composition. Defaults to Association.>
// }
// }
//
//
// A toolbar of icons. If no toolbar is defined the standard toolbar is shown.
//
// Toolbar {
// id: <id>
// title: <a Ui title. Defaults to the id of the toolbar>
......@@ -104,6 +182,54 @@ Icon {
}
}
Association {
id: AggregationOne
title: "Aggregation (?:1)"
End {
end: A
cardinality: 1
navigable: yes
relationship: aggregation
}
}
Association {
id: AggregationMany
title: "Aggregation (?:N)"
End {
end: A
cardinality: "*"
navigable: yes
relationship: aggregation
}
}
// ********************
// ** Class Toolbars **
// ********************
Toolbar {
id: ClassToolbar
element: class
Tools {
Tool { element: dependency }
Tool { element: inheritance }
Tool { element: association }
Tool { element: AggregationOne }
Tool { element: AggregationMany }
}
}
Toolbar {
id: InterfaceToolbar
element: Interface
Tools {
Tool { element: dependency }
Tool { element: inheritance }
}
}
// ****************
// ** Components **
// ****************
......@@ -276,6 +402,34 @@ Icon {
}
}
Relation {
id: Controlflow
pattern: solid
color: A
End {
end: A
elements: Start, Activity, Condition, HorizontalBar, VerticalBar
role: ""
}
End {
end: B
elements: Activity, Condition, HorizontalBar, VerticalBar, Termination
head: filledtriangle
//Shape {
// Triangle { x: 6; y: 5.2; width: 12; height: 10.4; filled: yes }
//}
}
}
Toolbar {
id: ActivityToolbar
element: Start, Activity, Condition, HorizontalBar, VerticalBar
Tools {
Tool { element: Controlflow }
Tool { element: dependency }
}
}
// **************
// ** Toolbars **
// **************
......
......@@ -252,6 +252,8 @@ QtcLibrary {
"serializer/modelserializer.h",
"serializer/projectserializer.cpp",
"serializer/projectserializer.h",
"stereotype/customrelation.cpp",
"stereotype/customrelation.h",
"stereotype/iconshape.cpp",
"stereotype/iconshape.h",
"stereotype/shape.h",
......
......@@ -71,6 +71,8 @@ void ConfigController::readStereotypeDefinitions(const QString &path)
StereotypeDefinitionParser parser;
connect(&parser, &StereotypeDefinitionParser::iconParsed,
this, &ConfigController::onStereotypeIconParsed);
connect(&parser, &StereotypeDefinitionParser::relationParsed,
this, &ConfigController::onRelationParsed);
connect(&parser, &StereotypeDefinitionParser::toolbarParsed,
this, &ConfigController::onToolbarParsed);
......@@ -116,6 +118,11 @@ void ConfigController::onStereotypeIconParsed(const StereotypeIcon &stereotypeIc
d->m_stereotypeController->addStereotypeIcon(stereotypeIcon);
}
void ConfigController::onRelationParsed(const CustomRelation &customRelation)
{
d->m_stereotypeController->addCustomRelation(customRelation);
}
void ConfigController::onToolbarParsed(const Toolbar &toolbar)
{
d->m_stereotypeController->addToolbar(toolbar);
......
......@@ -30,6 +30,7 @@
namespace qmt {
class CustomRelation;
class StereotypeController;
class StereotypeIcon;
class Toolbar;
......@@ -49,6 +50,7 @@ public:
private:
void onStereotypeIconParsed(const StereotypeIcon &stereotypeIcon);
void onRelationParsed(const CustomRelation &customRelation);
void onToolbarParsed(const Toolbar &toolbar);
ConfigControllerPrivate *d;
......
......@@ -30,6 +30,7 @@
#include "qmt/infrastructure/qmtassert.h"
#include "qmt/stereotype/stereotypeicon.h"
#include "qmt/stereotype/shapevalue.h"
#include "qmt/stereotype/customrelation.h"
#include "qmt/stereotype/toolbar.h"
#include <QHash>
......@@ -89,6 +90,40 @@ static const int KEYWORD_TOOL = 73;
static const int KEYWORD_ELEMENT = 74;
static const int KEYWORD_SEPARATOR = 75;
// Relation Definition
static const int KEYWORD_RELATION = 100;
static const int KEYWORD_DEPENDENCY = 101;
static const int KEYWORD_INHERITANCE = 102;
static const int KEYWORD_ASSOCIATION = 103;
static const int KEYWORD_NAME = 104;
static const int KEYWORD_DIRECTION = 105;
static const int KEYWORD_ATOB = 106;
static const int KEYWORD_BTOA = 107;
static const int KEYWORD_BI = 108;
static const int KEYWORD_END = 109;
static const int KEYWORD_A = 110;
static const int KEYWORD_B = 111;
static const int KEYWORD_ROLE = 112;
static const int KEYWORD_CARDINALITY = 113;
static const int KEYWORD_NAVIGABLE = 114;
static const int KEYWORD_RELATIONSHIP = 115;
static const int KEYWORD_AGGREGATION = 116;
static const int KEYWORD_COMPOSITION = 117;
static const int KEYWORD_SHAFT = 118;
static const int KEYWORD_HEAD = 119;
// Relation Shapes
static const int KEYWORD_DIAMOND = 130;
static const int KEYWORD_TRIANGLE = 131;
static const int KEYWORD_FILLED = 132;
static const int KEYWORD_PATTERN = 133;
static const int KEYWORD_SOLID = 134;
static const int KEYWORD_DOT = 135;
static const int KEYWORD_DASH = 136;
static const int KEYWORD_DASHDOT = 137;
static const int KEYWORD_DASHDOTDOT = 138;
static const int KEYWORD_COLOR = 139;
// Operatoren
static const int OPERATOR_SEMICOLON = 1;
static const int OPERATOR_BRACE_OPEN = 2;
......@@ -124,18 +159,61 @@ public:
class StereotypeDefinitionParser::IconCommandParameter
{
public:
enum Type {
ShapeValue,
Boolean
};
IconCommandParameter() = default;
IconCommandParameter(int keyword, ShapeValueF::Unit unit, ShapeValueF::Origin origin = ShapeValueF::OriginSmart)
: m_keyword(keyword),
m_type(ShapeValue),
m_unit(unit),
m_origin(origin)
{
}
IconCommandParameter(int keyword, Type type)
: m_keyword(keyword),
m_type(type)
{
}
operator ShapeValueF() const { return m_shapeValue; }
Type type() const { return m_type; }
ShapeValueF::Unit unit() const { return m_unit; }
ShapeValueF::Origin origin() const { return m_origin; }
ShapeValueF shapeValue() const { return m_shapeValue; }
void setShapeValue(const ShapeValueF &shapeValue) { m_shapeValue = shapeValue; }
bool boolean() const { return m_boolean; }
void setBoolean(bool boolean) { m_boolean = boolean; }
private:
int m_keyword = -1;
Type m_type = ShapeValue;
ShapeValueF::Unit m_unit = ShapeValueF::UnitAbsolute;
ShapeValueF::Origin m_origin = ShapeValueF::OriginCenter;
ShapeValueF::Origin m_origin = ShapeValueF::OriginSmart;
ShapeValueF m_shapeValue;
bool m_boolean = false;
};
class StereotypeDefinitionParser::Value
{
public:
Value(StereotypeDefinitionParser::Type type, QVariant value)
: m_type(type),
m_value(value)
{
}
StereotypeDefinitionParser::Type type() const { return m_type; }
QVariant value() const { return m_value; }
private:
StereotypeDefinitionParser::Type m_type = StereotypeDefinitionParser::Void;
QVariant m_value;
};
StereotypeDefinitionParser::StereotypeDefinitionParser(QObject *parent)
......@@ -196,6 +274,36 @@ void StereotypeDefinitionParser::parse(ITextSource *source)
<< qMakePair(QString(QStringLiteral("tool")), KEYWORD_TOOL)
<< qMakePair(QString(QStringLiteral("element")), KEYWORD_ELEMENT)
<< qMakePair(QString(QStringLiteral("separator")), KEYWORD_SEPARATOR)
<< qMakePair(QString(QStringLiteral("relation")), KEYWORD_RELATION)
<< qMakePair(QString(QStringLiteral("dependency")), KEYWORD_DEPENDENCY)
<< qMakePair(QString(QStringLiteral("inheritance")), KEYWORD_INHERITANCE)
<< qMakePair(QString(QStringLiteral("association")), KEYWORD_ASSOCIATION)
<< qMakePair(QString(QStringLiteral("name")), KEYWORD_NAME)
<< qMakePair(QString(QStringLiteral("direction")), KEYWORD_DIRECTION)
<< qMakePair(QString(QStringLiteral("atob")), KEYWORD_ATOB)
<< qMakePair(QString(QStringLiteral("btoa")), KEYWORD_BTOA)
<< qMakePair(QString(QStringLiteral("bi")), KEYWORD_BI)
<< qMakePair(QString(QStringLiteral("end")), KEYWORD_END)
<< qMakePair(QString(QStringLiteral("a")), KEYWORD_A)
<< qMakePair(QString(QStringLiteral("b")), KEYWORD_B)
<< qMakePair(QString(QStringLiteral("role")), KEYWORD_ROLE)
<< qMakePair(QString(QStringLiteral("cardinality")), KEYWORD_CARDINALITY)
<< qMakePair(QString(QStringLiteral("navigable")), KEYWORD_NAVIGABLE)
<< qMakePair(QString(QStringLiteral("relationship")), KEYWORD_RELATIONSHIP)
<< qMakePair(QString(QStringLiteral("aggregation")), KEYWORD_AGGREGATION)
<< qMakePair(QString(QStringLiteral("composition")), KEYWORD_COMPOSITION)
<< qMakePair(QString(QStringLiteral("shaft")), KEYWORD_SHAFT)
<< qMakePair(QString(QStringLiteral("head")), KEYWORD_HEAD)
<< qMakePair(QString(QStringLiteral("diamond")), KEYWORD_DIAMOND)
<< qMakePair(QString(QStringLiteral("triangle")), KEYWORD_TRIANGLE)
<< qMakePair(QString(QStringLiteral("filled")), KEYWORD_FILLED)
<< qMakePair(QString(QStringLiteral("pattern")), KEYWORD_PATTERN)
<< qMakePair(QString(QStringLiteral("solid")), KEYWORD_SOLID)
<< qMakePair(QString(QStringLiteral("dot")), KEYWORD_DOT)
<< qMakePair(QString(QStringLiteral("dash")), KEYWORD_DASH)
<< qMakePair(QString(QStringLiteral("dashdot")), KEYWORD_DASHDOT)
<< qMakePair(QString(QStringLiteral("dashdotdot")), KEYWORD_DASHDOTDOT)
<< qMakePair(QString(QStringLiteral("color")), KEYWORD_COLOR)
);
textScanner.setOperators(
QList<QPair<QString, int> >()
......@@ -229,8 +337,16 @@ void StereotypeDefinitionParser::parseFile()
parseIcon();
else if (token.type() == Token::TokenKeyword && token.subtype() == KEYWORD_TOOLBAR)
parseToolbar();
else if (token.type() == Token::TokenKeyword && token.subtype() == KEYWORD_RELATION)
parseRelation(CustomRelation::Element::Relation);
else if (token.type() == Token::TokenKeyword && token.subtype() == KEYWORD_DEPENDENCY)
parseRelation(CustomRelation::Element::Dependency);
else if (token.type() == Token::TokenKeyword && token.subtype() == KEYWORD_INHERITANCE)
parseRelation(CustomRelation::Element::Inheritance);
else if (token.type() == Token::TokenKeyword && token.subtype() == KEYWORD_ASSOCIATION)
parseRelation(CustomRelation::Element::Association);
else
throw StereotypeDefinitionParserError(QStringLiteral("Expected 'Icon' or 'Toolbar'."), token.sourcePos());
throw StereotypeDefinitionParserError(QStringLiteral("Expected 'Icon', 'Toolbar', 'Relation', 'Dependency', 'Inheritance' or 'Association'."), token.sourcePos());
}
}
......@@ -251,19 +367,15 @@ void StereotypeDefinitionParser::parseIcon()
break;
case KEYWORD_ELEMENTS:
{
QList<QString> identifiers = parseIdentifierListProperty();
foreach (const QString &identifier, identifiers) {
static QHash<QString, StereotypeIcon::Element> elementNames = QHash<QString, StereotypeIcon::Element>()
<< qMakePair(QString(QStringLiteral("package")), StereotypeIcon::ElementPackage)
<< qMakePair(QString(QStringLiteral("component")), StereotypeIcon::ElementComponent)
<< qMakePair(QString(QStringLiteral("class")), StereotypeIcon::ElementClass)
<< qMakePair(QString(QStringLiteral("diagram")), StereotypeIcon::ElementDiagram)
<< qMakePair(QString(QStringLiteral("item")), StereotypeIcon::ElementItem);
QString elementName = identifier.toLower();
if (!elementNames.contains(elementName))
throw StereotypeDefinitionParserError(QString(QStringLiteral("Unexpected value \"%1\" for element.")).arg(identifier), token.sourcePos());
elements.insert(elementNames.value(elementName));
}
const static QHash<QString, StereotypeIcon::Element> elementNames = QHash<QString, StereotypeIcon::Element>()
<< qMakePair(QString(QStringLiteral("package")), StereotypeIcon::ElementPackage)
<< qMakePair(QString(QStringLiteral("component")), StereotypeIcon::ElementComponent)
<< qMakePair(QString(QStringLiteral("class")), StereotypeIcon::ElementClass)
<< qMakePair(QString(QStringLiteral("diagram")), StereotypeIcon::ElementDiagram)
<< qMakePair(QString(QStringLiteral("item")), StereotypeIcon::ElementItem);
parseEnums<StereotypeIcon::Element>(
parseIdentifierListProperty(), elementNames, token.sourcePos(),
[&](StereotypeIcon::Element element) { elements.insert(element); });
break;
}
case KEYWORD_STEREOTYPE:
......@@ -283,61 +395,46 @@ void StereotypeDefinitionParser::parseIcon()
break;
case KEYWORD_LOCK_SIZE:
{
QString lockValue = parseIdentifierProperty();
QString lockName = lockValue.toLower();
static QHash<QString, StereotypeIcon::SizeLock> lockNames = QHash<QString, StereotypeIcon::SizeLock>()
const static QHash<QString, StereotypeIcon::SizeLock> lockNames = QHash<QString, StereotypeIcon::SizeLock>()
<< qMakePair(QString(QStringLiteral("none")), StereotypeIcon::LockNone)
<< qMakePair(QString(QStringLiteral("width")), StereotypeIcon::LockWidth)
<< qMakePair(QString(QStringLiteral("height")), StereotypeIcon::LockHeight)
<< qMakePair(QString(QStringLiteral("size")), StereotypeIcon::LockSize)
<< qMakePair(QString(QStringLiteral("ratio")), StereotypeIcon::LockRatio);
if (lockNames.contains(lockName)) {
StereotypeIcon::SizeLock sizeLock = lockNames.value(lockName);
stereotypeIcon.setSizeLock(sizeLock);
} else {
throw StereotypeDefinitionParserError(QString(QStringLiteral("Unexpected value \"%1\" for size lock.")).arg(lockValue), token.sourcePos());
}
parseEnum<StereotypeIcon::SizeLock>(
parseIdentifierProperty(), lockNames, token.sourcePos(),
[&](StereotypeIcon::SizeLock lock) { stereotypeIcon.setSizeLock(lock); });
break;
}
case KEYWORD_DISPLAY:
{
QString displayValue = parseIdentifierProperty();
QString displayName = displayValue.toLower();
static QHash<QString, StereotypeIcon::Display> displayNames = QHash<QString, StereotypeIcon::Display>()
const static QHash<QString, StereotypeIcon::Display> displayNames = QHash<QString, StereotypeIcon::Display>()
<< qMakePair(QString(QStringLiteral("none")), StereotypeIcon::DisplayNone)
<< qMakePair(QString(QStringLiteral("label")), StereotypeIcon::DisplayLabel)
<< qMakePair(QString(QStringLiteral("decoration")), StereotypeIcon::DisplayDecoration)
<< qMakePair(QString(QStringLiteral("icon")), StereotypeIcon::DisplayIcon)
<< qMakePair(QString(QStringLiteral("smart")), StereotypeIcon::DisplaySmart);
if (displayNames.contains(displayName)) {
StereotypeIcon::Display display = displayNames.value(displayName);
stereotypeIcon.setDisplay(display);
} else {
throw StereotypeDefinitionParserError(QString(QStringLiteral("Unexpected value \"%1\" for stereotype display.")).arg(displayValue), token.sourcePos());
}
parseEnum<StereotypeIcon::Display>(
parseIdentifierProperty(), displayNames, token.sourcePos(),
[&](StereotypeIcon::Display display) { stereotypeIcon.setDisplay(display); });
break;
}
case KEYWORD_TEXTALIGN:
{
QString alignValue = parseIdentifierProperty();
QString alignName = alignValue.toLower();
static QHash<QString, StereotypeIcon::TextAlignment> alignNames = QHash<QString, StereotypeIcon::TextAlignment>()
const static QHash<QString, StereotypeIcon::TextAlignment> alignNames = QHash<QString, StereotypeIcon::TextAlignment>()
<< qMakePair(QString(QStringLiteral("below")), StereotypeIcon::TextalignBelow)
<< qMakePair(QString(QStringLiteral("center")), StereotypeIcon::TextalignCenter)
<< qMakePair(QString(QStringLiteral("none")), StereotypeIcon::TextalignNone);
if (alignNames.contains(alignName)) {
StereotypeIcon::TextAlignment textAlignment = alignNames.value(alignName);
stereotypeIcon.setTextAlignment(textAlignment);
} else {
throw StereotypeDefinitionParserError(QString(QStringLiteral("Unexpected value \"%1\" for text alignment.")).arg(alignValue), token.sourcePos());
}
parseEnum<StereotypeIcon::TextAlignment>(
parseIdentifierProperty(), alignNames, token.sourcePos(),
[&](StereotypeIcon::TextAlignment align) { stereotypeIcon.setTextAlignment(align); });
break;
}
case KEYWORD_BASECOLOR:
stereotypeIcon.setBaseColor(parseColorProperty());
break;
case KEYWORD_SHAPE:
parseIconShape(&stereotypeIcon);
stereotypeIcon.setIconShape(parseIconShape());
break;
default:
throwUnknownPropertyError(token);
......@@ -367,10 +464,15 @@ QPair<int, StereotypeDefinitionParser::IconCommandParameter> StereotypeDefinitio
return qMakePair(keyword, IconCommandParameter(keyword, ShapeValueF::UnitAbsolute));
}
void StereotypeDefinitionParser::parseIconShape(StereotypeIcon *stereotypeIcon)
QPair<int, StereotypeDefinitionParser::IconCommandParameter> StereotypeDefinitionParser::BOOLEAN(int keyword)
{
return qMakePair(keyword, IconCommandParameter(keyword, IconCommandParameter::Boolean));
}
IconShape StereotypeDefinitionParser::parseIconShape()
{
IconShape iconShape;
QHash<int, ShapeValueF> values;
QHash<int, IconCommandParameter> values;
typedef QHash<int, IconCommandParameter> Parameters;
expectBlockBegin();
Token token;
......@@ -458,26 +560,50 @@ void StereotypeDefinitionParser::parseIconShape(StereotypeIcon *stereotypeIcon)
iconShape.closePath();
skipOptionalEmptyBlock();
break;
case KEYWORD_DIAMOND:
values = parseIconShapeProperties(
Parameters() << SCALED(KEYWORD_X) << SCALED(KEYWORD_Y)
<< SCALED(KEYWORD_WIDTH) << SCALED(KEYWORD_HEIGHT)
<< BOOLEAN(KEYWORD_FILLED));
iconShape.addDiamond(ShapePointF(values.value(KEYWORD_X), values.value(KEYWORD_Y)),
ShapeSizeF(values.value(KEYWORD_WIDTH), values.value(KEYWORD_HEIGHT)),
values.value(KEYWORD_FILLED).boolean());
break;
case KEYWORD_TRIANGLE:
values = parseIconShapeProperties(
Parameters() << SCALED(KEYWORD_X) << SCALED(KEYWORD_Y)
<< SCALED(KEYWORD_WIDTH) << SCALED(KEYWORD_HEIGHT)
<< BOOLEAN(KEYWORD_FILLED));
iconShape.addTriangle(ShapePointF(values.value(KEYWORD_X), values.value(KEYWORD_Y)),
ShapeSizeF(values.value(KEYWORD_WIDTH), values.value(KEYWORD_HEIGHT)),
values.value(KEYWORD_FILLED).boolean());
break;
default:
throwUnknownPropertyError(token);
}
if (!expectPropertySeparatorOrBlockEnd())
break;
}
stereotypeIcon->setIconShape(iconShape);
return iconShape;
}
QHash<int, ShapeValueF> StereotypeDefinitionParser::parseIconShapeProperties(const QHash<int, IconCommandParameter> &parameters)
QHash<int, StereotypeDefinitionParser::IconCommandParameter> StereotypeDefinitionParser::parseIconShapeProperties(const QHash<int, IconCommandParameter> &parameters)
{
expectBlockBegin();
QHash<int, ShapeValueF> values;
QHash<int, IconCommandParameter> values;
Token token;
while (readProperty(&token)) {
if (parameters.contains(token.subtype())) {
IconCommandParameter parameter = parameters.value(token.subtype());
if (values.contains(token.subtype()))
throw StereotypeDefinitionParserError(QStringLiteral("Property givent twice."), token.sourcePos());
values.insert(token.subtype(), ShapeValueF(parseFloatProperty(), parameter.m_unit, parameter.m_origin));
throw StereotypeDefinitionParserError(QStringLiteral("Property given twice."), token.sourcePos());
IconCommandParameter parameter = parameters.value(token.subtype());
if (parameter.type() == IconCommandParameter::ShapeValue)
parameter.setShapeValue(ShapeValueF(parseFloatProperty(), parameter.unit(), parameter.origin()));
else if (parameter.type() == IconCommandParameter::Boolean)
parameter.setBoolean(parseBoolProperty());
else
throw StereotypeDefinitionParserError("Unexpected type of property.", token.sourcePos());
values.insert(token.subtype(), parameter);
} else {
throwUnknownPropertyError(token);
}
......@@ -491,6 +617,192 @@ QHash<int, ShapeValueF> StereotypeDefinitionParser::parseIconShapeProperties(con
return values;
}
void StereotypeDefinitionParser::parseRelation(CustomRelation::Element element)
{
CustomRelation relation;
relation.setElement(element);
QSet<QString> stereotypes;
expectBlockBegin();
Token token;
while (readProperty(&token)) {
switch (token.subtype()) {
case KEYWORD_ID:
relation.setId(parseIdentifierProperty());
break;
case KEYWORD_TITLE:
relation.setTitle(parseStringProperty());
break;
case KEYWORD_ELEMENTS:
relation.setEndItems(parseIdentifierListProperty());
break;
case KEYWORD_STEREOTYPE:
stereotypes.insert(parseStringProperty());
break;
case KEYWORD_NAME:
relation.setName(parseStringProperty());
break;
case KEYWORD_DIRECTION:
{
const static QHash<QString, CustomRelation::Direction> directionNames = QHash<QString, CustomRelation::Direction>()
<< qMakePair(QString(QStringLiteral("atob")), CustomRelation::Direction::AtoB)
<< qMakePair(QString(QStringLiteral("btoa")), CustomRelation::Direction::BToA)
<< qMakePair(QString(QStringLiteral("bi")), CustomRelation::Direction::Bi);
if (element != CustomRelation::Element::Dependency)
throwUnknownPropertyError(token);
parseEnum<CustomRelation::Direction>(
parseIdentifierProperty(), directionNames, token.sourcePos(),
[&](CustomRelation::Direction direction) { relation.setDirection(direction); });
break;
}
case KEYWORD_PATTERN:
{
const static QHash<QString, CustomRelation::ShaftPattern> patternNames = QHash<QString, CustomRelation::ShaftPattern>()
<< qMakePair(QString(QStringLiteral("solid")), CustomRelation::ShaftPattern::Solid)
<< qMakePair(QString(QStringLiteral("dash")), CustomRelation::ShaftPattern::Dash)
<< qMakePair(QString(QStringLiteral("dot")), CustomRelation::ShaftPattern::Dot)
<< qMakePair(QString(QStringLiteral("dashdot")), CustomRelation::ShaftPattern::DashDot)
<< qMakePair(QString(QStringLiteral("dashdotdot")), CustomRelation::ShaftPattern::DashDotDot);
if (element != CustomRelation::Element::Relation)
throwUnknownPropertyError(token);
parseEnum<CustomRelation::ShaftPattern>(
parseIdentifierProperty(), patternNames, token.sourcePos(),
[&](CustomRelation::ShaftPattern pattern) { relation.setShaftPattern(pattern); });
break;
}
case KEYWORD_COLOR:
{
if (element != CustomRelation::Element::Relation)
throwUnknownPropertyError(token);
Value expression = parseProperty();
if (expression.type() == Color) {
relation.setColorType(CustomRelation::ColorType::Custom);
relation.setColor(expression.value().value<QColor>());