aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/modelinglib/qmt
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/modelinglib/qmt')
-rw-r--r--src/libs/modelinglib/qmt/config/configcontroller.cpp33
-rw-r--r--src/libs/modelinglib/qmt/config/configcontroller.h4
-rw-r--r--src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp145
-rw-r--r--src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h3
-rw-r--r--src/libs/modelinglib/qmt/controller/namecontroller.cpp41
-rw-r--r--src/libs/modelinglib/qmt/controller/namecontroller.h10
-rw-r--r--src/libs/modelinglib/qmt/diagram/dobject.cpp34
-rw-r--r--src/libs/modelinglib/qmt/diagram/dobject.h13
-rw-r--r--src/libs/modelinglib/qmt/diagram/drelation.cpp25
-rw-r--r--src/libs/modelinglib/qmt/diagram/drelation.h32
-rw-r--r--src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp5
-rw-r--r--src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp5
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/capabilities/windable.h2
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp79
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h2
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp65
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/classitem.h1
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp46
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h1
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp42
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.h1
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp43
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h1
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp184
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h9
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp40
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h1
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp52
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/relationitem.h2
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp4
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp24
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp86
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h5
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.cpp14
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.h2
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.cpp10
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.h3
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp2
-rw-r--r--src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp45
-rw-r--r--src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.h7
-rw-r--r--src/libs/modelinglib/qmt/document_controller/documentcontroller.cpp6
-rw-r--r--src/libs/modelinglib/qmt/document_controller/documentcontroller.h6
-rw-r--r--src/libs/modelinglib/qmt/infrastructure/ioexceptions.cpp16
-rw-r--r--src/libs/modelinglib/qmt/infrastructure/ioexceptions.h20
-rw-r--r--src/libs/modelinglib/qmt/model/mdiagram.h2
-rw-r--r--src/libs/modelinglib/qmt/model/mobject.cpp9
-rw-r--r--src/libs/modelinglib/qmt/model/mobject.h5
-rw-r--r--src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp1
-rw-r--r--src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.cpp43
-rw-r--r--src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.h72
-rw-r--r--src/libs/modelinglib/qmt/model_ui/sortedtreemodel.cpp220
-rw-r--r--src/libs/modelinglib/qmt/model_ui/sortedtreemodel.h7
-rw-r--r--src/libs/modelinglib/qmt/model_ui/treemodel.cpp4
-rw-r--r--src/libs/modelinglib/qmt/model_ui/treemodel.h7
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.cpp426
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.h43
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.cpp173
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.h39
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.cpp50
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.h4
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp281
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h143
-rw-r--r--src/libs/modelinglib/qmt/project/project.cpp6
-rw-r--r--src/libs/modelinglib/qmt/project/project.h14
-rw-r--r--src/libs/modelinglib/qmt/project_controller/projectcontroller.cpp8
-rw-r--r--src/libs/modelinglib/qmt/project_controller/projectcontroller.h10
-rw-r--r--src/libs/modelinglib/qmt/serializer/diagramserializer.cpp31
-rw-r--r--src/libs/modelinglib/qmt/serializer/diagramserializer.h3
-rw-r--r--src/libs/modelinglib/qmt/serializer/infrastructureserializer.h18
-rw-r--r--src/libs/modelinglib/qmt/serializer/modelserializer.cpp1
-rw-r--r--src/libs/modelinglib/qmt/serializer/projectserializer.cpp10
-rw-r--r--src/libs/modelinglib/qmt/serializer/projectserializer.h6
-rw-r--r--src/libs/modelinglib/qmt/stereotype/customrelation.cpp5
-rw-r--r--src/libs/modelinglib/qmt/stereotype/customrelation.h8
-rw-r--r--src/libs/modelinglib/qmt/stereotype/shapevalue.cpp2
-rw-r--r--src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp21
-rw-r--r--src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h13
-rw-r--r--src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp15
-rw-r--r--src/libs/modelinglib/qmt/stereotype/stereotypeicon.h25
-rw-r--r--src/libs/modelinglib/qmt/style/defaultstyleengine.cpp201
-rw-r--r--src/libs/modelinglib/qmt/style/defaultstyleengine.h8
-rw-r--r--src/libs/modelinglib/qmt/style/relationvisuals.cpp58
-rw-r--r--src/libs/modelinglib/qmt/style/relationvisuals.h42
-rw-r--r--src/libs/modelinglib/qmt/style/stylecontroller.cpp6
-rw-r--r--src/libs/modelinglib/qmt/style/stylecontroller.h4
-rw-r--r--src/libs/modelinglib/qmt/style/styledrelation.cpp6
-rw-r--r--src/libs/modelinglib/qmt/style/styledrelation.h6
-rw-r--r--src/libs/modelinglib/qmt/style/styleengine.h4
-rw-r--r--src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp56
-rw-r--r--src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h7
-rw-r--r--src/libs/modelinglib/qmt/tasks/ielementtasks.h7
-rw-r--r--src/libs/modelinglib/qmt/tasks/voidelementtasks.cpp20
-rw-r--r--src/libs/modelinglib/qmt/tasks/voidelementtasks.h7
93 files changed, 2736 insertions, 592 deletions
diff --git a/src/libs/modelinglib/qmt/config/configcontroller.cpp b/src/libs/modelinglib/qmt/config/configcontroller.cpp
index 4bb9b806c4..c584bce1c2 100644
--- a/src/libs/modelinglib/qmt/config/configcontroller.cpp
+++ b/src/libs/modelinglib/qmt/config/configcontroller.cpp
@@ -9,12 +9,11 @@
#include "qmt/stereotype/stereotypecontroller.h"
-#include <QDir>
-#include <QFileInfo>
-#include <QFile>
-
#include <QDebug>
+using Utils::FilePath;
+using Utils::FilePaths;
+
namespace qmt {
class ConfigController::ConfigControllerPrivate
@@ -39,7 +38,7 @@ void ConfigController::setStereotypeController(StereotypeController *stereotypeC
d->m_stereotypeController = stereotypeController;
}
-void ConfigController::readStereotypeDefinitions(const QString &path)
+void ConfigController::readStereotypeDefinitions(const FilePath &path)
{
if (path.isEmpty()) {
// TODO add error handling
@@ -54,25 +53,19 @@ void ConfigController::readStereotypeDefinitions(const QString &path)
connect(&parser, &StereotypeDefinitionParser::toolbarParsed,
this, &ConfigController::onToolbarParsed);
- QStringList fileNames;
- QDir dir;
- QFileInfo fileInfo(path);
- if (fileInfo.isFile()) {
- dir.setPath(fileInfo.path());
- fileNames.append(fileInfo.fileName());
- } else if (fileInfo.isDir()) {
- dir.setPath(path);
- dir.setNameFilters(QStringList("*.def"));
- fileNames = dir.entryList(QDir::Files);
+ FilePaths paths;
+ if (path.isFile()) {
+ paths.append(path);
+ } else if (path.isDir()) {
+ paths = path.dirEntries({ { "*.def" } });
} else {
// TODO add error handling
return;
}
- for (const QString &fileName : std::as_const(fileNames)) {
- QFile file(QFileInfo(dir, fileName).absoluteFilePath());
- if (file.open(QIODevice::ReadOnly)) {
- QString text = QString::fromUtf8(file.readAll());
- file.close();
+ for (const FilePath &filePath : std::as_const(paths)) {
+ auto data = filePath.fileContents();
+ if (data.has_value()) {
+ QString text = QString::fromUtf8(data.value());
StringTextSource source;
source.setSourceId(1);
source.setText(text);
diff --git a/src/libs/modelinglib/qmt/config/configcontroller.h b/src/libs/modelinglib/qmt/config/configcontroller.h
index 28e6d65afc..7d8af82f6e 100644
--- a/src/libs/modelinglib/qmt/config/configcontroller.h
+++ b/src/libs/modelinglib/qmt/config/configcontroller.h
@@ -5,6 +5,8 @@
#include "qmt/infrastructure/qmt_global.h"
+#include <utils/filepath.h>
+
#include <QObject>
namespace qmt {
@@ -24,7 +26,7 @@ public:
void setStereotypeController(StereotypeController *stereotypeController);
- void readStereotypeDefinitions(const QString &path);
+ void readStereotypeDefinitions(const Utils::FilePath &path);
private:
void onStereotypeIconParsed(const StereotypeIcon &stereotypeIcon);
diff --git a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp
index b3caebb164..d81f71c500 100644
--- a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp
+++ b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp
@@ -28,12 +28,15 @@ static const int KEYWORD_WIDTH = 6;
static const int KEYWORD_HEIGHT = 7;
static const int KEYWORD_MINWIDTH = 8;
static const int KEYWORD_MINHEIGHT = 9;
-static const int KEYWORD_LOCK_SIZE = 10;
-static const int KEYWORD_DISPLAY = 11;
-static const int KEYWORD_TEXTALIGN = 12;
-static const int KEYWORD_BASECOLOR = 13;
-static const int KEYWORD_SHAPE = 14;
-static const int KEYWORD_OUTLINE = 15;
+static const int KEYWORD_ICONWIDTH = 10;
+static const int KEYWORD_ICONHEIGHT = 11;
+static const int KEYWORD_LOCK_SIZE = 12;
+static const int KEYWORD_DISPLAY = 13;
+static const int KEYWORD_TEXTALIGN = 14;
+static const int KEYWORD_BASECOLOR = 15;
+static const int KEYWORD_SHAPE = 16;
+static const int KEYWORD_OUTLINE = 17;
+static const int KEYWORD_Z = 18;
// Shape items
static const int KEYWORD_CIRCLE = 30;
@@ -102,8 +105,18 @@ 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 KEYWORD_EMPHASIZED = 140;
+
+// Shape Value Units and Origin
+static const int KEYWORD_ABS = 150;
+static const int KEYWORD_FIX = 151;
+static const int KEYWORD_SCALE = 152;
+static const int KEYWORD_FRACT = 153;
+static const int KEYWORD_ORIGIN = 154;
+static const int KEYWORD_CENTER = 155;
+static const int KEYWORD_SIZE = 156;
+
+// Operators
static const int OPERATOR_SEMICOLON = 1;
static const int OPERATOR_BRACE_OPEN = 2;
static const int OPERATOR_BRACE_CLOSE = 3;
@@ -111,6 +124,7 @@ static const int OPERATOR_COLON = 4;
static const int OPERATOR_COMMA = 5;
static const int OPERATOR_PERIOD = 6;
static const int OPERATOR_MINUS = 7;
+static const int OPERATOR_PERCENTAGE = 8;
template <typename T, typename U>
QHash<T, U> operator<<(QHash<T, U> hash, QPair<T, U> pair) {
@@ -213,12 +227,15 @@ void StereotypeDefinitionParser::parse(ITextSource *source)
{"height", KEYWORD_HEIGHT},
{"minwidth", KEYWORD_MINWIDTH},
{"minheight", KEYWORD_MINHEIGHT},
+ {"iconwidth", KEYWORD_ICONWIDTH},
+ {"iconheight", KEYWORD_ICONHEIGHT},
{"locksize", KEYWORD_LOCK_SIZE},
{"display", KEYWORD_DISPLAY},
{"textalignment", KEYWORD_TEXTALIGN},
{"basecolor", KEYWORD_BASECOLOR},
{"shape", KEYWORD_SHAPE},
{"outline", KEYWORD_OUTLINE},
+ {"z", KEYWORD_Z},
{"circle", KEYWORD_CIRCLE},
{"ellipse", KEYWORD_ELLIPSE},
{"line", KEYWORD_LINE},
@@ -276,7 +293,15 @@ void StereotypeDefinitionParser::parse(ITextSource *source)
{"dash", KEYWORD_DASH},
{"dashdot", KEYWORD_DASHDOT},
{"dashdotdot", KEYWORD_DASHDOTDOT},
- {"color", KEYWORD_COLOR}});
+ {"color", KEYWORD_COLOR},
+ {"emphasized", KEYWORD_EMPHASIZED},
+ {"abs", KEYWORD_ABS},
+ {"fix", KEYWORD_FIX},
+ {"scale", KEYWORD_SCALE},
+ {"fract", KEYWORD_FRACT},
+ {"origin", KEYWORD_ORIGIN},
+ {"center", KEYWORD_CENTER},
+ {"size", KEYWORD_SIZE}});
textScanner.setOperators({{";", OPERATOR_SEMICOLON},
{"{", OPERATOR_BRACE_OPEN},
@@ -284,7 +309,8 @@ void StereotypeDefinitionParser::parse(ITextSource *source)
{":", OPERATOR_COLON},
{",", OPERATOR_COMMA},
{".", OPERATOR_PERIOD},
- {"-", OPERATOR_MINUS}});
+ {"-", OPERATOR_MINUS},
+ {"%", OPERATOR_PERCENTAGE}});
textScanner.setSource(source);
@@ -364,6 +390,23 @@ void StereotypeDefinitionParser::parseIcon()
case KEYWORD_MINHEIGHT:
stereotypeIcon.setMinHeight(parseFloatProperty());
break;
+ case KEYWORD_ICONWIDTH:
+ stereotypeIcon.setIconWith(parseFloatProperty());
+ break;
+ case KEYWORD_ICONHEIGHT:
+ stereotypeIcon.setIconHeight(parseFloatProperty());
+ break;
+ case KEYWORD_Z:
+ {
+ const static QHash<QString, StereotypeIcon::DepthLayer> zNames = QHash<QString, StereotypeIcon::DepthLayer>()
+ << qMakePair(QString("behinditems"), StereotypeIcon::DepthBehindItems)
+ << qMakePair(QString("amongitems"), StereotypeIcon::DepthAmongItems)
+ << qMakePair(QString("beforeitems"), StereotypeIcon::DepthBeforeItems);
+ parseEnum<StereotypeIcon::DepthLayer>(
+ parseIdentifierProperty(), zNames, token.sourcePos(),
+ [&](StereotypeIcon::DepthLayer layer) { stereotypeIcon.setDepthLayer(layer); });
+ break;
+ }
case KEYWORD_LOCK_SIZE:
{
const static QHash<QString, StereotypeIcon::SizeLock> lockNames
@@ -577,7 +620,7 @@ QHash<int, StereotypeDefinitionParser::IconCommandParameter> StereotypeDefinitio
throw StereotypeDefinitionParserError("Property given twice.", token.sourcePos());
IconCommandParameter parameter = parameters.value(token.subtype());
if (parameter.type() == IconCommandParameter::ShapeValue)
- parameter.setShapeValue(ShapeValueF(parseFloatProperty(), parameter.unit(), parameter.origin()));
+ parameter.setShapeValue(parseShapeValueProperty(parameter.unit(), parameter.origin()));
else if (parameter.type() == IconCommandParameter::Boolean)
parameter.setBoolean(parseBoolProperty());
else
@@ -650,8 +693,6 @@ void StereotypeDefinitionParser::parseRelation(CustomRelation::Element element)
}
case KEYWORD_COLOR:
{
- if (element != CustomRelation::Element::Relation)
- throwUnknownPropertyError(token);
Value expression = parseProperty();
if (expression.type() == Color) {
relation.setColorType(CustomRelation::ColorType::Custom);
@@ -663,6 +704,10 @@ void StereotypeDefinitionParser::parseRelation(CustomRelation::Element element)
relation.setColorType(CustomRelation::ColorType::EndA);
} else if (colorName == "b") {
relation.setColorType(CustomRelation::ColorType::EndB);
+ } else if (colorName == "warning") {
+ relation.setColorType(CustomRelation::ColorType::Warning);
+ } else if (colorName == "error") {
+ relation.setColorType(CustomRelation::ColorType::Error);
} else if (QColor::isValidColor(colorName)) {
relation.setColorType(CustomRelation::ColorType::Custom);
relation.setColor(QColor(colorName));
@@ -674,6 +719,9 @@ void StereotypeDefinitionParser::parseRelation(CustomRelation::Element element)
}
break;
}
+ case KEYWORD_EMPHASIZED:
+ relation.setEmphasized(parseBoolProperty());
+ break;
case KEYWORD_END:
parseRelationEnd(&relation);
break;
@@ -976,6 +1024,65 @@ StereotypeDefinitionParser::Value StereotypeDefinitionParser::parseProperty()
return parseExpression();
}
+ShapeValueF StereotypeDefinitionParser::parseShapeValueProperty(ShapeValueF::Unit unit, ShapeValueF::Origin origin)
+{
+ expectColon();
+ qreal value = parseFloatExpression();
+ // unit
+ Token token = d->m_scanner->read();
+ if (token.type() == Token::TokenOperator) {
+ switch (token.subtype()) {
+ case OPERATOR_PERCENTAGE:
+ unit = ShapeValueF::UnitPercentage;
+ break;
+ default:
+ d->m_scanner->unread(token);
+ break;
+ }
+ } else if (token.type() == Token::TokenKeyword) {
+ switch (token.subtype()) {
+ case KEYWORD_ABS:
+ unit = ShapeValueF::UnitAbsolute;
+ break;
+ case KEYWORD_FIX:
+ unit = ShapeValueF::UnitRelative;
+ break;
+ case KEYWORD_SCALE:
+ unit = ShapeValueF::UnitScaled;
+ break;
+ case KEYWORD_FRACT:
+ unit = ShapeValueF::UnitPercentage;
+ break;
+ default:
+ d->m_scanner->unread(token);
+ break;
+ }
+ } else {
+ d->m_scanner->unread(token);
+ }
+ // origin
+ token = d->m_scanner->read();
+ if (token.type() == Token::TokenKeyword) {
+ switch (token.subtype()) {
+ case KEYWORD_ORIGIN:
+ origin = ShapeValueF::OriginTopOrLeft;
+ break;
+ case KEYWORD_CENTER:
+ origin = ShapeValueF::OriginCenter;
+ break;
+ case KEYWORD_SIZE:
+ origin = ShapeValueF::OriginBottomOrRight;
+ break;
+ default:
+ d->m_scanner->unread(token);
+ break;
+ }
+ } else {
+ d->m_scanner->unread(token);
+ }
+ return ShapeValueF(value, unit, origin);
+}
+
QString StereotypeDefinitionParser::parseStringExpression()
{
Token token = d->m_scanner->read();
@@ -1050,11 +1157,8 @@ QColor StereotypeDefinitionParser::parseColorExpression()
Token token = d->m_scanner->read();
if (token.type() == Token::TokenIdentifier || token.type() == Token::TokenColor) {
QString value = token.text().toLower();
- QColor color;
- if (QColor::isValidColor(value)) {
- color.setNamedColor(value);
- return color;
- }
+ if (QColor::isValidColorName(value))
+ return QColor::fromString(value);
}
throw StereotypeDefinitionParserError("Expected color name.", token.sourcePos());
}
@@ -1084,9 +1188,8 @@ StereotypeDefinitionParser::Value StereotypeDefinitionParser::parseExpression()
return Value(Float, QVariant(value));
} else if (token.type() == Token::TokenColor) {
QString value = token.text().toLower();
- QColor color;
- if (QColor::isValidColor(value)) {
- color.setNamedColor(value);
+ if (QColor::isValidColorName(value)) {
+ const QColor color = QColor::fromString(value);
return Value(Color, QVariant(color));
} else {
throw StereotypeDefinitionParserError("Invalid color.", token.sourcePos());
diff --git a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h
index e32126c730..97b14211ca 100644
--- a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h
+++ b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.h
@@ -6,6 +6,7 @@
#include <QObject>
#include "qmt/infrastructure/exceptions.h"
#include "qmt/stereotype/customrelation.h"
+#include "qmt/stereotype/shapevalue.h"
#include "qmt/stereotype/toolbar.h"
#include "sourcepos.h"
@@ -20,7 +21,6 @@ class ITextSource;
class Token;
class StereotypeIcon;
class Toolbar;
-class ShapeValueF;
class QMT_EXPORT StereotypeDefinitionParserError : public Exception
{
@@ -97,6 +97,7 @@ private:
bool parseBoolProperty();
QColor parseColorProperty();
Value parseProperty();
+ ShapeValueF parseShapeValueProperty(ShapeValueF::Unit unit, ShapeValueF::Origin origin);
QString parseStringExpression();
qreal parseFloatExpression();
diff --git a/src/libs/modelinglib/qmt/controller/namecontroller.cpp b/src/libs/modelinglib/qmt/controller/namecontroller.cpp
index d910be4b12..2f9506d3fe 100644
--- a/src/libs/modelinglib/qmt/controller/namecontroller.cpp
+++ b/src/libs/modelinglib/qmt/controller/namecontroller.cpp
@@ -3,9 +3,10 @@
#include "namecontroller.h"
-#include <QFileInfo>
#include <QDebug>
+using Utils::FilePath;
+
namespace qmt {
NameController::NameController(QObject *parent)
@@ -17,10 +18,9 @@ NameController::~NameController()
{
}
-QString NameController::convertFileNameToElementName(const QString &fileName)
+QString NameController::convertFileNameToElementName(const FilePath &fileName)
{
- QFileInfo fileInfo(fileName);
- QString baseName = fileInfo.baseName().trimmed();
+ QString baseName = fileName.baseName().trimmed();
QString elementName;
bool makeTitlecase = true;
bool insertSpace = false;
@@ -65,13 +65,19 @@ QString NameController::convertElementNameToBaseFileName(const QString &elementN
return baseFileName;
}
-QString NameController::calcRelativePath(const QString &absoluteFileName, const QString &anchorPath)
+FilePath NameController::calcRelativePath(const FilePath &absoluteFileName,
+ const FilePath &anchorPath)
{
+ // TODO try using Utils::FilePath::relativePath
+ QString absoluteFilePath = absoluteFileName.path();
+ QString anchorPathString = anchorPath.path();
int secondLastSlashIndex = -1;
int slashIndex = -1;
int i = 0;
- while (i < absoluteFileName.size() && i < anchorPath.size() && absoluteFileName.at(i) == anchorPath.at(i)) {
- if (absoluteFileName.at(i) == QLatin1Char('/')) {
+ while (i < absoluteFilePath.size() && i < anchorPathString.size()
+ && absoluteFilePath.at(i) == anchorPathString.at(i))
+ {
+ if (absoluteFilePath.at(i) == QLatin1Char('/')) {
secondLastSlashIndex = slashIndex;
slashIndex = i;
}
@@ -81,22 +87,22 @@ QString NameController::calcRelativePath(const QString &absoluteFileName, const
QString relativePath;
if (slashIndex < 0) {
- relativePath = absoluteFileName;
- } else if (i >= absoluteFileName.size()) {
+ relativePath = absoluteFilePath;
+ } else if (i >= absoluteFilePath.size()) {
// absoluteFileName is a substring of anchor path.
if (slashIndex == i - 1) {
if (secondLastSlashIndex < 0)
- relativePath = absoluteFileName;
+ relativePath = absoluteFilePath;
else
- relativePath = absoluteFileName.mid(secondLastSlashIndex + 1);
+ relativePath = absoluteFilePath.mid(secondLastSlashIndex + 1);
} else {
- relativePath = absoluteFileName.mid(slashIndex + 1);
+ relativePath = absoluteFilePath.mid(slashIndex + 1);
}
} else {
- relativePath = absoluteFileName.mid(slashIndex + 1);
+ relativePath = absoluteFilePath.mid(slashIndex + 1);
}
- return relativePath;
+ return FilePath::fromString(relativePath);
}
QString NameController::calcElementNameSearchId(const QString &elementName)
@@ -109,16 +115,17 @@ QString NameController::calcElementNameSearchId(const QString &elementName)
return searchId;
}
-QStringList NameController::buildElementsPath(const QString &filePath, bool ignoreLastFilePathPart)
+QStringList NameController::buildElementsPath(const FilePath &filePath,
+ bool ignoreLastFilePathPart)
{
QList<QString> relativeElements;
- QStringList split = filePath.split("/");
+ QStringList split = filePath.toString().split("/");
QStringList::const_iterator splitEnd = split.constEnd();
if (ignoreLastFilePathPart || split.last().isEmpty())
--splitEnd;
for (auto it = split.constBegin(); it != splitEnd; ++it) {
- QString packageName = qmt::NameController::convertFileNameToElementName(*it);
+ QString packageName = qmt::NameController::convertFileNameToElementName(FilePath::fromString(*it));
relativeElements.append(packageName);
}
return relativeElements;
diff --git a/src/libs/modelinglib/qmt/controller/namecontroller.h b/src/libs/modelinglib/qmt/controller/namecontroller.h
index 03e3be30bb..bb1ff0c3e1 100644
--- a/src/libs/modelinglib/qmt/controller/namecontroller.h
+++ b/src/libs/modelinglib/qmt/controller/namecontroller.h
@@ -6,6 +6,8 @@
#include <QObject>
#include "qmt/infrastructure/qmt_global.h"
+#include <utils/filepath.h>
+
#include <QString>
#include <QStringList>
@@ -18,12 +20,12 @@ private:
~NameController() override;
public:
- static QString convertFileNameToElementName(const QString &fileName);
+ static QString convertFileNameToElementName(const Utils::FilePath &fileName);
static QString convertElementNameToBaseFileName(const QString &elementName);
- // TODO use Utils::FilePath instead
- static QString calcRelativePath(const QString &absoluteFileName, const QString &anchorPath);
+ static Utils::FilePath calcRelativePath(const Utils::FilePath &absoluteFileName,
+ const Utils::FilePath &anchorPath);
static QString calcElementNameSearchId(const QString &elementName);
- static QStringList buildElementsPath(const QString &filePath, bool ignoreLastFilePathPart);
+ static QStringList buildElementsPath(const Utils::FilePath &filePath, bool ignoreLastFilePathPart);
static bool parseClassName(const QString &fullClassName, QString *umlNamespace,
QString *className, QStringList *templateParameters);
};
diff --git a/src/libs/modelinglib/qmt/diagram/dobject.cpp b/src/libs/modelinglib/qmt/diagram/dobject.cpp
index 4e0e5cb642..543e6af30f 100644
--- a/src/libs/modelinglib/qmt/diagram/dobject.cpp
+++ b/src/libs/modelinglib/qmt/diagram/dobject.cpp
@@ -6,11 +6,11 @@
#include "dvisitor.h"
#include "dconstvisitor.h"
+using Utils::FilePath;
+
namespace qmt {
-DObject::DObject()
-{
-}
+DObject::DObject() {}
DObject::DObject(const DObject &rhs)
: DElement(rhs),
@@ -25,7 +25,10 @@ DObject::DObject(const DObject &rhs)
m_visualSecondaryRole(rhs.m_visualSecondaryRole),
m_stereotypeDisplay(rhs.m_stereotypeDisplay),
m_isAutoSized(rhs.m_isAutoSized),
- m_isVisualEmphasized(rhs.m_isVisualEmphasized)
+ m_isVisualEmphasized(rhs.m_isVisualEmphasized),
+ m_hasLinkedFile(rhs.m_hasLinkedFile),
+ m_imagePath(rhs.m_imagePath),
+ m_image(rhs.m_image)
{
}
@@ -49,6 +52,9 @@ DObject &DObject::operator =(const DObject &rhs)
m_stereotypeDisplay = rhs.m_stereotypeDisplay;
m_isAutoSized = rhs.m_isAutoSized;
m_isVisualEmphasized = rhs.m_isVisualEmphasized;
+ m_hasLinkedFile = rhs.m_hasLinkedFile;
+ m_imagePath = rhs.m_imagePath;
+ m_image = rhs.m_image;
}
return *this;
}
@@ -113,6 +119,26 @@ void DObject::setVisualEmphasized(bool visualEmphasized)
m_isVisualEmphasized = visualEmphasized;
}
+void DObject::setLinkedFile(bool linkedFile)
+{
+ m_hasLinkedFile = linkedFile;
+}
+
+bool DObject::hasImage() const
+{
+ return !m_image.isNull();
+}
+
+void DObject::setImagePath(const FilePath &path)
+{
+ m_imagePath = path;
+}
+
+void DObject::setImage(const QImage &image)
+{
+ m_image = image;
+}
+
void DObject::accept(DVisitor *visitor)
{
visitor->visitDObject(this);
diff --git a/src/libs/modelinglib/qmt/diagram/dobject.h b/src/libs/modelinglib/qmt/diagram/dobject.h
index c8cf2b0e4d..7364f15749 100644
--- a/src/libs/modelinglib/qmt/diagram/dobject.h
+++ b/src/libs/modelinglib/qmt/diagram/dobject.h
@@ -7,6 +7,9 @@
#include "qmt/infrastructure/uid.h"
+#include <utils/filepath.h>
+
+#include <QImage>
#include <QList>
#include <QPointF>
#include <QRectF>
@@ -78,6 +81,13 @@ public:
void setAutoSized(bool autoSized);
bool isVisualEmphasized() const { return m_isVisualEmphasized; }
void setVisualEmphasized(bool visualEmphasized);
+ bool hasLinkedFile() const { return m_hasLinkedFile; }
+ void setLinkedFile(bool linkedFile);
+ Utils::FilePath imagePath() const { return m_imagePath; }
+ void setImagePath(const Utils::FilePath &path);
+ bool hasImage() const;
+ QImage image() const { return m_image; }
+ void setImage(const QImage &image);
void accept(DVisitor *visitor) override;
void accept(DConstVisitor *visitor) const override;
@@ -95,6 +105,9 @@ private:
StereotypeDisplay m_stereotypeDisplay = StereotypeSmart;
bool m_isAutoSized = true;
bool m_isVisualEmphasized = false;
+ bool m_hasLinkedFile = false;
+ Utils::FilePath m_imagePath;
+ QImage m_image;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/diagram/drelation.cpp b/src/libs/modelinglib/qmt/diagram/drelation.cpp
index a21f61c707..890bd275e4 100644
--- a/src/libs/modelinglib/qmt/diagram/drelation.cpp
+++ b/src/libs/modelinglib/qmt/diagram/drelation.cpp
@@ -65,6 +65,31 @@ void DRelation::setIntermediatePoints(const QList<DRelation::IntermediatePoint>
m_intermediatePoints = intermediatePoints;
}
+void DRelation::setVisualPrimaryRole(VisualPrimaryRole visualPrimaryRole)
+{
+ m_visualPrimaryRole = visualPrimaryRole;
+}
+
+void DRelation::setVisualSecondaryRole(VisualSecondaryRole visualSecondaryRole)
+{
+ m_visualSecondaryRole = visualSecondaryRole;
+}
+
+void DRelation::setVisualEmphasized(bool visualEmphasized)
+{
+ m_isVisualEmphasized = visualEmphasized;
+}
+
+void DRelation::setColor(const QColor &color)
+{
+ m_color = color;
+}
+
+void DRelation::setThickness(qreal thickness)
+{
+ m_thickness = thickness;
+}
+
void DRelation::accept(DVisitor *visitor)
{
visitor->visitDRelation(this);
diff --git a/src/libs/modelinglib/qmt/diagram/drelation.h b/src/libs/modelinglib/qmt/diagram/drelation.h
index 34bdaf1986..ed5624ad9f 100644
--- a/src/libs/modelinglib/qmt/diagram/drelation.h
+++ b/src/libs/modelinglib/qmt/diagram/drelation.h
@@ -5,6 +5,7 @@
#include "delement.h"
+#include <QColor>
#include <QList>
#include <QPointF>
@@ -15,6 +16,22 @@ class DObject;
class QMT_EXPORT DRelation : public DElement
{
public:
+ enum VisualPrimaryRole {
+ PrimaryRoleNormal,
+ PrimaryRoleCustom1,
+ PrimaryRoleCustom2,
+ PrimaryRoleCustom3,
+ PrimaryRoleCustom4,
+ PrimaryRoleCustom5
+ };
+
+ enum VisualSecondaryRole {
+ SecondaryRoleNone,
+ SecondaryRoleWarning,
+ SecondaryRoleError,
+ SecondaryRoleSoften
+ };
+
class IntermediatePoint
{
public:
@@ -42,6 +59,16 @@ public:
void setName(const QString &name);
const QList<IntermediatePoint> intermediatePoints() const { return m_intermediatePoints; }
void setIntermediatePoints(const QList<IntermediatePoint> &intermediatePoints);
+ VisualPrimaryRole visualPrimaryRole() const { return m_visualPrimaryRole; }
+ void setVisualPrimaryRole(VisualPrimaryRole visualPrimaryRole);
+ VisualSecondaryRole visualSecondaryRole() const { return m_visualSecondaryRole; }
+ void setVisualSecondaryRole(VisualSecondaryRole visualSecondaryRole);
+ bool isVisualEmphasized() const { return m_isVisualEmphasized; }
+ void setVisualEmphasized(bool visualEmphasized);
+ QColor color() const { return m_color; }
+ void setColor(const QColor &color);
+ qreal thickness() const { return m_thickness; }
+ void setThickness(qreal thickness);
void accept(DVisitor *visitor) override;
void accept(DConstVisitor *visitor) const override;
@@ -53,6 +80,11 @@ private:
Uid m_endBUid;
QString m_name;
QList<IntermediatePoint> m_intermediatePoints;
+ VisualPrimaryRole m_visualPrimaryRole = PrimaryRoleNormal;
+ VisualSecondaryRole m_visualSecondaryRole = SecondaryRoleNone;
+ bool m_isVisualEmphasized = false;
+ QColor m_color;
+ qreal m_thickness = 0;
};
bool operator==(const DRelation::IntermediatePoint &lhs, const DRelation::IntermediatePoint &rhs);
diff --git a/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp b/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp
index 5e88175812..5e4c072588 100644
--- a/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp
+++ b/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp
@@ -49,7 +49,10 @@ void DFlatAssignmentVisitor::visitDObject(const DObject *object)
target->setVisualPrimaryRole(object->visualPrimaryRole());
target->setVisualSecondaryRole(object->visualSecondaryRole());
target->setVisualEmphasized(object->isVisualEmphasized());
+ target->setLinkedFile(object->hasLinkedFile());
target->setStereotypeDisplay(object->stereotypeDisplay());
+ target->setImagePath(object->imagePath());
+ target->setImage(object->image());
}
void DFlatAssignmentVisitor::visitDPackage(const DPackage *package)
@@ -100,6 +103,8 @@ void DFlatAssignmentVisitor::visitDRelation(const DRelation *relation)
QMT_ASSERT(target, return);
target->setStereotypes(relation->stereotypes());
target->setIntermediatePoints(relation->intermediatePoints());
+ target->setVisualPrimaryRole(relation->visualPrimaryRole());
+ target->setThickness(relation->thickness());
}
void DFlatAssignmentVisitor::visitDInheritance(const DInheritance *inheritance)
diff --git a/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp b/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp
index 91a95438ad..2dd079e1bc 100644
--- a/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp
+++ b/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp
@@ -65,13 +65,16 @@ void DUpdateVisitor::visitMObject(const MObject *object)
}
if (isUpdating(object->name() != dobject->name()))
dobject->setName(object->name());
+ bool hasLinkedFile = !object->linkedFileName().isEmpty();
+ if (isUpdating(hasLinkedFile != dobject->hasLinkedFile()))
+ dobject->setLinkedFile(hasLinkedFile);
// TODO unlikely that this is called for all objects if hierarchy is modified
// PERFORM remove loop
int depth = 1;
const MObject *owner = object->owner();
while (owner) {
owner = owner->owner();
- depth += 1;
+ depth += 3;
}
if (isUpdating(depth != dobject->depth()))
dobject->setDepth(depth);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/capabilities/windable.h b/src/libs/modelinglib/qmt/diagram_scene/capabilities/windable.h
index a21f1caea3..c31249e5c1 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/capabilities/windable.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/capabilities/windable.h
@@ -20,7 +20,7 @@ public:
virtual void insertHandle(int beforeIndex, const QPointF &pos, double rasterWidth, double rasterHeight) = 0;
virtual void deleteHandle(int index) = 0;
virtual void setHandlePos(int index, const QPointF &pos) = 0;
- virtual void dropHandle(int index, double rasterWidth, double rasterHeight) = 0;
+ virtual void dropHandle(int index, bool extraSnap, double rasterWidth, double rasterHeight) = 0;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp
index de8b82de20..9366a39503 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp
@@ -209,15 +209,26 @@ DSelection DiagramSceneModel::selectedElements() const
return selection;
}
-DElement *DiagramSceneModel::findTopmostElement(const QPointF &scenePos) const
+QGraphicsItem *DiagramSceneModel::findTopmostItem(const QPointF &scenePos) const
{
// fetch affected items from scene in correct drawing order to find topmost element
const QList<QGraphicsItem *> items = m_graphicsScene->items(scenePos);
+ QGraphicsItem *candidate = NULL;
for (QGraphicsItem *item : items) {
- if (m_graphicsItems.contains(item))
- return m_itemToElementMap.value(item);
+ if (m_graphicsItems.contains(item)) {
+ if (!candidate || item->zValue() > candidate->zValue())
+ candidate = item;
+ }
}
- return nullptr;
+ return candidate;
+}
+
+DElement *DiagramSceneModel::findTopmostElement(const QPointF &scenePos) const
+{
+ QGraphicsItem *item = findTopmostItem(scenePos);
+ if (!item)
+ return nullptr;
+ return m_itemToElementMap.value(item);
}
DObject *DiagramSceneModel::findTopmostObject(const QPointF &scenePos) const
@@ -230,16 +241,13 @@ DObject *DiagramSceneModel::findTopmostObject(const QPointF &scenePos) const
ObjectItem *DiagramSceneModel::findTopmostObjectItem(const QPointF &scenePos) const
{
- // fetch affected items from scene in correct drawing order to find topmost element
- const QList<QGraphicsItem *> items = m_graphicsScene->items(scenePos);
- for (QGraphicsItem *item : std::as_const(items)) {
- if (m_graphicsItems.contains(item)) {
- DObject *object = dynamic_cast<DObject *>(m_itemToElementMap.value(item));
- if (object)
- return dynamic_cast<ObjectItem *>(item);
- }
- }
- return nullptr;
+ QGraphicsItem *item = findTopmostItem(scenePos);
+ if (!item)
+ return nullptr;
+ DObject *object = dynamic_cast<DObject *>(m_itemToElementMap.value(item));
+ if (!object)
+ return nullptr;
+ return dynamic_cast<ObjectItem *>(item);
}
QGraphicsItem *DiagramSceneModel::graphicsItem(DElement *element) const
@@ -353,7 +361,8 @@ void DiagramSceneModel::selectAllElements()
void DiagramSceneModel::selectElement(DElement *element)
{
QGraphicsItem *selectItem = m_elementToItemMap.value(element);
- for (QGraphicsItem *item : std::as_const(m_selectedItems)) {
+ auto selectedItems = m_selectedItems;
+ for (QGraphicsItem *item : std::as_const(selectedItems)) {
if (item != selectItem)
item->setSelected(false);
}
@@ -363,9 +372,17 @@ void DiagramSceneModel::selectElement(DElement *element)
void DiagramSceneModel::editElement(DElement *element)
{
- auto editable = dynamic_cast<IEditable *>(m_elementToItemMap.value(element));
- if (editable && editable->isEditable())
+ QGraphicsItem *item = m_elementToItemMap.value(element);
+ auto editable = dynamic_cast<IEditable *>(item);
+ if (editable && editable->isEditable()) {
+ auto selectable = dynamic_cast<ISelectable *>(item);
+ if (selectable && item != m_focusItem) {
+ unsetFocusItem();
+ selectable->setFocusSelected(true);
+ m_focusItem = item;
+ }
editable->edit();
+ }
}
void DiagramSceneModel::copyToClipboard()
@@ -507,9 +524,8 @@ void DiagramSceneModel::selectItem(QGraphicsItem *item, bool multiSelect)
{
if (!multiSelect) {
if (!item->isSelected()) {
- // We have to create a copy since "setSelected" may modify m_selectedItems
- const QSet<QGraphicsItem *> copy = m_selectedItems;
- for (QGraphicsItem *selectedItem : copy) {
+ auto selectedItems = m_selectedItems;
+ for (QGraphicsItem *selectedItem : std::as_const(selectedItems)) {
if (selectedItem != item)
selectedItem->setSelected(false);
}
@@ -624,6 +640,7 @@ void DiagramSceneModel::keyReleaseEvent(QKeyEvent *event)
void DiagramSceneModel::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
+ m_mousePressed = true;
updateFocusItem(Utils::toSet(m_graphicsScene->selectedItems()));
m_latchController->mousePressEventLatching(event);
mousePressEventReparenting(event);
@@ -658,8 +675,10 @@ void DiagramSceneModel::mouseMoveEventReparenting(QGraphicsSceneMouseEvent *even
void DiagramSceneModel::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
+ m_mousePressed = false;
m_latchController->mouseReleaseEventLatching(event);
mouseReleaseEventReparenting(event);
+ recalcSceneRectSize();
}
void DiagramSceneModel::mouseReleaseEventReparenting(QGraphicsSceneMouseEvent *event)
@@ -851,7 +870,7 @@ void DiagramSceneModel::onSelectionChanged()
QSet<QGraphicsItem *> newSecondarySelectedItems;
// select all contained objects secondarily
- for (QGraphicsItem *selectedItem : std::as_const(m_secondarySelectedItems)) {
+ for (QGraphicsItem *selectedItem : std::as_const(m_selectedItems)) {
const QList<QGraphicsItem *> items = collectCollidingObjectItems(selectedItem, CollidingInnerItems);
for (QGraphicsItem *item : items) {
if (!item->isSelected() && dynamic_cast<ISelectable *>(item)
@@ -908,7 +927,8 @@ void DiagramSceneModel::onSelectionChanged()
}
}
- for (QGraphicsItem *item : std::as_const(m_secondarySelectedItems)) {
+ auto secondarySelectedItems = m_secondarySelectedItems;
+ for (QGraphicsItem *item : std::as_const(secondarySelectedItems)) {
if (!newSecondarySelectedItems.contains(item)) {
auto selectable = dynamic_cast<ISelectable *>(item);
QMT_ASSERT(selectable, return);
@@ -1039,8 +1059,19 @@ void DiagramSceneModel::recalcSceneRectSize()
if (!dynamic_cast<SwimlaneItem *>(item))
sceneRect |= item->mapRectToScene(item->boundingRect());
}
- m_sceneRect = sceneRect;
- emit sceneRectChanged(sceneRect);
+ if (m_mousePressed) {
+ if (sceneRect.left() < m_sceneRect.left())
+ m_sceneRect.setLeft(sceneRect.left());
+ if (sceneRect.right() > m_sceneRect.right())
+ m_sceneRect.setRight(sceneRect.right());
+ if (sceneRect.top() < m_sceneRect.top())
+ m_sceneRect.setTop(sceneRect.top());
+ if (sceneRect.bottom() > m_sceneRect.bottom())
+ m_sceneRect.setBottom(sceneRect.bottom());
+ } else {
+ m_sceneRect = sceneRect;
+ }
+ emit sceneRectChanged(m_sceneRect);
}
QGraphicsItem *DiagramSceneModel::createGraphicsItem(DElement *element)
diff --git a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h
index 0021faf459..b976f421f9 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h
@@ -79,6 +79,7 @@ public:
bool hasSelection() const;
bool hasMultiObjectsSelection() const;
DSelection selectedElements() const;
+ QGraphicsItem *findTopmostItem(const QPointF &scenePos) const;
DElement *findTopmostElement(const QPointF &scenePos) const;
DObject *findTopmostObject(const QPointF &scenePos) const;
ObjectItem *findTopmostObjectItem(const QPointF &scenePos) const;
@@ -169,6 +170,7 @@ private:
QGraphicsItem *m_focusItem = nullptr;
QRectF m_sceneRect;
QList<Uid> m_relationEndsUid;
+ bool m_mousePressed = false;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp
index 14ad25b2c1..23a9c524a2 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp
@@ -85,29 +85,16 @@ void ClassItem::update()
m_methodsText.clear();
}
- // custom icon
- if (stereotypeIconDisplay() == StereotypeIcon::DisplayIcon) {
- if (!m_customIcon)
- m_customIcon = new CustomIconItem(diagramSceneModel(), this);
- m_customIcon->setStereotypeIconId(stereotypeIconId());
- 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());
- m_customIcon->setZValue(SHAPE_ZVALUE);
- } else if (m_customIcon) {
- m_customIcon->scene()->removeItem(m_customIcon);
- delete m_customIcon;
- m_customIcon = nullptr;
- }
+ updateCustomIcon(style);
// shape
- if (!m_customIcon) {
+ if (!customIconItem()) {
if (!m_shape)
m_shape = new QGraphicsRectItem(this);
m_shape->setBrush(style->fillBrush());
m_shape->setPen(style->outerLinePen());
m_shape->setZValue(SHAPE_ZVALUE);
- } else if (m_shape){
+ } else if (m_shape) {
m_shape->scene()->removeItem(m_shape);
delete m_shape;
m_shape = nullptr;
@@ -259,7 +246,7 @@ void ClassItem::update()
m_templateParameterBox = nullptr;
}
- updateSelectionMarker(m_customIcon);
+ updateSelectionMarker(customIconItem());
updateRelationStarter();
updateAlignmentButtons();
updateGeometry();
@@ -267,8 +254,8 @@ void ClassItem::update()
bool ClassItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- if (m_customIcon) {
- QList<QPolygonF> polygons = m_customIcon->outline();
+ if (customIconItem()) {
+ QList<QPolygonF> polygons = customIconItem()->outline();
for (int i = 0; i < polygons.size(); ++i)
polygons[i].translate(object()->pos() + object()->rect().topLeft());
if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
@@ -508,7 +495,7 @@ DClass::TemplateDisplay ClassItem::templateDisplay() const
DClass::TemplateDisplay templateDisplay = diagramClass->templateDisplay();
if (templateDisplay == DClass::TemplateSmart) {
- if (m_customIcon)
+ if (customIconItem())
templateDisplay = DClass::TemplateName;
else
templateDisplay = DClass::TemplateBox;
@@ -521,8 +508,8 @@ QSizeF ClassItem::calcMinimumGeometry() const
double width = 0.0;
double height = 0.0;
- if (m_customIcon) {
- QSizeF sz = stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(),
+ if (customIconItem()) {
+ QSizeF sz = customIconItemMinimumSize(customIconItem(),
CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT);
if (shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignTop
&& shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignCenter)
@@ -589,12 +576,7 @@ void ClassItem::updateGeometry()
height = geometry.height();
if (object()->isAutoSized()) {
- if (!m_customIcon) {
- if (width < MINIMUM_AUTO_WIDTH)
- width = MINIMUM_AUTO_WIDTH;
- if (height < MINIMUM_AUTO_HEIGHT)
- height = MINIMUM_AUTO_HEIGHT;
- }
+ correctAutoSize(customIconItem(), width, height, MINIMUM_AUTO_WIDTH, MINIMUM_AUTO_HEIGHT);
} else {
QRectF rect = object()->rect();
if (rect.width() > width)
@@ -619,15 +601,15 @@ void ClassItem::updateGeometry()
// a backup for the graphics item used for manual resized and persistency.
object()->setRect(rect);
- if (m_customIcon) {
- m_customIcon->setPos(left, top);
- m_customIcon->setActualSize(QSizeF(width, height));
+ if (customIconItem()) {
+ customIconItem()->setPos(left, top);
+ customIconItem()->setActualSize(QSizeF(width, height));
}
if (m_shape)
m_shape->setRect(rect);
- if (m_customIcon) {
+ if (customIconItem()) {
switch (shapeIcon().textAlignment()) {
case qmt::StereotypeIcon::TextalignBelow:
y += height + BODY_VERT_BORDER;
@@ -679,7 +661,7 @@ void ClassItem::updateGeometry()
y += nameItem()->boundingRect().height();
}
if (m_contextLabel) {
- if (m_customIcon)
+ if (customIconItem())
m_contextLabel->resetMaxWidth();
else
m_contextLabel->setMaxWidth(width - 2 * BODY_HORIZ_BORDER);
@@ -692,7 +674,7 @@ void ClassItem::updateGeometry()
y += 8.0;
}
if (m_attributes) {
- if (m_customIcon)
+ if (customIconItem())
m_attributes->setPos(-m_attributes->boundingRect().width() / 2.0, y);
else
m_attributes->setPos(left + BODY_HORIZ_BORDER, y);
@@ -704,7 +686,7 @@ void ClassItem::updateGeometry()
y += 8.0;
}
if (m_methods) {
- if (m_customIcon)
+ if (customIconItem())
m_methods->setPos(-m_methods->boundingRect().width() / 2.0, y);
else
m_methods->setPos(left + BODY_HORIZ_BORDER, y);
@@ -765,21 +747,22 @@ void ClassItem::updateMembers(const Style *style)
break;
}
+ bool needBr = false;
if (text && !text->isEmpty())
- *text += "<br/>";
+ needBr = true;
- bool addNewline = false;
- bool addSpace = false;
if (currentVisibility)
*currentVisibility = member.visibility();
if (currentGroup && member.group() != *currentGroup) {
- *text += QString("[%1]").arg(member.group());
- addNewline = true;
+ needBr = false;
+ *text += QString("<p style=\"padding:0;margin-top:6;margin-bottom:0;\"><b>[%1]</b></p>").arg(member.group());
*currentGroup = member.group();
}
- if (addNewline)
+
+ if (needBr)
*text += "<br/>";
+ bool addSpace = false;
bool haveSignal = false;
bool haveSlot = false;
if (member.visibility() != MClassMember::VisibilityUndefined) {
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.h
index 83ce0a9a5a..cc92ab1ff5 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.h
@@ -53,7 +53,6 @@ private:
void updateGeometry();
void updateMembers(const Style *style);
- CustomIconItem *m_customIcon = nullptr;
QGraphicsRectItem *m_shape = nullptr;
QGraphicsSimpleTextItem *m_baseClasses = nullptr;
QGraphicsSimpleTextItem *m_namespace = nullptr;
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp
index 6a54a001e5..e7fffcbf9a 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp
@@ -53,24 +53,11 @@ void ComponentItem::update()
const Style *style = adaptedStyle(stereotypeIconId());
- // custom icon
- if (stereotypeIconDisplay() == StereotypeIcon::DisplayIcon) {
- if (!m_customIcon)
- m_customIcon = new CustomIconItem(diagramSceneModel(), this);
- m_customIcon->setStereotypeIconId(stereotypeIconId());
- 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());
- m_customIcon->setZValue(SHAPE_ZVALUE);
- } else if (m_customIcon) {
- m_customIcon->scene()->removeItem(m_customIcon);
- delete m_customIcon;
- m_customIcon = nullptr;
- }
+ updateCustomIcon(style);
// shape
bool deleteRects = false;
- if (!m_customIcon) {
+ if (!customIconItem()) {
if (!m_shape)
m_shape = new QGraphicsRectItem(this);
m_shape->setBrush(style->fillBrush());
@@ -130,7 +117,7 @@ void ComponentItem::update()
m_contextLabel = nullptr;
}
- updateSelectionMarker(m_customIcon);
+ updateSelectionMarker(customIconItem());
updateRelationStarter();
updateAlignmentButtons();
updateGeometry();
@@ -138,8 +125,8 @@ void ComponentItem::update()
bool ComponentItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- if (m_customIcon) {
- QList<QPolygonF> polygons = m_customIcon->outline();
+ if (customIconItem()) {
+ QList<QPolygonF> polygons = customIconItem()->outline();
for (int i = 0; i < polygons.size(); ++i)
polygons[i].translate(object()->pos() + object()->rect().topLeft());
if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
@@ -207,14 +194,16 @@ QSizeF ComponentItem::calcMinimumGeometry() const
{
double width = 0.0;
double height = 0.0;
+ double customMinHeight = 0.0;
- if (m_customIcon) {
- QSizeF sz = stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(),
+ if (customIconItem()) {
+ QSizeF sz = customIconItemMinimumSize(customIconItem(),
CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT);
if (shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignTop
&& shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignCenter)
return sz;
width = sz.width();
+ customMinHeight = sz.height();
}
height += BODY_VERT_BORDER;
@@ -234,7 +223,7 @@ QSizeF ComponentItem::calcMinimumGeometry() const
height += m_contextLabel->height();
height += BODY_VERT_BORDER;
- if (!hasPlainShape()) {
+ if (!customIconItem() && !hasPlainShape()) {
width = RECT_WIDTH * 0.5 + BODY_HORIZ_BORDER + width + BODY_HORIZ_BORDER + RECT_WIDTH * 0.5;
double minHeight = UPPER_RECT_Y + RECT_HEIGHT + RECT_Y_DISTANCE + RECT_HEIGHT + LOWER_RECT_MIN_Y;
if (height < minHeight)
@@ -243,6 +232,9 @@ QSizeF ComponentItem::calcMinimumGeometry() const
width = BODY_HORIZ_BORDER + width + BODY_HORIZ_BORDER;
}
+ if (height < customMinHeight)
+ height = customMinHeight;
+
return GeometryUtilities::ensureMinimumRasterSize(QSizeF(width, height), 2 * RASTER_WIDTH, 2 * RASTER_HEIGHT);
}
@@ -259,7 +251,7 @@ void ComponentItem::updateGeometry()
height = geometry.height();
if (object()->isAutoSized()) {
- // nothing
+ correctAutoSize(customIconItem(), width, height, 0, 0);
} else {
QRectF rect = object()->rect();
if (rect.width() > width)
@@ -283,9 +275,9 @@ void ComponentItem::updateGeometry()
// a backup for the graphics item used for manual resized and persistency.
object()->setRect(rect);
- if (m_customIcon) {
- m_customIcon->setPos(left, top);
- m_customIcon->setActualSize(QSizeF(width, height));
+ if (customIconItem()) {
+ customIconItem()->setPos(left, top);
+ customIconItem()->setActualSize(QSizeF(width, height));
}
if (m_shape)
@@ -303,7 +295,7 @@ void ComponentItem::updateGeometry()
m_lowerRect->setPos(left - RECT_WIDTH * 0.5, top + UPPER_RECT_Y + RECT_HEIGHT + RECT_Y_DISTANCE);
}
- if (m_customIcon) {
+ if (customIconItem()) {
switch (shapeIcon().textAlignment()) {
case qmt::StereotypeIcon::TextalignBelow:
y += height + BODY_VERT_BORDER;
@@ -345,7 +337,7 @@ void ComponentItem::updateGeometry()
y += nameItem()->boundingRect().height();
}
if (m_contextLabel) {
- if (m_customIcon) {
+ if (customIconItem()) {
m_contextLabel->resetMaxWidth();
} else {
double maxContextWidth = width - 2 * BODY_HORIZ_BORDER - (hasPlainShape() ? 0 : RECT_WIDTH);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h
index f00fbf30eb..f4910f53ce 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h
@@ -41,7 +41,6 @@ private:
QSizeF calcMinimumGeometry() const;
void updateGeometry();
- CustomIconItem *m_customIcon = nullptr;
QGraphicsRectItem *m_shape = nullptr;
QGraphicsRectItem *m_upperRect = nullptr;
QGraphicsRectItem *m_lowerRect = nullptr;
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp
index c37c38b3bb..951d6f3b1a 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp
@@ -47,23 +47,10 @@ void DiagramItem::update()
const Style *style = adaptedStyle(stereotypeIconId());
- // custom icon
- if (stereotypeIconDisplay() == StereotypeIcon::DisplayIcon) {
- if (!m_customIcon)
- m_customIcon = new CustomIconItem(diagramSceneModel(), this);
- m_customIcon->setStereotypeIconId(stereotypeIconId());
- 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());
- m_customIcon->setZValue(SHAPE_ZVALUE);
- } else if (m_customIcon) {
- m_customIcon->scene()->removeItem(m_customIcon);
- delete m_customIcon;
- m_customIcon = nullptr;
- }
+ updateCustomIcon(style);
// shape
- if (!m_customIcon) {
+ if (!customIconItem()) {
if (!m_body)
m_body = new QGraphicsPolygonItem(this);
m_body->setBrush(style->fillBrush());
@@ -93,15 +80,15 @@ void DiagramItem::update()
// diagram name
updateNameItem(style);
- updateSelectionMarker(m_customIcon);
+ updateSelectionMarker(customIconItem());
updateAlignmentButtons();
updateGeometry();
}
bool DiagramItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- if (m_customIcon) {
- QList<QPolygonF> polygons = m_customIcon->outline();
+ if (customIconItem()) {
+ QList<QPolygonF> polygons = customIconItem()->outline();
for (int i = 0; i < polygons.size(); ++i)
polygons[i].translate(object()->pos() + object()->rect().topLeft());
if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
@@ -131,8 +118,8 @@ QSizeF DiagramItem::calcMinimumGeometry() const
double width = MINIMUM_WIDTH;
double height = 0.0;
- if (m_customIcon) {
- QSizeF sz = stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(),
+ if (customIconItem()) {
+ QSizeF sz = customIconItemMinimumSize(customIconItem(),
CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT);
if (shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignTop
&& shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignCenter)
@@ -175,12 +162,7 @@ void DiagramItem::updateGeometry()
height = geometry.height();
if (object()->isAutoSized()) {
- if (!m_customIcon) {
- if (width < MINIMUM_AUTO_WIDTH)
- width = MINIMUM_AUTO_WIDTH;
- if (height < MINIMUM_AUTO_HEIGHT)
- height = MINIMUM_AUTO_HEIGHT;
- }
+ correctAutoSize(customIconItem(), width, height, MINIMUM_AUTO_WIDTH, MINIMUM_AUTO_HEIGHT);
} else {
QRectF rect = object()->rect();
if (rect.width() > width)
@@ -203,9 +185,9 @@ void DiagramItem::updateGeometry()
// a backup for the graphics item used for manual resized and persistency.
object()->setRect(rect);
- if (m_customIcon) {
- m_customIcon->setPos(left, top);
- m_customIcon->setActualSize(QSizeF(width, height));
+ if (customIconItem()) {
+ customIconItem()->setPos(left, top);
+ customIconItem()->setActualSize(QSizeF(width, height));
}
if (m_body) {
@@ -227,7 +209,7 @@ void DiagramItem::updateGeometry()
m_fold->setPolygon(foldPolygon);
}
- if (m_customIcon) {
+ if (customIconItem()) {
switch (shapeIcon().textAlignment()) {
case qmt::StereotypeIcon::TextalignBelow:
y += height + BODY_VERT_BORDER;
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.h
index 81012b04a1..88d9f9a7a8 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.h
@@ -29,7 +29,6 @@ private:
QSizeF calcMinimumGeometry() const;
void updateGeometry();
- CustomIconItem *m_customIcon = nullptr;
QGraphicsPolygonItem *m_body = nullptr;
QGraphicsPolygonItem *m_fold = nullptr;
};
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp
index 97a1b337fc..9855889b08 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp
@@ -52,22 +52,10 @@ void ItemItem::update()
const Style *style = adaptedStyle(shapeIconId());
- if (!shapeIconId().isEmpty()) {
- if (!m_customIcon)
- 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());
- m_customIcon->setZValue(SHAPE_ZVALUE);
- } else if (m_customIcon) {
- m_customIcon->scene()->removeItem(m_customIcon);
- delete m_customIcon;
- m_customIcon = nullptr;
- }
+ updateCustomIcon(style);
// shape
- if (!m_customIcon) {
+ if (!customIconItem()) {
if (!m_shape)
m_shape = new QGraphicsRectItem(this);
m_shape->setBrush(style->fillBrush());
@@ -100,7 +88,7 @@ void ItemItem::update()
m_contextLabel = nullptr;
}
- updateSelectionMarker(m_customIcon);
+ updateSelectionMarker(customIconItem());
updateRelationStarter();
updateAlignmentButtons();
updateGeometry();
@@ -108,8 +96,8 @@ void ItemItem::update()
bool ItemItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- if (m_customIcon) {
- QList<QPolygonF> polygons = m_customIcon->outline();
+ if (customIconItem()) {
+ QList<QPolygonF> polygons = customIconItem()->outline();
for (int i = 0; i < polygons.size(); ++i)
polygons[i].translate(object()->pos() + object()->rect().topLeft());
if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
@@ -152,14 +140,16 @@ QSizeF ItemItem::calcMinimumGeometry() const
{
double width = 0.0;
double height = 0.0;
+ double customMinHeight = 0.0;
- if (m_customIcon) {
- QSizeF sz = stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(),
+ if (customIconItem()) {
+ QSizeF sz = customIconItemMinimumSize(customIconItem(),
CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT);
if (shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignTop
&& shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignCenter)
return sz;
width = sz.width();
+ customMinHeight = sz.height();
}
height += BODY_VERT_BORDER;
@@ -181,6 +171,9 @@ QSizeF ItemItem::calcMinimumGeometry() const
width = BODY_HORIZ_BORDER + width + BODY_HORIZ_BORDER;
+ if (height < customMinHeight)
+ height = customMinHeight;
+
return GeometryUtilities::ensureMinimumRasterSize(QSizeF(width, height), 2 * RASTER_WIDTH, 2 * RASTER_HEIGHT);
}
@@ -197,7 +190,7 @@ void ItemItem::updateGeometry()
height = geometry.height();
if (object()->isAutoSized()) {
- // nothing
+ correctAutoSize(customIconItem(), width, height, 0, 0);
} else {
QRectF rect = object()->rect();
if (rect.width() > width)
@@ -221,15 +214,15 @@ void ItemItem::updateGeometry()
// a backup for the graphics item used for manual resized and persistency.
object()->setRect(rect);
- if (m_customIcon) {
- m_customIcon->setPos(left, top);
- m_customIcon->setActualSize(QSizeF(width, height));
+ if (customIconItem()) {
+ customIconItem()->setPos(left, top);
+ customIconItem()->setActualSize(QSizeF(width, height));
}
if (m_shape)
m_shape->setRect(rect);
- if (m_customIcon) {
+ if (customIconItem()) {
switch (shapeIcon().textAlignment()) {
case qmt::StereotypeIcon::TextalignBelow:
y += height + BODY_VERT_BORDER;
@@ -271,7 +264,7 @@ void ItemItem::updateGeometry()
y += nameItem()->boundingRect().height();
}
if (m_contextLabel) {
- if (m_customIcon) {
+ if (customIconItem()) {
m_contextLabel->resetMaxWidth();
} else {
double maxContextWidth = width - 2 * BODY_HORIZ_BORDER;
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h
index 327b3799ac..de091a2bc7 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h
@@ -39,7 +39,6 @@ private:
QSizeF calcMinimumGeometry() const;
void updateGeometry();
- CustomIconItem *m_customIcon = nullptr;
QGraphicsRectItem *m_shape = nullptr;
ContextLabelItem *m_contextLabel = nullptr;
};
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp
index 0fe32080cf..d4f6bd386b 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp
@@ -185,6 +185,8 @@ void ObjectItem::setFocusSelected(bool focusSelected)
if (m_isFocusSelected != focusSelected) {
m_isFocusSelected = focusSelected;
update();
+ if (m_nameItem)
+ m_nameItem->setEditable(focusSelected);
}
}
@@ -353,9 +355,9 @@ void ObjectItem::relationDrawn(const QString &id, ObjectItem *targetItem, const
elementType = targetItem->stereotypeIconId();
else if (!targetItem->shapeIconId().isEmpty())
elementType = targetItem->shapeIconId();
- else
- elementType = targetItem->elementType();
- if (!endItems.contains(elementType)) {
+ if ((!elementType.isEmpty() && !endItems.contains(elementType))
+ && !endItems.contains(targetItem->elementType()))
+ {
return;
}
// create relation
@@ -498,6 +500,7 @@ void ObjectItem::updateStereotypes(const QString &stereotypeIconId, StereotypeIc
m_stereotypeIcon = new CustomIconItem(m_diagramSceneModel, this);
m_stereotypeIcon->setStereotypeIconId(stereotypeIconId);
m_stereotypeIcon->setBaseSize(QSizeF(m_stereotypeIcon->shapeWidth(), m_stereotypeIcon->shapeHeight()));
+ m_stereotypeIcon->setActualSize(QSizeF(m_stereotypeIcon->shapeWidth(), m_stereotypeIcon->shapeHeight()));
m_stereotypeIcon->setBrush(style->fillBrush());
m_stereotypeIcon->setPen(style->innerLinePen());
} else if (m_stereotypeIcon) {
@@ -518,45 +521,92 @@ void ObjectItem::updateStereotypes(const QString &stereotypeIconId, StereotypeIc
}
}
-QSizeF ObjectItem::stereotypeIconMinimumSize(const StereotypeIcon &stereotypeIcon,
+QSizeF ObjectItem::customIconItemMinimumSize(const CustomIconItem *customIconItem,
qreal minimumWidth, qreal minimumHeight) const
{
Q_UNUSED(minimumWidth)
qreal width = 0.0;
qreal height = 0.0;
- if (stereotypeIcon.hasMinWidth() && !stereotypeIcon.hasMinHeight()) {
- width = stereotypeIcon.minWidth();
- if (stereotypeIcon.sizeLock() == StereotypeIcon::LockHeight || stereotypeIcon.sizeLock() == StereotypeIcon::LockSize)
- height = stereotypeIcon.minHeight();
- else
- height = width * stereotypeIcon.height() / stereotypeIcon.width();
- } else if (!stereotypeIcon.hasMinWidth() && stereotypeIcon.hasMinHeight()) {
- height = stereotypeIcon.minHeight();
- if (stereotypeIcon.sizeLock() == StereotypeIcon::LockWidth || stereotypeIcon.sizeLock() == StereotypeIcon::LockSize)
- width = stereotypeIcon.minWidth();
- else
- width = height * stereotypeIcon.width() / stereotypeIcon.height();
- } else if (stereotypeIcon.hasMinWidth() && stereotypeIcon.hasMinHeight()) {
- if (stereotypeIcon.sizeLock() == StereotypeIcon::LockRatio) {
+ if (customIconItem->hasImage()) {
+ const QImage &image = customIconItem->image();
+ width = minimumWidth;
+ height = image.height() * width / image.width();
+ if (height < minimumHeight) {
+ height = minimumHeight;
+ width = image.width() * height / image.height();
+ }
+ } else {
+ const StereotypeIcon &stereotypeIcon = customIconItem->stereotypeIcon();
+ if (stereotypeIcon.hasMinWidth() && !stereotypeIcon.hasMinHeight()) {
width = stereotypeIcon.minWidth();
- height = width * stereotypeIcon.height() / stereotypeIcon.width();
- if (height < stereotypeIcon.minHeight()) {
+ if (stereotypeIcon.sizeLock() == StereotypeIcon::LockHeight || stereotypeIcon.sizeLock() == StereotypeIcon::LockSize)
height = stereotypeIcon.minHeight();
+ else
+ height = width * stereotypeIcon.height() / stereotypeIcon.width();
+ } else if (!stereotypeIcon.hasMinWidth() && stereotypeIcon.hasMinHeight()) {
+ height = stereotypeIcon.minHeight();
+ if (stereotypeIcon.sizeLock() == StereotypeIcon::LockWidth || stereotypeIcon.sizeLock() == StereotypeIcon::LockSize)
+ width = stereotypeIcon.minWidth();
+ else
width = height * stereotypeIcon.width() / stereotypeIcon.height();
- QMT_CHECK(width <= stereotypeIcon.minWidth());
+ } else if (stereotypeIcon.hasMinWidth() && stereotypeIcon.hasMinHeight()) {
+ if (stereotypeIcon.sizeLock() == StereotypeIcon::LockRatio) {
+ width = stereotypeIcon.minWidth();
+ height = width * stereotypeIcon.height() / stereotypeIcon.width();
+ if (height < stereotypeIcon.minHeight()) {
+ height = stereotypeIcon.minHeight();
+ width = height * stereotypeIcon.width() / stereotypeIcon.height();
+ QMT_CHECK(width <= stereotypeIcon.minWidth());
+ }
+ } else {
+ width = stereotypeIcon.minWidth();
+ height = stereotypeIcon.minHeight();
}
} else {
- width = stereotypeIcon.minWidth();
- height = stereotypeIcon.minHeight();
+ height = minimumHeight;
+ width = height * stereotypeIcon.width() / stereotypeIcon.height();
}
- } else {
- height = minimumHeight;
- width = height * stereotypeIcon.width() / stereotypeIcon.height();
}
return QSizeF(width, height);
}
+void ObjectItem::correctAutoSize(const CustomIconItem* customIconItem, qreal &width, qreal &height, qreal minimumWidth, qreal minimumHeight) const
+{
+ if (customIconItem) {
+ if (customIconItem->hasImage()) {
+ width = customIconItem->image().width();
+ height = customIconItem->image().height();
+ }
+ } else {
+ if (width < minimumWidth)
+ width = minimumWidth;
+ if (height < minimumHeight)
+ height = minimumHeight;
+ }
+}
+
+void ObjectItem::updateCustomIcon(const Style *style)
+{
+ if (object()->hasImage()) {
+ if (!m_customIcon)
+ m_customIcon = new CustomIconItem(diagramSceneModel(), this);
+ m_customIcon->setImage(object()->image());
+ m_customIcon->setZValue(SHAPE_ZVALUE);
+ } else if (!shapeIconId().isEmpty()) {
+ if (!m_customIcon)
+ m_customIcon = new CustomIconItem(diagramSceneModel(), this);
+ m_customIcon->setStereotypeIconId(shapeIconId());
+ m_customIcon->setBrush(style->fillBrush());
+ m_customIcon->setPen(style->outerLinePen());
+ m_customIcon->setZValue(SHAPE_ZVALUE);
+ } else if (m_customIcon) {
+ m_customIcon->scene()->removeItem(m_customIcon);
+ delete m_customIcon;
+ m_customIcon = nullptr;
+ }
+}
+
bool ObjectItem::suppressTextDisplay() const
{
return m_shapeIcon.textAlignment() == StereotypeIcon::TextalignNone;
@@ -564,6 +614,7 @@ bool ObjectItem::suppressTextDisplay() const
void ObjectItem::updateNameItem(const Style *style)
{
+ QString display_name = buildDisplayName();
if (!suppressTextDisplay()) {
if (!m_nameItem) {
m_nameItem = new EditableTextItem(this);
@@ -582,16 +633,18 @@ void ObjectItem::updateNameItem(const Style *style)
QObject::connect(m_nameItem, &EditableTextItem::returnKeyPressed, m_nameItem,
[this] { this->m_nameItem->clearFocus(); });
}
- if (style->headerFont() != m_nameItem->font())
- m_nameItem->setFont(style->headerFont());
+ QFont font = style->headerFont();
+ if (object()->hasLinkedFile())
+ font.setUnderline(true);
+ if (font != m_nameItem->font())
+ m_nameItem->setFont(font);
if (style->textBrush().color() != m_nameItem->defaultTextColor())
m_nameItem->setDefaultTextColor(style->textBrush().color());
if (!m_nameItem->hasFocus()) {
- QString name = buildDisplayName();
- if (name != m_nameItem->toPlainText())
- m_nameItem->setPlainText(name);
+ if (display_name != m_nameItem->toPlainText())
+ m_nameItem->setPlainText(display_name);
}
- } else if (m_nameItem ){
+ } else if (m_nameItem) {
m_nameItem->scene()->removeItem(m_nameItem);
delete m_nameItem;
m_nameItem = nullptr;
@@ -621,30 +674,45 @@ void ObjectItem::setObjectName(const QString &objectName)
void ObjectItem::updateDepth()
{
- setZValue(m_object->depth());
+ int depth_delta = 0;
+ switch (m_shapeIcon.depthLayer()) {
+ case StereotypeIcon::DepthBehindItems:
+ depth_delta = -1;
+ break;
+ case StereotypeIcon::DepthAmongItems:
+ depth_delta = 0;
+ break;
+ case StereotypeIcon::DepthBeforeItems:
+ depth_delta = 1;
+ break;
+ }
+ setZValue(m_object->depth() + depth_delta);
}
-void ObjectItem::updateSelectionMarker(CustomIconItem *customIconItem)
+void ObjectItem::updateSelectionMarker(const CustomIconItem *customIconItem)
{
if (customIconItem) {
- StereotypeIcon stereotypeIcon = customIconItem->stereotypeIcon();
ResizeFlags resizeFlags = ResizeUnlocked;
- switch (stereotypeIcon.sizeLock()) {
- case StereotypeIcon::LockNone:
- resizeFlags = ResizeUnlocked;
- break;
- case StereotypeIcon::LockWidth:
- resizeFlags = ResizeLockedWidth;
- break;
- case StereotypeIcon::LockHeight:
- resizeFlags = ResizeLockedHeight;
- break;
- case StereotypeIcon::LockSize:
- resizeFlags = ResizeLockedSize;
- break;
- case StereotypeIcon::LockRatio:
+ if (customIconItem->hasImage()) {
resizeFlags = ResizeLockedRatio;
- break;
+ } else {
+ switch (customIconItem->stereotypeIcon().sizeLock()) {
+ case StereotypeIcon::LockNone:
+ resizeFlags = ResizeUnlocked;
+ break;
+ case StereotypeIcon::LockWidth:
+ resizeFlags = ResizeLockedWidth;
+ break;
+ case StereotypeIcon::LockHeight:
+ resizeFlags = ResizeLockedHeight;
+ break;
+ case StereotypeIcon::LockSize:
+ resizeFlags = ResizeLockedSize;
+ break;
+ case StereotypeIcon::LockRatio:
+ resizeFlags = ResizeLockedRatio;
+ break;
+ }
}
updateSelectionMarker(resizeFlags);
} else {
@@ -990,6 +1058,10 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
addSeparator = true;
if (element_tasks->extendContextMenu(object(), diagramSceneModel()->diagram(), &menu))
addSeparator = true;
+ if (element_tasks->hasLinkedFile(m_object, m_diagramSceneModel->diagram())) {
+ menu.addAction(new ContextMenuAction(Tr::tr("Open Linked File"), "openLinkedFile", &menu));
+ addSeparator = true;
+ }
if (addSeparator)
menu.addSeparator();
menu.addAction(new ContextMenuAction(Tr::tr("Remove"), "remove",
@@ -1000,12 +1072,12 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
QMenu alignMenu;
alignMenu.setTitle(Tr::tr("Align Objects"));
alignMenu.addAction(new ContextMenuAction(Tr::tr("Align Left"), "alignLeft", &alignMenu));
- alignMenu.addAction(new ContextMenuAction(Tr::tr("Center Vertically"), "centerVertically",
+ alignMenu.addAction(new ContextMenuAction(Tr::tr("Center Horizontally"), "centerHorizontally",
&alignMenu));
alignMenu.addAction(new ContextMenuAction(Tr::tr("Align Right"), "alignRight", &alignMenu));
alignMenu.addSeparator();
alignMenu.addAction(new ContextMenuAction(Tr::tr("Align Top"), "alignTop", &alignMenu));
- alignMenu.addAction(new ContextMenuAction(Tr::tr("Center Horizontally"), "centerHorizontally",
+ alignMenu.addAction(new ContextMenuAction(Tr::tr("Center Vertically"), "centerVertically",
&alignMenu));
alignMenu.addAction(new ContextMenuAction(Tr::tr("Align Bottom"), "alignBottom", &alignMenu));
alignMenu.addSeparator();
@@ -1022,7 +1094,6 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
layoutMenu.addAction(new ContextMenuAction(Tr::tr("Equal Vertical Space"), "sameVBorderDistance", &alignMenu));
layoutMenu.setEnabled(m_diagramSceneModel->hasMultiObjectsSelection());
menu.addMenu(&layoutMenu);
- menu.addAction(new ContextMenuAction(Tr::tr("Add Related Elements"), "addRelatedElements", &menu));
QAction *selectedAction = menu.exec(event->screenPos());
if (selectedAction) {
@@ -1035,6 +1106,8 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
m_diagramSceneModel->diagramSceneController()->elementTasks()->openDiagram(m_object, m_diagramSceneModel->diagram());
} else if (action->id() == "createDiagram") {
m_diagramSceneModel->diagramSceneController()->elementTasks()->createAndOpenDiagram(m_object, m_diagramSceneModel->diagram());
+ } else if (action->id() == "openLinkedFile") {
+ m_diagramSceneModel->diagramSceneController()->elementTasks()->openLinkedFile(m_object, m_diagramSceneModel->diagram());
} else if (action->id() == "remove") {
DSelection selection = m_diagramSceneModel->selectedElements();
if (selection.isEmpty())
@@ -1073,11 +1146,6 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
align(IAlignable::AlignHeight, "height");
} else if (action->id() == "sameSize") {
align(IAlignable::AlignSize, "size");
- } else if (action->id() == "addRelatedElements") {
- DSelection selection = m_diagramSceneModel->selectedElements();
- if (selection.isEmpty())
- selection.append(m_object->uid(), m_diagramSceneModel->diagram()->uid());
- m_diagramSceneModel->diagramSceneController()->addRelatedElements(selection, m_diagramSceneModel->diagram());
}
}
}
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h
index e7acd5705c..254ef215ca 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h
@@ -120,8 +120,12 @@ protected:
StereotypeIcon::Display stereotypeDisplay, const Style *style);
StereotypesItem *stereotypesItem() const { return m_stereotypesItem; }
CustomIconItem *stereotypeIconItem() const { return m_stereotypeIcon; }
- QSizeF stereotypeIconMinimumSize(const StereotypeIcon &stereotypeIcon, qreal minimumWidth,
+ CustomIconItem *customIconItem() const { return m_customIcon; }
+ QSizeF customIconItemMinimumSize(const CustomIconItem* customIconItem, qreal minimumWidth,
qreal minimumHeight) const;
+ void correctAutoSize(const CustomIconItem *customIconItem, qreal& width, qreal& height,
+ qreal minimumWidth, qreal minimumHeight) const;
+ void updateCustomIcon(const Style* style);
bool suppressTextDisplay() const;
void updateNameItem(const Style *style);
EditableTextItem *nameItem() const { return m_nameItem; }
@@ -130,7 +134,7 @@ protected:
void setObjectName(const QString &objectName);
void updateDepth();
- void updateSelectionMarker(CustomIconItem *customIconItem);
+ void updateSelectionMarker(const CustomIconItem* customIconItem);
void updateSelectionMarker(ResizeFlags resizeFlags);
void updateSelectionMarkerGeometry(const QRectF &objectRect);
void updateRelationStarter();
@@ -169,6 +173,7 @@ private:
StereotypeIcon::Display m_stereotypeIconDisplay = StereotypeIcon::DisplayLabel;
StereotypesItem *m_stereotypesItem = nullptr;
CustomIconItem *m_stereotypeIcon = nullptr;
+ CustomIconItem *m_customIcon = nullptr;
EditableTextItem *m_nameItem = nullptr;
RectangularSelectionItem *m_selectionMarker = nullptr;
RelationStarter *m_relationStarter = nullptr;
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp
index b473d17ec8..03e6d8d0f5 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp
@@ -64,23 +64,10 @@ void PackageItem::update()
const Style *style = adaptedStyle(stereotypeIconId());
- // custom icon
- if (stereotypeIconDisplay() == StereotypeIcon::DisplayIcon) {
- if (!m_customIcon)
- m_customIcon = new CustomIconItem(diagramSceneModel(), this);
- m_customIcon->setStereotypeIconId(stereotypeIconId());
- 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());
- m_customIcon->setZValue(SHAPE_ZVALUE);
- } else if (m_customIcon) {
- m_customIcon->scene()->removeItem(m_customIcon);
- delete m_customIcon;
- m_customIcon = nullptr;
- }
+ updateCustomIcon(style);
// shape
- if (!m_customIcon) {
+ if (!customIconItem()) {
if (!m_shape)
m_shape = new QGraphicsPolygonItem(this);
m_shape->setBrush(style->fillBrush());
@@ -111,7 +98,7 @@ void PackageItem::update()
m_contextLabel = nullptr;
}
- updateSelectionMarker(m_customIcon);
+ updateSelectionMarker(customIconItem());
updateRelationStarter();
updateAlignmentButtons();
updateGeometry();
@@ -119,8 +106,8 @@ void PackageItem::update()
bool PackageItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- if (m_customIcon) {
- QList<QPolygonF> polygons = m_customIcon->outline();
+ if (customIconItem()) {
+ QList<QPolygonF> polygons = customIconItem()->outline();
for (int i = 0; i < polygons.size(); ++i)
polygons[i].translate(object()->pos() + object()->rect().topLeft());
if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
@@ -169,8 +156,8 @@ PackageItem::ShapeGeometry PackageItem::calcMinimumGeometry() const
double width = 0.0;
double height = 0.0;
- if (m_customIcon) {
- QSizeF sz = stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(),
+ if (customIconItem()) {
+ QSizeF sz = customIconItemMinimumSize(customIconItem(),
CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT);
if (shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignTop
&& shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignCenter)
@@ -244,12 +231,7 @@ void PackageItem::updateGeometry()
// calc width and height
if (object()->isAutoSized()) {
- if (!m_customIcon) {
- if (width < MINIMUM_AUTO_WIDTH)
- width = MINIMUM_AUTO_WIDTH;
- if (height < MINIMUM_AUTO_HEIGHT)
- height = MINIMUM_AUTO_HEIGHT;
- }
+ correctAutoSize(customIconItem(), width, height, MINIMUM_AUTO_WIDTH, MINIMUM_AUTO_HEIGHT);
} else {
QRectF rect = object()->rect();
if (rect.width() > width)
@@ -273,9 +255,9 @@ void PackageItem::updateGeometry()
// a backup for the graphics item used for manual resized and persistency.
object()->setRect(rect);
- if (m_customIcon) {
- m_customIcon->setPos(left, top);
- m_customIcon->setActualSize(QSizeF(width, height));
+ if (customIconItem()) {
+ customIconItem()->setPos(left, top);
+ customIconItem()->setActualSize(QSizeF(width, height));
switch (shapeIcon().textAlignment()) {
case qmt::StereotypeIcon::TextalignBelow:
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h
index 19c2fe54ab..f87af2fa35 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h
@@ -40,7 +40,6 @@ private:
ShapeGeometry calcMinimumGeometry() const;
void updateGeometry();
- CustomIconItem *m_customIcon = nullptr;
QGraphicsPolygonItem *m_shape = nullptr;
ContextLabelItem *m_contextLabel = nullptr;
};
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp
index a2f444f59e..ca9dd8c3a2 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp
@@ -380,7 +380,12 @@ void RelationItem::setHandlePos(int index, const QPointF &pos)
}
}
-void RelationItem::dropHandle(int index, double rasterWidth, double rasterHeight)
+static inline bool between(double v, double mid, double range)
+{
+ return v >= mid-range && v <= mid+range;
+}
+
+void RelationItem::dropHandle(int index, bool extraSnap, double rasterWidth, double rasterHeight)
{
if (index == 0) {
m_grabbedEndA = false;
@@ -398,9 +403,40 @@ void RelationItem::dropHandle(int index, double rasterWidth, double rasterHeight
QMT_ASSERT(index >= 0 && index < intermediatePoints.size(), return);
QPointF pos = intermediatePoints.at(index).pos();
- double x = qRound(pos.x() / rasterWidth) * rasterWidth;
- double y = qRound(pos.y() / rasterHeight) * rasterHeight;
- intermediatePoints[index].setPos(QPointF(x, y));
+ static constexpr int ANGLE = 20.0;
+ bool roundX = true;
+ bool roundY = true;
+ if (extraSnap) {
+ if (index >= 1) {
+ double angle = GeometryUtilities::calcAngle(QLineF(intermediatePoints.at(index).pos(),
+ intermediatePoints.at(index - 1).pos()));
+ if (between(qAbs(angle), 90, ANGLE)) {
+ pos.setX(intermediatePoints.at(index - 1).pos().x());
+ roundX = false;
+ }
+ if (between(angle, 0, ANGLE) || between(qAbs(angle), 180, ANGLE)) {
+ pos.setY(intermediatePoints.at(index - 1).pos().y());
+ roundY = false;
+ }
+ }
+ if (index < intermediatePoints.size() - 1) {
+ double angle = GeometryUtilities::calcAngle(QLineF(intermediatePoints.at(index).pos(),
+ intermediatePoints.at(index + 1).pos()));
+ if (between(qAbs(angle), 90, ANGLE)) {
+ pos.setX(intermediatePoints.at(index + 1).pos().x());
+ roundX = false;
+ }
+ if (between(angle, 0, ANGLE) || between(qAbs(angle), 180, ANGLE)) {
+ pos.setY(intermediatePoints.at(index + 1).pos().y());
+ roundY = false;
+ }
+ }
+ }
+ if (roundX)
+ pos.setX(qRound(pos.x() / rasterWidth) * rasterWidth);
+ if (roundY)
+ pos.setY(qRound(pos.y() / rasterHeight) * rasterHeight);
+ intermediatePoints[index].setPos(pos);
m_diagramSceneModel->diagramController()->startUpdateElement(m_relation, m_diagramSceneModel->diagram(), DiagramController::UpdateMinor);
m_relation->setIntermediatePoints(intermediatePoints);
@@ -507,9 +543,11 @@ void RelationItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
const Style *RelationItem::adaptedStyle()
{
- DObject *endAObject = m_diagramSceneModel->diagramController()->findElement<DObject>(m_relation->endAUid(), m_diagramSceneModel->diagram());
- DObject *endBObject = m_diagramSceneModel->diagramController()->findElement<DObject>(m_relation->endBUid(), m_diagramSceneModel->diagram());
- StyledRelation styledRelation(m_relation, endAObject, endBObject);
+ const DObject *endAObject = m_diagramSceneModel->diagramController()->findElement<DObject>(m_relation->endAUid(), m_diagramSceneModel->diagram());
+ const DObject *endBObject = m_diagramSceneModel->diagramController()->findElement<DObject>(m_relation->endBUid(), m_diagramSceneModel->diagram());
+ const CustomRelation customRelation = m_diagramSceneModel->stereotypeController()
+ ->findCustomRelationByStereotype(m_relation->stereotypes().value(0));
+ StyledRelation styledRelation(m_relation, endAObject, endBObject, &customRelation);
return m_diagramSceneModel->styleController()->adaptRelationStyle(styledRelation);
}
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.h
index a43b8b2749..0980d232e4 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.h
@@ -56,7 +56,7 @@ public:
void insertHandle(int beforeIndex, const QPointF &pos, double rasterWidth, double rasterHeight) override;
void deleteHandle(int index) override;
void setHandlePos(int index, const QPointF &pos) override;
- void dropHandle(int index, double rasterWidth, double rasterHeight) override;
+ void dropHandle(int index, bool extraSnap, double rasterWidth, double rasterHeight) override;
virtual void update();
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp
index ad668f6bee..9313327c87 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp
@@ -57,7 +57,9 @@ void StereotypeDisplayVisitor::visitDObject(const DObject *object)
DObject::StereotypeDisplay stereotypeDisplay = object->stereotypeDisplay();
m_stereotypeIconId = m_stereotypeController->findStereotypeIconId(m_stereotypeIconElement, object->stereotypes());
- if (m_stereotypeIconId.isEmpty() && stereotypeDisplay == DObject::StereotypeIcon) {
+ if (object->hasImage() && stereotypeDisplay == DObject::StereotypeSmart) {
+ stereotypeDisplay = DObject::StereotypeLabel;
+ } else if (m_stereotypeIconId.isEmpty() && stereotypeDisplay == DObject::StereotypeIcon) {
stereotypeDisplay = DObject::StereotypeLabel;
} else if (!m_stereotypeIconId.isEmpty() && stereotypeDisplay == DObject::StereotypeSmart) {
StereotypeIcon stereotypeIcon = m_stereotypeController->findStereotypeIcon(m_stereotypeIconId);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp
index 3a14eb10d9..632da76f05 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp
@@ -384,27 +384,29 @@ void ArrowItem::updateShaft(const Style *style)
QMT_ASSERT(m_shaftItem, return);
QPen pen(style->linePen());
+ pen.setCapStyle(Qt::FlatCap);
+
+ auto scale = [&pen](qreal v) {
+ return v / ((pen.widthF() - 1.0) / 2.0 + 1.0);
+ };
+
switch (m_shaft) {
case ShaftSolid:
break;
case ShaftDashed:
- pen.setDashPattern(QVector<qreal>()
- << (4.0 / pen.widthF()) << (4.0 / pen.widthF()));
+ pen.setDashPattern(QVector<qreal>() << scale(5.0) << scale(3.0));
break;
case ShaftDot:
- pen.setDashPattern(QVector<qreal>()
- << (2.0 / pen.widthF()) << (2.0 / pen.widthF()));
+ pen.setDashPattern(QVector<qreal>() << scale(3.0) << scale(3.0));
break;
case ShaftDashDot:
- pen.setDashPattern(QVector<qreal>()
- << (4.0 / pen.widthF()) << (2.0 / pen.widthF())
- << (2.0 / pen.widthF()) << (2.0 / pen.widthF()));
+ pen.setDashPattern(QVector<qreal>() << scale(5.0) << scale(3.0)
+ << scale(3.0) << scale(3.0));
break;
case ShaftDashDotDot:
- pen.setDashPattern(QVector<qreal>()
- << (4.0 / pen.widthF()) << (2.0 / pen.widthF())
- << (2.0 / pen.widthF()) << (2.0 / pen.widthF())
- << (2.0 / pen.widthF()) << (2.0 / pen.widthF()));
+ pen.setDashPattern(QVector<qreal>() << scale(5.0) << scale(3.0)
+ << scale(3.0) << scale(3.0)
+ << scale(3.0) << scale(3.0));
break;
}
m_shaftItem->setPen(pen);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp
index 066f9b7875..36e4c4f789 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp
@@ -57,55 +57,97 @@ void CustomIconItem::setPen(const QPen &pen)
m_pen = pen;
}
+void CustomIconItem::setImage(const QImage &image)
+{
+ m_image = image;
+}
+
double CustomIconItem::shapeWidth() const
{
- return m_stereotypeIcon.width();
+ if (!m_image.isNull())
+ return m_image.width();
+ return m_stereotypeIcon.hasIconWidth() ? m_stereotypeIcon.iconWidth()
+ : m_stereotypeIcon.width();
}
double CustomIconItem::shapeHeight() const
{
- return m_stereotypeIcon.height();
+ if (!m_image.isNull())
+ return m_image.height();
+ return m_stereotypeIcon.hasIconHeight() ? m_stereotypeIcon.iconHeight()
+ : m_stereotypeIcon.height();
}
QRectF CustomIconItem::boundingRect() const
{
- ShapeSizeVisitor visitor(QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
+ if (!m_image.isNull())
+ return QRectF(QPointF(0.0, 0.0), m_actualSize) | childrenBoundingRect();
+ ShapeSizeVisitor visitor(QPointF(0.0, 0.0),
+ QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()),
+ m_baseSize,
+ m_actualSize);
m_stereotypeIcon.iconShape().visitShapes(&visitor);
return visitor.boundingRect() | childrenBoundingRect();
}
-void CustomIconItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+void CustomIconItem::paint(QPainter *painter,
+ const QStyleOptionGraphicsItem *option,
+ QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
painter->save();
- painter->setBrush(m_brush);
- painter->setPen(m_pen);
+ if (!m_image.isNull()) {
+ painter->drawImage(QRectF(QPointF(0.0, 0.0), m_actualSize), m_image);
+ } else {
+ painter->setBrush(m_brush);
+ painter->setPen(m_pen);
#ifdef DEBUG_OUTLINE
- ShapePolygonVisitor visitor(QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
- IconShape shape = m_stereotypeIcon.outlineShape();
- if (shape.isEmpty())
- shape = m_stereotypeIcon.iconShape();
- shape.visitShapes(&visitor);
- painter->drawPath(visitor.path());
- ShapePaintVisitor visitor1(painter, QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
- m_stereotypeIcon.iconShape().visitShapes(&visitor1);
+ ShapePolygonVisitor visitor(QPointF(0.0, 0.0),
+ QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()),
+ m_baseSize,
+ m_actualSize);
+ IconShape shape = m_stereotypeIcon.outlineShape();
+ if (shape.isEmpty())
+ shape = m_stereotypeIcon.iconShape();
+ shape.visitShapes(&visitor);
+ painter->drawPath(visitor.path());
+ ShapePaintVisitor visitor1(painter,
+ QPointF(0.0, 0.0),
+ QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()),
+ m_baseSize,
+ m_actualSize);
+ m_stereotypeIcon.iconShape().visitShapes(&visitor1);
#else
- ShapePaintVisitor visitor(painter, QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
- m_stereotypeIcon.iconShape().visitShapes(&visitor);
+ ShapePaintVisitor visitor(painter,
+ QPointF(0.0, 0.0),
+ QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()),
+ m_baseSize,
+ m_actualSize);
+ m_stereotypeIcon.iconShape().visitShapes(&visitor);
#endif
+ }
painter->restore();
}
QList<QPolygonF> CustomIconItem::outline() const
{
- ShapePolygonVisitor visitor(QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
- IconShape shape = m_stereotypeIcon.outlineShape();
- if (shape.isEmpty())
- shape = m_stereotypeIcon.iconShape();
- shape.visitShapes(&visitor);
- return visitor.toPolygons();
+ if (!m_image.isNull()) {
+ QList<QPolygonF> polygons;
+ polygons.append(QPolygonF(QRectF(QPointF(0.0, 0.0), m_actualSize)));
+ return polygons;
+ } else {
+ ShapePolygonVisitor visitor(QPointF(0.0, 0.0),
+ QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()),
+ m_baseSize,
+ m_actualSize);
+ IconShape shape = m_stereotypeIcon.outlineShape();
+ if (shape.isEmpty())
+ shape = m_stereotypeIcon.iconShape();
+ shape.visitShapes(&visitor);
+ return visitor.toPolygons();
+ }
}
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h
index 7f85e87516..f61db552ac 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h
@@ -9,6 +9,7 @@
#include "qmt/stereotype/stereotypeicon.h"
#include <QBrush>
+#include <QImage>
#include <QPen>
namespace qmt {
@@ -26,6 +27,9 @@ public:
void setActualSize(const QSizeF &actualSize);
void setBrush(const QBrush &brush);
void setPen(const QPen &pen);
+ QImage image() const { return m_image; }
+ bool hasImage() const { return !m_image.isNull(); }
+ void setImage(const QImage &image);
StereotypeIcon stereotypeIcon() const { return m_stereotypeIcon; }
double shapeWidth() const;
double shapeHeight() const;
@@ -43,6 +47,7 @@ private:
QSizeF m_actualSize;
QBrush m_brush;
QPen m_pen;
+ QImage m_image;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.cpp
index 60275cb5ec..185321d84c 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.cpp
@@ -13,13 +13,18 @@ namespace qmt {
EditableTextItem::EditableTextItem(QGraphicsItem *parent)
: QGraphicsTextItem(parent)
{
- setTextInteractionFlags(Qt::TextEditorInteraction);
+ setTextInteractionFlags(Qt::NoTextInteraction);
}
EditableTextItem::~EditableTextItem()
{
}
+void EditableTextItem::setEditable(bool editable)
+{
+ setTextInteractionFlags(editable ? Qt::TextEditorInteraction : Qt::NoTextInteraction);
+}
+
void EditableTextItem::setShowFocus(bool showFocus)
{
m_showFocus = showFocus;
@@ -72,13 +77,6 @@ void EditableTextItem::keyReleaseEvent(QKeyEvent *event)
QGraphicsTextItem::keyReleaseEvent(event);
}
-void EditableTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
-{
- scene()->clearSelection();
- parentItem()->setSelected(true);
- QGraphicsTextItem::mousePressEvent(event);
-}
-
void EditableTextItem::focusOutEvent(QFocusEvent *event)
{
QGraphicsTextItem::focusOutEvent(event);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.h b/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.h
index 7c361b72fd..b18bf85cfc 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/editabletextitem.h
@@ -19,6 +19,7 @@ signals:
void returnKeyPressed();
public:
+ void setEditable(bool editable);
void setShowFocus(bool showFocus);
void setFilterReturnKey(bool filterReturnKey);
void setFilterTabKey(bool filterTabKey);
@@ -30,7 +31,6 @@ public:
protected:
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *event) override;
- void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void focusOutEvent(QFocusEvent *event) override;
private:
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.cpp
index 8206a7fe9a..231b78a3a0 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.cpp
@@ -79,7 +79,10 @@ protected:
{
m_lastPos = event->scenePos();
QPointF delta = m_lastPos - m_startPos;
- m_owner->moveHandle(m_pointIndex, delta, Release, m_qualifier);
+ HandleQualifier qualifier = m_qualifier;
+ if (qualifier == None && (event->modifiers() & Qt::ShiftModifier) != 0)
+ qualifier = SnapHandle;
+ m_owner->moveHandle(m_pointIndex, delta, Release, qualifier);
clearFocus();
}
@@ -267,6 +270,7 @@ void PathSelectionItem::moveHandle(int pointIndex, const QPointF &deltaMove, Han
{
switch (handleQualifier) {
case None:
+ case SnapHandle:
{
if (handleStatus == Press) {
m_focusHandleItem = m_handles.at(pointIndex);
@@ -275,13 +279,13 @@ void PathSelectionItem::moveHandle(int pointIndex, const QPointF &deltaMove, Han
QPointF newPos = m_originalHandlePos + deltaMove;
m_windable->setHandlePos(pointIndex, newPos);
if (handleStatus == Release) {
- m_windable->dropHandle(pointIndex, RASTER_WIDTH, RASTER_HEIGHT);
+ m_windable->dropHandle(pointIndex, handleQualifier == SnapHandle, RASTER_WIDTH, RASTER_HEIGHT);
m_focusHandleItem = nullptr;
}
break;
}
case DeleteHandle:
- if (handleStatus == Press)
+ if (handleStatus == Release)
m_windable->deleteHandle(pointIndex);
break;
}
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.h b/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.h
index 0c4891948a..06a2d36c49 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/pathselectionitem.h
@@ -25,7 +25,8 @@ class PathSelectionItem : public QGraphicsItem
enum HandleQualifier {
None,
- DeleteHandle
+ DeleteHandle,
+ SnapHandle
};
public:
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp
index 26b8ebc1c4..49bca85162 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp
@@ -121,11 +121,13 @@ void RelationStarter::keyPressEvent(QKeyEvent *event)
m_currentPreviewArrowIntermediatePoints.append(p);
// Do not update the preview arrow here because last two points are now identical which looks wired
}
+ event->accept();
} else if (event->key() == Qt::Key_Control) {
if (!m_currentPreviewArrowIntermediatePoints.isEmpty()) {
m_currentPreviewArrowIntermediatePoints.removeLast();
updateCurrentPreviewArrow(m_currentPreviewArrow->lastLineSegment().p1());
}
+ event->accept();
}
}
diff --git a/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp b/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp
index 5634c4eb7f..555dc812e6 100644
--- a/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp
+++ b/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp
@@ -14,9 +14,14 @@
#include <QDragLeaveEvent>
#include <QDropEvent>
#include <QMimeData>
+#include <QScrollBar>
namespace qmt {
+namespace {
+const qreal ADJUSTMENT = 80;
+};
+
DiagramView::DiagramView(QWidget *parent)
: QGraphicsView(parent)
{
@@ -25,6 +30,9 @@ DiagramView::DiagramView(QWidget *parent)
setDragMode(QGraphicsView::RubberBandDrag);
setFrameShape(QFrame::NoFrame);
setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ m_panTimer.setInterval(200);
+ m_panTimer.setSingleShot(false);
+ connect(&m_panTimer, &QTimer::timeout, this, &DiagramView::onPanTimeout);
}
DiagramView::~DiagramView()
@@ -104,7 +112,7 @@ void DiagramView::dropEvent(QDropEvent *event)
if (diagramSceneController->isAddingAllowed(Uid(QUuid(key)),
m_diagramSceneModel->diagram())) {
diagramSceneController->addExistingModelElement(Uid(QUuid(key)),
- mapToScene(event->pos()),
+ mapToScene(event->position().toPoint()),
m_diagramSceneModel->diagram());
}
}
@@ -118,10 +126,10 @@ void DiagramView::dropEvent(QDropEvent *event)
QString stereotype;
dataStream >> newElementId >> name >> stereotype;
if (!newElementId.isEmpty()) {
- QPointF pos = mapToScene(event->pos());
+ QPointF pos = mapToScene(event->position().toPoint());
diagramSceneController->dropNewElement(
newElementId, name, stereotype, m_diagramSceneModel->findTopmostElement(pos),
- pos, m_diagramSceneModel->diagram(), event->pos(), size());
+ pos, m_diagramSceneModel->diagram(), event->position().toPoint(), size());
}
}
event->accept();
@@ -130,12 +138,41 @@ void DiagramView::dropEvent(QDropEvent *event)
}
}
+void DiagramView::mousePressEvent(QMouseEvent *event)
+{
+ m_panTimer.start();
+ QGraphicsView::mousePressEvent(event);
+}
+
+void DiagramView::mouseReleaseEvent(QMouseEvent *event)
+{
+ m_panTimer.stop();
+ QGraphicsView::mouseReleaseEvent(event);
+}
+
+void DiagramView::mouseMoveEvent(QMouseEvent *event)
+{
+ QGraphicsView::mouseMoveEvent(event);
+ m_lastMouse = event->pos();
+}
+
void DiagramView::onSceneRectChanged(const QRectF &sceneRect)
{
// add some adjustment to all 4 sides
- static const qreal ADJUSTMENT = 80;
QRectF rect = sceneRect.adjusted(-ADJUSTMENT, -ADJUSTMENT, ADJUSTMENT, ADJUSTMENT);
setSceneRect(rect);
}
+void DiagramView::onPanTimeout()
+{
+ if (m_lastMouse.x() < ADJUSTMENT)
+ horizontalScrollBar()->triggerAction(QScrollBar::SliderSingleStepSub);
+ else if (m_lastMouse.x() > viewport()->size().width() - ADJUSTMENT)
+ horizontalScrollBar()->triggerAction(QScrollBar::SliderSingleStepAdd);
+ if (m_lastMouse.y() < ADJUSTMENT)
+ verticalScrollBar()->triggerAction(QScrollBar::SliderSingleStepSub);
+ else if (m_lastMouse.y() > viewport()->size().height() - ADJUSTMENT)
+ verticalScrollBar()->triggerAction(QScrollBar::SliderSingleStepAdd);
+}
+
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.h b/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.h
index 41386f09bd..4eee60ff44 100644
--- a/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.h
+++ b/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.h
@@ -7,6 +7,7 @@
#include "qmt/infrastructure/qmt_global.h"
#include <QPointer>
+#include <QTimer>
namespace qmt {
@@ -27,11 +28,17 @@ protected:
void dragLeaveEvent(QDragLeaveEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dropEvent(QDropEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
private:
void onSceneRectChanged(const QRectF &sceneRect);
+ void onPanTimeout();
QPointer<DiagramSceneModel> m_diagramSceneModel;
+ QPointF m_lastMouse;
+ QTimer m_panTimer;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/document_controller/documentcontroller.cpp b/src/libs/modelinglib/qmt/document_controller/documentcontroller.cpp
index 68184d2fb5..696fc30558 100644
--- a/src/libs/modelinglib/qmt/document_controller/documentcontroller.cpp
+++ b/src/libs/modelinglib/qmt/document_controller/documentcontroller.cpp
@@ -32,7 +32,7 @@
#include "../../modelinglibtr.h"
-#include <QFileInfo>
+using Utils::FilePath;
namespace qmt {
@@ -233,7 +233,7 @@ MDiagram *DocumentController::findOrCreateRootDiagram()
return rootDiagram;
}
-void DocumentController::createNewProject(const QString &fileName)
+void DocumentController::createNewProject(const FilePath &fileName)
{
m_diagramsManager->removeAllDiagrams();
m_treeModel->setModelController(nullptr);
@@ -246,7 +246,7 @@ void DocumentController::createNewProject(const QString &fileName)
m_modelController->setRootPackage(m_projectController->project()->rootPackage());
}
-void DocumentController::loadProject(const QString &fileName)
+void DocumentController::loadProject(const FilePath &fileName)
{
m_diagramsManager->removeAllDiagrams();
m_treeModel->setModelController(nullptr);
diff --git a/src/libs/modelinglib/qmt/document_controller/documentcontroller.h b/src/libs/modelinglib/qmt/document_controller/documentcontroller.h
index 8053d189e0..9c5188e3f7 100644
--- a/src/libs/modelinglib/qmt/document_controller/documentcontroller.h
+++ b/src/libs/modelinglib/qmt/document_controller/documentcontroller.h
@@ -7,6 +7,8 @@
#include "qmt/infrastructure/qmt_global.h"
#include "qmt/model_controller/modelcontroller.h"
+#include <utils/filepath.h>
+
namespace qmt {
class ProjectController;
@@ -77,8 +79,8 @@ public:
MDiagram *findRootDiagram();
MDiagram *findOrCreateRootDiagram();
- void createNewProject(const QString &fileName);
- void loadProject(const QString &fileName);
+ void createNewProject(const Utils::FilePath &fileName);
+ void loadProject(const Utils::FilePath &fileName);
private:
ProjectController *m_projectController = nullptr;
diff --git a/src/libs/modelinglib/qmt/infrastructure/ioexceptions.cpp b/src/libs/modelinglib/qmt/infrastructure/ioexceptions.cpp
index 4af8df9236..bb11a4d566 100644
--- a/src/libs/modelinglib/qmt/infrastructure/ioexceptions.cpp
+++ b/src/libs/modelinglib/qmt/infrastructure/ioexceptions.cpp
@@ -7,6 +7,8 @@
#include <QObject>
+using Utils::FilePath;
+
namespace qmt {
IOException::IOException(const QString &errorMsg)
@@ -14,39 +16,39 @@ IOException::IOException(const QString &errorMsg)
{
}
-FileIOException::FileIOException(const QString &errorMsg, const QString &fileName, int lineNumber)
+FileIOException::FileIOException(const QString &errorMsg, const FilePath &fileName, int lineNumber)
: IOException(errorMsg),
m_fileName(fileName),
m_lineNumber(lineNumber)
{
}
-FileNotFoundException::FileNotFoundException(const QString &fileName)
+FileNotFoundException::FileNotFoundException(const FilePath &fileName)
: FileIOException(Tr::tr("File not found."), fileName)
{
}
-FileCreationException::FileCreationException(const QString &fileName)
+FileCreationException::FileCreationException(const FilePath &fileName)
: FileIOException(Tr::tr("Unable to create file."), fileName)
{
}
-FileWriteError::FileWriteError(const QString &fileName, int lineNumber)
+FileWriteError::FileWriteError(const FilePath &fileName, int lineNumber)
: FileIOException(Tr::tr("Writing to file failed."), fileName, lineNumber)
{
}
-FileReadError::FileReadError(const QString &fileName, int lineNumber)
+FileReadError::FileReadError(const FilePath &fileName, int lineNumber)
: FileIOException(Tr::tr("Reading from file failed."), fileName, lineNumber)
{
}
-IllegalXmlFile::IllegalXmlFile(const QString &fileName, int lineNumber)
+IllegalXmlFile::IllegalXmlFile(const FilePath &fileName, int lineNumber)
: FileIOException(Tr::tr("Illegal XML file."), fileName, lineNumber)
{
}
-UnknownFileVersion::UnknownFileVersion(int version, const QString &fileName, int lineNumber)
+UnknownFileVersion::UnknownFileVersion(int version, const FilePath &fileName, int lineNumber)
: FileIOException(Tr::tr("Unable to handle file version %1.")
.arg(version), fileName, lineNumber)
{
diff --git a/src/libs/modelinglib/qmt/infrastructure/ioexceptions.h b/src/libs/modelinglib/qmt/infrastructure/ioexceptions.h
index aece890529..7dc91ff4ba 100644
--- a/src/libs/modelinglib/qmt/infrastructure/ioexceptions.h
+++ b/src/libs/modelinglib/qmt/infrastructure/ioexceptions.h
@@ -5,6 +5,8 @@
#include "exceptions.h"
+#include <utils/filepath.h>
+
namespace qmt {
class IOException : public Exception
@@ -16,51 +18,51 @@ public:
class FileIOException : public IOException
{
public:
- explicit FileIOException(const QString &errorMsg, const QString &fileName = QString(),
+ explicit FileIOException(const QString &errorMsg, const Utils::FilePath &fileName = {},
int lineNumber = -1);
- QString fileName() const { return m_fileName; }
+ Utils::FilePath fileName() const { return m_fileName; }
int lineNumber() const { return m_lineNumber; }
private:
- QString m_fileName;
+ Utils::FilePath m_fileName;
int m_lineNumber = -1;
};
class FileNotFoundException : public FileIOException
{
public:
- explicit FileNotFoundException(const QString &fileName);
+ explicit FileNotFoundException(const Utils::FilePath &fileName);
};
class FileCreationException : public FileIOException
{
public:
- explicit FileCreationException(const QString &fileName);
+ explicit FileCreationException(const Utils::FilePath &fileName);
};
class FileWriteError : public FileIOException
{
public:
- explicit FileWriteError(const QString &fileName, int lineNumber = -1);
+ explicit FileWriteError(const Utils::FilePath &fileName, int lineNumber = -1);
};
class FileReadError : public FileIOException
{
public:
- explicit FileReadError(const QString &fileName, int lineNumber = -1);
+ explicit FileReadError(const Utils::FilePath &fileName, int lineNumber = -1);
};
class IllegalXmlFile : public FileIOException
{
public:
- explicit IllegalXmlFile(const QString &fileName, int lineNumber = -1);
+ explicit IllegalXmlFile(const Utils::FilePath &fileName, int lineNumber = -1);
};
class UnknownFileVersion : public FileIOException
{
public:
- UnknownFileVersion(int version, const QString &fileName, int lineNumber = -1);
+ UnknownFileVersion(int version, const Utils::FilePath &fileName, int lineNumber = -1);
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model/mdiagram.h b/src/libs/modelinglib/qmt/model/mdiagram.h
index 8f327daabc..bebe17cb50 100644
--- a/src/libs/modelinglib/qmt/model/mdiagram.h
+++ b/src/libs/modelinglib/qmt/model/mdiagram.h
@@ -21,7 +21,7 @@ public:
MDiagram &operator=(const MDiagram &rhs);
- const QList<DElement *> &diagramElements() const { return m_elements; }
+ const QList<DElement *> diagramElements() const { return m_elements; }
DElement *findDiagramElement(const Uid &key) const;
DElement *findDelegate(const Uid &modelUid) const;
void setDiagramElements(const QList<DElement *> &elements);
diff --git a/src/libs/modelinglib/qmt/model/mobject.cpp b/src/libs/modelinglib/qmt/model/mobject.cpp
index 734be13567..f5b4e2b36f 100644
--- a/src/libs/modelinglib/qmt/model/mobject.cpp
+++ b/src/libs/modelinglib/qmt/model/mobject.cpp
@@ -8,6 +8,8 @@
#include "mvisitor.h"
#include "mconstvisitor.h"
+using Utils::FilePath;
+
namespace qmt {
MObject::MObject()
@@ -20,6 +22,7 @@ MObject::MObject()
MObject::MObject(const MObject &rhs)
: MElement(rhs),
m_name(rhs.m_name),
+ m_linkedfilename(rhs.m_linkedfilename),
m_children(true),
m_relations(true)
{
@@ -34,6 +37,7 @@ MObject &MObject::operator =(const MObject &rhs)
if (this != &rhs) {
MElement::operator=(rhs);
m_name = rhs.m_name;
+ m_linkedfilename = rhs.m_linkedfilename;
// no deep copy; list of children remains unchanged
}
return *this;
@@ -44,6 +48,11 @@ void MObject::setName(const QString &name)
m_name = name;
}
+void MObject::setLinkedFileName(const FilePath &linkedfilename)
+{
+ m_linkedfilename = linkedfilename;
+}
+
void MObject::setChildren(const Handles<MObject> &children)
{
m_children = children;
diff --git a/src/libs/modelinglib/qmt/model/mobject.h b/src/libs/modelinglib/qmt/model/mobject.h
index 1dc95887d9..29d10da4ba 100644
--- a/src/libs/modelinglib/qmt/model/mobject.h
+++ b/src/libs/modelinglib/qmt/model/mobject.h
@@ -6,6 +6,8 @@
#include "melement.h"
#include "qmt/infrastructure/handles.h"
+#include <utils/filepath.h>
+
#include <QString>
namespace qmt {
@@ -23,6 +25,8 @@ public:
QString name() const { return m_name; }
void setName(const QString &name);
+ Utils::FilePath linkedFileName() const { return m_linkedfilename; }
+ void setLinkedFileName(const Utils::FilePath &linkedfilename);
const Handles<MObject> &children() const { return m_children; }
void setChildren(const Handles<MObject> &children);
@@ -48,6 +52,7 @@ public:
private:
QString m_name;
+ Utils::FilePath m_linkedfilename;
Handles<MObject> m_children;
Handles<MRelation> m_relations;
};
diff --git a/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp b/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp
index deb458e4bc..66cfb4576f 100644
--- a/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp
+++ b/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp
@@ -35,6 +35,7 @@ void MFlatAssignmentVisitor::visitMObject(const MObject *object)
auto targetObject = dynamic_cast<MObject *>(m_target);
QMT_ASSERT(targetObject, return);
targetObject->setName(object->name());
+ targetObject->setLinkedFileName(object->linkedFileName());
}
void MFlatAssignmentVisitor::visitMPackage(const MPackage *package)
diff --git a/src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.cpp b/src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.cpp
new file mode 100644
index 0000000000..ba411690f5
--- /dev/null
+++ b/src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.cpp
@@ -0,0 +1,43 @@
+// Copyright (C) 2018 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "modeltreefilterdata.h"
+
+namespace qmt {
+
+void ModelTreeViewData::setShowRelations(bool newShowRelations)
+{
+ m_showRelations = newShowRelations;
+}
+
+void ModelTreeViewData::setShowDiagramElements(bool newShowDiagramElements)
+{
+ m_showDiagramElements = newShowDiagramElements;
+}
+
+void ModelTreeFilterData::setType(Type newType)
+{
+ m_type = newType;
+}
+
+void ModelTreeFilterData::setCustomId(const QString &newCustomId)
+{
+ m_customId = newCustomId;
+}
+
+void ModelTreeFilterData::setStereotypes(const QStringList &newStereotypes)
+{
+ m_stereotypes = newStereotypes;
+}
+
+void ModelTreeFilterData::setName(const QString &newName)
+{
+ m_name = newName;
+}
+
+void ModelTreeFilterData::setDirection(Direction newDirection)
+{
+ m_direction = newDirection;
+}
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.h b/src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.h
new file mode 100644
index 0000000000..3af018fefd
--- /dev/null
+++ b/src/libs/modelinglib/qmt/model_ui/modeltreefilterdata.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2018 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <QString>
+#include <QStringList>
+
+namespace qmt {
+
+class ModelTreeViewData
+{
+public:
+
+ bool showRelations() const { return m_showRelations; }
+ void setShowRelations(bool newShowRelations);
+
+ bool showDiagramElements() const { return m_showDiagramElements; }
+ void setShowDiagramElements(bool newShowDiagramElements);
+
+private:
+ bool m_showRelations = true;
+ bool m_showDiagramElements = false;
+};
+
+class ModelTreeFilterData
+{
+public:
+ enum class Type {
+ Any,
+ Package,
+ Component,
+ Class,
+ Diagram,
+ Item,
+ Dependency,
+ Association,
+ Inheritance,
+ Connection
+ };
+
+ enum class Direction {
+ Any,
+ Outgoing,
+ Incoming,
+ Bidirectional
+ };
+
+ Type type() const { return m_type; }
+ void setType(Type newType);
+
+ QString customId() const { return m_customId; }
+ void setCustomId(const QString &newCustomId);
+
+ QStringList stereotypes() const { return m_stereotypes; }
+ void setStereotypes(const QStringList &newStereotypes);
+
+ QString name() const { return m_name; }
+ void setName(const QString &newName);
+
+ Direction direction() const { return m_direction; }
+ void setDirection(Direction newDirection);
+
+private:
+ Type m_type = Type::Any;
+ QString m_customId;
+ QStringList m_stereotypes;
+ QString m_name;
+ Direction m_direction = Direction::Any;
+};
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.cpp b/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.cpp
index 972c2f9c00..e69e1635a7 100644
--- a/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.cpp
+++ b/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.cpp
@@ -3,14 +3,203 @@
#include "sortedtreemodel.h"
+#include "qmt/model/massociation.h"
+#include "qmt/model/mcanvasdiagram.h"
+#include "qmt/model/mclass.h"
+#include "qmt/model/mcomponent.h"
+#include "qmt/model/mconnection.h"
+#include "qmt/model/mdependency.h"
+#include "qmt/model/minheritance.h"
+#include "qmt/model/mitem.h"
+#include "qmt/model/mpackage.h"
+#include "qmt/model/mconstvisitor.h"
#include "treemodel.h"
namespace qmt {
+namespace {
+
+class Filter : public MConstVisitor {
+public:
+
+ void setModelTreeViewData(const ModelTreeViewData *viewData)
+ {
+ m_viewData = viewData;
+ }
+
+ void setModelTreeFilterData(const ModelTreeFilterData *filterData)
+ {
+ m_filterData = filterData;
+ }
+
+ bool keep() const { return m_keep; }
+
+ void visitMElement(const MElement *element) override
+ {
+ if (!m_filterData->stereotypes().isEmpty()) {
+ const QStringList stereotypes = element->stereotypes();
+ bool containsElementStereotype = std::any_of(
+ stereotypes.constBegin(), stereotypes.constEnd(),
+ [&](const QString &s) { return m_filterData->stereotypes().contains(s); });
+ if (!containsElementStereotype) {
+ m_keep = false;
+ return;
+ }
+ }
+ }
+
+ void visitMObject(const MObject *object) override
+ {
+ if (!m_filterData->name().isEmpty() && m_filterData->name() != object->name())
+ m_keep = false;
+ else
+ visitMElement(object);
+ }
+
+ void visitMPackage(const MPackage *package) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Package)
+ {
+ m_keep = false;
+ } else {
+ visitMObject(package);
+ }
+ }
+
+ void visitMClass(const MClass *klass) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Class)
+ {
+ m_keep = false;
+ } else {
+ visitMObject(klass);
+ }
+ }
+
+ void visitMComponent(const MComponent *component) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Component)
+ {
+ m_keep = false;
+ } else {
+ visitMObject(component);
+ }
+ }
+
+ void visitMDiagram(const MDiagram *diagram) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Diagram)
+ {
+ m_keep = false;
+ } else {
+ visitMObject(diagram);
+ }
+ }
+
+ void visitMCanvasDiagram(const MCanvasDiagram *diagram) override
+ {
+ visitMDiagram(diagram);
+ }
+
+ void visitMItem(const MItem *item) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Item)
+ {
+ m_keep = false;
+ } else {
+ visitMObject(item);
+ }
+ }
+
+ void visitMRelation(const MRelation *relation) override
+ {
+ if (!m_viewData->showRelations())
+ m_keep = false;
+ else if (!m_filterData->name().isEmpty() && m_filterData->name() != relation->name())
+ m_keep = false;
+ else
+ visitMElement(relation);
+ }
+
+ void visitMDependency(const MDependency *dependency) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Dependency)
+ {
+ m_keep = false;
+ } else {
+ switch (m_filterData->direction()) {
+ case ModelTreeFilterData::Direction::Any:
+ break;
+ case ModelTreeFilterData::Direction::Outgoing:
+ if (dependency->direction() != MDependency::AToB)
+ m_keep = false;
+ break;
+ case ModelTreeFilterData::Direction::Incoming:
+ if (dependency->direction() != MDependency::BToA)
+ m_keep = false;
+ break;
+ case ModelTreeFilterData::Direction::Bidirectional:
+ if (dependency->direction() != MDependency::Bidirectional)
+ m_keep = false;
+ break;
+ }
+ if (m_keep)
+ visitMRelation(dependency);
+ }
+ }
+
+ void visitMInheritance(const MInheritance *inheritance) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Inheritance)
+ {
+ m_keep = false;
+ } else {
+ visitMRelation(inheritance);
+ }
+ }
+
+ void visitMAssociation(const MAssociation *association) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Association)
+ {
+ m_keep = false;
+ } else {
+ visitMRelation(association);
+ }
+ }
+
+ void visitMConnection(const MConnection *connection) override
+ {
+ if (m_filterData->type() != ModelTreeFilterData::Type::Any
+ && m_filterData->type() != ModelTreeFilterData::Type::Connection)
+ {
+ m_keep = false;
+ } else {
+ visitMRelation(connection);
+ }
+ }
+
+private:
+ const ModelTreeViewData *m_viewData = nullptr;
+ const ModelTreeFilterData *m_filterData = nullptr;
+ bool m_keep = true;
+};
+
+}
+
SortedTreeModel::SortedTreeModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
setDynamicSortFilter(false);
+ setRecursiveFilteringEnabled(true);
setSortCaseSensitivity(Qt::CaseInsensitive);
m_delayedSortTimer.setSingleShot(true);
@@ -33,6 +222,37 @@ void SortedTreeModel::setTreeModel(TreeModel *treeModel)
startDelayedSortTimer();
}
+void SortedTreeModel::setModelTreeViewData(const ModelTreeViewData &viewData)
+{
+ m_modelTreeViewData = viewData;
+ beginResetModel();
+ endResetModel();
+ startDelayedSortTimer();
+}
+
+void SortedTreeModel::setModelTreeFilterData(const ModelTreeFilterData &filterData)
+{
+ m_modelTreeViewFilterData = filterData;
+ beginResetModel();
+ endResetModel();
+ startDelayedSortTimer();
+}
+
+bool SortedTreeModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+{
+ QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
+ MElement *element = m_treeModel->element(index);
+ if (element) {
+ Filter filter;
+ filter.setModelTreeViewData(&m_modelTreeViewData);
+ filter.setModelTreeFilterData(&m_modelTreeViewFilterData);
+ element->accept(&filter);
+ if (!filter.keep())
+ return false;
+ }
+ return true;
+}
+
bool SortedTreeModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
TreeModel::ItemType leftItemType = TreeModel::ItemType(sourceModel()->data(left, TreeModel::RoleItemType).toInt());
diff --git a/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.h b/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.h
index 0c01cf7de7..797a321132 100644
--- a/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.h
+++ b/src/libs/modelinglib/qmt/model_ui/sortedtreemodel.h
@@ -4,6 +4,7 @@
#pragma once
#include "qmt/infrastructure/qmt_global.h"
+#include "qmt/model_ui/modeltreefilterdata.h"
#include <QSortFilterProxyModel>
#include <QTimer>
@@ -21,7 +22,11 @@ public:
TreeModel *treeModel() const { return m_treeModel; }
void setTreeModel(TreeModel *treeModel);
+ void setModelTreeViewData(const ModelTreeViewData &viewData);
+ void setModelTreeFilterData(const ModelTreeFilterData &filterData);
+
protected:
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
private:
@@ -32,6 +37,8 @@ private:
void startDelayedSortTimer();
TreeModel *m_treeModel = nullptr;
+ ModelTreeViewData m_modelTreeViewData;
+ ModelTreeFilterData m_modelTreeViewFilterData;
QTimer m_delayedSortTimer;
};
diff --git a/src/libs/modelinglib/qmt/model_ui/treemodel.cpp b/src/libs/modelinglib/qmt/model_ui/treemodel.cpp
index 3e8d5a59b6..23d589a654 100644
--- a/src/libs/modelinglib/qmt/model_ui/treemodel.cpp
+++ b/src/libs/modelinglib/qmt/model_ui/treemodel.cpp
@@ -30,6 +30,8 @@
#include <QStandardItem>
+using Utils::FilePath;
+
namespace qmt {
class TreeModel::ModelItem : public QStandardItem
@@ -807,7 +809,7 @@ QString TreeModel::createRelationLabel(const MRelation *relation)
}
QIcon TreeModel::createIcon(StereotypeIcon::Element stereotypeIconElement, StyleEngine::ElementType styleElementType,
- const QStringList &stereotypes, const QString &defaultIconPath)
+ const QStringList &stereotypes, const FilePath &defaultIconPath)
{
const Style *style = m_styleController->adaptStyle(styleElementType);
return m_stereotypeController->createIcon(stereotypeIconElement, stereotypes, defaultIconPath, style,
diff --git a/src/libs/modelinglib/qmt/model_ui/treemodel.h b/src/libs/modelinglib/qmt/model_ui/treemodel.h
index add325a94a..5ea3596348 100644
--- a/src/libs/modelinglib/qmt/model_ui/treemodel.h
+++ b/src/libs/modelinglib/qmt/model_ui/treemodel.h
@@ -9,6 +9,8 @@
#include <qmt/stereotype/stereotypeicon.h>
#include <qmt/style/styleengine.h>
+#include <utils/filepath.h>
+
#include <QScopedPointer>
#include <QHash>
@@ -93,8 +95,9 @@ private:
QString createObjectLabel(const MObject *object);
QString createRelationLabel(const MRelation *relation);
QIcon createIcon(StereotypeIcon::Element stereotypeIconElement,
- StyleEngine::ElementType styleElementType, const QStringList &stereotypes,
- const QString &defaultIconPath);
+ StyleEngine::ElementType styleElementType,
+ const QStringList &stereotypes,
+ const Utils::FilePath &defaultIconPath);
enum Busy {
NotBusy,
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.cpp
new file mode 100644
index 0000000000..40499e2839
--- /dev/null
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.cpp
@@ -0,0 +1,426 @@
+// Copyright (C) 2018 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "addrelatedelementsdialog.h"
+
+#include <qmt/tasks/diagramscenecontroller.h>
+#include <qmt/diagram_controller/dselection.h>
+#include <qmt/model/mdiagram.h>
+#include <qmt/model/mrelation.h>
+#include <qmt/model/mdependency.h>
+#include <qmt/model/minheritance.h>
+#include <qmt/model/massociation.h>
+#include <qmt/model/mconnection.h>
+#include <qmt/model_controller/modelcontroller.h>
+#include <qmt/model_controller/mvoidvisitor.h>
+
+#include "../../modelinglibtr.h"
+
+#include <utils/layoutbuilder.h>
+
+#include <QComboBox>
+#include <QDialogButtonBox>
+#include <QLabel>
+#include <QStringListModel>
+
+namespace qmt {
+
+namespace {
+
+enum class RelationType {
+ Any,
+ Dependency,
+ Association,
+ Inheritance,
+ Connection
+};
+
+enum class RelationDirection {
+ Any,
+ Outgoing,
+ Incoming,
+ Bidirectional
+};
+
+enum class ElementType {
+ Any,
+ Package,
+ Component,
+ Class,
+ Diagram,
+ Item,
+};
+
+class Filter : public qmt::MVoidConstVisitor {
+public:
+
+ void setRelationType(RelationType newRelationType)
+ {
+ m_relationType = newRelationType;
+ }
+
+ void setRelationTypeId(const QString &newRelationTypeId)
+ {
+ m_relationTypeId = newRelationTypeId;
+ }
+
+ void setRelationDirection(RelationDirection newRelationDirection)
+ {
+ m_relationDirection = newRelationDirection;
+ }
+
+ void setRelationStereotypes(const QStringList &newRelationStereotypes)
+ {
+ m_relationStereotypes = newRelationStereotypes;
+ }
+
+ void setElementType(ElementType newElementType)
+ {
+ m_elementType = newElementType;
+ }
+
+ void setElementStereotypes(const QStringList &newElementStereotypes)
+ {
+ m_elementStereotypes = newElementStereotypes;
+ }
+
+ void setObject(const qmt::DObject *dobject, const qmt::MObject *mobject)
+ {
+ m_dobject = dobject;
+ m_mobject = mobject;
+ }
+
+ void setRelation(const qmt::MRelation *relation)
+ {
+ m_relation = relation;
+ }
+
+ bool keep() const { return m_keep; }
+
+ void reset()
+ {
+ m_dobject = nullptr;
+ m_mobject = nullptr;
+ m_relation = nullptr;
+ m_keep = true;
+ }
+
+ // MConstVisitor interface
+ void visitMObject(const qmt::MObject *object) override
+ {
+ if (!m_elementStereotypes.isEmpty()) {
+ const QStringList stereotypes = object->stereotypes();
+ bool containsElementStereotype = std::any_of(
+ stereotypes.constBegin(), stereotypes.constEnd(),
+ [&](const QString &s) { return m_elementStereotypes.contains(s); });
+ if (!containsElementStereotype) {
+ m_keep = false;
+ return;
+ }
+ }
+ }
+
+ void visitMPackage(const qmt::MPackage *package) override
+ {
+ if (m_elementType == ElementType::Any || m_elementType == ElementType::Package)
+ qmt::MVoidConstVisitor::visitMPackage(package);
+ else
+ m_keep = false;
+ }
+
+ void visitMClass(const qmt::MClass *klass) override
+ {
+ if (m_elementType == ElementType::Any || m_elementType == ElementType::Class)
+ qmt::MVoidConstVisitor::visitMClass(klass);
+ else
+ m_keep = false;
+ }
+
+ void visitMComponent(const qmt::MComponent *component) override
+ {
+ if (m_elementType == ElementType::Any || m_elementType == ElementType::Component)
+ qmt::MVoidConstVisitor::visitMComponent(component);
+ else
+ m_keep = false;
+ }
+
+ void visitMDiagram(const qmt::MDiagram *diagram) override
+ {
+ if (m_elementType == ElementType::Any || m_elementType == ElementType::Diagram)
+ qmt::MVoidConstVisitor::visitMDiagram(diagram);
+ else
+ m_keep = false;
+ }
+
+ void visitMItem(const qmt::MItem *item) override
+ {
+ if (m_elementType == ElementType::Any || m_elementType == ElementType::Item)
+ qmt::MVoidConstVisitor::visitMItem(item);
+ else
+ m_keep = false;
+ }
+
+ void visitMRelation(const qmt::MRelation *relation) override
+ {
+ if (!m_relationStereotypes.isEmpty()) {
+ const QStringList relationStereotypes = relation->stereotypes();
+ bool containsRelationStereotype = std::any_of(
+ relationStereotypes.constBegin(), relationStereotypes.constEnd(),
+ [&](const QString &s) { return m_relationStereotypes.contains(s); });
+ if (!containsRelationStereotype) {
+ m_keep = false;
+ return;
+ }
+ }
+ }
+
+ void visitMDependency(const qmt::MDependency *dependency) override
+ {
+ if (m_relationDirection != RelationDirection::Any) {
+ bool keep = false;
+ if (m_relationDirection == RelationDirection::Outgoing) {
+ if (dependency->direction() == qmt::MDependency::AToB && dependency->endAUid() == m_mobject->uid())
+ keep = true;
+ else if (dependency->direction() == qmt::MDependency::BToA && dependency->endBUid() == m_mobject->uid())
+ keep = true;
+ } else if (m_relationDirection == RelationDirection::Incoming) {
+ if (dependency->direction() == qmt::MDependency::AToB && dependency->endBUid() == m_mobject->uid())
+ keep = true;
+ else if (dependency->direction() == qmt::MDependency::BToA && dependency->endAUid() == m_mobject->uid())
+ keep = true;
+ } else if (m_relationDirection == RelationDirection::Bidirectional) {
+ if (dependency->direction() == qmt::MDependency::Bidirectional)
+ keep = true;
+ }
+ m_keep = keep;
+ if (!keep)
+ return;
+ }
+ if (m_relationType == RelationType::Any || m_relationType == RelationType::Dependency)
+ qmt::MVoidConstVisitor::visitMDependency(dependency);
+ else
+ m_keep = false;
+ }
+
+ bool testDirection(const qmt::MRelation *relation)
+ {
+ if (m_relationDirection != RelationDirection::Any) {
+ bool keep = false;
+ if (m_relationDirection == RelationDirection::Outgoing) {
+ if (relation->endAUid() == m_mobject->uid())
+ keep = true;
+ } else if (m_relationDirection == RelationDirection::Incoming) {
+ if (relation->endBUid() == m_mobject->uid())
+ keep = true;
+ }
+ m_keep = keep;
+ if (!keep)
+ return false;
+ }
+ return true;
+ }
+
+ void visitMInheritance(const qmt::MInheritance *inheritance) override
+ {
+ if (!testDirection(inheritance))
+ return;
+ if (m_relationType == RelationType::Any || m_relationType == RelationType::Inheritance)
+ qmt::MVoidConstVisitor::visitMInheritance(inheritance);
+ else
+ m_keep = false;
+ }
+
+ void visitMAssociation(const qmt::MAssociation *association) override
+ {
+ if (!testDirection(association))
+ return;
+ if (m_relationType == RelationType::Any || m_relationType == RelationType::Association)
+ qmt::MVoidConstVisitor::visitMAssociation(association);
+ else
+ m_keep = false;
+ }
+
+ void visitMConnection(const qmt::MConnection *connection) override
+ {
+ if (!testDirection(connection))
+ return;
+ if (m_relationType == RelationType::Any || m_relationType == RelationType::Connection)
+ qmt::MVoidConstVisitor::visitMConnection(connection);
+ else
+ m_keep = false;
+ }
+
+private:
+ RelationType m_relationType = RelationType::Any;
+ QString m_relationTypeId;
+ RelationDirection m_relationDirection = RelationDirection::Any;
+ QStringList m_relationStereotypes;
+ ElementType m_elementType = ElementType::Any;
+ QStringList m_elementStereotypes;
+ const qmt::DObject *m_dobject = nullptr;
+ const qmt::MObject *m_mobject = nullptr;
+ const qmt::MRelation *m_relation = nullptr;
+ bool m_keep = true;
+};
+} // namespace
+
+class AddRelatedElementsDialog::Private {
+public:
+ qmt::DiagramSceneController *m_diagramSceneController = nullptr;
+ qmt::DSelection m_selection;
+ qmt::Uid m_diagramUid;
+ QStringListModel m_relationTypeModel;
+ QStringListModel m_relationDirectionModel;
+ QStringListModel m_relationStereotypesModel;
+ QStringListModel m_elementTypeModel;
+ QStringListModel m_elementStereotypesModel;
+ Filter m_filter;
+
+ QComboBox *RelationTypeCombobox;
+ QComboBox *DirectionCombobox;
+ QComboBox *StereotypesCombobox;
+ QComboBox *ElementStereotypesCombobox;
+ QComboBox *ElementTypeComboBox;
+ QLabel *NumberOfMatchingElementsValue;
+ QDialogButtonBox *buttonBox;
+};
+
+AddRelatedElementsDialog::AddRelatedElementsDialog(QWidget *parent) :
+ QDialog(parent),
+ d(new Private)
+{
+ setMinimumWidth(500);
+
+ d->RelationTypeCombobox = new QComboBox;
+ d->DirectionCombobox = new QComboBox;
+ d->StereotypesCombobox = new QComboBox;
+ d->StereotypesCombobox->setEditable(true);
+ d->ElementTypeComboBox = new QComboBox;
+ d->ElementStereotypesCombobox = new QComboBox;
+ d->ElementStereotypesCombobox->setEditable(true);
+ d->NumberOfMatchingElementsValue = new QLabel;
+ d->buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
+
+ using namespace Layouting;
+ Column {
+ Group {
+ title(Tr::tr("Relation Attributes")),
+ Form {
+ Tr::tr("Type"), d->RelationTypeCombobox, br,
+ Tr::tr("Direction"), d->DirectionCombobox, br,
+ Tr::tr("Stereotypes"), d->StereotypesCombobox, br,
+ },
+ },
+ Group {
+ title(Tr::tr("Other Element Attributes")),
+ Form {
+ Tr::tr("Type"), d->ElementTypeComboBox, br,
+ Tr::tr("Stereotypes"), d->ElementStereotypesCombobox, br,
+ },
+ },
+ Row {
+ Tr::tr("Number of matching elements: "), d->NumberOfMatchingElementsValue, st,
+ },
+ st,
+ d->buttonBox,
+ }.attachTo(this);
+
+ connect(d->RelationTypeCombobox, &QComboBox::currentIndexChanged, this, &AddRelatedElementsDialog::updateNumberOfElements);
+ connect(d->DirectionCombobox, &QComboBox::currentIndexChanged, this, &AddRelatedElementsDialog::updateNumberOfElements);
+ connect(d->StereotypesCombobox, &QComboBox::currentTextChanged, this, &AddRelatedElementsDialog::updateNumberOfElements);
+ connect(d->ElementTypeComboBox, &QComboBox::currentIndexChanged, this, &AddRelatedElementsDialog::updateNumberOfElements);
+ connect(d->ElementStereotypesCombobox, &QComboBox::currentTextChanged, this, &AddRelatedElementsDialog::updateNumberOfElements);
+ connect(d->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ connect(this, &QDialog::accepted, this, &AddRelatedElementsDialog::onAccepted);
+}
+
+AddRelatedElementsDialog::~AddRelatedElementsDialog()
+{
+ delete d;
+}
+
+void AddRelatedElementsDialog::setDiagramSceneController(qmt::DiagramSceneController *diagramSceneController)
+{
+ d->m_diagramSceneController = diagramSceneController;
+}
+
+void AddRelatedElementsDialog::setElements(const qmt::DSelection &selection, qmt::MDiagram *diagram)
+{
+ d->m_selection = selection;
+ d->m_diagramUid = diagram->uid();
+ QStringList relationTypes = {"Any", "Dependency", "Association", "Inheritance"};
+ d->m_relationTypeModel.setStringList(relationTypes);
+ d->RelationTypeCombobox->setModel(&d->m_relationTypeModel);
+ QStringList relationDirections = {"Any", "Outgoing (->)", "Incoming (<-)", "Bidirectional (<->)"};
+ d->m_relationDirectionModel.setStringList(relationDirections);
+ d->DirectionCombobox->setModel(&d->m_relationDirectionModel);
+ QStringList relationStereotypes = { };
+ d->m_relationStereotypesModel.setStringList(relationStereotypes);
+ d->StereotypesCombobox->setModel(&d->m_relationStereotypesModel);
+ QStringList elementTypes = {"Any", "Package", "Component", "Class", "Diagram", "Item"};
+ d->m_elementTypeModel.setStringList(elementTypes);
+ d->ElementTypeComboBox->setModel(&d->m_elementTypeModel);
+ QStringList elementStereotypes = { };
+ d->m_elementStereotypesModel.setStringList(elementStereotypes);
+ d->ElementStereotypesCombobox->setModel(&d->m_elementStereotypesModel);
+ updateNumberOfElements();
+}
+
+void AddRelatedElementsDialog::onAccepted()
+{
+ qmt::MDiagram *diagram = d->m_diagramSceneController->modelController()->findElement<qmt::MDiagram>(d->m_diagramUid);
+ if (diagram) {
+ updateFilter();
+ d->m_diagramSceneController->addRelatedElements(
+ d->m_selection, diagram,
+ [this](qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation) -> bool
+ {
+ return this->filter(dobject, mobject, relation);
+ });
+ }
+}
+
+void AddRelatedElementsDialog::updateFilter()
+{
+ d->m_filter.setRelationType((RelationType) d->RelationTypeCombobox->currentIndex());
+ d->m_filter.setRelationDirection((RelationDirection) d->DirectionCombobox->currentIndex());
+ d->m_filter.setRelationStereotypes(d->StereotypesCombobox->currentText().split(',', Qt::SkipEmptyParts));
+ d->m_filter.setElementType((ElementType) d->ElementTypeComboBox->currentIndex());
+ d->m_filter.setElementStereotypes(d->ElementStereotypesCombobox->currentText().split(',', Qt::SkipEmptyParts));
+}
+
+bool AddRelatedElementsDialog::filter(qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation)
+{
+ d->m_filter.reset();
+ d->m_filter.setObject(dobject, mobject);
+ d->m_filter.setRelation(relation);
+ relation->accept(&d->m_filter);
+ if (!d->m_filter.keep())
+ return false;
+ qmt::MObject *targetObject = nullptr;
+ if (relation->endAUid() != mobject->uid())
+ targetObject = d->m_diagramSceneController->modelController()->findObject(relation->endAUid());
+ else if (relation->endBUid() != mobject->uid())
+ targetObject = d->m_diagramSceneController->modelController()->findObject(relation->endBUid());
+ if (!targetObject)
+ return false;
+ targetObject->accept(&d->m_filter);
+ return d->m_filter.keep();
+}
+
+void AddRelatedElementsDialog::updateNumberOfElements()
+{
+ qmt::MDiagram *diagram = d->m_diagramSceneController->modelController()->findElement<qmt::MDiagram>(d->m_diagramUid);
+ if (diagram) {
+ updateFilter();
+ d->NumberOfMatchingElementsValue->setText(QString::number(d->m_diagramSceneController->countRelatedElements(
+ d->m_selection, diagram,
+ [this](qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation) -> bool
+ {
+ return this->filter(dobject, mobject, relation);
+ })));
+ }
+}
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.h b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.h
new file mode 100644
index 0000000000..e0fefa1c6c
--- /dev/null
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2018 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "qmt/infrastructure/qmt_global.h"
+
+#include <QDialog>
+
+namespace qmt {
+
+class DSelection;
+class DObject;
+class MObject;
+class MDiagram;
+class MRelation;
+class DiagramSceneController;
+}
+
+namespace qmt {
+
+class QMT_EXPORT AddRelatedElementsDialog : public QDialog
+{
+ Q_OBJECT
+ class Private;
+
+public:
+ explicit AddRelatedElementsDialog(QWidget *parent = nullptr);
+ ~AddRelatedElementsDialog();
+
+ void setDiagramSceneController(qmt::DiagramSceneController *diagramSceneController);
+ void setElements(const qmt::DSelection &selection, qmt::MDiagram *diagram);
+
+private:
+ void onAccepted();
+ void updateFilter();
+ bool filter(qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation);
+ void updateNumberOfElements();
+
+ Private *d = nullptr;
+};
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.cpp
new file mode 100644
index 0000000000..f02b466830
--- /dev/null
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.cpp
@@ -0,0 +1,173 @@
+// Copyright (C) 2018 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "modeltreefilter.h"
+
+#include "../../modelinglibtr.h"
+
+#include <utils/layoutbuilder.h>
+
+#include <QCheckBox>
+#include <QComboBox>
+#include <QFrame>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QStringListModel>
+
+namespace qmt {
+
+class ModelTreeFilter::Private {
+public:
+ QStringListModel m_typeModel;
+ QStringListModel m_stereotypesModel;
+ QStringListModel m_directionModel;
+
+ QPushButton *resetViewButton;
+ QCheckBox *relationsCheckBox;
+ QCheckBox *diagramElementsCheckBox;
+ QPushButton *clearFilterButton;
+ QComboBox *typeComboBox;
+ QComboBox *stereotypesComboBox;
+ QLineEdit *nameLineEdit;
+ QComboBox *directionComboBox;
+};
+
+ModelTreeFilter::ModelTreeFilter(QWidget *parent) :
+ QWidget(parent),
+ d(new Private)
+{
+ d->resetViewButton = new QPushButton(Tr::tr("Reset"));
+ d->relationsCheckBox = new QCheckBox(Tr::tr("Relations"));
+ d->diagramElementsCheckBox = new QCheckBox(Tr::tr("Diagram Elements"));
+ d->diagramElementsCheckBox->setMaximumHeight(0);
+ d->clearFilterButton = new QPushButton(Tr::tr("Clear"));
+ d->typeComboBox = new QComboBox;
+ d->stereotypesComboBox = new QComboBox;
+ d->stereotypesComboBox->setEditable(true);
+ d->nameLineEdit = new QLineEdit;
+ d->directionComboBox = new QComboBox;
+
+ const auto boldLabel = [] (const QString &title) -> QLabel * {
+ auto label = new QLabel(title);
+ QFont boldFont = label->font();
+ boldFont.setWeight(QFont::Bold);
+ label->setFont(boldFont);
+ return label;
+ };
+
+ const auto line = [] () -> QFrame * {
+ auto line = new QFrame;
+ line->setFrameShadow(QFrame::Plain);
+ line->setFrameShape(QFrame::HLine);
+ return line;
+ };
+
+ const int margin = 9;
+
+ using namespace Layouting;
+ Column {
+ Column {
+ Row {
+ boldLabel(Tr::tr("View")), st, d->resetViewButton
+ },
+ d->relationsCheckBox,
+ d->diagramElementsCheckBox,
+ customMargins(margin, 0, margin, 0),
+ },
+ Space(10),
+ line(),
+ Column {
+ Row {
+ boldLabel(Tr::tr("Filter")), st, d->clearFilterButton
+ },
+ Space(10),
+ Form {
+ Tr::tr("Type:"), d->typeComboBox, br,
+ Tr::tr("Stereotypes:"), d->stereotypesComboBox, br,
+ Tr::tr("Name:"), d->nameLineEdit, br,
+ Tr::tr("Direction:"), d->directionComboBox, br,
+ },
+ customMargins(margin, 0, margin, 0),
+ },
+ st,
+ line(),
+ customMargins(0, margin, 0, 0),
+ }.attachTo(this);
+
+ connect(d->resetViewButton, &QPushButton::clicked, this, &ModelTreeFilter::resetView);
+ connect(d->relationsCheckBox, &QCheckBox::clicked, this, &ModelTreeFilter::onViewChanged);
+ connect(d->diagramElementsCheckBox, &QCheckBox::clicked, this, &ModelTreeFilter::onViewChanged);
+ connect(d->clearFilterButton, &QPushButton::clicked, this, &ModelTreeFilter::clearFilter);
+ connect(d->typeComboBox, &QComboBox::currentIndexChanged, this, [this](int index) {
+ d->directionComboBox->setDisabled(index != (int) ModelTreeFilterData::Type::Dependency);
+ });
+ connect(d->typeComboBox, &QComboBox::currentIndexChanged, this, &ModelTreeFilter::onFilterChanged);
+ connect(d->stereotypesComboBox, &QComboBox::currentTextChanged, this, &ModelTreeFilter::onFilterChanged);
+ connect(d->nameLineEdit, &QLineEdit::textChanged, this, &ModelTreeFilter::onFilterChanged);
+ connect(d->directionComboBox, &QComboBox::currentTextChanged, this, &ModelTreeFilter::onFilterChanged);
+ setupFilter();
+ resetView();
+ clearFilter();
+}
+
+ModelTreeFilter::~ModelTreeFilter()
+{
+ delete d;
+}
+
+void ModelTreeFilter::setupFilter()
+{
+ QStringList types = {"Any", "Package", "Component", "Class", "Diagram", "Item",
+ "Dependency", "Association", "Inheritance", "Connection"};
+ d->m_typeModel.setStringList(types);
+ d->typeComboBox->setModel(&d->m_typeModel);
+
+ QStringList stereotypes = { };
+ d->m_stereotypesModel.setStringList(stereotypes);
+ d->stereotypesComboBox->setModel(&d->m_stereotypesModel);
+
+ QStringList directions = {"Any", "Outgoing (->)", "Incoming (<-)", "Bidirectional (<->)"};
+ d->m_directionModel.setStringList(directions);
+ d->directionComboBox->setModel(&d->m_directionModel);
+}
+
+void ModelTreeFilter::resetView()
+{
+ d->relationsCheckBox->setChecked(true);
+ d->diagramElementsCheckBox->setChecked(false);
+ onViewChanged();
+}
+
+void ModelTreeFilter::clearFilter()
+{
+ d->typeComboBox->setCurrentIndex(0);
+ d->stereotypesComboBox->clearEditText();
+ d->nameLineEdit->clear();
+ d->directionComboBox->setCurrentIndex(0);
+ onFilterChanged();
+}
+
+void ModelTreeFilter::onViewChanged()
+{
+ ModelTreeViewData modelTreeViewData;
+ modelTreeViewData.setShowRelations(d->relationsCheckBox->isChecked());
+ modelTreeViewData.setShowDiagramElements(d->diagramElementsCheckBox->isChecked());
+ emit viewDataChanged(modelTreeViewData);
+}
+
+void ModelTreeFilter::onFilterChanged()
+{
+ ModelTreeFilterData modelTreeFilterData;
+ modelTreeFilterData.setType((ModelTreeFilterData::Type) d->typeComboBox->currentIndex());
+ modelTreeFilterData.setCustomId(QString());
+ modelTreeFilterData.setStereotypes(d->stereotypesComboBox->currentText().split(',', Qt::SkipEmptyParts));
+ modelTreeFilterData.setName(d->nameLineEdit->text().trimmed());
+ if (modelTreeFilterData.type() == ModelTreeFilterData::Type::Dependency)
+ modelTreeFilterData.setDirection((ModelTreeFilterData::Direction) d->directionComboBox->currentIndex());
+ else
+ modelTreeFilterData.setDirection(ModelTreeFilterData::Direction::Any);
+ emit filterDataChanged(modelTreeFilterData);
+}
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.h b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.h
new file mode 100644
index 0000000000..1de7237c6e
--- /dev/null
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreefilter.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2018 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "qmt/infrastructure/qmt_global.h"
+#include "qmt/model_ui/modeltreefilterdata.h"
+
+#include <QWidget>
+
+namespace qmt {
+
+class QMT_EXPORT ModelTreeFilter : public QWidget
+{
+ Q_OBJECT
+ class Private;
+
+public:
+ explicit ModelTreeFilter(QWidget *parent = nullptr);
+ ~ModelTreeFilter();
+
+signals:
+ void viewDataChanged(const ModelTreeViewData &modelTreeViewData);
+ void filterDataChanged(const ModelTreeFilterData &modelTreeFilterData);
+
+private:
+
+ void setupFilter();
+ void resetView();
+ void clearFilter();
+ void onViewChanged();
+ void onFilterChanged();
+
+private:
+ Private *d = nullptr;
+};
+
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.cpp
index 68c22ce6df..e2006a37b5 100644
--- a/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.cpp
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.cpp
@@ -71,6 +71,46 @@ void ModelTreeView::setElementTasks(IElementTasks *elementTasks)
m_elementTasks = elementTasks;
}
+static void StoreStatus(QTreeView *view, QSortFilterProxyModel *model, const QModelIndex &parent, QVector<QModelIndex> &expanded_items)
+{
+ for (int index = 0; index < model->rowCount(parent); ++index) {
+ auto proxy_index = model->index(index, 0, parent);
+ if (view->isExpanded(proxy_index)) {
+ auto source_index = model->mapToSource(proxy_index);
+ expanded_items.append(source_index);
+ }
+ StoreStatus(view, model, proxy_index, expanded_items);
+ }
+}
+
+static void ApplyStatus(QTreeView *view, QSortFilterProxyModel *model, QVector<QModelIndex> &expanded_items)
+{
+ for (auto source_index : expanded_items) {
+ auto proxy_index = model->mapFromSource(source_index);
+ view->setExpanded(proxy_index, true);
+ }
+}
+
+void ModelTreeView::setModelTreeViewData(const ModelTreeViewData &viewData)
+{
+ if (m_sortedTreeModel) {
+ QVector<QModelIndex> expanded_items;
+ StoreStatus(this, m_sortedTreeModel, QModelIndex(), expanded_items);
+ m_sortedTreeModel->setModelTreeViewData(viewData);
+ ApplyStatus(this, m_sortedTreeModel, expanded_items);
+ }
+}
+
+void ModelTreeView::setModelTreeFilterData(const ModelTreeFilterData &filterData)
+{
+ if (m_sortedTreeModel) {
+ QVector<QModelIndex> expanded_items;
+ StoreStatus(this, m_sortedTreeModel, QModelIndex(), expanded_items);
+ m_sortedTreeModel->setModelTreeFilterData(filterData);
+ ApplyStatus(this, m_sortedTreeModel, expanded_items);
+ }
+}
+
QModelIndex ModelTreeView::mapToSourceModelIndex(const QModelIndex &index) const
{
return m_sortedTreeModel->mapToSource(index);
@@ -144,7 +184,7 @@ void ModelTreeView::dragMoveEvent(QDragMoveEvent *event)
{
QTreeView::dragMoveEvent(event);
bool accept = false;
- QModelIndex dropIndex = indexAt(event->pos());
+ QModelIndex dropIndex = indexAt(event->position().toPoint());
QModelIndex dropSourceModelIndex = m_sortedTreeModel->mapToSource(dropIndex);
if (dropSourceModelIndex.isValid()) {
TreeModel *treeModel = m_sortedTreeModel->treeModel();
@@ -175,7 +215,7 @@ void ModelTreeView::dropEvent(QDropEvent *event)
bool accept = false;
event->setDropAction(Qt::MoveAction);
if (event->mimeData()->hasFormat("text/model-elements")) {
- QModelIndex dropIndex = indexAt(event->pos());
+ QModelIndex dropIndex = indexAt(event->position().toPoint());
QModelIndex dropSourceModelIndex = m_sortedTreeModel->mapToSource(dropIndex);
if (dropSourceModelIndex.isValid()) {
TreeModel *treeModel = m_sortedTreeModel->treeModel();
@@ -237,6 +277,10 @@ void ModelTreeView::contextMenuEvent(QContextMenuEvent *event)
menu.addAction(new ContextMenuAction(Tr::tr("Open Diagram"), "openDiagram", &menu));
addSeparator = true;
}
+ if (m_elementTasks->hasLinkedFile(melement)) {
+ menu.addAction(new ContextMenuAction(Tr::tr("Open Linked File"), "openLinkedFile", &menu));
+ addSeparator = true;
+ }
if (melement->owner()) {
if (addSeparator)
menu.addSeparator();
@@ -253,6 +297,8 @@ void ModelTreeView::contextMenuEvent(QContextMenuEvent *event)
m_elementTasks->openClassDefinition(melement);
} else if (action->id() == "openDiagram") {
m_elementTasks->openDiagram(melement);
+ } else if (action->id() == "openLinkedFile") {
+ m_elementTasks->openLinkedFile(melement);
} else if (action->id() == "delete") {
MSelection selection;
selection.append(melement->uid(), melement->owner()->uid());
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.h b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.h
index 0c07cb0372..e5537644a3 100644
--- a/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.h
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/modeltreeview.h
@@ -5,6 +5,7 @@
#include "qmt/infrastructure/qmt_global.h"
#include "qmt/model_ui/modeltreeviewinterface.h"
+#include "qmt/model_ui/modeltreefilterdata.h"
#include <QElapsedTimer>
#include <QTreeView>
@@ -32,6 +33,9 @@ public:
void setTreeModel(SortedTreeModel *model);
void setElementTasks(IElementTasks *elementTasks);
+ void setModelTreeViewData(const ModelTreeViewData &viewData);
+ void setModelTreeFilterData(const ModelTreeFilterData &filterData);
+
QModelIndex mapToSourceModelIndex(const QModelIndex &index) const;
void selectFromSourceModelIndex(const QModelIndex &index);
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
index 969313ca33..11df24188d 100644
--- a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
@@ -43,6 +43,7 @@
#include "qmt/diagram_scene/items/stereotypedisplayvisitor.h"
#include "qmt/stereotype/stereotypecontroller.h"
#include "qmt/stereotype/customrelation.h"
+#include "qmt/style/relationvisuals.h"
#include "qmt/style/stylecontroller.h"
#include "qmt/style/style.h"
#include "qmt/style/objectvisuals.h"
@@ -237,6 +238,61 @@ static DClass::TemplateDisplay translateIndexToTemplateDisplay(int index)
return map[index];
}
+static int translateRelationVisualPrimaryRoleToIndex(DRelation::VisualPrimaryRole visualRole)
+{
+ switch (visualRole) {
+ case DRelation::PrimaryRoleNormal:
+ return 0;
+ case DRelation::PrimaryRoleCustom1:
+ return 1;
+ case DRelation::PrimaryRoleCustom2:
+ return 2;
+ case DRelation::PrimaryRoleCustom3:
+ return 3;
+ case DRelation::PrimaryRoleCustom4:
+ return 4;
+ case DRelation::PrimaryRoleCustom5:
+ return 5;
+ }
+ return 0;
+}
+
+static DRelation::VisualPrimaryRole translateIndexToRelationVisualPrimaryRole(int index)
+{
+ static const DRelation::VisualPrimaryRole map[] = {
+ DRelation::PrimaryRoleNormal,
+ DRelation::PrimaryRoleCustom1, DRelation::PrimaryRoleCustom2, DRelation::PrimaryRoleCustom3,
+ DRelation::PrimaryRoleCustom4, DRelation::PrimaryRoleCustom5
+ };
+ QMT_ASSERT(index >= 0 && index <= 5, return DRelation::PrimaryRoleNormal);
+ return map[index];
+}
+
+static int translateRelationVisualSecondaryRoleToIndex(DRelation::VisualSecondaryRole visualRole)
+{
+ switch (visualRole) {
+ case DRelation::SecondaryRoleNone:
+ return 0;
+ case DRelation::SecondaryRoleWarning:
+ return 1;
+ case DRelation::SecondaryRoleError:
+ return 2;
+ case DRelation::SecondaryRoleSoften:
+ return 3;
+ }
+ return 0;
+}
+
+static DRelation::VisualSecondaryRole translateIndexToRelationVisualSecondaryRole(int index)
+{
+ static const DRelation::VisualSecondaryRole map[] = {
+ DRelation::SecondaryRoleNone,
+ DRelation::SecondaryRoleWarning, DRelation::SecondaryRoleError, DRelation::SecondaryRoleSoften
+ };
+ QMT_ASSERT(index >= 0 && index <= 5, return DRelation::SecondaryRoleNone);
+ return map[index];
+}
+
static int translateAnnotationVisualRoleToIndex(DAnnotation::VisualRole visualRole)
{
switch (visualRole) {
@@ -398,6 +454,7 @@ void PropertiesView::MView::visitMPackage(const MPackage *package)
else
setTitle<MPackage>(m_modelElements, Tr::tr("Package"), Tr::tr("Packages"));
visitMObject(package);
+ visitMObjectBehind(package);
}
void PropertiesView::MView::visitMClass(const MClass *klass)
@@ -472,12 +529,14 @@ void PropertiesView::MView::visitMClass(const MClass *klass)
}
if (m_classMembersEdit->isEnabled() != isSingleSelection)
m_classMembersEdit->setEnabled(isSingleSelection);
+ visitMObjectBehind(klass);
}
void PropertiesView::MView::visitMComponent(const MComponent *component)
{
setTitle<MComponent>(m_modelElements, Tr::tr("Component"), Tr::tr("Components"));
visitMObject(component);
+ visitMObjectBehind(component);
}
void PropertiesView::MView::visitMDiagram(const MDiagram *diagram)
@@ -497,6 +556,7 @@ void PropertiesView::MView::visitMCanvasDiagram(const MCanvasDiagram *diagram)
{
setTitle<MCanvasDiagram>(m_modelElements, Tr::tr("Canvas Diagram"), Tr::tr("Canvas Diagrams"));
visitMDiagram(diagram);
+ visitMDiagramBehind(diagram);
}
void PropertiesView::MView::visitMItem(const MItem *item)
@@ -521,6 +581,7 @@ void PropertiesView::MView::visitMItem(const MItem *item)
if (m_itemVarietyEdit->isEnabled() != isSingleSelection)
m_itemVarietyEdit->setEnabled(isSingleSelection);
}
+ visitMObjectBehind(item);
}
void PropertiesView::MView::visitMRelation(const MRelation *relation)
@@ -850,6 +911,7 @@ void PropertiesView::MView::visitDElement(const DElement *element)
void PropertiesView::MView::visitDObject(const DObject *object)
{
visitDElement(object);
+ visitDObjectBefore(object);
#ifdef SHOW_DEBUG_PROPERTIES
if (!m_posRectLabel) {
m_posRectLabel = new QLabel(m_topWidget);
@@ -1057,6 +1119,52 @@ void PropertiesView::MView::visitDItem(const DItem *item)
void PropertiesView::MView::visitDRelation(const DRelation *relation)
{
visitDElement(relation);
+ if (!m_relationVisualPrimaryRoleSelector) {
+ m_relationVisualPrimaryRoleSelector = new PaletteBox(m_topWidget);
+ setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleNormal);
+ setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom1);
+ setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom2);
+ setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom3);
+ setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom4);
+ setRelationPrimaryRolePalette(m_styleElementType, DRelation::PrimaryRoleCustom5);
+ addRow(Tr::tr("Color:"), m_relationVisualPrimaryRoleSelector, "color");
+ connect(m_relationVisualPrimaryRoleSelector, &PaletteBox::activated,
+ this, &PropertiesView::MView::onRelationVisualPrimaryRoleChanged);
+ }
+ if (!m_relationVisualPrimaryRoleSelector->hasFocus()) {
+ DRelation::VisualPrimaryRole visualPrimaryRole;
+ if (haveSameValue(m_diagramElements, &DRelation::visualPrimaryRole, &visualPrimaryRole))
+ m_relationVisualPrimaryRoleSelector->setCurrentIndex(translateRelationVisualPrimaryRoleToIndex(visualPrimaryRole));
+ else
+ m_relationVisualPrimaryRoleSelector->setCurrentIndex(-1);
+ }
+ if (!m_relationVisualSecondaryRoleSelector) {
+ m_relationVisualSecondaryRoleSelector = new QComboBox(m_topWidget);
+ m_relationVisualSecondaryRoleSelector->addItems({ Tr::tr("Normal"), Tr::tr("Warning"), Tr::tr("Error"), Tr::tr("Soften") });
+ addRow(Tr::tr("Role:"), m_relationVisualSecondaryRoleSelector, "role");
+ connect(m_relationVisualSecondaryRoleSelector, QOverload<int>::of(&QComboBox::activated),
+ this, &PropertiesView::MView::onRelationVisualSecondaryRoleChanged);
+ }
+ if (!m_relationVisualSecondaryRoleSelector->hasFocus()) {
+ DRelation::VisualSecondaryRole visualSecondaryRole;
+ if (haveSameValue(m_diagramElements, &DRelation::visualSecondaryRole, &visualSecondaryRole))
+ m_relationVisualSecondaryRoleSelector->setCurrentIndex(translateRelationVisualSecondaryRoleToIndex(visualSecondaryRole));
+ else
+ m_relationVisualSecondaryRoleSelector->setCurrentIndex(-1);
+ }
+ if (!m_relationVisualEmphasizedCheckbox) {
+ m_relationVisualEmphasizedCheckbox = new QCheckBox(Tr::tr("Emphasized"), m_topWidget);
+ addRow(QString(), m_relationVisualEmphasizedCheckbox, "emphasized");
+ connect(m_relationVisualEmphasizedCheckbox, &QAbstractButton::clicked,
+ this, &PropertiesView::MView::onRelationVisualEmphasizedChanged);
+ }
+ if (!m_relationVisualEmphasizedCheckbox->hasFocus()) {
+ bool emphasized;
+ if (haveSameValue(m_diagramElements, &DRelation::isVisualEmphasized, &emphasized))
+ m_relationVisualEmphasizedCheckbox->setChecked(emphasized);
+ else
+ m_relationVisualEmphasizedCheckbox->setChecked(false);
+ }
#ifdef SHOW_DEBUG_PROPERTIES
if (!m_pointsLabel) {
m_pointsLabel = new QLabel(m_topWidget);
@@ -1145,6 +1253,26 @@ void PropertiesView::MView::visitDSwimlane(const DSwimlane *swimlane)
visitDElement(swimlane);
}
+void PropertiesView::MView::visitMElementBehind(const MElement *element)
+{
+ Q_UNUSED(element)
+}
+
+void PropertiesView::MView::visitMObjectBehind(const MObject *object)
+{
+ visitMElementBehind(object);
+}
+
+void PropertiesView::MView::visitMDiagramBehind(const MDiagram *diagram)
+{
+ visitMObjectBehind(diagram);
+}
+
+void PropertiesView::MView::visitDObjectBefore(const DObject *object)
+{
+ Q_UNUSED(object);
+}
+
void PropertiesView::MView::onStereotypesChanged(const QString &stereotypes)
{
QList<QString> set = m_stereotypesController->fromString(stereotypes);
@@ -1392,7 +1520,42 @@ void PropertiesView::MView::onAnnotationVisualRoleChanged(int visualRoleIndex)
{
DAnnotation::VisualRole visualRole = translateIndexToAnnotationVisualRole((visualRoleIndex));
assignModelElement<DAnnotation, DAnnotation::VisualRole>(
- m_diagramElements, SelectionMulti, visualRole, &DAnnotation::visualRole, &DAnnotation::setVisualRole);
+ m_diagramElements, SelectionMulti, visualRole, &DAnnotation::visualRole, &DAnnotation::setVisualRole);
+}
+
+
+void PropertiesView::MView::onRelationVisualPrimaryRoleChanged(int visualRoleIndex)
+{
+ DRelation::VisualPrimaryRole visualRole = translateIndexToRelationVisualPrimaryRole(visualRoleIndex);
+ assignModelElement<DRelation, DRelation::VisualPrimaryRole>(
+ m_diagramElements, SelectionMulti, visualRole,
+ &DRelation::visualPrimaryRole, &DRelation::setVisualPrimaryRole);
+}
+
+void PropertiesView::MView::onRelationVisualSecondaryRoleChanged(int visualRoleIndex)
+{
+ DRelation::VisualSecondaryRole visualRole = translateIndexToRelationVisualSecondaryRole(visualRoleIndex);
+ assignModelElement<DRelation, DRelation::VisualSecondaryRole>(
+ m_diagramElements, SelectionMulti, visualRole,
+ &DRelation::visualSecondaryRole, &DRelation::setVisualSecondaryRole);
+}
+
+void PropertiesView::MView::onRelationVisualEmphasizedChanged(bool visualEmphasized)
+{
+ assignModelElement<DRelation, bool>(m_diagramElements, SelectionMulti, visualEmphasized,
+ &DRelation::isVisualEmphasized, &DRelation::setVisualEmphasized);
+}
+
+void PropertiesView::MView::onRelationColorChanged(const QColor &color)
+{
+ assignModelElement<DRelation, QColor>(m_diagramElements, SelectionMulti, color,
+ &DRelation::color, &DRelation::setColor);
+}
+
+void PropertiesView::MView::onRelationThicknessChanged(qreal thickness)
+{
+ assignModelElement<DRelation, qreal>(m_diagramElements, SelectionMulti, thickness,
+ &DRelation::thickness, &DRelation::setThickness);
}
void PropertiesView::MView::prepare()
@@ -1553,7 +1716,8 @@ void PropertiesView::MView::setPrimaryRolePalette(StyleEngine::ElementType eleme
DObject::VisualPrimaryRole visualPrimaryRole, const QColor &baseColor)
{
int index = translateVisualPrimaryRoleToIndex(visualPrimaryRole);
- const Style *style = m_propertiesView->styleController()->adaptObjectStyle(elementType, ObjectVisuals(visualPrimaryRole, DObject::SecondaryRoleNone, false, baseColor, 0));
+ const Style *style = m_propertiesView->styleController()->adaptObjectStyle(
+ elementType, ObjectVisuals(visualPrimaryRole, DObject::SecondaryRoleNone, false, baseColor, 0));
m_visualPrimaryRoleSelector->setBrush(index, style->fillBrush());
m_visualPrimaryRoleSelector->setLinePen(index, style->linePen());
}
@@ -1595,112 +1759,15 @@ QString PropertiesView::MView::formatTemplateParameters(const QList<QString> &te
return templateParamters;
}
-template<class T, class V>
-QList<T *> PropertiesView::MView::filter(const QList<V *> &elements)
-{
- QList<T *> filtered;
- for (V *element : elements) {
- auto t = dynamic_cast<T *>(element);
- if (t)
- filtered.append(t);
- }
- return filtered;
-}
-
-template<class T, class V, class BASE>
-bool PropertiesView::MView::haveSameValue(const QList<BASE *> &baseElements, V (T::*getter)() const, V *value)
+void PropertiesView::MView::setRelationPrimaryRolePalette(StyleEngine::ElementType elementType,
+ DRelation::VisualPrimaryRole visualPrimaryRole)
{
- const QList<T *> elements = filter<T>(baseElements);
- QMT_CHECK(!elements.isEmpty());
- V candidate = V(); // avoid warning of reading uninitialized variable
- bool haveCandidate = false;
- for (T *element : elements) {
- if (!haveCandidate) {
- candidate = ((*element).*getter)();
- haveCandidate = true;
- } else {
- if (candidate != ((*element).*getter)())
- return false;
- }
- }
- QMT_CHECK(haveCandidate);
- if (!haveCandidate)
- return false;
- if (value)
- *value = candidate;
- return true;
-}
-
-template<class T, class V, class BASE>
-void PropertiesView::MView::assignModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
- const V &value, V (T::*getter)() const, void (T::*setter)(const V &))
-{
- const QList<T *> elements = filter<T>(baseElements);
- if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
- for (T *element : elements) {
- if (value != ((*element).*getter)()) {
- m_propertiesView->beginUpdate(element);
- ((*element).*setter)(value);
- m_propertiesView->endUpdate(element, false);
- }
- }
- }
-}
-
-template<class T, class V, class BASE>
-void PropertiesView::MView::assignModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
- const V &value, V (T::*getter)() const, void (T::*setter)(V))
-{
- const QList<T *> elements = filter<T>(baseElements);
- if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
- for (T *element : elements) {
- if (value != ((*element).*getter)()) {
- m_propertiesView->beginUpdate(element);
- ((*element).*setter)(value);
- m_propertiesView->endUpdate(element, false);
- }
- }
- }
-}
-
-template<class T, class E, class V, class BASE>
-void PropertiesView::MView::assignEmbeddedModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
- const V &value, E (T::*getter)() const,
- void (T::*setter)(const E &),
- V (E::*vGetter)() const, void (E::*vSetter)(const V &))
-{
- const QList<T *> elements = filter<T>(baseElements);
- if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
- for (T *element : elements) {
- E embedded = ((*element).*getter)();
- if (value != (embedded.*vGetter)()) {
- m_propertiesView->beginUpdate(element);
- (embedded.*vSetter)(value);
- ((*element).*setter)(embedded);
- m_propertiesView->endUpdate(element, false);
- }
- }
- }
-}
-
-template<class T, class E, class V, class BASE>
-void PropertiesView::MView::assignEmbeddedModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
- const V &value, E (T::*getter)() const,
- void (T::*setter)(const E &),
- V (E::*vGetter)() const, void (E::*vSetter)(V))
-{
- const QList<T *> elements = filter<T>(baseElements);
- if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
- for (T *element : elements) {
- E embedded = ((*element).*getter)();
- if (value != (embedded.*vGetter)()) {
- m_propertiesView->beginUpdate(element);
- (embedded.*vSetter)(value);
- ((*element).*setter)(embedded);
- m_propertiesView->endUpdate(element, false);
- }
- }
- }
+ int index = translateRelationVisualPrimaryRoleToIndex(visualPrimaryRole);
+ const Style *style = m_propertiesView->styleController()->adaptRelationStyle(
+ elementType, RelationVisuals(DObject::PrimaryRoleNormal, visualPrimaryRole,
+ DRelation::SecondaryRoleNone, false));
+ m_relationVisualPrimaryRoleSelector->setBrush(index, style->fillBrush());
+ m_relationVisualPrimaryRoleSelector->setLinePen(index, style->linePen());
}
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h
index 4762803a20..8fa9f0d137 100644
--- a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h
@@ -8,6 +8,8 @@
#include "qmt/model/mconstvisitor.h"
#include "qmt/diagram/dconstvisitor.h"
#include "qmt/diagram/dobject.h"
+#include "qmt/diagram/drelation.h"
+#include "qmt/infrastructure/qmtassert.h"
#include "qmt/stereotype/stereotypeicon.h"
#include "qmt/style/styleengine.h"
@@ -76,6 +78,11 @@ public:
void edit();
protected:
+ virtual void visitMElementBehind(const MElement *element);
+ virtual void visitMObjectBehind(const MObject *object);
+ virtual void visitMDiagramBehind(const MDiagram *diagram);
+ virtual void visitDObjectBefore(const DObject *object);
+
void onStereotypesChanged(const QString &stereotypes);
void onObjectNameChanged(const QString &name);
void onNamespaceChanged(const QString &umlNamespace);
@@ -110,6 +117,11 @@ protected:
void onPlainShapeChanged(bool plainShape);
void onItemShapeChanged(const QString &shape);
void onAutoWidthChanged(bool autoWidthed);
+ void onRelationVisualPrimaryRoleChanged(int visualRoleIndex);
+ void onRelationVisualSecondaryRoleChanged(int visualRoleIndex);
+ void onRelationVisualEmphasizedChanged(bool visualEmphasized);
+ void onRelationColorChanged(const QColor &color);
+ void onRelationThicknessChanged(qreal thickness);
void onAnnotationVisualRoleChanged(int visualRoleIndex);
void prepare();
@@ -139,6 +151,9 @@ protected:
QList<QString> splitTemplateParameters(const QString &templateParameters);
QString formatTemplateParameters(const QList<QString> &templateParametersList);
+ void setRelationPrimaryRolePalette(StyleEngine::ElementType elementType,
+ DRelation::VisualPrimaryRole visualPrimaryRole);
+
enum SelectionType {
SelectionSingle,
SelectionMulti
@@ -149,6 +164,9 @@ protected:
template<class T, class V, class BASE>
bool haveSameValue(const QList<BASE *> &baseElements, V (T::*getter)() const, V *value);
template<class T, class V, class BASE>
+ bool isValueChanged(const QList<BASE *> &baseElements, SelectionType selectionType,
+ const V &value, V (T::*getter)() const);
+ template<class T, class V, class BASE>
void assignModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
const V &value, V (T::*getter)() const, void (T::*setter)(const V &));
template<class T, class V, class BASE>
@@ -232,7 +250,132 @@ protected:
QCheckBox *m_annotationAutoWidthCheckbox = nullptr;
QComboBox *m_annotationVisualRoleSelector = nullptr;
// DRelation
+ PaletteBox *m_relationVisualPrimaryRoleSelector = nullptr;
+ QComboBox *m_relationVisualSecondaryRoleSelector = nullptr;
+ QCheckBox *m_relationVisualEmphasizedCheckbox = nullptr;
QLabel *m_pointsLabel = nullptr;
};
+template<class T, class V>
+QList<T *> PropertiesView::MView::filter(const QList<V *> &elements)
+{
+ QList<T *> filtered;
+ for (auto *element : elements) {
+ auto t = dynamic_cast<T *>(element);
+ if (t)
+ filtered.append(t);
+ }
+ return filtered;
+}
+
+template<class T, class V, class BASE>
+inline bool PropertiesView::MView::haveSameValue(const QList<BASE *> &baseElements, V (T::*getter)() const, V *value)
+{
+ QList<T *> elements = filter<T>(baseElements);
+ QMT_CHECK(!elements.isEmpty());
+ V candidate = V(); // avoid warning of reading uninitialized variable
+ bool haveCandidate = false;
+ for (const auto *element : elements) {
+ if (!haveCandidate) {
+ candidate = ((*element).*getter)();
+ haveCandidate = true;
+ } else {
+ if (candidate != ((*element).*getter)())
+ return false;
+ }
+ }
+ QMT_CHECK(haveCandidate);
+ if (!haveCandidate)
+ return false;
+ if (value)
+ *value = candidate;
+ return true;
+}
+
+template<class T, class V, class BASE>
+inline bool PropertiesView::MView::isValueChanged(const QList<BASE *> &baseElements, SelectionType selectionType,
+ const V &value, V (T::*getter)() const)
+{
+ QList<T *> elements = filter<T>(baseElements);
+ if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
+ for (const auto *element : elements) {
+ if (value != ((*element).*getter)())
+ return true;
+ }
+ }
+ return false;
+}
+
+template<class T, class V, class BASE>
+inline void PropertiesView::MView::assignModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
+ const V &value, V (T::*getter)() const, void (T::*setter)(const V &))
+{
+ QList<T *> elements = filter<T>(baseElements);
+ if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
+ for (auto *element : elements) {
+ if (value != ((*element).*getter)()) {
+ m_propertiesView->beginUpdate(element);
+ ((*element).*setter)(value);
+ m_propertiesView->endUpdate(element, false);
+ }
+ }
+ }
+}
+
+template<class T, class V, class BASE>
+inline void PropertiesView::MView::assignModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
+ const V &value, V (T::*getter)() const, void (T::*setter)(V))
+{
+ QList<T *> elements = filter<T>(baseElements);
+ if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
+ for (auto *element : elements) {
+ if (value != ((*element).*getter)()) {
+ m_propertiesView->beginUpdate(element);
+ ((*element).*setter)(value);
+ m_propertiesView->endUpdate(element, false);
+ }
+ }
+ }
+}
+
+template<class T, class E, class V, class BASE>
+inline void PropertiesView::MView::assignEmbeddedModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
+ const V &value, E (T::*getter)() const,
+ void (T::*setter)(const E &),
+ V (E::*vGetter)() const, void (E::*vSetter)(const V &))
+{
+ QList<T *> elements = filter<T>(baseElements);
+ if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
+ for (auto *element : elements) {
+ E embedded = ((*element).*getter)();
+ if (value != (embedded.*vGetter)()) {
+ m_propertiesView->beginUpdate(element);
+ (embedded.*vSetter)(value);
+ ((*element).*setter)(embedded);
+ m_propertiesView->endUpdate(element, false);
+ }
+ }
+ }
+}
+
+template<class T, class E, class V, class BASE>
+inline void PropertiesView::MView::assignEmbeddedModelElement(const QList<BASE *> &baseElements, SelectionType selectionType,
+ const V &value, E (T::*getter)() const,
+ void (T::*setter)(const E &),
+ V (E::*vGetter)() const, void (E::*vSetter)(V))
+{
+ QList<T *> elements = filter<T>(baseElements);
+ if ((selectionType == SelectionSingle && elements.size() == 1) || selectionType == SelectionMulti) {
+ for (auto *element : elements) {
+ E embedded = ((*element).*getter)();
+ if (value != (embedded.*vGetter)()) {
+ m_propertiesView->beginUpdate(element);
+ (embedded.*vSetter)(value);
+ ((*element).*setter)(embedded);
+ m_propertiesView->endUpdate(element, false);
+ }
+ }
+ }
+}
+
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/project/project.cpp b/src/libs/modelinglib/qmt/project/project.cpp
index 098db684ef..2e08adc6df 100644
--- a/src/libs/modelinglib/qmt/project/project.cpp
+++ b/src/libs/modelinglib/qmt/project/project.cpp
@@ -3,6 +3,8 @@
#include "project.h"
+using Utils::FilePath;
+
namespace qmt {
Project::Project()
@@ -23,7 +25,7 @@ bool Project::hasFileName() const
return !m_fileName.isEmpty();
}
-void Project::setFileName(const QString &fileName)
+void Project::setFileName(const FilePath &fileName)
{
m_fileName = fileName;
}
@@ -33,7 +35,7 @@ void Project::setRootPackage(MPackage *rootPackage)
m_rootPackage = rootPackage;
}
-void Project::setConfigPath(const QString &configPath)
+void Project::setConfigPath(const FilePath &configPath)
{
m_configPath = configPath;
}
diff --git a/src/libs/modelinglib/qmt/project/project.h b/src/libs/modelinglib/qmt/project/project.h
index fab6bb4228..556471e9ed 100644
--- a/src/libs/modelinglib/qmt/project/project.h
+++ b/src/libs/modelinglib/qmt/project/project.h
@@ -5,6 +5,8 @@
#include "qmt/infrastructure/uid.h"
+#include <utils/filepath.h>
+
#include <QString>
namespace qmt {
@@ -20,18 +22,18 @@ public:
Uid uid() const { return m_uid; }
void setUid(const Uid &uid);
bool hasFileName() const;
- QString fileName() const { return m_fileName; }
- void setFileName(const QString &fileName);
+ Utils::FilePath fileName() const { return m_fileName; }
+ void setFileName(const Utils::FilePath &fileName);
MPackage *rootPackage() const { return m_rootPackage; }
void setRootPackage(MPackage *rootPackage);
- QString configPath() const { return m_configPath; }
- void setConfigPath(const QString &configPath);
+ Utils::FilePath configPath() const { return m_configPath; }
+ void setConfigPath(const Utils::FilePath &configPath);
private:
Uid m_uid;
- QString m_fileName;
+ Utils::FilePath m_fileName;
MPackage *m_rootPackage = nullptr;
- QString m_configPath;
+ Utils::FilePath m_configPath;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/project_controller/projectcontroller.cpp b/src/libs/modelinglib/qmt/project_controller/projectcontroller.cpp
index f7a7e6d2c9..47eb01138e 100644
--- a/src/libs/modelinglib/qmt/project_controller/projectcontroller.cpp
+++ b/src/libs/modelinglib/qmt/project_controller/projectcontroller.cpp
@@ -10,6 +10,8 @@
#include "../../modelinglibtr.h"
+using Utils::FilePath;
+
namespace qmt {
NoFileNameException::NoFileNameException()
@@ -31,7 +33,7 @@ ProjectController::~ProjectController()
{
}
-void ProjectController::newProject(const QString &fileName)
+void ProjectController::newProject(const FilePath &fileName)
{
m_project.reset(new Project());
auto rootPackage = new MPackage();
@@ -43,7 +45,7 @@ void ProjectController::newProject(const QString &fileName)
emit changed();
}
-void ProjectController::setFileName(const QString &fileName)
+void ProjectController::setFileName(const FilePath &fileName)
{
if (fileName != m_project->fileName()) {
m_project->setFileName(fileName);
@@ -82,7 +84,7 @@ void ProjectController::save()
emit changed();
}
-void ProjectController::saveAs(const QString &fileName)
+void ProjectController::saveAs(const FilePath &fileName)
{
setFileName(fileName);
save();
diff --git a/src/libs/modelinglib/qmt/project_controller/projectcontroller.h b/src/libs/modelinglib/qmt/project_controller/projectcontroller.h
index 1992c72448..09cf65074a 100644
--- a/src/libs/modelinglib/qmt/project_controller/projectcontroller.h
+++ b/src/libs/modelinglib/qmt/project_controller/projectcontroller.h
@@ -6,6 +6,8 @@
#include "qmt/infrastructure/exceptions.h"
#include "qmt/infrastructure/qmt_global.h"
+#include <utils/filepath.h>
+
#include <QObject>
#include <QString>
@@ -35,19 +37,19 @@ public:
signals:
void changed();
- void fileNameChanged(const QString &fileName);
+ void fileNameChanged(const Utils::FilePath &fileName);
public:
Project *project() const { return m_project.data(); }
bool isModified() const { return m_isModified; }
- void newProject(const QString &fileName);
- void setFileName(const QString &fileName);
+ void newProject(const Utils::FilePath &fileName);
+ void setFileName(const Utils::FilePath &fileName);
void setModified();
void load();
void save();
- void saveAs(const QString &fileName);
+ void saveAs(const Utils::FilePath &fileName);
private:
QScopedPointer<Project> m_project;
diff --git a/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp b/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp
index 5170d4fdc7..2d68862c32 100644
--- a/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp
+++ b/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp
@@ -29,10 +29,35 @@
#include "qark/qxmlinarchive.h"
#include "qark/serialize.h"
+#include <QBuffer>
+
using namespace qmt;
namespace qark {
+template<class Archive>
+inline void save(Archive &archive, const QImage &image)
+{
+ QByteArray a;
+ QBuffer buffer(&a);
+ buffer.open(QIODevice::WriteOnly);
+ image.save(&buffer, "PNG");
+ // TODO add write(const QByteArray &)
+ archive.write(QString::fromLatin1(a.toBase64()));
+}
+
+template<class Archive>
+inline void load(Archive &archive, QImage &image)
+{
+ QString s;
+ // TODO add read(QByteArray &)
+ archive.read(&s);
+ QByteArray a = QByteArray::fromBase64(s.toLatin1());
+ QBuffer buffer(&a);
+ buffer.open(QIODevice::ReadOnly);
+ image.load(&buffer, "PNG");
+}
+
// DElement
QARK_REGISTER_TYPE_NAME(DElement, "DElement")
@@ -102,7 +127,10 @@ inline void Access<Archive, DObject>::serialize(Archive &archive, DObject &objec
|| attr("visual-role", object, &visualRole, &setVisualRole)
|| attr("visual-role2", object, &DObject::visualSecondaryRole, &DObject::setVisualSecondaryRole)
|| attr("visual-emphasized", object, &DObject::isVisualEmphasized, &DObject::setVisualEmphasized)
+ || attr("linkedfile", object, &DObject::hasLinkedFile, &DObject::setLinkedFile)
|| attr("stereotype-display", object, &DObject::stereotypeDisplay, &DObject::setStereotypeDisplay)
+ || attr("image-path", object, &DObject::imagePath, &DObject::setImagePath)
+ || attr("image", object, &DObject::image, &DObject::setImage)
// depth is not persistent
|| end;
}
@@ -220,6 +248,9 @@ inline void Access<Archive, DRelation>::serialize(Archive &archive, DRelation &r
|| attr("b", relation, &DRelation::endBUid, &DRelation::setEndBUid)
|| attr("name", relation, &DRelation::name, &DRelation::setName)
|| attr("points", relation, &DRelation::intermediatePoints, &DRelation::setIntermediatePoints)
+ || attr("visualPrimaryRole", relation, &DRelation::visualPrimaryRole, &DRelation::setVisualPrimaryRole)
+ || attr("visualSecondaryRole", relation, &DRelation::visualSecondaryRole, &DRelation::setVisualSecondaryRole)
+ || attr("thickness", relation, &DRelation::thickness, &DRelation::setThickness)
|| end;
}
diff --git a/src/libs/modelinglib/qmt/serializer/diagramserializer.h b/src/libs/modelinglib/qmt/serializer/diagramserializer.h
index a571ff94ef..aa5d1adb52 100644
--- a/src/libs/modelinglib/qmt/serializer/diagramserializer.h
+++ b/src/libs/modelinglib/qmt/serializer/diagramserializer.h
@@ -6,6 +6,7 @@
#include "qmt/diagram/dannotation.h"
#include "qmt/diagram/dobject.h"
#include "qmt/diagram/dclass.h"
+#include "qmt/diagram/drelation.h"
#include "qark/serialize_enum.h"
@@ -16,5 +17,7 @@ QARK_SERIALIZE_ENUM(qmt::DObject::VisualSecondaryRole)
QARK_SERIALIZE_ENUM(qmt::DObject::StereotypeDisplay)
QARK_SERIALIZE_ENUM(qmt::DClass::TemplateDisplay)
QARK_SERIALIZE_ENUM(qmt::DAnnotation::VisualRole)
+QARK_SERIALIZE_ENUM(qmt::DRelation::VisualPrimaryRole)
+QARK_SERIALIZE_ENUM(qmt::DRelation::VisualSecondaryRole)
} // namespace qark
diff --git a/src/libs/modelinglib/qmt/serializer/infrastructureserializer.h b/src/libs/modelinglib/qmt/serializer/infrastructureserializer.h
index e67e5af4eb..59103b3fa9 100644
--- a/src/libs/modelinglib/qmt/serializer/infrastructureserializer.h
+++ b/src/libs/modelinglib/qmt/serializer/infrastructureserializer.h
@@ -3,6 +3,8 @@
#pragma once
+#include <utils/filepath.h>
+
#include "qmt/infrastructure/handle.h"
#include "qmt/infrastructure/handles.h"
#include "qmt/infrastructure/uid.h"
@@ -51,4 +53,20 @@ inline void serialize(Archive &archive, qmt::Handles<T> &handles)
|| end;
}
+// Utils::FilePath
+
+template<class Archive>
+inline void save(Archive &archive, const Utils::FilePath &filePath)
+{
+ archive.write(filePath.toFSPathString());
+}
+
+template<class Archive>
+inline void load(Archive &archive, Utils::FilePath &filePath)
+{
+ QString s;
+ archive.read(&s);
+ filePath = Utils::FilePath::fromUserInput(s);
+}
+
} // namespace qark
diff --git a/src/libs/modelinglib/qmt/serializer/modelserializer.cpp b/src/libs/modelinglib/qmt/serializer/modelserializer.cpp
index 115eba08d0..935a825ab2 100644
--- a/src/libs/modelinglib/qmt/serializer/modelserializer.cpp
+++ b/src/libs/modelinglib/qmt/serializer/modelserializer.cpp
@@ -95,6 +95,7 @@ inline void Access<Archive, MObject>::serialize(Archive &archive, MObject &objec
archive || tag(object)
|| base<MElement>(object)
|| attr("name", object, &MObject::name, &MObject::setName)
+ || attr("linkedfilename", object, &MObject::linkedFileName, &MObject::setLinkedFileName)
|| attr("children", object, &MObject::children, &MObject::setChildren)
|| attr("relations", object, &MObject::relations, &MObject::setRelations)
|| end;
diff --git a/src/libs/modelinglib/qmt/serializer/projectserializer.cpp b/src/libs/modelinglib/qmt/serializer/projectserializer.cpp
index 77f231b358..832d47309b 100644
--- a/src/libs/modelinglib/qmt/serializer/projectserializer.cpp
+++ b/src/libs/modelinglib/qmt/serializer/projectserializer.cpp
@@ -20,6 +20,8 @@
#include <QFile>
+using Utils::FilePath;
+
namespace qark {
using namespace qmt;
@@ -48,11 +50,11 @@ ProjectSerializer::~ProjectSerializer()
{
}
-void ProjectSerializer::save(const QString &fileName, const Project *project)
+void ProjectSerializer::save(const FilePath &fileName, const Project *project)
{
QMT_ASSERT(project, return);
- QFile file(fileName);
+ QFile file(fileName.toFSPathString());
if (!file.open(QIODevice::WriteOnly))
throw FileCreationException(fileName);
@@ -84,11 +86,11 @@ QByteArray ProjectSerializer::save(const Project *project)
return buffer;
}
-void ProjectSerializer::load(const QString &fileName, Project *project)
+void ProjectSerializer::load(const FilePath &fileName, Project *project)
{
QMT_ASSERT(project, return);
- QFile file(fileName);
+ QFile file(fileName.toFSPathString());
if (!file.open(QIODevice::ReadOnly))
throw FileNotFoundException(fileName);
diff --git a/src/libs/modelinglib/qmt/serializer/projectserializer.h b/src/libs/modelinglib/qmt/serializer/projectserializer.h
index c6dd74bcd8..bafa407071 100644
--- a/src/libs/modelinglib/qmt/serializer/projectserializer.h
+++ b/src/libs/modelinglib/qmt/serializer/projectserializer.h
@@ -5,6 +5,8 @@
#include "qmt/infrastructure/qmt_global.h"
+#include <utils/filepath.h>
+
#include <QString>
QT_BEGIN_NAMESPACE
@@ -21,9 +23,9 @@ public:
ProjectSerializer();
~ProjectSerializer();
- void save(const QString &fileName, const Project *project);
+ void save(const Utils::FilePath &fileName, const Project *project);
QByteArray save(const Project *project);
- void load(const QString &fileName, Project *project);
+ void load(const Utils::FilePath &fileName, Project *project);
private:
void write(QXmlStreamWriter *writer, const Project *project);
diff --git a/src/libs/modelinglib/qmt/stereotype/customrelation.cpp b/src/libs/modelinglib/qmt/stereotype/customrelation.cpp
index fa9c80a1a0..cc80da1b80 100644
--- a/src/libs/modelinglib/qmt/stereotype/customrelation.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/customrelation.cpp
@@ -114,4 +114,9 @@ void CustomRelation::setColor(const QColor &color)
m_color = color;
}
+void CustomRelation::setEmphasized(bool emphasized)
+{
+ m_emphasized = emphasized;
+}
+
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/stereotype/customrelation.h b/src/libs/modelinglib/qmt/stereotype/customrelation.h
index 7125865ade..dd32c542c0 100644
--- a/src/libs/modelinglib/qmt/stereotype/customrelation.h
+++ b/src/libs/modelinglib/qmt/stereotype/customrelation.h
@@ -55,7 +55,10 @@ public:
enum class ColorType {
EndA,
EndB,
- Custom
+ Custom,
+ Warning,
+ Error,
+ Soften,
};
class End {
@@ -113,6 +116,8 @@ public:
void setColorType(ColorType colorType);
QColor color() const { return m_color; }
void setColor(const QColor &color);
+ bool emphasized() const { return m_emphasized; }
+ void setEmphasized(bool emphasized);
friend auto qHash(CustomRelation::Relationship relationship) {
return ::qHash(static_cast<int>(relationship));
@@ -139,6 +144,7 @@ private:
ShaftPattern m_shaftPattern = ShaftPattern::Solid;
ColorType m_colorType = ColorType::EndA;
QColor m_color;
+ bool m_emphasized = false;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/stereotype/shapevalue.cpp b/src/libs/modelinglib/qmt/stereotype/shapevalue.cpp
index 9e1ee46c15..cf8ea5ef65 100644
--- a/src/libs/modelinglib/qmt/stereotype/shapevalue.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/shapevalue.cpp
@@ -29,7 +29,7 @@ qreal ShapeValueF::mapScaledTo(qreal scaledOrigin, qreal originalSize, qreal bas
v = originalSize != 0 ? (m_value * actualSize / originalSize) : m_value;
break;
case UnitPercentage:
- v = m_value * actualSize;
+ v = m_value * actualSize / 100.0;
break;
}
switch (m_origin) {
diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp
index 030c9e12a5..2f679df117 100644
--- a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp
@@ -10,6 +10,8 @@
#include "qmt/infrastructure/qmtassert.h"
#include "qmt/style/style.h"
+
+#include <utils/filepath.h>
#include <utils/algorithm.h>
#include <QHash>
@@ -19,12 +21,14 @@
#include <algorithm>
+using Utils::FilePath;
+
namespace qmt {
namespace {
struct IconKey {
- IconKey(StereotypeIcon::Element element, const QList<QString> &stereotypes, const QString &defaultIconPath,
+ IconKey(StereotypeIcon::Element element, const QList<QString> &stereotypes, const FilePath &defaultIconPath,
const Uid &styleUid, const QSize &size, const QMarginsF &margins, qreal lineWidth)
: m_element(element),
m_stereotypes(stereotypes),
@@ -53,7 +57,7 @@ struct IconKey {
const StereotypeIcon::Element m_element;
const QList<QString> m_stereotypes;
- const QString m_defaultIconPath;
+ const FilePath m_defaultIconPath;
const Uid m_styleUid;
const QSize m_size;
const QMarginsF m_margins;
@@ -68,6 +72,7 @@ public:
QHash<QPair<StereotypeIcon::Element, QString>, QString> m_stereotypeToIconIdMap;
QHash<QString, StereotypeIcon> m_iconIdToStereotypeIconsMap;
QHash<QString, CustomRelation> m_relationIdToCustomRelationMap;
+ QHash<QString, CustomRelation> m_stereotypeToCustomRelationMap;
QList<Toolbar> m_toolbars;
QList<Toolbar> m_elementToolbars;
QHash<IconKey, QIcon> m_iconMap;
@@ -150,8 +155,13 @@ CustomRelation StereotypeController::findCustomRelation(const QString &customRel
return d->m_relationIdToCustomRelationMap.value(customRelationId);
}
+CustomRelation StereotypeController::findCustomRelationByStereotype(const QString &steoreotype) const
+{
+ return d->m_stereotypeToCustomRelationMap.value(steoreotype);
+}
+
QIcon StereotypeController::createIcon(StereotypeIcon::Element element, const QList<QString> &stereotypes,
- const QString &defaultIconPath, const Style *style, const QSize &size,
+ const FilePath &defaultIconPath, const Style *style, const QSize &size,
const QMarginsF &margins, qreal lineWidth)
{
IconKey key(element, stereotypes, defaultIconPath, style->uid(), size, margins, lineWidth);
@@ -225,7 +235,7 @@ QIcon StereotypeController::createIcon(StereotypeIcon::Element element, const QL
icon = QIcon(pixmap);
}
if (icon.isNull() && !defaultIconPath.isEmpty())
- icon = QIcon(defaultIconPath);
+ icon = QIcon(defaultIconPath.toFSPathString());
d->m_iconMap.insert(key, icon);
return icon;
@@ -251,6 +261,9 @@ void StereotypeController::addStereotypeIcon(const StereotypeIcon &stereotypeIco
void StereotypeController::addCustomRelation(const CustomRelation &customRelation)
{
d->m_relationIdToCustomRelationMap.insert(customRelation.id(), customRelation);
+ QString stereotype = Utils::toList(customRelation.stereotypes()).value(0);
+ if (!stereotype.isEmpty())
+ d->m_stereotypeToCustomRelationMap.insert(stereotype, customRelation);
}
void StereotypeController::addToolbar(const Toolbar &toolbar)
diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h
index 676f9a275a..49acc5f937 100644
--- a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h
+++ b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.h
@@ -5,6 +5,8 @@
#include "stereotypeicon.h"
+#include <utils/filepath.h>
+
#include <QMarginsF>
#include <QObject>
@@ -33,9 +35,14 @@ public:
const QList<QString> &stereotypes) const;
StereotypeIcon findStereotypeIcon(const QString &stereotypeIconId) const;
CustomRelation findCustomRelation(const QString &customRelationId) const;
- QIcon createIcon(StereotypeIcon::Element element, const QList<QString> &stereotypes,
- const QString &defaultIconPath, const Style *style,
- const QSize &size, const QMarginsF &margins, qreal lineWidth);
+ CustomRelation findCustomRelationByStereotype(const QString &steoreotype) const;
+ QIcon createIcon(StereotypeIcon::Element element,
+ const QList<QString> &stereotypes,
+ const Utils::FilePath &defaultIconPath,
+ const Style *style,
+ const QSize &size,
+ const QMarginsF &margins,
+ qreal lineWidth);
void addStereotypeIcon(const StereotypeIcon &stereotypeIcon);
void addCustomRelation(const CustomRelation &customRelation);
diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp
index 8bcf5df170..19e466c509 100644
--- a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp
@@ -62,6 +62,21 @@ void StereotypeIcon::setMinHeight(qreal minHeight)
m_minHeight = minHeight;
}
+void StereotypeIcon::setIconWith(qreal iconWidth)
+{
+ m_iconWidth = iconWidth;
+}
+
+void StereotypeIcon::setIconHeight(qreal iconHeight)
+{
+ m_iconHeight = iconHeight;
+}
+
+void StereotypeIcon::setDepthLayer(DepthLayer depthLayer)
+{
+ m_depthLayer = depthLayer;
+}
+
void StereotypeIcon::setSizeLock(StereotypeIcon::SizeLock sizeLock)
{
m_sizeLock = sizeLock;
diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h
index be45245da5..fcb5f1a15c 100644
--- a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h
+++ b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h
@@ -31,6 +31,12 @@ public:
DisplaySmart
};
+ enum DepthLayer {
+ DepthBehindItems,
+ DepthAmongItems,
+ DepthBeforeItems,
+ };
+
enum SizeLock {
LockNone,
LockWidth,
@@ -62,12 +68,20 @@ public:
void setWidth(qreal width);
qreal height() const { return m_height; }
void setHeight(qreal height);
- bool hasMinWidth() const { return m_minWidth > 0; }
+ bool hasMinWidth() const { return m_minWidth > 0.0; }
qreal minWidth() const { return m_minWidth; }
void setMinWidth(qreal minWidth);
- bool hasMinHeight() const { return m_minHeight > 0; }
+ bool hasMinHeight() const { return m_minHeight > 0.0; }
qreal minHeight() const { return m_minHeight; }
void setMinHeight(qreal minHeight);
+ bool hasIconWidth() const { return m_iconWidth > 0.0; }
+ qreal iconWidth() const { return m_iconWidth; }
+ void setIconWith(qreal iconWidth);
+ bool hasIconHeight() const { return m_iconHeight > 0.0; }
+ qreal iconHeight() const { return m_iconHeight; }
+ void setIconHeight(qreal iconHeight);
+ DepthLayer depthLayer() const { return m_depthLayer; }
+ void setDepthLayer(DepthLayer depthLayer);
SizeLock sizeLock() const { return m_sizeLock; }
void setSizeLock(SizeLock sizeLock);
Display display() const { return m_display; }
@@ -90,8 +104,11 @@ private:
QString m_name;
qreal m_width = 100.0;
qreal m_height = 100.0;
- qreal m_minWidth = -1;
- qreal m_minHeight = -1;
+ qreal m_minWidth = -1.0;
+ qreal m_minHeight = -1.0;
+ qreal m_iconWidth = -1.0;
+ qreal m_iconHeight = -1.0;
+ DepthLayer m_depthLayer = DepthAmongItems;
SizeLock m_sizeLock = LockNone;
Display m_display = DisplaySmart;
TextAlignment m_textAlignment = TextalignBelow;
diff --git a/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp b/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp
index 74e91837dc..bce1804892 100644
--- a/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp
+++ b/src/libs/modelinglib/qmt/style/defaultstyleengine.cpp
@@ -5,6 +5,7 @@
#include "defaultstyle.h"
#include "objectvisuals.h"
+#include "relationvisuals.h"
#include "styledobject.h"
#include "styledrelation.h"
@@ -14,6 +15,7 @@
#include "qmt/diagram/ditem.h"
#include "qmt/diagram/dannotation.h"
#include "qmt/infrastructure/qmtassert.h"
+#include "qmt/stereotype/customrelation.h"
#include <utils/algorithm.h>
@@ -73,25 +75,29 @@ bool operator==(const ObjectStyleKey &lhs, const ObjectStyleKey &rhs)
class RelationStyleKey
{
public:
- RelationStyleKey(StyleEngine::ElementType elementType = StyleEngine::TypeOther,
- DObject::VisualPrimaryRole visualPrimaryRole = DObject::PrimaryRoleNormal)
+ RelationStyleKey(StyleEngine::ElementType elementType, const RelationVisuals &relationVisuals,
+ bool withObject = false)
: m_elementType(elementType),
- m_visualPrimaryRole(visualPrimaryRole)
+ m_relationVisuals(relationVisuals),
+ m_withObject(withObject)
{
}
StyleEngine::ElementType m_elementType = StyleEngine::TypeOther;
- DObject::VisualPrimaryRole m_visualPrimaryRole = DObject::PrimaryRoleNormal;
+ RelationVisuals m_relationVisuals;
+ bool m_withObject = false;
};
size_t qHash(const RelationStyleKey &styleKey)
{
- return ::qHash(styleKey.m_elementType) ^ ::qHash(styleKey.m_visualPrimaryRole);
+ return ::qHash(styleKey.m_elementType) ^ qHash(styleKey.m_relationVisuals);
}
bool operator==(const RelationStyleKey &lhs, const RelationStyleKey &rhs)
{
- return lhs.m_elementType == rhs.m_elementType && lhs.m_visualPrimaryRole == rhs.m_visualPrimaryRole;
+ return lhs.m_elementType == rhs.m_elementType
+ && lhs.m_relationVisuals == rhs.m_relationVisuals
+ && lhs.m_withObject == rhs.m_withObject;
}
class AnnotationStyleKey
@@ -253,34 +259,6 @@ const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, StyleE
return derivedStyle;
}
-static bool areStackingRoles(DObject::VisualPrimaryRole rhsPrimaryRole,
- DObject::VisualSecondaryRole rhsSecondaryRole,
- DObject::VisualPrimaryRole lhsPrimaryRole,
- DObject::VisualSecondaryRole lhsSecondaryRols)
-{
- switch (rhsSecondaryRole) {
- case DObject::SecondaryRoleNone:
- case DObject::SecondaryRoleLighter:
- case DObject::SecondaryRoleDarker:
- case DObject::SecondaryRoleFlat:
- switch (lhsSecondaryRols) {
- case DObject::SecondaryRoleNone:
- case DObject::SecondaryRoleLighter:
- case DObject::SecondaryRoleDarker:
- case DObject::SecondaryRoleFlat:
- return lhsPrimaryRole == rhsPrimaryRole;
- case DObject::SecondaryRoleSoften:
- case DObject::SecondaryRoleOutline:
- return false;
- }
- break;
- case DObject::SecondaryRoleSoften:
- case DObject::SecondaryRoleOutline:
- return false;
- }
- return true;
-}
-
const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, const StyledObject &styledObject,
const Parameters *parameters)
{
@@ -325,10 +303,12 @@ const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, const
}
int depth = 0;
if (!depths.isEmpty()) {
- for (auto it = depths.cbegin(); it != depths.cend(); ++it) {
- if (it->m_elementType == elementType
- && areStackingRoles(it->m_visualPrimaryRole, it->m_visualSecondaryRole,
- styledVisualPrimaryRole, styledVisualSecondaryRole)) {
+ const QList<int> keys = Utils::sorted(depths.keys());
+ for (int d : keys) {
+ DepthProperties properties = depths.value(d);
+ if (properties.m_elementType == elementType
+ && areStackingRoles(properties.m_visualPrimaryRole, properties.m_visualSecondaryRole,
+ styledVisualPrimaryRole, styledVisualSecondaryRole)) {
++depth;
} else {
depth = 0;
@@ -345,13 +325,100 @@ const Style *DefaultStyleEngine::applyObjectStyle(const Style *baseStyle, const
parameters);
}
+const Style *DefaultStyleEngine::applyRelationStyle(const Style *baseStyle, ElementType elementType, const RelationVisuals &relationVisuals, const Parameters *parameters)
+{
+ Q_UNUSED(parameters);
+
+ RelationStyleKey key(elementType, relationVisuals);
+ const Style *derivedStyle = m_relationStyleMap.value(key);
+ if (!derivedStyle) {
+ auto style = new Style(baseStyle->type());
+ static QColor customColors[] = {
+ QColor(0xEE, 0x8E, 0x99).darker(110), // ROLE_CUSTOM1,
+ QColor(0x80, 0xAF, 0x47).lighter(130), // ROLE_CUSTOM2,
+ QColor(0xFF, 0xA1, 0x5B).lighter(100), // ROLE_CUSTOM3,
+ QColor(0x55, 0xC4, 0xCF).lighter(120), // ROLE_CUSTOM4,
+ QColor(0xFF, 0xE1, 0x4B) // ROLE_CUSTOM5,
+ };
+
+ int index = static_cast<int>(relationVisuals.visualPrimaryRole()) - static_cast<int>(DRelation::PrimaryRoleCustom1);
+ QColor lineColor = index >= 0 && index <= 4 ? customColors[index] : Qt::black;
+ switch (relationVisuals.visualSecondaryRole()) {
+ case DRelation::SecondaryRoleNone:
+ break;
+ case DRelation::SecondaryRoleWarning:
+ lineColor = Qt::yellow;
+ break;
+ case DRelation::SecondaryRoleError:
+ lineColor = Qt::red;
+ break;
+ case DRelation::SecondaryRoleSoften:
+ lineColor = Qt::gray;
+ break;
+ }
+
+ QColor fillColor = lineColor == Qt::black ? Qt::darkGray : lineColor.lighter(150);
+ QPen linePen = baseStyle->linePen();
+ linePen.setWidth(1);
+ linePen.setColor(lineColor);
+ style->setLinePen(linePen);
+ QBrush textBrush = baseStyle->textBrush();
+ textBrush.setColor(Qt::black);
+ style->setTextBrush(textBrush);
+ QBrush brush = baseStyle->fillBrush();
+ brush.setColor(fillColor);
+ brush.setStyle(Qt::SolidPattern);
+ style->setFillBrush(brush);
+ style->setNormalFont(baseStyle->normalFont());
+ style->setSmallFont(baseStyle->smallFont());
+ style->setHeaderFont(baseStyle->headerFont());
+ m_relationStyleMap.insert(key, style);
+ derivedStyle = style;
+ }
+ return derivedStyle;
+}
+
const Style *DefaultStyleEngine::applyRelationStyle(const Style *baseStyle, const StyledRelation &styledRelation,
const Parameters *parameters)
{
Q_UNUSED(parameters)
ElementType elementType = objectType(styledRelation.endA());
- RelationStyleKey key(elementType, styledRelation.endA() ? styledRelation.endA()->visualPrimaryRole() : DObject::PrimaryRoleNormal);
+ RelationVisuals relationVisuals;
+ if (styledRelation.customRelation()) {
+ switch (styledRelation.customRelation()->colorType()) {
+ case CustomRelation::ColorType::EndA:
+ // TODO implement
+ break;
+ case CustomRelation::ColorType::EndB:
+ // TODO implement
+ break;
+ case CustomRelation::ColorType::Custom:
+ // TODO implement
+ break;
+ case CustomRelation::ColorType::Warning:
+ relationVisuals.setVisualSecondaryRole(DRelation::VisualSecondaryRole::SecondaryRoleWarning);
+ break;
+ case CustomRelation::ColorType::Error:
+ relationVisuals.setVisualSecondaryRole(DRelation::VisualSecondaryRole::SecondaryRoleError);
+ break;
+ case CustomRelation::ColorType::Soften:
+ relationVisuals.setVisualSecondaryRole(DRelation::VisualSecondaryRole::SecondaryRoleSoften);
+ break;
+ }
+ relationVisuals.setEmphasized(styledRelation.customRelation()->emphasized());
+ }
+ if (styledRelation.endA())
+ relationVisuals.setVisualObjectPrimaryRole(styledRelation.endA()->visualPrimaryRole());
+ if (styledRelation.relation()) {
+ if (styledRelation.relation()->visualPrimaryRole() != DRelation::VisualPrimaryRole::PrimaryRoleNormal)
+ relationVisuals.setVisualPrimaryRole(styledRelation.relation()->visualPrimaryRole());
+ if (styledRelation.relation()->visualSecondaryRole() != DRelation::VisualSecondaryRole::SecondaryRoleNone)
+ relationVisuals.setVisualSecondaryRole(styledRelation.relation()->visualSecondaryRole());
+ if (styledRelation.relation()->isVisualEmphasized())
+ relationVisuals.setEmphasized(styledRelation.relation()->isVisualEmphasized());
+ }
+ RelationStyleKey key(elementType, relationVisuals, true);
const Style *derivedStyle = m_relationStyleMap.value(key);
if (!derivedStyle) {
auto style = new Style(baseStyle->type());
@@ -365,12 +432,36 @@ const Style *DefaultStyleEngine::applyRelationStyle(const Style *baseStyle, cons
QColor lineColor = DefaultStyleEngine::lineColor(objectType(object), objectVisuals);
QColor fillColor = lineColor;
+ static QColor customColors[] = {
+ QColor(0xEE, 0x8E, 0x99).darker(110), // ROLE_CUSTOM1,
+ QColor(0x80, 0xAF, 0x47).lighter(130), // ROLE_CUSTOM2,
+ QColor(0xFF, 0xA1, 0x5B).lighter(100), // ROLE_CUSTOM3,
+ QColor(0x55, 0xC4, 0xCF).lighter(120), // ROLE_CUSTOM4,
+ QColor(0xFF, 0xE1, 0x4B) // ROLE_CUSTOM5,
+ };
+
+ int index = static_cast<int>(relationVisuals.visualPrimaryRole()) - static_cast<int>(DRelation::PrimaryRoleCustom1);
+ lineColor = (index >= 0 && index <= 4) ? customColors[index] : lineColor;
+ switch (relationVisuals.visualSecondaryRole()) {
+ case DRelation::SecondaryRoleNone:
+ break;
+ case DRelation::SecondaryRoleWarning:
+ lineColor = QColor(0xffc800);
+ break;
+ case DRelation::SecondaryRoleError:
+ lineColor = Qt::red;
+ break;
+ case DRelation::SecondaryRoleSoften:
+ lineColor = Qt::gray;
+ break;
+ }
+
QPen linePen = baseStyle->linePen();
- linePen.setWidth(1);
+ linePen.setWidth(relationVisuals.isEmphasized() ? 3 : 1);
linePen.setColor(lineColor);
style->setLinePen(linePen);
QBrush textBrush = baseStyle->textBrush();
- textBrush.setColor(QColor("black"));
+ textBrush.setColor(Qt::black);
style->setTextBrush(textBrush);
QBrush brush = baseStyle->fillBrush();
brush.setColor(fillColor);
@@ -497,6 +588,34 @@ DefaultStyleEngine::ElementType DefaultStyleEngine::objectType(const DObject *ob
return elementType;
}
+bool DefaultStyleEngine::areStackingRoles(DObject::VisualPrimaryRole rhsPrimaryRole,
+ DObject::VisualSecondaryRole rhsSecondaryRole,
+ DObject::VisualPrimaryRole lhsPrimaryRole,
+ DObject::VisualSecondaryRole lhsSecondaryRols)
+{
+ switch (rhsSecondaryRole) {
+ case DObject::SecondaryRoleNone:
+ case DObject::SecondaryRoleLighter:
+ case DObject::SecondaryRoleDarker:
+ case DObject::SecondaryRoleFlat:
+ switch (lhsSecondaryRols) {
+ case DObject::SecondaryRoleNone:
+ case DObject::SecondaryRoleLighter:
+ case DObject::SecondaryRoleDarker:
+ case DObject::SecondaryRoleFlat:
+ return lhsPrimaryRole == rhsPrimaryRole;
+ case DObject::SecondaryRoleSoften:
+ case DObject::SecondaryRoleOutline:
+ return false;
+ }
+ break;
+ case DObject::SecondaryRoleSoften:
+ case DObject::SecondaryRoleOutline:
+ return false;
+ }
+ return true;
+}
+
QColor DefaultStyleEngine::baseColor(ElementType elementType, ObjectVisuals objectVisuals)
{
if (objectVisuals.visualSecondaryRole() == DObject::SecondaryRoleOutline)
diff --git a/src/libs/modelinglib/qmt/style/defaultstyleengine.h b/src/libs/modelinglib/qmt/style/defaultstyleengine.h
index 67cdf9ed85..b5ebe557e0 100644
--- a/src/libs/modelinglib/qmt/style/defaultstyleengine.h
+++ b/src/libs/modelinglib/qmt/style/defaultstyleengine.h
@@ -37,6 +37,9 @@ public:
const Parameters *parameters) override;
const Style *applyObjectStyle(const Style *baseStyle, const StyledObject &styledObject,
const Parameters *parameters) override;
+ const Style *applyRelationStyle(const Style *baseStyle, ElementType elementType,
+ const RelationVisuals &relationVisuals,
+ const Parameters *parameters) override;
const Style *applyRelationStyle(const Style *baseStyle, const StyledRelation &styledRelation,
const Parameters *parameters) override;
const Style *applyAnnotationStyle(const Style *baseStyle, const DAnnotation *annotation,
@@ -54,6 +57,11 @@ private:
ElementType objectType(const DObject *object);
+ bool areStackingRoles(DObject::VisualPrimaryRole rhsPrimaryRole,
+ DObject::VisualSecondaryRole rhsSecondaryRole,
+ DObject::VisualPrimaryRole lhsPrimaryRole,
+ DObject::VisualSecondaryRole lhsSecondaryRols);
+
QColor baseColor(ElementType elementType, ObjectVisuals objectVisuals);
QColor lineColor(ElementType elementType, const ObjectVisuals &objectVisuals);
QColor fillColor(ElementType elementType, const ObjectVisuals &objectVisuals);
diff --git a/src/libs/modelinglib/qmt/style/relationvisuals.cpp b/src/libs/modelinglib/qmt/style/relationvisuals.cpp
new file mode 100644
index 0000000000..d297047ae1
--- /dev/null
+++ b/src/libs/modelinglib/qmt/style/relationvisuals.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2024 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "relationvisuals.h"
+
+namespace qmt {
+
+RelationVisuals::RelationVisuals() {}
+
+RelationVisuals::RelationVisuals(DObject::VisualPrimaryRole visualObjectPrimaryRole,
+ DRelation::VisualPrimaryRole visualPrimaryRole,
+ DRelation::VisualSecondaryRole visualSecondaryRole,
+ bool emphasized)
+ : m_visualObjectPrimaryRole(visualObjectPrimaryRole)
+ , m_visualPrimaryRole(visualPrimaryRole)
+ , m_visualSecondaryRole(visualSecondaryRole)
+ , m_isEmphasized(emphasized)
+{}
+
+RelationVisuals::~RelationVisuals() {}
+
+void RelationVisuals::setVisualPrimaryRole(DRelation::VisualPrimaryRole VisualPrimaryRole)
+{
+ m_visualPrimaryRole = VisualPrimaryRole;
+}
+
+void RelationVisuals::setVisualObjectPrimaryRole(DObject::VisualPrimaryRole visualPrimaryRole)
+{
+ m_visualObjectPrimaryRole = visualPrimaryRole;
+}
+
+void RelationVisuals::setVisualSecondaryRole(DRelation::VisualSecondaryRole visualSecondaryRole)
+{
+ m_visualSecondaryRole = visualSecondaryRole;
+}
+
+void RelationVisuals::setEmphasized(bool emphasized)
+{
+ m_isEmphasized = emphasized;
+}
+
+bool operator==(const RelationVisuals &lhs, const RelationVisuals &rhs)
+{
+ return lhs.visualObjectPrimaryRole() == rhs.visualObjectPrimaryRole()
+ && lhs.visualPrimaryRole() == rhs.visualPrimaryRole()
+ && lhs.visualSecondaryRole() == rhs.visualSecondaryRole()
+ && lhs.isEmphasized() == rhs.isEmphasized();
+}
+
+size_t qHash(const RelationVisuals &relationVisuals)
+{
+ return ::qHash(static_cast<int>(relationVisuals.visualObjectPrimaryRole()))
+ ^ ::qHash(static_cast<int>(relationVisuals.visualPrimaryRole()))
+ ^ ::qHash(static_cast<int>(relationVisuals.visualSecondaryRole()))
+ ^ ::qHash(relationVisuals.isEmphasized());
+}
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/style/relationvisuals.h b/src/libs/modelinglib/qmt/style/relationvisuals.h
new file mode 100644
index 0000000000..be87a7d291
--- /dev/null
+++ b/src/libs/modelinglib/qmt/style/relationvisuals.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2024 Jochen Becher
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "qmt/diagram/drelation.h"
+#include "qmt/diagram/dobject.h"
+
+#include <QColor>
+
+namespace qmt {
+
+class QMT_EXPORT RelationVisuals
+{
+public:
+ RelationVisuals();
+ RelationVisuals(DObject::VisualPrimaryRole visualObjectPrimaryRole,
+ DRelation::VisualPrimaryRole visualPrimaryRole,
+ DRelation::VisualSecondaryRole visualSecondaryRole,
+ bool emphasized);
+ ~RelationVisuals();
+
+ DObject::VisualPrimaryRole visualObjectPrimaryRole() const { return m_visualObjectPrimaryRole; }
+ void setVisualObjectPrimaryRole(DObject::VisualPrimaryRole visualPrimaryRole);
+ DRelation::VisualPrimaryRole visualPrimaryRole() const { return m_visualPrimaryRole; }
+ void setVisualPrimaryRole(DRelation::VisualPrimaryRole visualPrimaryRole);
+ DRelation::VisualSecondaryRole visualSecondaryRole() const { return m_visualSecondaryRole; }
+ void setVisualSecondaryRole(DRelation::VisualSecondaryRole visualSecondaryRole);
+ bool isEmphasized() const { return m_isEmphasized; }
+ void setEmphasized(bool emphasized);
+
+private:
+ DObject::VisualPrimaryRole m_visualObjectPrimaryRole = DObject::PrimaryRoleNormal;
+ DRelation::VisualPrimaryRole m_visualPrimaryRole = DRelation::PrimaryRoleNormal;
+ DRelation::VisualSecondaryRole m_visualSecondaryRole = DRelation::SecondaryRoleNone;
+ bool m_isEmphasized = false;
+};
+
+bool operator==(const RelationVisuals &lhs, const RelationVisuals &rhs);
+size_t qHash(const RelationVisuals &relationVisuals);
+
+} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/style/stylecontroller.cpp b/src/libs/modelinglib/qmt/style/stylecontroller.cpp
index 5cd50c1738..bbfc28622e 100644
--- a/src/libs/modelinglib/qmt/style/stylecontroller.cpp
+++ b/src/libs/modelinglib/qmt/style/stylecontroller.cpp
@@ -63,6 +63,12 @@ const Style *StyleController::adaptObjectStyle(const StyledObject &object)
return m_defaultStyleEngine->applyObjectStyle(m_defaultStyle.data(), object, &parameters);
}
+const Style *StyleController::adaptRelationStyle(StyleEngine::ElementType elementType, const RelationVisuals &relationVisuals)
+{
+ Parameters parameters(this);
+ return m_defaultStyleEngine->applyRelationStyle(m_defaultStyle.data(), elementType, relationVisuals, &parameters);
+}
+
const Style *StyleController::adaptRelationStyle(const StyledRelation &relation)
{
Parameters parameters(this);
diff --git a/src/libs/modelinglib/qmt/style/stylecontroller.h b/src/libs/modelinglib/qmt/style/stylecontroller.h
index 2627bb2caa..afa566460f 100644
--- a/src/libs/modelinglib/qmt/style/stylecontroller.h
+++ b/src/libs/modelinglib/qmt/style/stylecontroller.h
@@ -4,7 +4,6 @@
#pragma once
#include "styleengine.h"
-#include "qmt/diagram/dobject.h"
#include <QObject>
#include <QScopedPointer>
@@ -14,6 +13,7 @@ namespace qmt {
class Style;
class ObjectVisuals;
class StyledObject;
+class RelationVisuals;
class StyledRelation;
class DAnnotation;
class DBoundary;
@@ -33,6 +33,8 @@ public:
const Style *adaptObjectStyle(StyleEngine::ElementType elementType,
const ObjectVisuals &objectVisuals);
const Style *adaptObjectStyle(const StyledObject &object);
+ const Style *adaptRelationStyle(StyleEngine::ElementType elementType,
+ const RelationVisuals &relationVisuals);
const Style *adaptRelationStyle(const StyledRelation &relation);
const Style *adaptAnnotationStyle(const DAnnotation *annotation);
const Style *adaptBoundaryStyle(const DBoundary *boundary);
diff --git a/src/libs/modelinglib/qmt/style/styledrelation.cpp b/src/libs/modelinglib/qmt/style/styledrelation.cpp
index 3c78abf96d..144e5f22ac 100644
--- a/src/libs/modelinglib/qmt/style/styledrelation.cpp
+++ b/src/libs/modelinglib/qmt/style/styledrelation.cpp
@@ -5,10 +5,12 @@
namespace qmt {
-StyledRelation::StyledRelation(const DRelation *relation, const DObject *endA, const DObject *endB)
+StyledRelation::StyledRelation(const DRelation *relation, const DObject *endA, const DObject *endB,
+ const CustomRelation *customRelation)
: m_relation(relation),
m_endA(endA),
- m_endB(endB)
+ m_endB(endB),
+ m_customRelation(customRelation)
{
}
diff --git a/src/libs/modelinglib/qmt/style/styledrelation.h b/src/libs/modelinglib/qmt/style/styledrelation.h
index 422947908e..27e8735463 100644
--- a/src/libs/modelinglib/qmt/style/styledrelation.h
+++ b/src/libs/modelinglib/qmt/style/styledrelation.h
@@ -9,21 +9,25 @@ namespace qmt {
class DRelation;
class DObject;
+class CustomRelation;
class QMT_EXPORT StyledRelation
{
public:
- StyledRelation(const DRelation *relation, const DObject *endA, const DObject *endB);
+ StyledRelation(const DRelation *relation, const DObject *endA, const DObject *endB,
+ const CustomRelation *customRelation);
~StyledRelation();
const DRelation *relation() const { return m_relation; }
const DObject *endA() const { return m_endA; }
const DObject *endB() const { return m_endB; }
+ const CustomRelation *customRelation() const { return m_customRelation; }
private:
const DRelation *m_relation = nullptr;
const DObject *m_endA = nullptr;
const DObject *m_endB = nullptr;
+ const CustomRelation *m_customRelation = nullptr;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/style/styleengine.h b/src/libs/modelinglib/qmt/style/styleengine.h
index e78f4303d9..463a62a194 100644
--- a/src/libs/modelinglib/qmt/style/styleengine.h
+++ b/src/libs/modelinglib/qmt/style/styleengine.h
@@ -14,6 +14,7 @@ namespace qmt {
class Style;
class ObjectVisuals;
class StyledObject;
+class RelationVisuals;
class StyledRelation;
class DAnnotation;
@@ -51,6 +52,9 @@ public:
const Parameters *parameters) = 0;
virtual const Style *applyObjectStyle(const Style *baseStyle, const StyledObject &,
const Parameters *) = 0;
+ virtual const Style *applyRelationStyle(const Style *baseStyle, ElementType elementType,
+ const RelationVisuals &relationVisuals,
+ const Parameters *) = 0;
virtual const Style *applyRelationStyle(const Style *baseStyle, const StyledRelation &,
const Parameters *) = 0;
virtual const Style *applyAnnotationStyle(const Style *baseStyle, const DAnnotation *,
diff --git a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp
index 00aacf9c82..23f6ddc297 100644
--- a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp
+++ b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp
@@ -42,8 +42,6 @@
#include "../../modelinglibtr.h"
#include <QMenu>
-#include <QFileInfo>
-#include <QDir>
#include <QQueue>
#include <QPair>
@@ -421,7 +419,44 @@ void DiagramSceneController::dropNewModelElement(MObject *modelObject, MPackage
emit newElementCreated(element, diagram);
}
-void DiagramSceneController::addRelatedElements(const DSelection &selection, MDiagram *diagram)
+int DiagramSceneController::countRelatedElements(const DSelection &selection, MDiagram *diagram, std::function<bool (qmt::DObject *, qmt::MObject *, qmt::MRelation *)> filter)
+{
+ int counter = 0;
+ const QList<DSelection::Index> indices = selection.indices();
+ for (const DSelection::Index &index : indices) {
+ DElement *delement = m_diagramController->findElement(index.elementKey(), diagram);
+ QMT_ASSERT(delement, return 0);
+ DObject *dobject = dynamic_cast<DObject *>(delement);
+ if (dobject && dobject->modelUid().isValid()) {
+ MObject *mobject = m_modelController->findElement<MObject>(delement->modelUid());
+ if (mobject) {
+ const QList<MRelation *> relations = m_modelController->findRelationsOfObject(mobject);
+ QList<MRelation *> filteredRelations;
+ const QList<MRelation *> *relationsList = nullptr;
+ if (filter) {
+ for (MRelation *relation : relations) {
+ if (filter(dobject, mobject, relation))
+ filteredRelations.append(relation);
+ }
+ relationsList = &filteredRelations;
+ } else {
+ relationsList = &relations;
+ }
+ for (MRelation *relation : *relationsList) {
+ if (relation->endAUid() != mobject->uid())
+ ++counter;
+ else if (relation->endBUid() != mobject->uid())
+ ++counter;
+ }
+ }
+ }
+ }
+ return counter;
+}
+
+void DiagramSceneController::addRelatedElements(
+ const DSelection &selection, MDiagram *diagram,
+ std::function<bool (qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation)> filter)
{
m_diagramController->undoController()->beginMergeSequence(Tr::tr("Add Related Element"));
const QList<DSelection::Index> indices = selection.indices();
@@ -435,8 +470,19 @@ void DiagramSceneController::addRelatedElements(const DSelection &selection, MDi
qreal dAngle = 360.0 / 11.5;
qreal dRadius = 100.0;
const QList<MRelation *> relations = m_modelController->findRelationsOfObject(mobject);
+ QList<MRelation *> filteredRelations;
+ const QList<MRelation *> *relationsList = nullptr;
+ if (filter) {
+ for (MRelation *relation : relations) {
+ if (filter(dobject, mobject, relation))
+ filteredRelations.append(relation);
+ }
+ relationsList = &filteredRelations;
+ } else {
+ relationsList = &relations;
+ }
int count = 0;
- for (MRelation *relation : relations) {
+ for (MRelation *relation : *relationsList) {
if (relation->endAUid() != mobject->uid() || relation->endBUid() != mobject->uid())
++count;
}
@@ -446,7 +492,7 @@ void DiagramSceneController::addRelatedElements(const DSelection &selection, MDi
}
qreal radius = 200.0;
qreal angle = 0.0;
- for (MRelation *relation : relations) {
+ for (MRelation *relation : *relationsList) {
QPointF pos(dobject->pos());
pos += QPointF(radius * sin(angle / 180 * M_PI), -radius * cos(angle / 180 * M_PI));
bool added = false;
diff --git a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h
index a062fa10c4..14e704a192 100644
--- a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h
+++ b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h
@@ -86,7 +86,12 @@ public:
DElement *topMostElementAtPos, const QPointF &pos, MDiagram *diagram, const QPoint &viewPos, const QSize &viewSize);
void dropNewModelElement(MObject *modelObject, MPackage *parentPackage, const QPointF &pos,
MDiagram *diagram);
- void addRelatedElements(const DSelection &selection, MDiagram *diagram);
+ int countRelatedElements(
+ const DSelection &selection, MDiagram *diagram,
+ std::function<bool (qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation)> filter);
+ void addRelatedElements(
+ const DSelection &selection, MDiagram *diagram,
+ std::function<bool (qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation)> filter);
MPackage *findSuitableParentPackage(DElement *topmostDiagramElement, MDiagram *diagram);
MDiagram *findDiagramBySearchId(MPackage *package, const QString &diagramName);
diff --git a/src/libs/modelinglib/qmt/tasks/ielementtasks.h b/src/libs/modelinglib/qmt/tasks/ielementtasks.h
index a40277d874..8c22632762 100644
--- a/src/libs/modelinglib/qmt/tasks/ielementtasks.h
+++ b/src/libs/modelinglib/qmt/tasks/ielementtasks.h
@@ -59,8 +59,13 @@ public:
virtual void createAndOpenDiagram(const MElement *) = 0;
virtual void createAndOpenDiagram(const DElement *, const MDiagram *) = 0;
+ virtual bool hasLinkedFile(const MElement *) const = 0;
+ virtual bool hasLinkedFile(const DElement *, const MDiagram *) const = 0;
+ virtual void openLinkedFile(const MElement *) = 0;
+ virtual void openLinkedFile(const DElement *, const MDiagram *) = 0;
+
virtual bool extendContextMenu(const DElement *, const MDiagram *, QMenu *) = 0;
- virtual bool handleContextMenuAction(const DElement *, const MDiagram *, const QString &) = 0;
+ virtual bool handleContextMenuAction(DElement *, MDiagram *, const QString &) = 0;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/tasks/voidelementtasks.cpp b/src/libs/modelinglib/qmt/tasks/voidelementtasks.cpp
index 2bd7fbe049..fdc2e24bd4 100644
--- a/src/libs/modelinglib/qmt/tasks/voidelementtasks.cpp
+++ b/src/libs/modelinglib/qmt/tasks/voidelementtasks.cpp
@@ -147,12 +147,30 @@ void VoidElementTasks::createAndOpenDiagram(const DElement *, const MDiagram *)
{
}
+bool VoidElementTasks::hasLinkedFile(const MElement *) const
+{
+ return false;
+}
+
+bool VoidElementTasks::hasLinkedFile(const DElement *, const MDiagram *) const
+{
+ return false;
+}
+
+void VoidElementTasks::openLinkedFile(const MElement *)
+{
+}
+
+void VoidElementTasks::openLinkedFile(const DElement *, const MDiagram *)
+{
+}
+
bool VoidElementTasks::extendContextMenu(const DElement *, const MDiagram *, QMenu *)
{
return false;
}
-bool VoidElementTasks::handleContextMenuAction(const DElement *, const MDiagram *, const QString &)
+bool VoidElementTasks::handleContextMenuAction(DElement *, MDiagram *, const QString &)
{
return false;
}
diff --git a/src/libs/modelinglib/qmt/tasks/voidelementtasks.h b/src/libs/modelinglib/qmt/tasks/voidelementtasks.h
index 3e3d483d9a..9e8753b71e 100644
--- a/src/libs/modelinglib/qmt/tasks/voidelementtasks.h
+++ b/src/libs/modelinglib/qmt/tasks/voidelementtasks.h
@@ -51,8 +51,13 @@ public:
void createAndOpenDiagram(const MElement *) override;
void createAndOpenDiagram(const DElement *, const MDiagram *) override;
+ bool hasLinkedFile(const qmt::MElement *) const override;
+ bool hasLinkedFile(const qmt::DElement *, const qmt::MDiagram *) const override;
+ void openLinkedFile(const qmt::MElement *) override;
+ void openLinkedFile(const qmt::DElement *, const qmt::MDiagram *) override;
+
bool extendContextMenu(const DElement *, const MDiagram *, QMenu *) override;
- bool handleContextMenuAction(const DElement *, const MDiagram *, const QString &) override;
+ bool handleContextMenuAction(DElement *, MDiagram *, const QString &) override;
};
} // namespace qmt