logic: Group nodes in inheritance graph who have the same base and derived nodes (issue #459)

* added graph node for grouping nodes with separate sub-layout
* group nodes show name in top left corner
* clicking on single edge activates source locations of all edges
* removed separate setters for token components
* fixed text nodes missing or too many in list layout
* moved simple row and column layouts to ListLayouter
* added skewed layout type to ListLayouter

fortune cookie message = Sometimes you should have the courage and risk something.
This commit is contained in:
Eberhard Graether
2018-03-26 23:57:05 +02:00
parent f93638bcd1
commit bbd003f047
31 changed files with 770 additions and 273 deletions
@@ -422,6 +422,16 @@
<normal>#B1B1B1</normal>
</text>
</text>
<group>
<inheritance>
<fill>
<normal>transparent</normal>
</fill>
<border>
<normal>#797979</normal>
</border>
</inheritance>
</group>
</node>
<edge>
<default>
+10
View File
@@ -390,6 +390,16 @@
<normal>#A2A2A2</normal>
</text>
</text>
<group>
<inheritance>
<fill>
<normal>transparent</normal>
</fill>
<border>
<normal>#878787</normal>
</border>
</inheritance>
</group>
</node>
<edge>
<default>
+10
View File
@@ -393,6 +393,16 @@
<normal>#777777</normal>
</text>
</text>
<group>
<inheritance>
<fill>
<normal>transparent</normal>
</fill>
<border>
<normal>#797979</normal>
</border>
</inheritance>
</group>
</node>
<edge>
<default>
+1
View File
@@ -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
@@ -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);
+217 -86
View File
@@ -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> graph)
if (qualifier.size())
{
std::shared_ptr<DummyNode> qualifierNode = std::make_shared<DummyNode>();
qualifierNode->visible = true;
std::shared_ptr<DummyNode> qualifierNode = std::make_shared<DummyNode>(DummyNode::DUMMY_QUALIFIER);
qualifierNode->qualifierName = qualifier;
qualifierNode->visible = true;
node->subNodes.push_back(qualifierNode);
node->hasQualifier = true;
@@ -610,7 +616,7 @@ std::vector<std::shared_ptr<DummyNode>> GraphController::createDummyNodeTopDown(
{
std::vector<std::shared_ptr<DummyNode>> nodes;
std::shared_ptr<DummyNode> result = std::make_shared<DummyNode>();
std::shared_ptr<DummyNode> result = std::make_shared<DummyNode>(DummyNode::DUMMY_DATA);
result->data = node;
result->name = node->getName();
@@ -655,9 +661,8 @@ std::vector<std::shared_ptr<DummyNode>> GraphController::createDummyNodeTopDown(
if (!parent)
{
std::shared_ptr<DummyNode> accessNode = std::make_shared<DummyNode>();
std::shared_ptr<DummyNode> accessNode = std::make_shared<DummyNode>(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<Id>& 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<Id>& 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<Id>& 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<DummyNode> bundleNode = std::make_shared<DummyNode>();
std::shared_ptr<DummyNode> bundleNode = std::make_shared<DummyNode>(DummyNode::DUMMY_BUNDLE);
bundleNode->name = name;
bundleNode->visible = true;
@@ -1213,7 +1219,7 @@ std::shared_ptr<DummyNode> GraphController::bundleNodesMatching(
return nullptr;
}
std::shared_ptr<DummyNode> bundleNode = std::make_shared<DummyNode>();
std::shared_ptr<DummyNode> bundleNode = std::make_shared<DummyNode>(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<DummyNode> textNode = std::make_shared<DummyNode>();
textNode->textNode = true;
std::shared_ptr<DummyNode> textNode = std::make_shared<DummyNode>(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<Id> targetNodeIds;
std::set<Id> originNodeIds;
std::vector<DummyEdge*> targetEdges;
std::vector<DummyEdge*> originEdges;
};
std::set<Id> 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<Id, TrailNode> nodes;
for (const std::shared_ptr<DummyEdge>& 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<Id> groupedNodeIds;
while (nodes.size())
{
TrailNode node = nodes.begin()->second;
nodes.erase(nodes.begin());
std::vector<TrailNode> group;
std::map<Id, TrailNode>::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<DummyNode> groupNode = std::make_shared<DummyNode>(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<DummyEdge> targetEdge = std::make_shared<DummyEdge>();
targetEdge->ownerId = groupNode->tokenId;
std::shared_ptr<DummyEdge> originEdge = std::make_shared<DummyEdge>();
originEdge->targetId = groupNode->tokenId;
std::vector<Id> targetEdgeIds;
std::vector<Id> originEdgeIds;
for (TrailNode& node : group)
{
std::shared_ptr<DummyNode> 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<Edge*>(targetEdge->data)->addComponent(std::make_shared<TokenComponentEdgeIds>(targetEdgeIds));
}
m_dummyEdges.push_back(targetEdge);
}
if (originEdge->visible)
{
if (originEdge->data && originEdgeIds.size())
{
const_cast<Edge*>(targetEdge->data)->addComponent(std::make_shared<TokenComponentEdgeIds>(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<DummyNode>& 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<DummyNode>& 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<DummyNode>& subNode : node->subNodes)
{
@@ -1542,9 +1683,9 @@ void GraphController::layoutNestingRecursive(DummyNode* node) const
void GraphController::addExpandToggleNode(DummyNode* node) const
{
std::shared_ptr<DummyNode> expandNode = std::make_shared<DummyNode>();
expandNode->visible = true;
std::shared_ptr<DummyNode> expandNode = std::make_shared<DummyNode>(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<std::shared_ptr<DummyNode>> 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<DummyNode> GraphController::getDummyGraphNodeById(Id tokenId) const
{
std::map<Id, std::shared_ptr<DummyNode>>::const_iterator it = m_dummyGraphNodes.find(tokenId);
if (it != m_dummyGraphNodes.end())
{
return it->second.get();
return it->second;
}
for (const std::shared_ptr<DummyNode>& node : m_dummyNodes)
{
if (node->tokenId == tokenId)
{
return node.get();
return node;
}
}
@@ -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<DummyNode> getDummyGraphNodeById(Id tokenId) const;
DummyEdge* getDummyGraphEdgeById(Id tokenId) const;
void buildGraph(MessageBase* message, bool centerActiveNode, bool animatedTransition, bool scrollToTop);
@@ -97,7 +97,7 @@ void UndoRedoController::handleMessage(MessageActivateTrail* message)
void UndoRedoController::handleMessage(MessageActivateTrailEdge* message)
{
if (sameMessageTypeAsLast(message) &&
static_cast<MessageActivateTrailEdge*>(lastMessage())->tokenId == message->tokenId)
static_cast<MessageActivateTrailEdge*>(lastMessage())->edgeIds == message->edgeIds)
{
return;
}
+40 -13
View File
@@ -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<DummyNode> a, const std::shared_ptr<DummyNode> 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<DummyNode>& a, const std::shared_ptr<DummyNode>& 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
@@ -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<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gap)
{
return layoutSimple(nodes, top, left, gap, 0, true);
}
void ListLayouter::layoutList(std::vector<std::shared_ptr<DummyNode>>& nodes)
Vec2i ListLayouter::layoutColumn(std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gap)
{
return layoutSimple(nodes, top, left, 0, gap, false);
}
Vec2i ListLayouter::layoutMultiColumn(Vec2i viewSize, std::vector<std::shared_ptr<DummyNode>>* nodes)
{
size_t colsFinal;
std::vector<int> maxWidthsFinal;
@@ -18,14 +23,25 @@ void ListLayouter::layoutList(std::vector<std::shared_ptr<DummyNode>>& nodes)
int gapX = GraphViewStyle::s_gridCellSize + 2 * GraphViewStyle::s_gridCellPadding;
int gapY = GraphViewStyle::s_gridCellPadding;
std::vector<std::shared_ptr<DummyNode>> visibleNodes;
for (auto node : *nodes)
{
if (node->visible)
{
visibleNodes.push_back(node);
}
}
for (size_t cols = 1; cols <= 10; cols++)
{
std::vector<int> maxWidths = std::vector<int>(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<std::shared_ptr<DummyNode>>& 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<std::shared_ptr<DummyNode>>& 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<std::shared_ptr<DummyNode>>& nodes)
colsFinal = cols;
maxWidthsFinal = maxWidths;
if (height < m_viewSize.y)
if (height < viewSize.y)
{
break;
}
@@ -66,19 +82,23 @@ void ListLayouter::layoutList(std::vector<std::shared_ptr<DummyNode>>& 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<DummyNode> 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<DummyNode> textNode = std::make_shared<DummyNode>(*lastTextNode.get());
if (nodes[i - 1] == lastTextNode)
if (visibleNodes[i - 1] == lastTextNode)
{
lastTextNode->visible = false;
}
@@ -87,7 +107,8 @@ void ListLayouter::layoutList(std::vector<std::shared_ptr<DummyNode>>& 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<std::shared_ptr<DummyNode>>& 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<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gapX, int gapY, int maxWidth)
{
std::vector<std::shared_ptr<DummyNode>> visibleNodes;
std::multiset<int> 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<std::shared_ptr<DummyNode>>& 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<std::shared_ptr<DummyNode>>* 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<DummyNode>& 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);
}
@@ -1,19 +1,28 @@
#ifndef LIST_LAYOUTER_H
#define LIST_LAYOUTER_H
#include <memory>
#include <vector>
#include "utility/math/Vector2.h"
#include "utility/math/Vector4.h"
struct DummyNode;
class ListLayouter
{
public:
ListLayouter(Vec2i viewSize);
static Vec2i layoutRow(std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gap);
static Vec2i layoutColumn(std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gap);
void layoutList(std::vector<std::shared_ptr<DummyNode>>& nodes);
static Vec2i layoutMultiColumn(Vec2i viewSize, std::vector<std::shared_ptr<DummyNode>>* nodes);
static Vec2i layoutSkewed(
std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gapX, int gapY, int maxWidth);
static Vec4i boundingRect(const std::vector<std::shared_ptr<DummyNode>>& nodes);
private:
Vec2i m_viewSize;
static Vec2i layoutSimple(
std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gapX, int gapY, bool horizontal);
};
#endif // LIST_LAYOUTER_H
+75 -9
View File
@@ -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;
}
+6 -2
View File
@@ -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);
+6
View File
@@ -51,6 +51,12 @@ public:
STYLE_BIG_NODE = 2
};
enum GroupType
{
GROUP_FRAMELESS,
GROUP_INHERITANCE
};
struct BundleInfo
{
BundleInfo()
+2 -34
View File
@@ -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<TokenComponentAggregation> component)
{
if (getComponent<TokenComponentAggregation>())
{
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<TokenComponentInheritanceChain> component)
{
if (getComponent<TokenComponentInheritanceChain>())
{
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<TokenComponentAggregation>();
if (aggregation)
-6
View File
@@ -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<TokenComponentAggregation> component);
void addComponentInheritanceChain(std::shared_ptr<TokenComponentInheritanceChain> component);
static std::wstring getUnderscoredTypeString(EdgeType type);
static std::wstring getReadableTypeString(EdgeType type);
// Logging.
+2 -68
View File
@@ -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<TokenComponentAbstraction> component)
{
if (getComponent<TokenComponentAbstraction>())
{
// LOG_ERROR("TokenComponentAbstraction has been set before!");
return;
}
else
{
addComponent(component);
}
}
void Node::addComponentConst(std::shared_ptr<TokenComponentConst> component)
{
if (getComponent<TokenComponentConst>())
{
// LOG_ERROR("TokenComponentConst has been set before!");
return;
}
else
{
addComponent(component);
}
}
void Node::addComponentStatic(std::shared_ptr<TokenComponentStatic> component)
{
if (getComponent<TokenComponentStatic>())
{
// LOG_ERROR("TokenComponentStatic has been set before!");
return;
}
else
{
addComponent(component);
}
}
void Node::addComponentFilePath(std::shared_ptr<TokenComponentFilePath> component)
{
if (getComponent<TokenComponentFilePath>())
{
// LOG_ERROR("TokenComponentFilePath has been set before!");
return;
}
else
{
addComponent(component);
}
}
void Node::addComponentAccess(std::shared_ptr<TokenComponentAccess> component)
{
if (getComponent<TokenComponentAccess>())
{
LOG_WARNING("TokenComponentAccess has been set before!");
return;
}
else
{
addComponent(component);
}
}
std::wstring Node::getReadableTypeString() const
{
return m_type.getReadableTypeWString();
-14
View File
@@ -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<TokenComponentAbstraction> component);
void addComponentConst(std::shared_ptr<TokenComponentConst> component);
void addComponentStatic(std::shared_ptr<TokenComponentStatic> component);
void addComponentFilePath(std::shared_ptr<TokenComponentFilePath> component);
void addComponentAccess(std::shared_ptr<TokenComponentAccess> component);
// Logging.
virtual std::wstring getReadableTypeString() const override;
std::wstring getAsString() const;
+5 -5
View File
@@ -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<TokenComponent> 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<TokenComponent> component)
{
m_components.push_back(component);
}
+2 -1
View File
@@ -23,6 +23,8 @@ public:
void addLocationId(Id locationId);
void removeLocationId(Id locationId);
void addComponent(std::shared_ptr<TokenComponent> component);
template <typename ComponentType>
ComponentType* getComponent() const;
@@ -35,7 +37,6 @@ public:
protected:
Token(const Token& other);
void addComponent(std::shared_ptr<TokenComponent> component);
void copyComponentsFrom(const Token& other);
private:
@@ -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<Id>& edgeIds)
: edgeIds(edgeIds)
{
}
virtual std::shared_ptr<TokenComponent> copy() const
{
return std::make_shared<TokenComponentEdgeIds>(*this);
}
const std::vector<Id> edgeIds;
};
#endif // TOKEN_COMPONENT_EDGE_IDS_H
+4 -4
View File
@@ -2254,7 +2254,7 @@ void PersistentStorage::addNodesToGraph(const std::vector<Id>& newNodeIds, Graph
NameHierarchy(filePath.fileName(), NAME_DELIMITER_FILE),
defined
);
node->addComponentFilePath(std::make_shared<TokenComponentFilePath>(filePath));
node->addComponent(std::make_shared<TokenComponentFilePath>(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<TokenComponentAccess>(intToAccessKind(access.type)));
}
}
@@ -2564,7 +2564,7 @@ void PersistentStorage::addInheritanceChainsToGraph(const std::vector<Id>& activ
Edge* inheritanceEdge = graph->createEdge(
inheritanceEdgeId, Edge::EDGE_INHERITANCE, graph->getNodeById(sourceId), graph->getNodeById(targetId));
inheritanceEdge->addComponentInheritanceChain(std::make_shared<TokenComponentInheritanceChain>(edgeIds));
inheritanceEdge->addComponent(std::make_shared<TokenComponentInheritanceChain>(edgeIds));
}
}
}
@@ -13,9 +13,10 @@ class MessageActivateTrailEdge
{
public:
MessageActivateTrailEdge(
Id tokenId, Edge::EdgeType type, const NameHierarchy& sourceNameHierarchy, const NameHierarchy& targetNameHierarchy
const std::vector<Id>& 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<Id> edgeIds;
const Edge::EdgeType type;
const NameHierarchy sourceNameHierarchy;
const NameHierarchy targetNameHierarchy;
@@ -10,6 +10,7 @@ public:
MessageTooltipHide()
{
setSendAsTask(false);
setIsLogged(false);
}
static const std::string getStaticType()
+2
View File
@@ -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
+7 -1
View File
@@ -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<QtGraphNodeAccess*>(*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<QtGraphNode*, QtGraphNode*>(*it, *it2));
compareNodesRecursive(
@@ -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<TokenComponentEdgeIds>();
std::vector<Id> ids = { getData()->getId() };
MessageActivateTrailEdge(
getData()->getId(),
componentEdgeIds ? componentEdgeIds->edgeIds : ids,
getData()->getType(),
getData()->getFrom()->getNameHierarchy(),
getData()->getTo()->getNameHierarchy()
@@ -330,6 +330,11 @@ bool QtGraphNode::isTextNode() const
return false;
}
bool QtGraphNode::isGroupNode() const
{
return false;
}
Id QtGraphNode::getTokenId() const
{
return 0;
@@ -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;
@@ -0,0 +1,80 @@
#include "qt/view/graphElements/QtGraphNodeGroup.h"
#include <QBrush>
#include <QGraphicsRectItem>
#include <QPen>
#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);
}
@@ -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