diff --git a/bin/app/data/color_schemes/bad_rainbow.xml b/bin/app/data/color_schemes/bad_rainbow.xml
index 296ce438..f081b76b 100644
--- a/bin/app/data/color_schemes/bad_rainbow.xml
+++ b/bin/app/data/color_schemes/bad_rainbow.xml
@@ -422,6 +422,16 @@
#B1B1B1
+
+
+
+ transparent
+
+
+ #797979
+
+
+
diff --git a/bin/app/data/color_schemes/bright.xml b/bin/app/data/color_schemes/bright.xml
index 6030bf68..7b2599f6 100644
--- a/bin/app/data/color_schemes/bright.xml
+++ b/bin/app/data/color_schemes/bright.xml
@@ -390,6 +390,16 @@
#A2A2A2
+
+
+
+ transparent
+
+
+ #878787
+
+
+
diff --git a/bin/app/data/color_schemes/dark.xml b/bin/app/data/color_schemes/dark.xml
index e39464c7..cd85bc89 100644
--- a/bin/app/data/color_schemes/dark.xml
+++ b/bin/app/data/color_schemes/dark.xml
@@ -393,6 +393,16 @@
#777777
+
+
+
+ transparent
+
+
+ #797979
+
+
+
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index a50a17fd..f57347c3 100644
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -127,6 +127,7 @@ add_files(
data/graph/token_component/TokenComponentAggregation.h
data/graph/token_component/TokenComponentConst.cpp
data/graph/token_component/TokenComponentConst.h
+ data/graph/token_component/TokenComponentEdgeIds.h
data/graph/token_component/TokenComponentFilePath.cpp
data/graph/token_component/TokenComponentFilePath.h
data/graph/token_component/TokenComponentInheritanceChain.h
diff --git a/src/lib/component/controller/CodeController.cpp b/src/lib/component/controller/CodeController.cpp
index ffcae343..6bcb244f 100644
--- a/src/lib/component/controller/CodeController.cpp
+++ b/src/lib/component/controller/CodeController.cpp
@@ -185,7 +185,7 @@ void CodeController::handleMessage(MessageActivateTrailEdge* message)
CodeView::CodeParams params;
params.clearSnippets = true;
params.showContents = !message->isReplayed();
- params.activeTokenIds.push_back(message->tokenId);
+ params.activeTokenIds = message->edgeIds;
m_collection = m_storageAccess->getSourceLocationsForTokenIds(params.activeTokenIds);
showCodeSnippets(getSnippetsForActiveSourceLocations(m_collection.get(), 0), params);
diff --git a/src/lib/component/controller/GraphController.cpp b/src/lib/component/controller/GraphController.cpp
index 244648f9..8ae46d62 100644
--- a/src/lib/component/controller/GraphController.cpp
+++ b/src/lib/component/controller/GraphController.cpp
@@ -17,6 +17,7 @@
#include "component/view/GraphViewStyle.h"
#include "data/access/StorageAccess.h"
#include "data/graph/token_component/TokenComponentAccess.h"
+#include "data/graph/token_component/TokenComponentEdgeIds.h"
#include "data/graph/Graph.h"
#include "data/parser/AccessKind.h"
#include "settings/ApplicationSettings.h"
@@ -185,6 +186,11 @@ void GraphController::handleMessage(MessageActivateTrail* message)
MessageStatus(L"Layouting depth graph", false, true).dispatch();
+ if (message->trailType == Edge::EDGE_INHERITANCE)
+ {
+ groupTrailNodes(NodeType::GROUP_INHERITANCE);
+ }
+
layoutNesting();
layoutTrail(message->horizontalLayout, message->originId);
@@ -198,7 +204,7 @@ void GraphController::handleMessage(MessageActivateTrailEdge* message)
{
TRACE("trail edge activate");
- getView()->activateEdge(message->tokenId, message->isReplayed());
+ getView()->activateEdge(message->edgeIds.back(), message->isReplayed());
}
void GraphController::handleMessage(MessageFlushUpdates* message)
@@ -302,7 +308,7 @@ void GraphController::handleMessage(MessageGraphNodeExpand* message)
}
Id nodeId = message->tokenId;
- DummyNode* dummyNode = getDummyGraphNodeById(nodeId);
+ DummyNode* dummyNode = getDummyGraphNodeById(nodeId).get();
if (dummyNode)
{
dummyNode->expanded = message->expand;
@@ -380,7 +386,7 @@ void GraphController::handleMessage(MessageGraphNodeExpand* message)
void GraphController::handleMessage(MessageGraphNodeHide* message)
{
- DummyNode* node = getDummyGraphNodeById(message->tokenId);
+ DummyNode* node = getDummyGraphNodeById(message->tokenId).get();
DummyEdge* edge = nullptr;
if (node)
{
@@ -400,8 +406,8 @@ void GraphController::handleMessage(MessageGraphNodeHide* message)
edge->hidden = true;
edge->visible = false;
- DummyNode* from = getDummyGraphNodeById(edge->ownerId);
- DummyNode* to = getDummyGraphNodeById(edge->targetId);
+ DummyNode* from = getDummyGraphNodeById(edge->ownerId).get();
+ DummyNode* to = getDummyGraphNodeById(edge->targetId).get();
if (from)
{
@@ -447,7 +453,7 @@ void GraphController::handleMessage(MessageGraphNodeHide* message)
void GraphController::handleMessage(MessageGraphNodeMove* message)
{
- DummyNode* node = getDummyGraphNodeById(message->tokenId);
+ DummyNode* node = getDummyGraphNodeById(message->tokenId).get();
if (node)
{
node->position += message->delta;
@@ -564,9 +570,9 @@ void GraphController::createDummyGraph(const std::shared_ptr graph)
if (qualifier.size())
{
- std::shared_ptr qualifierNode = std::make_shared();
- qualifierNode->visible = true;
+ std::shared_ptr qualifierNode = std::make_shared(DummyNode::DUMMY_QUALIFIER);
qualifierNode->qualifierName = qualifier;
+ qualifierNode->visible = true;
node->subNodes.push_back(qualifierNode);
node->hasQualifier = true;
@@ -610,7 +616,7 @@ std::vector> GraphController::createDummyNodeTopDown(
{
std::vector> nodes;
- std::shared_ptr result = std::make_shared();
+ std::shared_ptr result = std::make_shared(DummyNode::DUMMY_DATA);
result->data = node;
result->name = node->getName();
@@ -655,9 +661,8 @@ std::vector> GraphController::createDummyNodeTopDown(
if (!parent)
{
- std::shared_ptr accessNode = std::make_shared();
+ std::shared_ptr accessNode = std::make_shared(DummyNode::DUMMY_ACCESS);
accessNode->accessKind = accessKind;
- accessNode->isAccess = true;
result->subNodes.push_back(accessNode);
parent = accessNode.get();
}
@@ -688,7 +693,7 @@ void GraphController::setExpandedNodeIds(const std::vector& nodeIds)
{
for (Id id : nodeIds)
{
- DummyNode* node = getDummyGraphNodeById(id);
+ DummyNode* node = getDummyGraphNodeById(id).get();
if (node)
{
node->expanded = true;
@@ -702,7 +707,7 @@ void GraphController::autoExpandActiveNode(const std::vector& activeTokenIds
DummyNode* node = nullptr;
if (activeTokenIds.size() == 1)
{
- node = getDummyGraphNodeById(activeTokenIds[0]);
+ node = getDummyGraphNodeById(activeTokenIds[0]).get();
}
if (node && !node->hasMissingChildNodes())
@@ -740,8 +745,8 @@ bool GraphController::setActive(const std::vector& activeTokenIds, bool show
noActive = false;
}
- DummyNode* from = getDummyGraphNodeById(edge->ownerId);
- DummyNode* to = getDummyGraphNodeById(edge->targetId);
+ DummyNode* from = getDummyGraphNodeById(edge->ownerId).get();
+ DummyNode* to = getDummyGraphNodeById(edge->targetId).get();
bool isInheritance = edge->data->isType(Edge::EDGE_INHERITANCE);
if (from && to && !edge->hidden &&
@@ -877,6 +882,7 @@ void GraphController::hideBuiltinTypes()
if (node->isGraphNode() && !node->active && node->data->getType().isBuiltin())
{
node->visible = false;
+ node->hidden = true;
}
}
}
@@ -1118,7 +1124,7 @@ void GraphController::bundleNodesAndEdgesMatching(
return;
}
- std::shared_ptr bundleNode = std::make_shared();
+ std::shared_ptr bundleNode = std::make_shared(DummyNode::DUMMY_BUNDLE);
bundleNode->name = name;
bundleNode->visible = true;
@@ -1213,7 +1219,7 @@ std::shared_ptr GraphController::bundleNodesMatching(
return nullptr;
}
- std::shared_ptr bundleNode = std::make_shared();
+ std::shared_ptr bundleNode = std::make_shared(DummyNode::DUMMY_BUNDLE);
bundleNode->name = name;
bundleNode->visible = true;
@@ -1345,8 +1351,7 @@ void GraphController::addCharacterIndex()
{
character = toupper(m_dummyNodes[i]->name[0]);
- std::shared_ptr textNode = std::make_shared();
- textNode->textNode = true;
+ std::shared_ptr textNode = std::make_shared(DummyNode::DUMMY_TEXT);
textNode->name = character;
textNode->visible = true;
@@ -1367,6 +1372,168 @@ bool GraphController::hasCharacterIndex() const
return false;
}
+void GraphController::groupTrailNodes(NodeType::GroupType groupType)
+{
+ TRACE();
+
+ struct TrailNode
+ {
+ Id nodeId;
+ std::set targetNodeIds;
+ std::set originNodeIds;
+
+ std::vector targetEdges;
+ std::vector originEdges;
+ };
+
+ std::set possibleNodeIds;
+ for (auto dummyNode : m_dummyNodes)
+ {
+ if (dummyNode->visible && dummyNode->tokenId &&
+ (!dummyNode->subNodes.size() || (dummyNode->subNodes.size() == 1 && dummyNode->subNodes[0]->isQualifierNode())))
+ {
+ possibleNodeIds.insert(dummyNode->tokenId);
+ }
+ }
+
+ std::map nodes;
+
+ for (const std::shared_ptr& edge : m_dummyEdges)
+ {
+ if (edge->visible &&
+ possibleNodeIds.find(edge->ownerId) != possibleNodeIds.end() &&
+ possibleNodeIds.find(edge->targetId) != possibleNodeIds.end())
+ {
+ TrailNode& fromNode = nodes[edge->ownerId];
+ fromNode.nodeId = edge->ownerId;
+ fromNode.targetNodeIds.insert(edge->targetId);
+ fromNode.targetEdges.push_back(edge.get());
+
+ TrailNode& toNode = nodes[edge->targetId];
+ toNode.nodeId = edge->targetId;
+ toNode.originNodeIds.insert(edge->ownerId);
+ toNode.originEdges.push_back(edge.get());
+ }
+ }
+
+ std::set groupedNodeIds;
+ while (nodes.size())
+ {
+ TrailNode node = nodes.begin()->second;
+ nodes.erase(nodes.begin());
+
+ std::vector group;
+ std::map::iterator it = nodes.begin();
+ while (it != nodes.end())
+ {
+ if (node.targetNodeIds.size() <= 1 && it->second.targetNodeIds == node.targetNodeIds &&
+ node.originNodeIds.size() <= 1 && it->second.originNodeIds == node.originNodeIds)
+ {
+ group.push_back(it->second);
+ it = nodes.erase(it);
+ }
+ else
+ {
+ it++;
+ }
+ }
+
+ group.push_back(node);
+ if (group.size() < 3)
+ {
+ continue;
+ }
+
+ std::shared_ptr groupNode = std::make_shared(DummyNode::DUMMY_GROUP);
+ groupNode->visible = true;
+ groupNode->groupType = groupType;
+
+ // Use token Id of first node and make first 2 bits 1
+ groupNode->tokenId = ~(~size_t(0) >> 2) + node.nodeId;
+
+ std::shared_ptr targetEdge = std::make_shared();
+ targetEdge->ownerId = groupNode->tokenId;
+
+ std::shared_ptr originEdge = std::make_shared();
+ originEdge->targetId = groupNode->tokenId;
+
+ std::vector targetEdgeIds;
+ std::vector originEdgeIds;
+
+ for (TrailNode& node : group)
+ {
+ std::shared_ptr dummyNode = getDummyGraphNodeById(node.nodeId);
+ if (!dummyNode)
+ {
+ continue;
+ }
+
+ groupedNodeIds.insert(node.nodeId);
+ groupNode->subNodes.push_back(dummyNode);
+
+ m_topLevelAncestorIds[node.nodeId] = groupNode->tokenId;
+
+ for (DummyEdge* edge : node.targetEdges)
+ {
+ targetEdge->visible = true;
+ targetEdge->targetId = edge->targetId;
+ targetEdge->data = edge->data;
+ edge->visible = false;
+ edge->hidden = true;
+
+ if (edge->data)
+ {
+ targetEdgeIds.push_back(edge->data->getId());
+ }
+ }
+
+ for (DummyEdge* edge : node.originEdges)
+ {
+ originEdge->visible = true;
+ originEdge->ownerId = edge->ownerId;
+ originEdge->data = edge->data;
+ edge->visible = false;
+ edge->hidden = true;
+
+ if (edge->data)
+ {
+ originEdgeIds.push_back(edge->data->getId());
+ }
+ }
+ }
+
+ if (targetEdge->visible)
+ {
+ if (targetEdge->data && targetEdgeIds.size())
+ {
+ const_cast(targetEdge->data)->addComponent(std::make_shared(targetEdgeIds));
+ }
+ m_dummyEdges.push_back(targetEdge);
+ }
+
+ if (originEdge->visible)
+ {
+ if (originEdge->data && originEdgeIds.size())
+ {
+ const_cast(targetEdge->data)->addComponent(std::make_shared(originEdgeIds));
+ }
+ m_dummyEdges.push_back(originEdge);
+ }
+
+ groupNode->sortSubNodesByName();
+ m_dummyNodes.push_back(groupNode);
+ }
+
+ for (int i = 0; i < int(m_dummyNodes.size()); i++)
+ {
+ if (groupedNodeIds.find(m_dummyNodes[i]->tokenId) != groupedNodeIds.end())
+ {
+ m_dummyNodes.erase(m_dummyNodes.begin() + i);
+ i--;
+ }
+ }
+}
+
void GraphController::layoutNesting()
{
TRACE();
@@ -1424,10 +1591,12 @@ void GraphController::layoutNestingRecursive(DummyNode* node) const
{
margins = GraphViewStyle::getMarginsOfTextNode();
}
+ else if (node->isGroupNode())
+ {
+ margins = GraphViewStyle::getMarginsOfGroupNode(node->groupType, node->name.size());
+ }
- int y = 0;
- int x = 0;
- int width = margins.minWidth;
+ int width = 0;
int height = 0;
if (node->isGraphNode())
@@ -1451,9 +1620,7 @@ void GraphController::layoutNestingRecursive(DummyNode* node) const
}
width += margins.iconWidth;
-
- // Horizontal layouting is currently not used, but left in place for experimentation.
- bool layoutHorizontal = false;
+ width = std::max(width, margins.minWidth);
for (const std::shared_ptr& subNode : node->subNodes)
{
@@ -1461,6 +1628,12 @@ void GraphController::layoutNestingRecursive(DummyNode* node) const
{
continue;
}
+ else if (subNode->isQualifierNode())
+ {
+ subNode->position.y = margins.top + margins.charHeight / 2;
+ width += 5;
+ continue;
+ }
layoutNestingRecursive(subNode.get());
@@ -1470,56 +1643,24 @@ void GraphController::layoutNestingRecursive(DummyNode* node) const
}
}
- for (const std::shared_ptr& subNode : node->subNodes)
+ int top = margins.top + margins.charHeight + margins.spacingA;
+ int left = margins.left;
+ Vec2i size;
+ if (node->isGroupNode())
{
- if (!subNode->visible || subNode->isExpandToggleNode())
- {
- continue;
- }
- else if (subNode->isQualifierNode())
- {
- subNode->position.y = margins.top + margins.charHeight / 2;
- width += 5;
- continue;
- }
-
- subNode->position.x = margins.left + x;
- subNode->position.y = margins.top + margins.charHeight + margins.spacingA + y;
-
- if (layoutHorizontal)
- {
- x += subNode->size.x + margins.spacingX;
- if (subNode->size.y > height)
- {
- height = subNode->size.y;
- }
- }
- else
- {
- y += subNode->size.y + margins.spacingY;
- if (subNode->size.x > width)
- {
- width = subNode->size.x;
- }
- }
+ size = ListLayouter::layoutSkewed(
+ &node->subNodes, top, left, margins.spacingX, margins.spacingY, getView()->getViewSize().x() * 1.5);
+ }
+ else
+ {
+ size = ListLayouter::layoutColumn(&node->subNodes, top, left, margins.spacingY);
}
- if (x > 0)
- {
- x -= margins.spacingX;
- }
- if (y > 0)
- {
- y -= margins.spacingY;
- }
-
- if (layoutHorizontal && x > width)
- {
- width = x;
- }
+ width = std::max(size.x(), width);
+ height = size.y();
node->size.x = margins.left + width + margins.right;
- node->size.y = margins.top + margins.charHeight + margins.spacingA + y + height + margins.bottom;
+ node->size.y = margins.top + margins.charHeight + margins.spacingA + height + margins.bottom;
for (const std::shared_ptr& subNode : node->subNodes)
{
@@ -1542,9 +1683,9 @@ void GraphController::layoutNestingRecursive(DummyNode* node) const
void GraphController::addExpandToggleNode(DummyNode* node) const
{
- std::shared_ptr expandNode = std::make_shared();
- expandNode->visible = true;
+ std::shared_ptr expandNode = std::make_shared(DummyNode::DUMMY_EXPAND_TOGGLE);
expandNode->expanded = node->expanded;
+ expandNode->visible = true;
size_t visibleSubNodeCount = 0;
for (size_t i = 0; i < node->subNodes.size(); i++)
@@ -1658,17 +1799,7 @@ void GraphController::layoutList()
{
TRACE();
- std::vector> visibleNodes;
- for (auto node : m_dummyNodes)
- {
- if (node->visible)
- {
- visibleNodes.push_back(node);
- }
- }
-
- ListLayouter layouter(getView()->getViewSize());
- layouter.layoutList(visibleNodes);
+ ListLayouter::layoutMultiColumn(getView()->getViewSize(), &m_dummyNodes);
}
void GraphController::layoutTrail(bool horizontal, bool hasOrigin)
@@ -1719,19 +1850,19 @@ void GraphController::assignBundleIds()
}
}
-DummyNode* GraphController::getDummyGraphNodeById(Id tokenId) const
+std::shared_ptr GraphController::getDummyGraphNodeById(Id tokenId) const
{
std::map>::const_iterator it = m_dummyGraphNodes.find(tokenId);
if (it != m_dummyGraphNodes.end())
{
- return it->second.get();
+ return it->second;
}
for (const std::shared_ptr& node : m_dummyNodes)
{
if (node->tokenId == tokenId)
{
- return node.get();
+ return node;
}
}
diff --git a/src/lib/component/controller/GraphController.h b/src/lib/component/controller/GraphController.h
index c11dd9cd..a0891b0f 100644
--- a/src/lib/component/controller/GraphController.h
+++ b/src/lib/component/controller/GraphController.h
@@ -107,6 +107,8 @@ private:
void addCharacterIndex();
bool hasCharacterIndex() const;
+ void groupTrailNodes(NodeType::GroupType groupType);
+
void layoutNesting();
void layoutNestingRecursive(DummyNode* node) const;
void addExpandToggleNode(DummyNode* node) const;
@@ -118,7 +120,7 @@ private:
void assignBundleIds();
- DummyNode* getDummyGraphNodeById(Id tokenId) const;
+ std::shared_ptr getDummyGraphNodeById(Id tokenId) const;
DummyEdge* getDummyGraphEdgeById(Id tokenId) const;
void buildGraph(MessageBase* message, bool centerActiveNode, bool animatedTransition, bool scrollToTop);
diff --git a/src/lib/component/controller/UndoRedoController.cpp b/src/lib/component/controller/UndoRedoController.cpp
index 15b8d393..4d793706 100644
--- a/src/lib/component/controller/UndoRedoController.cpp
+++ b/src/lib/component/controller/UndoRedoController.cpp
@@ -97,7 +97,7 @@ void UndoRedoController::handleMessage(MessageActivateTrail* message)
void UndoRedoController::handleMessage(MessageActivateTrailEdge* message)
{
if (sameMessageTypeAsLast(message) &&
- static_cast(lastMessage())->tokenId == message->tokenId)
+ static_cast(lastMessage())->edgeIds == message->edgeIds)
{
return;
}
diff --git a/src/lib/component/controller/helper/DummyNode.h b/src/lib/component/controller/helper/DummyNode.h
index 5efa8861..660fe902 100644
--- a/src/lib/component/controller/helper/DummyNode.h
+++ b/src/lib/component/controller/helper/DummyNode.h
@@ -14,6 +14,17 @@
struct DummyNode
{
public:
+ enum Type
+ {
+ DUMMY_DATA,
+ DUMMY_ACCESS,
+ DUMMY_EXPAND_TOGGLE,
+ DUMMY_BUNDLE,
+ DUMMY_QUALIFIER,
+ DUMMY_TEXT,
+ DUMMY_GROUP
+ };
+
struct DummyNodeComp
{
bool operator()(const std::shared_ptr a, const std::shared_ptr b) const
@@ -50,8 +61,9 @@ public:
bool isReferencing;
};
- DummyNode()
- : visible(false)
+ DummyNode(Type type)
+ : type(type)
+ , visible(false)
, hidden(false)
, childVisible(false)
, tokenId(0)
@@ -63,45 +75,49 @@ public:
, hasParent(true)
, hasQualifier(false)
, accessKind(ACCESS_NONE)
- , isAccess(false)
, invisibleSubNodeCount(0)
, bundleId(0)
, layoutBucket(0, 0)
, bundledNodeCount(0)
, bundledNodeType(NodeType::NODE_SYMBOL)
, qualifierName(NAME_DELIMITER_UNKNOWN)
- , textNode(false)
+ , groupType(NodeType::GROUP_FRAMELESS)
{
}
bool isGraphNode() const
{
- return data != nullptr;
+ return type == DUMMY_DATA;
}
bool isAccessNode() const
{
- return isAccess;
+ return type == DUMMY_ACCESS;
}
bool isExpandToggleNode() const
{
- return !isGraphNode() && !isAccessNode() && !isBundleNode() && !isQualifierNode() && !isTextNode();
+ return type == DUMMY_EXPAND_TOGGLE;
}
bool isBundleNode() const
{
- return bundledNodes.size() > 0;
+ return type == DUMMY_BUNDLE;
}
bool isQualifierNode() const
{
- return qualifierName.size();
+ return type == DUMMY_QUALIFIER;
}
bool isTextNode() const
{
- return textNode;
+ return type == DUMMY_TEXT;
+ }
+
+ bool isGroupNode() const
+ {
+ return type == DUMMY_GROUP;
}
bool isExpanded() const
@@ -339,6 +355,18 @@ public:
subNodes.insert(subNodes.end(), accessNodes.begin(), accessNodes.end());
}
+ void sortSubNodesByName()
+ {
+ std::sort(subNodes.begin(), subNodes.end(),
+ [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool
+ {
+ return a->name < b->name;
+ }
+ );
+ }
+
+ Type type;
+
Vec2i position;
Vec2i size;
@@ -363,7 +391,6 @@ public:
// AccessNode
AccessKind accessKind;
- bool isAccess;
// ExpandToggleNode
size_t invisibleSubNodeCount;
@@ -383,8 +410,8 @@ public:
// QualifierNode
NameHierarchy qualifierName;
- // TextNode
- bool textNode;
+ // GroupNode
+ NodeType::GroupType groupType;
};
#endif // DUMMY_NODE_H
diff --git a/src/lib/component/controller/helper/ListLayouter.cpp b/src/lib/component/controller/helper/ListLayouter.cpp
index 20534250..8f1fdc40 100644
--- a/src/lib/component/controller/helper/ListLayouter.cpp
+++ b/src/lib/component/controller/helper/ListLayouter.cpp
@@ -5,12 +5,17 @@
#include "component/controller/helper/DummyNode.h"
#include "component/view/GraphViewStyle.h"
-ListLayouter::ListLayouter(Vec2i viewSize)
- : m_viewSize(viewSize)
+Vec2i ListLayouter::layoutRow(std::vector>* nodes, int top, int left, int gap)
{
+ return layoutSimple(nodes, top, left, gap, 0, true);
}
-void ListLayouter::layoutList(std::vector>& nodes)
+Vec2i ListLayouter::layoutColumn(std::vector>* nodes, int top, int left, int gap)
+{
+ return layoutSimple(nodes, top, left, 0, gap, false);
+}
+
+Vec2i ListLayouter::layoutMultiColumn(Vec2i viewSize, std::vector>* nodes)
{
size_t colsFinal;
std::vector maxWidthsFinal;
@@ -18,14 +23,25 @@ void ListLayouter::layoutList(std::vector>& nodes)
int gapX = GraphViewStyle::s_gridCellSize + 2 * GraphViewStyle::s_gridCellPadding;
int gapY = GraphViewStyle::s_gridCellPadding;
+ std::vector> visibleNodes;
+ for (auto node : *nodes)
+ {
+ if (node->visible)
+ {
+ visibleNodes.push_back(node);
+ }
+ }
+
for (size_t cols = 1; cols <= 10; cols++)
{
std::vector maxWidths = std::vector(cols, 0);
- size_t nodesPerCol = cols == 1 ? nodes.size() : std::ceil((nodes.size() + cols - 1) / double(cols));
+ size_t nodesPerCol =
+ (cols == 1 ? visibleNodes.size() : std::ceil((visibleNodes.size() + cols - 1) / double(cols)));
+
int maxHeight = 0;
int height = -gapY;
- for (size_t i = 0; i < nodes.size(); i++)
+ for (size_t i = 0; i < visibleNodes.size(); i++)
{
size_t j = i / nodesPerCol;
@@ -33,9 +49,9 @@ void ListLayouter::layoutList(std::vector>& nodes)
{
height = -gapY;
}
- height += nodes[i]->size.y() + gapY;
+ height += visibleNodes[i]->size.y() + gapY;
- maxWidths[j] = std::max(nodes[i]->size.x(), maxWidths[j]);
+ maxWidths[j] = std::max(visibleNodes[i]->size.x(), maxWidths[j]);
maxHeight = std::max(height, maxHeight);
}
@@ -45,7 +61,7 @@ void ListLayouter::layoutList(std::vector>& nodes)
width += maxWidths[j] + gapX;
}
- if (width > m_viewSize.x)
+ if (width > viewSize.x)
{
if (!maxWidthsFinal.size())
{
@@ -58,7 +74,7 @@ void ListLayouter::layoutList(std::vector>& nodes)
colsFinal = cols;
maxWidthsFinal = maxWidths;
- if (height < m_viewSize.y)
+ if (height < viewSize.y)
{
break;
}
@@ -66,19 +82,23 @@ void ListLayouter::layoutList(std::vector>& nodes)
int x = 0;
int y = 0;
- size_t nodesPerCol = colsFinal == 1 ? nodes.size() : std::ceil((nodes.size() + colsFinal - 1) / double(colsFinal));
+ int width = 0;
+ int height = 0;
+
+ size_t nodesPerCol =
+ (colsFinal == 1 ? visibleNodes.size() : std::ceil((visibleNodes.size() + colsFinal - 1) / double(colsFinal)));
std::shared_ptr lastTextNode;
- for (size_t i = 0; i < nodes.size(); i++)
+ for (size_t i = 0; i < visibleNodes.size(); i++)
{
size_t j = i / nodesPerCol;
if (j != 0 && j != colsFinal && i % nodesPerCol == 0)
{
- if (lastTextNode)
+ if (lastTextNode && !visibleNodes[i]->isTextNode())
{
std::shared_ptr textNode = std::make_shared(*lastTextNode.get());
- if (nodes[i - 1] == lastTextNode)
+ if (visibleNodes[i - 1] == lastTextNode)
{
lastTextNode->visible = false;
}
@@ -87,7 +107,8 @@ void ListLayouter::layoutList(std::vector>& nodes)
textNode->name += L"..";
}
- nodes.insert(nodes.begin() + i, textNode);
+ visibleNodes.insert(visibleNodes.begin() + i, textNode);
+ nodes->push_back(textNode);
lastTextNode.reset();
i--;
continue;
@@ -97,14 +118,171 @@ void ListLayouter::layoutList(std::vector>& nodes)
x += maxWidthsFinal[j - 1] + gapX;
}
- nodes[i]->position.x = x;
- nodes[i]->position.y = y;
+ visibleNodes[i]->position.x = x;
+ visibleNodes[i]->position.y = y;
- y += nodes[i]->size.y + gapY;
+ y += visibleNodes[i]->size.y + gapY;
+ height = std::max(height, y);
- if (nodes[i]->isTextNode())
+ if (visibleNodes[i]->isTextNode())
{
- lastTextNode = nodes[i];
+ lastTextNode = visibleNodes[i];
}
}
+
+ for (int w : maxWidthsFinal)
+ {
+ width += w + gapX;
+ }
+
+ return Vec2i(width - gapX, height - gapY);
+}
+
+Vec2i ListLayouter::layoutSkewed(
+ std::vector>* nodes, int top, int left, int gapX, int gapY, int maxWidth)
+{
+ std::vector> visibleNodes;
+ std::multiset nodeWidths;
+ for (auto node : *nodes)
+ {
+ if (node->visible)
+ {
+ visibleNodes.push_back(node);
+ nodeWidths.insert(node->size.x());
+ }
+ }
+
+ int nodeWidth = nodeWidths.size() ? *nodeWidths.rbegin() : 0;
+ if (nodeWidths.size() > 1)
+ {
+ nodeWidth = *nodeWidths.rbegin() / 2 + *(++nodeWidths.rbegin()) / 2;
+ }
+
+ int height = 0;
+ int width = 0;
+
+ int nodesPerRowStart = std::max(int(std::floor(maxWidth * 2 / (nodeWidth + gapX))), 3);
+ for (int nodesPerRow = nodesPerRowStart; nodesPerRow >= 3; nodesPerRow--)
+ {
+ height = 0;
+ width = (nodeWidth * nodesPerRow + gapX * (nodesPerRow - 1)) / 2;
+
+ int x = 0;
+ int rowHeight = 0;
+ int nodeCount = 0;
+ bool evenRow = true;
+
+ for (size_t i = 0; i < visibleNodes.size(); i++)
+ {
+ if (nodeCount + 2 > nodesPerRow)
+ {
+ height += rowHeight + gapY;
+ rowHeight = 0;
+
+ evenRow = !evenRow;
+ nodeCount = evenRow ? 0 : 1;
+ x = evenRow ? 0 : ((nodeWidth + gapX) / 2);
+ }
+
+ DummyNode* node = visibleNodes[i].get();
+ node->position.x = left + x + (nodeWidth - node->size.x()) / 2;
+ node->position.y = top + height;
+
+ rowHeight = std::max(rowHeight, node->size.y());
+ x += nodeWidth + gapX;
+
+ nodeCount += 2;
+ }
+
+ height += rowHeight;
+
+ if (height * 3 >= width)
+ {
+ break;
+ }
+ }
+
+ Vec4i rect = boundingRect(visibleNodes);
+ Vec2i offset(left - rect.x(), top - rect.y());
+
+ for (auto node : visibleNodes)
+ {
+ node->position += offset;
+ }
+
+ return Vec2i(rect.z() - rect.x(), rect.w() - rect.y());
+}
+
+Vec4i ListLayouter::boundingRect(const std::vector>& nodes)
+{
+ Vec4i rect;
+
+ for (auto node : nodes)
+ {
+ if (!node->visible)
+ {
+ continue;
+ }
+
+ if (rect.z() - rect.x() == 0)
+ {
+ rect.x = node->position.x();
+ rect.y = node->position.y();
+ rect.z = node->position.x() + node->size.x();
+ rect.w = node->position.y() + node->size.y();
+ }
+ else
+ {
+ rect.x = std::min(rect.x(), node->position.x());
+ rect.y = std::min(rect.y(), node->position.y());
+ rect.z = std::max(rect.z(), node->position.x() + node->size.x());
+ rect.w = std::max(rect.w(), node->position.y() + node->size.y());
+ }
+ }
+
+ return rect;
+}
+
+Vec2i ListLayouter::layoutSimple(
+ std::vector>* nodes, int top, int left, int gapX, int gapY, bool horizontal)
+{
+ int y = 0;
+ int x = 0;
+
+ int width = 0;
+ int height = 0;
+
+ for (const std::shared_ptr& node : *nodes)
+ {
+ if (!node->visible || node->isExpandToggleNode() || node->isQualifierNode())
+ {
+ continue;
+ }
+
+ node->position.x = left + x;
+ node->position.y = top + y;
+
+ if (horizontal)
+ {
+ x += node->size.x + gapX;
+ height = std::max(height, node->size.y());
+ }
+ else
+ {
+ y += node->size.y + gapY;
+ width = std::max(width, node->size.x());
+ }
+ }
+
+ if (x > 0)
+ {
+ width = x - gapX;
+ }
+
+ if (y > 0)
+ {
+ height = y - gapY;
+ }
+
+ return Vec2i(width, height);
}
diff --git a/src/lib/component/controller/helper/ListLayouter.h b/src/lib/component/controller/helper/ListLayouter.h
index b6efc91a..b72a563b 100644
--- a/src/lib/component/controller/helper/ListLayouter.h
+++ b/src/lib/component/controller/helper/ListLayouter.h
@@ -1,19 +1,28 @@
#ifndef LIST_LAYOUTER_H
#define LIST_LAYOUTER_H
+#include
+#include
+
#include "utility/math/Vector2.h"
+#include "utility/math/Vector4.h"
struct DummyNode;
class ListLayouter
{
public:
- ListLayouter(Vec2i viewSize);
+ static Vec2i layoutRow(std::vector>* nodes, int top, int left, int gap);
+ static Vec2i layoutColumn(std::vector>* nodes, int top, int left, int gap);
- void layoutList(std::vector>& nodes);
+ static Vec2i layoutMultiColumn(Vec2i viewSize, std::vector>* nodes);
+ static Vec2i layoutSkewed(
+ std::vector>* nodes, int top, int left, int gapX, int gapY, int maxWidth);
+ static Vec4i boundingRect(const std::vector>& nodes);
private:
- Vec2i m_viewSize;
+ static Vec2i layoutSimple(
+ std::vector>* nodes, int top, int left, int gapX, int gapY, bool horizontal);
};
#endif // LIST_LAYOUTER_H
diff --git a/src/lib/component/view/GraphViewStyle.cpp b/src/lib/component/view/GraphViewStyle.cpp
index a5a23945..16abacbf 100644
--- a/src/lib/component/view/GraphViewStyle.cpp
+++ b/src/lib/component/view/GraphViewStyle.cpp
@@ -186,6 +186,11 @@ size_t GraphViewStyle::getFontSizeOfTextNode()
return s_fontSize + 5;
}
+size_t GraphViewStyle::getFontSizeOfGroupNode()
+{
+ return s_fontSize;
+}
+
std::string GraphViewStyle::getFontNameForDataNode()
{
return s_fontName;
@@ -206,6 +211,11 @@ std::string GraphViewStyle::getFontNameOfTextNode()
return "Fira Sans";
}
+std::string GraphViewStyle::getFontNameOfGroupNode()
+{
+ return s_fontName;
+}
+
GraphViewStyle::NodeMargins GraphViewStyle::getMarginsForDataNode(NodeType::StyleType type, bool hasIcon, bool hasChildren)
{
NodeMargins margins;
@@ -275,16 +285,16 @@ GraphViewStyle::NodeMargins GraphViewStyle::getMarginsOfAccessNode(AccessKind ac
margins.minWidth = 30;
break;
case ACCESS_PUBLIC:
- margins.minWidth = 56;
+ margins.minWidth = 57;
break;
case ACCESS_PROTECTED:
- margins.minWidth = 72;
+ margins.minWidth = 78;
break;
case ACCESS_PRIVATE:
- margins.minWidth = 58;
+ margins.minWidth = 62;
break;
case ACCESS_DEFAULT:
- margins.minWidth = 60;
+ margins.minWidth = 62;
break;
case ACCESS_TEMPLATE_PARAMETER:
case ACCESS_TYPE_PARAMETER:
@@ -321,6 +331,32 @@ GraphViewStyle::NodeMargins GraphViewStyle::getMarginsOfTextNode()
return margins;
}
+GraphViewStyle::NodeMargins GraphViewStyle::getMarginsOfGroupNode(NodeType::GroupType type, bool hasName)
+{
+ NodeMargins margins;
+ margins.spacingX = margins.spacingY = GraphViewStyle::s_gridCellPadding;
+
+ if (type == NodeType::GROUP_FRAMELESS)
+ {
+ return margins;
+ }
+
+ margins.spacingA = (hasName ? 22 : 0);
+
+ margins.left = margins.right = 20;
+ margins.top = (hasName ? 8 : 20);
+ margins.bottom = 20;
+
+ if (hasName)
+ {
+ margins.minWidth = margins.charHeight = getFontSizeOfGroupNode();
+ }
+
+ margins.charWidth = getCharWidth(NodeType::STYLE_BIG_NODE);
+
+ return margins;
+}
+
GraphViewStyle::NodeStyle GraphViewStyle::getStyleForNodeType(
NodeType type, bool defined, bool isActive, bool isFocused, bool hasChildren, bool hasQualifier
){
@@ -519,6 +555,31 @@ GraphViewStyle::NodeStyle GraphViewStyle::getStyleOfTextNode()
return style;
}
+GraphViewStyle::NodeStyle GraphViewStyle::getStyleOfGroupNode(NodeType::GroupType type, bool isFocused)
+{
+ NodeStyle style;
+
+ std::string colorType = "group/";
+ if (type == NodeType::GROUP_INHERITANCE)
+ {
+ colorType += "inheritance";
+ }
+
+ style.color = getNodeColor(colorType, isFocused);
+
+ style.cornerRadius = 15;
+ style.borderWidth = 2;
+
+ style.fontName = getFontNameOfGroupNode();
+ style.fontSize = getFontSizeOfGroupNode();
+ style.fontBold = true;
+
+ style.textOffset.x = 15;
+ style.textOffset.y = 6;
+
+ return style;
+}
+
GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(
Edge::EdgeType type, bool isActive, bool isFocused, bool isTrailEdge)
{
@@ -527,6 +588,11 @@ GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(
style.width = isActive ? 4 : 2;
style.zValue = isActive ? 5 : 2;
+ if (isTrailEdge)
+ {
+ style.zValue = isActive ? 5 : 2;
+ }
+
style.arrowLength = 5;
style.arrowWidth = 8;
@@ -582,6 +648,11 @@ GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(
style.verticalOffset = 0;
style.cornerRadius = 7;
style.zValue = isActive ? 2 : -3;
+
+ if (isTrailEdge)
+ {
+ style.zValue = isActive ? 2 : -20;
+ }
break;
case Edge::EDGE_INCLUDE:
case Edge::EDGE_MACRO_USAGE:
@@ -590,11 +661,6 @@ GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(
break;
}
- if (isTrailEdge)
- {
- style.zValue = isActive ? 5 : 2;
- }
-
return style;
}
diff --git a/src/lib/component/view/GraphViewStyle.h b/src/lib/component/view/GraphViewStyle.h
index 79057ca7..5c8bd7cf 100644
--- a/src/lib/component/view/GraphViewStyle.h
+++ b/src/lib/component/view/GraphViewStyle.h
@@ -104,17 +104,20 @@ public:
static size_t getFontSizeOfCountCircle();
static size_t getFontSizeOfQualifier();
static size_t getFontSizeOfTextNode();
+ static size_t getFontSizeOfGroupNode();
static std::string getFontNameForDataNode();
static std::string getFontNameOfAccessNode();
static std::string getFontNameOfExpandToggleNode();
static std::string getFontNameOfTextNode();
+ static std::string getFontNameOfGroupNode();
static NodeMargins getMarginsForDataNode(NodeType::StyleType type, bool hasIcon, bool hasChildren);
static NodeMargins getMarginsOfAccessNode(AccessKind access);
static NodeMargins getMarginsOfExpandToggleNode();
static NodeMargins getMarginsOfBundleNode();
static NodeMargins getMarginsOfTextNode();
+ static NodeMargins getMarginsOfGroupNode(NodeType::GroupType type, bool hasName);
static NodeStyle getStyleForNodeType(
NodeType type, bool defined, bool isActive, bool isFocused, bool hasChildren, bool hasQualifier);
@@ -124,6 +127,7 @@ public:
static NodeStyle getStyleOfBundleNode(bool isFocused);
static NodeStyle getStyleOfQualifier();
static NodeStyle getStyleOfTextNode();
+ static NodeStyle getStyleOfGroupNode(NodeType::GroupType type, bool isFocused);
static EdgeStyle getStyleForEdgeType(Edge::EdgeType type, bool isActive, bool isFocused, bool isTrailEdge);
@@ -142,8 +146,8 @@ public:
private:
static NodeStyle getStyleForNodeType(
- NodeType::StyleType type, const std::string& underscoredTypeString,
- const FilePath& iconPath, bool defined, bool isActive, bool isFocused,
+ NodeType::StyleType type, const std::string& underscoredTypeString,
+ const FilePath& iconPath, bool defined, bool isActive, bool isFocused,
bool hasChildren, bool hasQualifier);
static float getCharWidth(NodeType::StyleType type);
diff --git a/src/lib/data/NodeType.h b/src/lib/data/NodeType.h
index eae4505b..5e31aa0e 100644
--- a/src/lib/data/NodeType.h
+++ b/src/lib/data/NodeType.h
@@ -51,6 +51,12 @@ public:
STYLE_BIG_NODE = 2
};
+ enum GroupType
+ {
+ GROUP_FRAMELESS,
+ GROUP_INHERITANCE
+ };
+
struct BundleInfo
{
BundleInfo()
diff --git a/src/lib/data/graph/Edge.cpp b/src/lib/data/graph/Edge.cpp
index 3f47979d..61ff760c 100644
--- a/src/lib/data/graph/Edge.cpp
+++ b/src/lib/data/graph/Edge.cpp
@@ -4,7 +4,6 @@
#include "data/graph/Node.h"
#include "data/graph/token_component/TokenComponentAggregation.h"
-#include "data/graph/token_component/TokenComponentInheritanceChain.h"
#include "utility/logging/logging.h"
#include "utility/utilityString.h"
@@ -119,38 +118,6 @@ bool Edge::isEdge() const
return true;
}
-void Edge::addComponentAggregation(std::shared_ptr component)
-{
- if (getComponent())
- {
- LOG_ERROR(L"TokenComponentAggregation has been set before!");
- }
- else if (m_type != EDGE_AGGREGATION)
- {
- LOG_ERROR(L"TokenComponentAggregation can't be set on edge of type: " + getReadableTypeString());
- }
- else
- {
- addComponent(component);
- }
-}
-
-void Edge::addComponentInheritanceChain(std::shared_ptr component)
-{
- if (getComponent())
- {
- LOG_ERROR(L"TokenComponentInheritanceChain has been set before!");
- }
- else if (m_type != EDGE_INHERITANCE)
- {
- LOG_ERROR(L"TokenComponentInheritanceChain can't be set on edge of type: " + getReadableTypeString());
- }
- else
- {
- addComponent(component);
- }
-}
-
std::wstring Edge::getUnderscoredTypeString(EdgeType type)
{
return utility::replace(utility::replace(getReadableTypeString(type), L"-", L"_"), L" ", L"_");
@@ -205,7 +172,8 @@ std::wstring Edge::getReadableTypeString() const
std::wstring Edge::getAsString() const
{
std::wstringstream str;
- str << L"[" << getId() << L"] " << getReadableTypeString() << L": \"" << m_from->getName() << L"\" -> \"" + m_to->getName() << L"\"";
+ str << L"[" << getId() << L"] " << getReadableTypeString();
+ str << L": \"" << m_from->getName() << L"\" -> \"" + m_to->getName() << L"\"";
TokenComponentAggregation* aggregation = getComponent();
if (aggregation)
diff --git a/src/lib/data/graph/Edge.h b/src/lib/data/graph/Edge.h
index fc4eb3f1..11716969 100644
--- a/src/lib/data/graph/Edge.h
+++ b/src/lib/data/graph/Edge.h
@@ -7,8 +7,6 @@
#include "data/graph/Token.h"
class Node;
-class TokenComponentAggregation;
-class TokenComponentInheritanceChain;
class Edge
: public Token
@@ -54,10 +52,6 @@ public:
virtual bool isNode() const override;
virtual bool isEdge() const override;
- // Component setters
- void addComponentAggregation(std::shared_ptr component);
- void addComponentInheritanceChain(std::shared_ptr component);
-
static std::wstring getUnderscoredTypeString(EdgeType type);
static std::wstring getReadableTypeString(EdgeType type);
// Logging.
diff --git a/src/lib/data/graph/Node.cpp b/src/lib/data/graph/Node.cpp
index 0e19d3db..60d6bc5d 100644
--- a/src/lib/data/graph/Node.cpp
+++ b/src/lib/data/graph/Node.cpp
@@ -5,11 +5,9 @@
#include "utility/logging/logging.h"
#include "utility/utilityString.h"
-#include "data/graph/token_component/TokenComponentAbstraction.h"
#include "data/graph/token_component/TokenComponentAccess.h"
#include "data/graph/token_component/TokenComponentConst.h"
#include "data/graph/token_component/TokenComponentStatic.h"
-#include "data/graph/token_component/TokenComponentFilePath.h"
Node::Node(Id id, NodeType type, const NameHierarchy& nameHierarchy, bool defined)
: Token(id)
@@ -47,7 +45,8 @@ void Node::setType(NodeType type)
if (!isType(type.getType() | NodeType::NODE_SYMBOL))
{
LOG_WARNING(
- L"Cannot change NodeType after it was already set from " + getReadableTypeString() + L" to " + type.getReadableTypeWString()
+ L"Cannot change NodeType after it was already set from " + getReadableTypeString() +
+ L" to " + type.getReadableTypeWString()
);
return;
}
@@ -288,71 +287,6 @@ bool Node::isEdge() const
return false;
}
-void Node::addComponentAbstraction(std::shared_ptr component)
-{
- if (getComponent())
- {
- // LOG_ERROR("TokenComponentAbstraction has been set before!");
- return;
- }
- else
- {
- addComponent(component);
- }
-}
-
-void Node::addComponentConst(std::shared_ptr component)
-{
- if (getComponent())
- {
- // LOG_ERROR("TokenComponentConst has been set before!");
- return;
- }
- else
- {
- addComponent(component);
- }
-}
-
-void Node::addComponentStatic(std::shared_ptr component)
-{
- if (getComponent())
- {
- // LOG_ERROR("TokenComponentStatic has been set before!");
- return;
- }
- else
- {
- addComponent(component);
- }
-}
-
-void Node::addComponentFilePath(std::shared_ptr component)
-{
- if (getComponent())
- {
- // LOG_ERROR("TokenComponentFilePath has been set before!");
- return;
- }
- else
- {
- addComponent(component);
- }
-}
-
-void Node::addComponentAccess(std::shared_ptr component)
-{
- if (getComponent())
- {
- LOG_WARNING("TokenComponentAccess has been set before!");
- return;
- }
- else
- {
- addComponent(component);
- }
-}
-
std::wstring Node::getReadableTypeString() const
{
return m_type.getReadableTypeWString();
diff --git a/src/lib/data/graph/Node.h b/src/lib/data/graph/Node.h
index f19ea9c7..792e0c78 100644
--- a/src/lib/data/graph/Node.h
+++ b/src/lib/data/graph/Node.h
@@ -11,13 +11,6 @@
#include "data/name/NameHierarchy.h"
#include "data/NodeType.h"
-class TokenComponentAbstraction;
-class TokenComponentAccess;
-class TokenComponentConst;
-class TokenComponentStatic;
-class TokenComponentFilePath;
-class TokenComponentSignature;
-
class Node
: public Token
{
@@ -69,13 +62,6 @@ public:
virtual bool isNode() const override;
virtual bool isEdge() const override;
- // Component setters.
- void addComponentAbstraction(std::shared_ptr component);
- void addComponentConst(std::shared_ptr component);
- void addComponentStatic(std::shared_ptr component);
- void addComponentFilePath(std::shared_ptr component);
- void addComponentAccess(std::shared_ptr component);
-
// Logging.
virtual std::wstring getReadableTypeString() const override;
std::wstring getAsString() const;
diff --git a/src/lib/data/graph/Token.cpp b/src/lib/data/graph/Token.cpp
index c3eda8ba..e4ba7378 100644
--- a/src/lib/data/graph/Token.cpp
+++ b/src/lib/data/graph/Token.cpp
@@ -40,6 +40,11 @@ void Token::removeLocationId(Id locationId)
LOG_ERROR("Location Id was not referenced by this Token.");
}
+void Token::addComponent(std::shared_ptr component)
+{
+ m_components.push_back(component);
+}
+
Token::Token(const Token& other)
: m_id(other.m_id)
{
@@ -48,8 +53,3 @@ Token::Token(const Token& other)
addComponent(component->copy());
}
}
-
-void Token::addComponent(std::shared_ptr component)
-{
- m_components.push_back(component);
-}
diff --git a/src/lib/data/graph/Token.h b/src/lib/data/graph/Token.h
index c9b42d22..f5464a40 100644
--- a/src/lib/data/graph/Token.h
+++ b/src/lib/data/graph/Token.h
@@ -23,6 +23,8 @@ public:
void addLocationId(Id locationId);
void removeLocationId(Id locationId);
+ void addComponent(std::shared_ptr component);
+
template
ComponentType* getComponent() const;
@@ -35,7 +37,6 @@ public:
protected:
Token(const Token& other);
- void addComponent(std::shared_ptr component);
void copyComponentsFrom(const Token& other);
private:
diff --git a/src/lib/data/graph/token_component/TokenComponentEdgeIds.h b/src/lib/data/graph/token_component/TokenComponentEdgeIds.h
new file mode 100644
index 00000000..79388261
--- /dev/null
+++ b/src/lib/data/graph/token_component/TokenComponentEdgeIds.h
@@ -0,0 +1,23 @@
+#ifndef TOKEN_COMPONENT_EDGE_IDS_H
+#define TOKEN_COMPONENT_EDGE_IDS_H
+
+#include "data/graph/token_component/TokenComponent.h"
+
+class TokenComponentEdgeIds
+ : public TokenComponent
+{
+public:
+ TokenComponentEdgeIds(const std::vector& edgeIds)
+ : edgeIds(edgeIds)
+ {
+ }
+
+ virtual std::shared_ptr copy() const
+ {
+ return std::make_shared(*this);
+ }
+
+ const std::vector edgeIds;
+};
+
+#endif // TOKEN_COMPONENT_EDGE_IDS_H
diff --git a/src/lib/data/storage/PersistentStorage.cpp b/src/lib/data/storage/PersistentStorage.cpp
index ddce502f..b6608519 100644
--- a/src/lib/data/storage/PersistentStorage.cpp
+++ b/src/lib/data/storage/PersistentStorage.cpp
@@ -2254,7 +2254,7 @@ void PersistentStorage::addNodesToGraph(const std::vector& newNodeIds, Graph
NameHierarchy(filePath.fileName(), NAME_DELIMITER_FILE),
defined
);
- node->addComponentFilePath(std::make_shared(filePath));
+ node->addComponent(std::make_shared(filePath));
node->setExplicit(defined);
}
else
@@ -2465,7 +2465,7 @@ void PersistentStorage::addAggregationEdgesToGraph(
const Id aggregationId = ~(~Id(0) >> 1) + *componentAggregation->getAggregationIds().begin();
Edge* edge = graph->createEdge(aggregationId, Edge::EDGE_AGGREGATION, sourceNode, targetNode);
- edge->addComponentAggregation(componentAggregation);
+ edge->addComponent(componentAggregation);
}
}
@@ -2486,7 +2486,7 @@ void PersistentStorage::addComponentAccessToGraph(Graph* graph) const
{
if (access.nodeId != 0)
{
- graph->getNodeById(access.nodeId)->addComponentAccess(
+ graph->getNodeById(access.nodeId)->addComponent(
std::make_shared(intToAccessKind(access.type)));
}
}
@@ -2564,7 +2564,7 @@ void PersistentStorage::addInheritanceChainsToGraph(const std::vector& activ
Edge* inheritanceEdge = graph->createEdge(
inheritanceEdgeId, Edge::EDGE_INHERITANCE, graph->getNodeById(sourceId), graph->getNodeById(targetId));
- inheritanceEdge->addComponentInheritanceChain(std::make_shared(edgeIds));
+ inheritanceEdge->addComponent(std::make_shared(edgeIds));
}
}
}
diff --git a/src/lib/utility/messaging/type/MessageActivateTrailEdge.h b/src/lib/utility/messaging/type/MessageActivateTrailEdge.h
index e9d5097c..e0f53fbb 100644
--- a/src/lib/utility/messaging/type/MessageActivateTrailEdge.h
+++ b/src/lib/utility/messaging/type/MessageActivateTrailEdge.h
@@ -13,9 +13,10 @@ class MessageActivateTrailEdge
{
public:
MessageActivateTrailEdge(
- Id tokenId, Edge::EdgeType type, const NameHierarchy& sourceNameHierarchy, const NameHierarchy& targetNameHierarchy
+ const std::vector& edgeIds, Edge::EdgeType type,
+ const NameHierarchy& sourceNameHierarchy, const NameHierarchy& targetNameHierarchy
)
- : tokenId(tokenId)
+ : edgeIds(edgeIds)
, type(type)
, sourceNameHierarchy(sourceNameHierarchy)
, targetNameHierarchy(targetNameHierarchy)
@@ -37,10 +38,14 @@ public:
virtual void print(std::wostream& os) const
{
- os << tokenId << L" - " << getFullName();
+ for (Id edgeId : edgeIds)
+ {
+ os << edgeId << L",";
+ }
+ os << L" - " << getFullName();
}
- const Id tokenId;
+ const std::vector edgeIds;
const Edge::EdgeType type;
const NameHierarchy sourceNameHierarchy;
const NameHierarchy targetNameHierarchy;
diff --git a/src/lib/utility/messaging/type/MessageTooltipHide.h b/src/lib/utility/messaging/type/MessageTooltipHide.h
index 7a16b4d6..ae14002b 100644
--- a/src/lib/utility/messaging/type/MessageTooltipHide.h
+++ b/src/lib/utility/messaging/type/MessageTooltipHide.h
@@ -10,6 +10,7 @@ public:
MessageTooltipHide()
{
setSendAsTask(false);
+ setIsLogged(false);
}
static const std::string getStaticType()
diff --git a/src/lib_gui/CMakeLists.txt b/src/lib_gui/CMakeLists.txt
index bc6538fe..60f78ffc 100644
--- a/src/lib_gui/CMakeLists.txt
+++ b/src/lib_gui/CMakeLists.txt
@@ -127,6 +127,8 @@ add_files(
qt/view/graphElements/QtGraphNodeData.h
qt/view/graphElements/QtGraphNodeExpandToggle.cpp
qt/view/graphElements/QtGraphNodeExpandToggle.h
+ qt/view/graphElements/QtGraphNodeGroup.cpp
+ qt/view/graphElements/QtGraphNodeGroup.h
qt/view/graphElements/QtGraphNodeQualifier.cpp
qt/view/graphElements/QtGraphNodeQualifier.h
qt/view/graphElements/QtGraphNodeText.cpp
diff --git a/src/lib_gui/qt/view/QtGraphView.cpp b/src/lib_gui/qt/view/QtGraphView.cpp
index 14ab5cad..50c54e57 100644
--- a/src/lib_gui/qt/view/QtGraphView.cpp
+++ b/src/lib_gui/qt/view/QtGraphView.cpp
@@ -33,6 +33,7 @@
#include "qt/view/graphElements/QtGraphNodeBundle.h"
#include "qt/view/graphElements/QtGraphNodeData.h"
#include "qt/view/graphElements/QtGraphNodeExpandToggle.h"
+#include "qt/view/graphElements/QtGraphNodeGroup.h"
#include "qt/view/graphElements/QtGraphNodeQualifier.h"
#include "qt/view/graphElements/QtGraphNodeText.h"
#include "settings/ApplicationSettings.h"
@@ -890,6 +891,10 @@ QtGraphNode* QtGraphView::createNodeRecursive(
{
newNode = new QtGraphNodeText(node->name);
}
+ else if (node->isGroupNode())
+ {
+ newNode = new QtGraphNodeGroup(node->tokenId, node->name, node->groupType);
+ }
else
{
LOG_ERROR("DummyNode is not valid");
@@ -1083,7 +1088,8 @@ void QtGraphView::compareNodesRecursive(
dynamic_cast(*it2)->getAccessKind()) ||
((*it)->isExpandToggleNode() && (*it2)->isExpandToggleNode()) ||
((*it)->isBundleNode() && (*it2)->isBundleNode() && (*it)->getTokenId() == (*it2)->getTokenId()) ||
- ((*it)->isQualifierNode() && (*it2)->isQualifierNode() && (*it)->getTokenId() == (*it2)->getTokenId()))
+ ((*it)->isQualifierNode() && (*it2)->isQualifierNode() && (*it)->getTokenId() == (*it2)->getTokenId()) ||
+ ((*it)->isGroupNode() && (*it2)->isGroupNode() && (*it)->getName() == (*it2)->getName()))
{
remainingNodes->push_back(std::pair(*it, *it2));
compareNodesRecursive(
diff --git a/src/lib_gui/qt/view/graphElements/QtGraphEdge.cpp b/src/lib_gui/qt/view/graphElements/QtGraphEdge.cpp
index fbabbeab..83dbacc0 100644
--- a/src/lib_gui/qt/view/graphElements/QtGraphEdge.cpp
+++ b/src/lib_gui/qt/view/graphElements/QtGraphEdge.cpp
@@ -6,6 +6,7 @@
#include "component/view/GraphViewStyle.h"
#include "data/graph/Edge.h"
#include "data/graph/token_component/TokenComponentAggregation.h"
+#include "data/graph/token_component/TokenComponentEdgeIds.h"
#include "data/graph/token_component/TokenComponentInheritanceChain.h"
#include "qt/graphics/QtLineItemAngled.h"
#include "qt/graphics/QtLineItemBezier.h"
@@ -251,8 +252,11 @@ void QtGraphEdge::onClick()
{
if (isTrailEdge())
{
+ TokenComponentEdgeIds* componentEdgeIds = getData()->getComponent();
+ std::vector ids = { getData()->getId() };
+
MessageActivateTrailEdge(
- getData()->getId(),
+ componentEdgeIds ? componentEdgeIds->edgeIds : ids,
getData()->getType(),
getData()->getFrom()->getNameHierarchy(),
getData()->getTo()->getNameHierarchy()
diff --git a/src/lib_gui/qt/view/graphElements/QtGraphNode.cpp b/src/lib_gui/qt/view/graphElements/QtGraphNode.cpp
index 9e93af6a..59bb187f 100644
--- a/src/lib_gui/qt/view/graphElements/QtGraphNode.cpp
+++ b/src/lib_gui/qt/view/graphElements/QtGraphNode.cpp
@@ -330,6 +330,11 @@ bool QtGraphNode::isTextNode() const
return false;
}
+bool QtGraphNode::isGroupNode() const
+{
+ return false;
+}
+
Id QtGraphNode::getTokenId() const
{
return 0;
diff --git a/src/lib_gui/qt/view/graphElements/QtGraphNode.h b/src/lib_gui/qt/view/graphElements/QtGraphNode.h
index 9807834d..e43934ab 100644
--- a/src/lib_gui/qt/view/graphElements/QtGraphNode.h
+++ b/src/lib_gui/qt/view/graphElements/QtGraphNode.h
@@ -87,6 +87,7 @@ public:
virtual bool isBundleNode() const;
virtual bool isQualifierNode() const;
virtual bool isTextNode() const;
+ virtual bool isGroupNode() const;
virtual Id getTokenId() const;
diff --git a/src/lib_gui/qt/view/graphElements/QtGraphNodeGroup.cpp b/src/lib_gui/qt/view/graphElements/QtGraphNodeGroup.cpp
new file mode 100644
index 00000000..b89e68d8
--- /dev/null
+++ b/src/lib_gui/qt/view/graphElements/QtGraphNodeGroup.cpp
@@ -0,0 +1,80 @@
+#include "qt/view/graphElements/QtGraphNodeGroup.h"
+
+#include
+#include
+#include
+
+#include "qt/graphics/QtRoundedRectItem.h"
+
+QtGraphNodeGroup::QtGraphNodeGroup(Id tokenId, const std::wstring& name, NodeType::GroupType type)
+ : m_tokenId(tokenId)
+ , m_type(type)
+{
+ setName(name);
+ setZValue(-10.0f);
+ m_rect->setZValue(-10.0f);
+
+ if (type == NodeType::GROUP_FRAMELESS)
+ {
+ m_rect->hide();
+ return;
+ }
+
+ if (!name.size())
+ {
+ return;
+ }
+
+ m_background = new QtRoundedRectItem(this);
+ m_backgroundTopRight = new QGraphicsRectItem(this);
+ m_backgroundBottomLeft = new QGraphicsRectItem(this);
+
+ m_background->setZValue(-10.0f);
+ m_backgroundTopRight->setZValue(-10.0f);
+ m_backgroundBottomLeft->setZValue(-10.0f);
+
+ GraphViewStyle::NodeStyle style = GraphViewStyle::getStyleOfGroupNode(type, false);
+ GraphViewStyle::NodeMargins margins = GraphViewStyle::getMarginsOfGroupNode(type, true);
+
+ int width = style.textOffset.x * 2 + style.borderWidth + margins.charWidth * name.size();
+ int height = margins.top * 2 + margins.charHeight;
+
+ m_background->setRadius(style.cornerRadius);
+ m_background->setRect(0, 0, width, height);
+
+ m_backgroundTopRight->setRect(width - style.cornerRadius, 0, style.cornerRadius, style.cornerRadius);
+ m_backgroundBottomLeft->setRect(0, height - style.cornerRadius, style.cornerRadius, style.cornerRadius);
+}
+
+QtGraphNodeGroup::~QtGraphNodeGroup()
+{
+}
+
+bool QtGraphNodeGroup::isGroupNode() const
+{
+ return true;
+}
+
+Id QtGraphNodeGroup::getTokenId() const
+{
+ return m_tokenId;
+}
+
+void QtGraphNodeGroup::updateStyle()
+{
+ GraphViewStyle::NodeStyle style = GraphViewStyle::getStyleOfGroupNode(m_type, false);
+
+ if (m_background)
+ {
+ m_background->setBrush(QColor(style.color.border.c_str()));
+ m_background->setPen(QPen(Qt::transparent));
+
+ m_backgroundTopRight->setBrush(QColor(style.color.border.c_str()));
+ m_backgroundTopRight->setPen(QPen(Qt::transparent));
+
+ m_backgroundBottomLeft->setBrush(QColor(style.color.border.c_str()));
+ m_backgroundBottomLeft->setPen(QPen(Qt::transparent));
+ }
+
+ setStyle(style);
+}
diff --git a/src/lib_gui/qt/view/graphElements/QtGraphNodeGroup.h b/src/lib_gui/qt/view/graphElements/QtGraphNodeGroup.h
new file mode 100644
index 00000000..b0765a04
--- /dev/null
+++ b/src/lib_gui/qt/view/graphElements/QtGraphNodeGroup.h
@@ -0,0 +1,33 @@
+#ifndef QT_GRAPH_NODE_GROUP_H
+#define QT_GRAPH_NODE_GROUP_H
+
+#include "data/NodeType.h"
+#include "qt/view/graphElements/QtGraphNode.h"
+
+class QGraphicsRectItem;
+class QtRoundedRectItem;
+
+class QtGraphNodeGroup
+ : public QtGraphNode
+{
+ Q_OBJECT
+public:
+ QtGraphNodeGroup(Id tokenId, const std::wstring& name, NodeType::GroupType type);
+ virtual ~QtGraphNodeGroup();
+
+ // QtGraphNode implementation
+ virtual bool isGroupNode() const;
+ virtual Id getTokenId() const;
+
+ virtual void updateStyle();
+
+private:
+ Id m_tokenId;
+ NodeType::GroupType m_type;
+
+ QtRoundedRectItem* m_background = nullptr;
+ QGraphicsRectItem* m_backgroundTopRight = nullptr;
+ QGraphicsRectItem* m_backgroundBottomLeft = nullptr;
+};
+
+#endif // QT_GRAPH_NODE_GROUP_H