ui: Show call graphs, inheritance trees and include trees for active symbol (issue 249 337)

* Added TrailLayouter with Sugiyama dependency layouting
* Layouter supports horizontal and vertical layouts
* Added basic ui to graph view for showing incoming and outgoing paths
* Added depth slider, with infinity at maximum
* Disable trail ui when not available
* Added trail messages to undo stack and only use last one when undoing
* Added QtGraphLineBezier for trail graphs and refactored other line types
* Disabled edge activation for trail layouts, shown only visually
* Highlight all connected edges when hovering a node in trail layout
* Use different color when highlighting call edges for better contrast
* Fixed BucketLayouter issue when edge does not leave node
* Increased click area for angled edges

bug id = 249 337

fortune cookie message = Answer just what the heart prompts to you.
This commit is contained in:
Eberhard Graether
2017-04-24 01:14:53 +02:00
parent 01bd0efefb
commit f0b7dcdcdd
40 changed files with 1892 additions and 487 deletions
+6 -3
View File
@@ -12,6 +12,8 @@ add_files(
component/controller/helper/NetworkProtocolHelper.h
component/controller/helper/SnippetMerger.cpp
component/controller/helper/SnippetMerger.h
component/controller/helper/TrailLayouter.cpp
component/controller/helper/TrailLayouter.h
component/controller/ActivationController.cpp
component/controller/ActivationController.h
@@ -225,7 +227,7 @@ add_files(
data/TaskMergeStorages.h
data/TaskShowStatusDialog.cpp
data/TaskShowStatusDialog.h
project/Project.cpp
project/Project.h
project/SourceGroupFactory.cpp
@@ -234,7 +236,7 @@ add_files(
project/SourceGroupFactoryModule.h
project/SourceGroup.cpp
project/SourceGroup.h
settings/migration/Migration.cpp
settings/migration/Migration.h
settings/migration/MigrationDeleteKey.cpp
@@ -245,7 +247,7 @@ add_files(
settings/migration/MigrationMoveKey.h
settings/migration/SettingsMigrator.cpp
settings/migration/SettingsMigrator.h
settings/ApplicationSettings.cpp
settings/ApplicationSettings.h
settings/ColorScheme.cpp
@@ -327,6 +329,7 @@ add_files(
utility/messaging/type/MessageActivateSourceLocations.h
utility/messaging/type/MessageActivateTokenIds.h
utility/messaging/type/MessageActivateTokens.h
utility/messaging/type/MessageActivateTrail.h
utility/messaging/type/MessageActivateWindow.h
utility/messaging/type/MessageChangeFileView.h
utility/messaging/type/MessageClearErrorCount.h
@@ -9,6 +9,7 @@
#include "component/controller/helper/BucketLayouter.h"
#include "component/controller/helper/ListLayouter.h"
#include "component/controller/helper/TrailLayouter.h"
#include "component/view/GraphView.h"
#include "component/view/GraphViewStyle.h"
#include "data/access/StorageAccess.h"
@@ -42,7 +43,7 @@ void GraphController::handleMessage(MessageActivateAll* message)
assignBundleIds();
layoutGraph();
buildGraph(message, false);
buildGraph(message, false, true, false);
}
void GraphController::handleMessage(MessageActivateTokens* message)
@@ -53,7 +54,7 @@ void GraphController::handleMessage(MessageActivateTokens* message)
{
m_activeEdgeIds = message->tokenIds;
setActiveAndVisibility(utility::concat(m_activeNodeIds, m_activeEdgeIds));
buildGraph(message, false, false);
buildGraph(message, false, false, false);
return;
}
else if (message->isAggregation)
@@ -101,9 +102,55 @@ void GraphController::handleMessage(MessageActivateTokens* message)
buildGraph(message, !isNamespace, true, isNamespace);
}
void GraphController::handleMessage(MessageActivateTrail* message)
{
TRACE("trail activate");
m_activeEdgeIds.clear();
std::shared_ptr<Graph> graph = m_storageAccess->getGraphForTrail(
message->originId, message->targetId, message->trailType, message->depth);
createDummyGraphForTokenIds(m_activeNodeIds, graph);
m_graph->setTrailMode(message->horizontalLayout ? Graph::TRAIL_HORIZONTAL : Graph::TRAIL_VERTICAL);
setVisibility(setActive(m_activeNodeIds, true));
layoutNesting();
TrailLayouter::LayoutDirection direction;
if (message->horizontalLayout)
{
if (message->originId)
{
direction = TrailLayouter::LAYOUT_LEFT_RIGHT;
}
else
{
direction = TrailLayouter::LAYOUT_RIGHT_LEFT;
}
}
else
{
if (message->originId)
{
direction = TrailLayouter::LAYOUT_TOP_BOTTOM;
}
else
{
direction = TrailLayouter::LAYOUT_BOTTOM_TOP;
}
}
TrailLayouter layout(direction);
layout.layoutGraph(m_dummyNodes, m_dummyEdges, m_topLevelAncestorIds);
buildGraph(message, true, true, false);
}
void GraphController::handleMessage(MessageFlushUpdates* message)
{
buildGraph(message, true, !message->keepContent());
buildGraph(message, true, !message->keepContent(), false);
}
void GraphController::handleMessage(MessageScrollGraph* message)
@@ -228,7 +275,7 @@ void GraphController::handleMessage(MessageGraphNodeExpand* message)
layoutNesting();
layoutGraph();
buildGraph(message, false);
buildGraph(message, false, true, false);
}
}
@@ -241,7 +288,7 @@ void GraphController::handleMessage(MessageGraphNodeMove* message)
if (message->isReplayed())
{
buildGraph(message, false);
buildGraph(message, false, true, false);
}
else
{
@@ -264,7 +311,7 @@ void GraphController::handleMessage(MessageShowReference* message)
m_activeEdgeIds = std::vector<Id>(1, message->tokenId);
setActiveAndVisibility(utility::concat(m_activeNodeIds, m_activeEdgeIds));
buildGraph(message, false, false);
buildGraph(message, false, false, false);
}
GraphView* GraphController::getView() const
@@ -300,6 +347,7 @@ void GraphController::createDummyGraphForTokenIds(const std::vector<Id>& tokenId
m_dummyEdges.clear();
m_dummyGraphNodes.clear();
m_topLevelAncestorIds.clear();
std::set<Id> addedNodes;
std::vector<std::shared_ptr<DummyNode>> dummyNodes;
@@ -308,14 +356,14 @@ void GraphController::createDummyGraphForTokenIds(const std::vector<Id>& tokenId
[&addedNodes, &dummyNodes, this](Node* node)
{
Node* parent = node->getLastParentNode();
Id id = parent->getId();
if (addedNodes.find(id) != addedNodes.end())
Id parentId = parent->getId();
if (addedNodes.find(parentId) != addedNodes.end())
{
return;
}
addedNodes.insert(id);
addedNodes.insert(parentId);
utility::append(dummyNodes, createDummyNodeTopDown(parent));
utility::append(dummyNodes, createDummyNodeTopDown(parent, parentId));
}
);
@@ -370,7 +418,7 @@ void GraphController::createDummyGraphForTokenIdsAndSetActiveAndVisibility(
createDummyGraphForTokenIds(tokenIds, graph);
bool noActive = setActive(tokenIds);
bool noActive = setActive(tokenIds, false);
autoExpandActiveNode(tokenIds);
setExpandedNodeIds(expandedNodeIds);
@@ -378,24 +426,26 @@ void GraphController::createDummyGraphForTokenIdsAndSetActiveAndVisibility(
setVisibility(noActive);
}
std::vector<std::shared_ptr<DummyNode>> GraphController::createDummyNodeTopDown(Node* node)
std::vector<std::shared_ptr<DummyNode>> GraphController::createDummyNodeTopDown(Node* node, Id ancestorId)
{
std::vector<std::shared_ptr<DummyNode>> nodes;
std::shared_ptr<DummyNode> result = std::make_shared<DummyNode>();
result->data = node;
result->tokenId = node->getId();
result->name = node->getName();
result->tokenId = node->getId();
m_topLevelAncestorIds.emplace(node->getId(), ancestorId);
m_dummyGraphNodes.emplace(result->data->getId(), result);
nodes.push_back(result);
if (node->isType(Node::NODE_NAMESPACE))
{
node->forEachChildNode(
[&nodes, this](Node* child)
[&nodes, &ancestorId, this](Node* child)
{
utility::append(nodes, createDummyNodeTopDown(child));
utility::append(nodes, createDummyNodeTopDown(child, ancestorId));
}
);
@@ -403,7 +453,7 @@ std::vector<std::shared_ptr<DummyNode>> GraphController::createDummyNodeTopDown(
}
node->forEachChildNode(
[node, &result, this](Node* child)
[node, &result, &ancestorId, this](Node* child)
{
DummyNode* parent = nullptr;
AccessKind accessKind = ACCESS_NONE;
@@ -432,7 +482,7 @@ std::vector<std::shared_ptr<DummyNode>> GraphController::createDummyNodeTopDown(
parent = accessNode.get();
}
utility::append(parent->subNodes, createDummyNodeTopDown(child));
utility::append(parent->subNodes, createDummyNodeTopDown(child, ancestorId));
}
);
@@ -482,7 +532,7 @@ void GraphController::autoExpandActiveNode(const std::vector<Id>& activeTokenIds
}
}
bool GraphController::setActive(const std::vector<Id>& activeTokenIds)
bool GraphController::setActive(const std::vector<Id>& activeTokenIds, bool showAllEdges)
{
TRACE();
@@ -513,7 +563,7 @@ bool GraphController::setActive(const std::vector<Id>& activeTokenIds)
DummyNode* from = getDummyGraphNodeById(edge->ownerId);
DummyNode* to = getDummyGraphNodeById(edge->targetId);
if (from && to && (noActive || from->active || to->active || edge->active))
if (from && to && (showAllEdges || noActive || from->active || to->active || edge->active))
{
edge->visible = true;
from->connected = true;
@@ -540,7 +590,7 @@ void GraphController::setActiveAndVisibility(const std::vector<Id>& activeTokenI
{
TRACE();
setVisibility(setActive(activeTokenIds));
setVisibility(setActive(activeTokenIds, false));
}
void GraphController::setNodeActiveRecursive(DummyNode* node, const std::vector<Id>& activeTokenIds, bool* noActive) const
@@ -1468,7 +1518,8 @@ DummyNode* GraphController::getDummyGraphNodeById(Id tokenId) const
return nullptr;
}
void GraphController::buildGraph(MessageBase* message, bool centerActiveNode, bool animatedTransition, bool scrollToTop)
void GraphController::buildGraph(
MessageBase* message, bool centerActiveNode, bool animatedTransition, bool scrollToTop)
{
if (!message->isReplayed())
{
@@ -1742,7 +1793,7 @@ void GraphController::handleMessage(MessageColorSchemeTest* message)
}
);
setActive(activeTokenIds);
setActive(activeTokenIds, true);
layoutNesting();
@@ -1758,7 +1809,7 @@ void GraphController::handleMessage(MessageColorSchemeTest* message)
grid.createBuckets(m_dummyNodes, std::vector<std::shared_ptr<DummyEdge>>());
grid.layoutBuckets();
buildGraph(message, false);
buildGraph(message, false, true, false);
getView()->focusTokenIds(focusedTokenIds);
}
@@ -7,6 +7,7 @@
#include "utility/messaging/MessageListener.h"
#include "utility/messaging/type/MessageActivateAll.h"
#include "utility/messaging/type/MessageActivateTokens.h"
#include "utility/messaging/type/MessageActivateTrail.h"
#include "utility/messaging/type/MessageColorSchemeTest.h"
#include "utility/messaging/type/MessageFlushUpdates.h"
#include "utility/messaging/type/MessageFocusIn.h"
@@ -34,6 +35,7 @@ class GraphController
: public Controller
, public MessageListener<MessageActivateAll>
, public MessageListener<MessageActivateTokens>
, public MessageListener<MessageActivateTrail>
, public MessageListener<MessageColorSchemeTest>
, public MessageListener<MessageFlushUpdates>
, public MessageListener<MessageFocusIn>
@@ -53,6 +55,7 @@ public:
private:
virtual void handleMessage(MessageActivateAll* message);
virtual void handleMessage(MessageActivateTokens* message);
virtual void handleMessage(MessageActivateTrail* message);
virtual void handleMessage(MessageFlushUpdates* message);
virtual void handleMessage(MessageFocusIn* message);
virtual void handleMessage(MessageFocusOut* message);
@@ -71,13 +74,13 @@ private:
void createDummyGraphForTokenIds(const std::vector<Id>& tokenIds, const std::shared_ptr<Graph> graph);
void createDummyGraphForTokenIdsAndSetActiveAndVisibility(
const std::vector<Id>& tokenIds, const std::shared_ptr<Graph> graph);
std::vector<std::shared_ptr<DummyNode>> createDummyNodeTopDown(Node* node);
std::vector<std::shared_ptr<DummyNode>> createDummyNodeTopDown(Node* node, Id ancestorId);
std::vector<Id> getExpandedNodeIds() const;
void setExpandedNodeIds(const std::vector<Id>& nodeIds);
void autoExpandActiveNode(const std::vector<Id>& activeTokenIds);
bool setActive(const std::vector<Id>& activeTokenIds);
bool setActive(const std::vector<Id>& activeTokenIds, bool showAllEdges);
void setVisibility(bool noActive);
void setActiveAndVisibility(const std::vector<Id>& activeTokenIds);
void setNodeActiveRecursive(DummyNode* node, const std::vector<Id>& activeTokenIds, bool* noActive) const;
@@ -108,7 +111,7 @@ private:
DummyNode* getDummyGraphNodeById(Id tokenId) const;
void buildGraph(MessageBase* message, bool centerActiveNode, bool animatedTransition = true, bool scrollToTop = false);
void buildGraph(MessageBase* message, bool centerActiveNode, bool animatedTransition, bool scrollToTop);
void forEachDummyNodeRecursive(std::function<void(DummyNode*)> func);
void forEachDummyEdge(std::function<void(DummyEdge*)> func);
@@ -126,6 +129,8 @@ private:
std::vector<Id> m_activeEdgeIds;
std::shared_ptr<Graph> m_graph;
std::map<Id, Id> m_topLevelAncestorIds;
};
#endif // GRAPH_CONTROLLER_H
@@ -77,6 +77,19 @@ void UndoRedoController::handleMessage(MessageActivateTokens* message)
processCommand(command);
}
void UndoRedoController::handleMessage(MessageActivateTrail* message)
{
if (sameMessageTypeAsLast(message) &&
static_cast<MessageActivateTrail*>(lastMessage())->originId == message->originId &&
static_cast<MessageActivateTrail*>(lastMessage())->targetId == message->targetId)
{
return;
}
Command command(std::make_shared<MessageActivateTrail>(*message), Command::ORDER_ADAPT, true);
processCommand(command);
}
void UndoRedoController::handleMessage(MessageChangeFileView* message)
{
Command command(std::make_shared<MessageChangeFileView>(*message), Command::ORDER_VIEW);
@@ -320,9 +333,21 @@ void UndoRedoController::replayCommands(std::list<Command>::iterator it)
std::vector<std::list<Command>::iterator> viewCommands;
bool keepsContent = true;
std::map<std::string, std::list<Command>::iterator> lastOfType;
std::list<Command>::iterator at = it;
while (at != m_iterator)
{
if (at->replayLastOnly)
{
lastOfType[at->message->getType()] = at;
}
std::advance(at, 1);
}
while (it != m_iterator)
{
if (it->order != Command::ORDER_VIEW || it->replayLastOnly == false)
if (!it->replayLastOnly || lastOfType[it->message->getType()] == it)
{
replayCommand(it);
@@ -330,13 +355,8 @@ void UndoRedoController::replayCommands(std::list<Command>::iterator it)
{
keepsContent = false;
}
if (it->order != Command::ORDER_VIEW)
{
viewCommands.clear();
}
}
else
else if (it->order == Command::ORDER_VIEW)
{
viewCommands.push_back(it);
}
@@ -8,6 +8,7 @@
#include "utility/messaging/type/MessageActivateAll.h"
#include "utility/messaging/type/MessageActivateLocalSymbols.h"
#include "utility/messaging/type/MessageActivateTokens.h"
#include "utility/messaging/type/MessageActivateTrail.h"
#include "utility/messaging/type/MessageChangeFileView.h"
#include "utility/messaging/type/MessageDeactivateEdge.h"
#include "utility/messaging/type/MessageFinishedParsing.h"
@@ -34,6 +35,7 @@ class UndoRedoController
, public MessageListener<MessageActivateAll>
, public MessageListener<MessageActivateLocalSymbols>
, public MessageListener<MessageActivateTokens>
, public MessageListener<MessageActivateTrail>
, public MessageListener<MessageChangeFileView>
, public MessageListener<MessageDeactivateEdge>
, public MessageListener<MessageFinishedParsing>
@@ -78,6 +80,7 @@ private:
virtual void handleMessage(MessageActivateAll* message);
virtual void handleMessage(MessageActivateLocalSymbols* message);
virtual void handleMessage(MessageActivateTokens* message);
virtual void handleMessage(MessageActivateTrail* message);
virtual void handleMessage(MessageChangeFileView* message);
virtual void handleMessage(MessageDeactivateEdge* message);
virtual void handleMessage(MessageFinishedParsing* message);
@@ -154,7 +154,7 @@ void BucketLayouter::createBuckets(
std::shared_ptr<DummyNode> target = findTopMostDummyNodeRecursive(nodes, edge->targetId, nullptr);
bool removeEdge = false;
if (!owner || !target)
if (!owner || !target || owner == target)
{
removeEdge = true;
}
@@ -2,6 +2,7 @@
#define DUMMY_EDGE_H
#include "utility/types.h"
#include "utility/math/Vector4.h"
#include "data/graph/Edge.h"
#include "data/graph/token_component/TokenComponentAggregation.h"
@@ -86,6 +87,8 @@ struct DummyEdge
bool visible;
bool active;
std::vector<Vec4i> path;
// BundleEdge
int weight;
TokenComponentAggregation::Direction direction;
@@ -53,7 +53,6 @@ public:
DummyNode()
: visible(false)
, childVisible(false)
, topLevelAncestorId(0)
, tokenId(0)
, data(nullptr)
, active(false)
@@ -244,7 +243,6 @@ public:
bool visible;
bool childVisible;
Id topLevelAncestorId;
Id tokenId;
std::vector<std::shared_ptr<DummyNode>> subNodes;
@@ -0,0 +1,573 @@
#include "component/controller/helper/TrailLayouter.h"
#include <iostream>
TrailLayouter::TrailLayouter(LayoutDirection dir)
: m_direction(dir)
{
}
void TrailLayouter::layoutGraph(
std::vector<std::shared_ptr<DummyNode>>& dummyNodes,
const std::vector<std::shared_ptr<DummyEdge>>& dummyEdges,
const std::map<Id, Id>& topLevelAncestorIds)
{
buildGraph(dummyNodes, dummyEdges, topLevelAncestorIds);
makeAcyclic();
assignLongestPathLevels();
assignRemainingLevels();
addVirtualNodes();
buildColumns();
reduceEdgeCrossings();
layout();
retrievePositions(topLevelAncestorIds);
// print();
}
void TrailLayouter::buildGraph(
std::vector<std::shared_ptr<DummyNode>>& dummyNodes,
const std::vector<std::shared_ptr<DummyEdge>>& dummyEdges,
const std::map<Id, Id>& topLevelAncestorIds)
{
for (const std::shared_ptr<DummyNode> dummyNode : dummyNodes)
{
addNode(dummyNode);
}
for (const std::shared_ptr<DummyEdge> dummyEdge : dummyEdges)
{
dummyEdge->path.clear();
if (dummyEdge->data && !dummyEdge->data->isType(Edge::EDGE_OVERRIDE | Edge::EDGE_INHERITANCE))
{
addEdge(dummyEdge, topLevelAncestorIds);
}
}
for (const std::shared_ptr<DummyEdge> dummyEdge : dummyEdges)
{
if (dummyEdge->data && dummyEdge->data->isType(Edge::EDGE_OVERRIDE | Edge::EDGE_INHERITANCE))
{
addEdge(dummyEdge, topLevelAncestorIds);
}
}
}
void TrailLayouter::makeAcyclic()
{
std::set<TrailEdge*> edgesToSwitch;
for (std::shared_ptr<TrailNode> node : m_allNodes)
{
if (!node->incomingEdges.size())
{
utility::append(edgesToSwitch, node->outgoingEdges);
}
}
for (TrailEdge* edge : edgesToSwitch)
{
switchEdge(edge);
}
for (TrailNode* node : m_rootNodes)
{
std::set<TrailEdge*> edgesToSwitch = node->incomingEdges;
for (TrailEdge* edge : edgesToSwitch)
{
switchEdge(edge);
}
makeAcyclicRecursive(node, std::set<TrailNode*>());
}
}
void TrailLayouter::makeAcyclicRecursive(TrailNode* node, std::set<TrailNode*> predecessors)
{
predecessors.insert(node);
std::set<TrailEdge*> edgesToSwitch;
for (TrailEdge* edge : node->outgoingEdges)
{
if (predecessors.find(edge->target) != predecessors.end())
{
edgesToSwitch.insert(edge);
}
else
{
makeAcyclicRecursive(edge->target, predecessors);
}
}
for (TrailEdge* edge : edgesToSwitch)
{
switchEdge(edge);
}
}
void TrailLayouter::assignLongestPathLevels()
{
std::set<TrailNode*> nodes(m_rootNodes.begin(), m_rootNodes.end());
std::map<TrailNode*, TrailNode*> predecessorNodes;
int level = 0;
while (nodes.size())
{
std::set<TrailNode*> newNodes;
for (TrailNode* node : nodes)
{
for (TrailEdge* edge : node->outgoingEdges)
{
newNodes.insert(edge->target);
predecessorNodes[edge->target] = node;
}
}
if (!newNodes.size())
{
break;
}
nodes = newNodes;
level++;
}
while (nodes.size())
{
std::set<TrailNode*> newNodes;
for (TrailNode* node : nodes)
{
node->level = level;
if (level > 0)
{
newNodes.insert(predecessorNodes[node]);
}
}
nodes = newNodes;
level--;
}
}
void TrailLayouter::assignRemainingLevels()
{
std::set<TrailNode*> nodes(m_rootNodes.begin(), m_rootNodes.end());
while (nodes.size())
{
std::set<TrailNode*> newNodes;
for (TrailNode* node : nodes)
{
for (TrailEdge* edge : node->outgoingEdges)
{
newNodes.insert(edge->target);
}
if (node->level < 0)
{
int level = -1;
for (TrailEdge* edge : node->incomingEdges)
{
level = std::max(level, edge->origin->level + 1);
}
node->level = level;
}
}
nodes = newNodes;
}
}
void TrailLayouter::addVirtualNodes()
{
std::vector<std::shared_ptr<TrailEdge>> newEdges;
for (std::shared_ptr<TrailEdge> edge : m_allEdges)
{
for (int i = edge->origin->level + 1; i < edge->target->level; i++)
{
std::shared_ptr<TrailNode> virtualNode = std::make_shared<TrailNode>();
virtualNode->id = 0;
virtualNode->name = "<virtual>";
virtualNode->dummyNode = nullptr;
virtualNode->level = i;
virtualNode->size = Vec2i(50, 20);
m_allNodes.push_back(virtualNode);
edge->virtualNodes.push_back(virtualNode.get());
std::shared_ptr<TrailEdge> virtualEdge = std::make_shared<TrailEdge>();
virtualEdge->id = 0;
virtualEdge->origin = edge->origin;
virtualEdge->origin->outgoingEdges.erase(edge.get());
virtualEdge->origin->outgoingEdges.insert(virtualEdge.get());
virtualEdge->target = virtualNode.get();
virtualEdge->target->incomingEdges.insert(virtualEdge.get());
virtualEdge->target->outgoingEdges.insert(edge.get());
edge->origin = virtualNode.get();
newEdges.push_back(virtualEdge);
}
}
m_allEdges.insert(m_allEdges.end(), newEdges.begin(), newEdges.end());
}
void TrailLayouter::buildColumns()
{
for (std::shared_ptr<TrailNode> node : m_allNodes)
{
int level = node->level + 1;
for (int i = m_nodesPerCol.size(); i <= level; i++)
{
m_nodesPerCol.push_back(std::vector<TrailNode*>());
}
m_nodesPerCol[level].push_back(node.get());
}
}
void TrailLayouter::reduceEdgeCrossings()
{
for (size_t i = 1; i < m_nodesPerCol.size(); i++)
{
std::vector<TrailNode*> nodes = m_nodesPerCol[i];
bool usePredecessors = true;
std::vector<TrailNode*> neighbors = m_nodesPerCol[i - 1];
if (neighbors.size() == 1 && i + 1 < m_nodesPerCol.size() && m_nodesPerCol[i + 1].size() > 0)
{
neighbors = m_nodesPerCol[i + 1];
usePredecessors = false;
}
std::map<TrailNode*, size_t> neighborIndices;
for (size_t j = 0; j < neighbors.size(); j++)
{
neighborIndices.emplace(neighbors[j], j);
}
std::multimap<float, TrailNode*> newOrder;
for (size_t j = 0; j < nodes.size(); j++)
{
TrailNode* node = nodes[j];
size_t sum = 0;
size_t count = 0;
if (usePredecessors)
{
for (TrailEdge* edge : node->incomingEdges)
{
sum += neighborIndices[edge->origin];
count++;
}
}
else
{
for (TrailEdge* edge : node->outgoingEdges)
{
sum += neighborIndices[edge->target];
count++;
}
}
float value = j;
if (count)
{
value = float(sum) / count;
}
newOrder.emplace(value, node);
}
nodes.clear();
for (std::pair<float, TrailNode*> p : newOrder)
{
nodes.push_back(p.second);
}
m_nodesPerCol[i] = nodes;
}
}
void TrailLayouter::layout()
{
// calculate widths and heights of columns, and find largest column
std::vector<int> widthsPerCol;
std::vector<int> heightsPerCol;
int maxHeight = 0;
size_t maxHeightIndex = 0;
unsigned int xIdx = horizontalLayout() ? 0 : 1;
unsigned int yIdx = horizontalLayout() ? 1 : 0;
for (size_t i = 0; i < m_nodesPerCol.size(); i++)
{
std::vector<TrailNode*>& nodes = m_nodesPerCol[i];
int width = 0;
int height = -30;
for (TrailNode* node : nodes)
{
height += node->size.getValue(yIdx) + 30;
width = std::max(width, node->size.getValue(xIdx));
}
widthsPerCol.push_back(width);
heightsPerCol.push_back(height);
if (height > maxHeight)
{
maxHeight = height;
maxHeightIndex = i;
}
}
// layout nodes within columns
int x = 0;
for (size_t i = 0; i < m_nodesPerCol.size(); i++)
{
std::vector<TrailNode*>& nodes = m_nodesPerCol[i];
int y = -heightsPerCol[i] / 2;
for (TrailNode* node : nodes)
{
node->pos = horizontalLayout() ? Vec2i(x, y) : Vec2i(y, x);
y += node->size.getValue(yIdx) + 30;
if (!node->id)
{
node->size.setValue(xIdx, widthsPerCol[i]);
}
}
if (i + 1 == m_nodesPerCol.size())
{
continue;
}
if (invertedLayout())
{
x -= widthsPerCol[i + 1] + 150;
}
else
{
x += widthsPerCol[i] + 150;
}
}
// process layout before highest column
for (size_t i = maxHeightIndex; i > 0; i--)
{
moveNodesToAveragePosition(m_nodesPerCol[i - 1]);
}
// process layout after highest column
for (size_t i = maxHeightIndex + 1; i < m_nodesPerCol.size(); i++)
{
moveNodesToAveragePosition(m_nodesPerCol[i]);
}
// put into grid
}
void TrailLayouter::moveNodesToAveragePosition(std::vector<TrailNode*> nodes)
{
unsigned int yIdx = horizontalLayout() ? 1 : 0;
for (size_t k = 0; k < 2; k++)
{
for (size_t j = 0; j < nodes.size(); j++)
{
size_t l = k ? nodes.size() - 1 - j : j;
size_t i = l % 2 ? nodes.size() - (l + 1) / 2 : l / 2;
TrailNode* node = nodes[i];
int sum = 0;
int count = 0;
for (TrailEdge* edge : node->outgoingEdges)
{
sum += edge->target->pos.getValue(yIdx) + edge->target->size.getValue(yIdx) / 2;
count++;
}
for (TrailEdge* edge : node->incomingEdges)
{
sum += edge->origin->pos.getValue(yIdx) + edge->origin->size.getValue(yIdx) / 2;
count++;
}
if (count)
{
node->pos.setValue(yIdx, sum / count - node->size.getValue(yIdx) / 2);
TrailNode* above = i > 0 ? nodes[i - 1] : nullptr;
if (above && above->pos.getValue(yIdx) + above->size.getValue(yIdx) + 30 > node->pos.getValue(yIdx))
{
node->pos.setValue(yIdx, above->pos.getValue(yIdx) + above->size.getValue(yIdx) + 30);
}
TrailNode* below = i + 1 < nodes.size() ? nodes[i + 1] : nullptr;
if (below && below->pos.getValue(yIdx) - 30 < node->pos.getValue(yIdx) + node->size.getValue(yIdx))
{
node->pos.setValue(yIdx, below->pos.getValue(yIdx) - 30 - node->size.getValue(yIdx));
}
}
}
}
}
void TrailLayouter::retrievePositions(const std::map<Id, Id>& topLevelAncestorIds)
{
for (std::shared_ptr<TrailNode> node : m_allNodes)
{
if (node->dummyNode)
{
node->dummyNode->position = node->pos;
}
}
for (std::shared_ptr<TrailEdge> edge : m_allEdges)
{
if (edge->virtualNodes.size())
{
for (DummyEdge* dummyEdge : edge->dummyEdges)
{
bool forward = edge->target->id == topLevelAncestorIds.find(dummyEdge->targetId)->second;
for (size_t i = 0; i < edge->virtualNodes.size(); i++)
{
TrailNode* node = edge->virtualNodes[forward ? i : edge->virtualNodes.size() - 1 - i];
dummyEdge->path.push_back(
Vec4i(node->pos.x, node->pos.y, node->pos.x + node->size.x, node->pos.y + node->size.y));
}
}
}
}
}
void TrailLayouter::print()
{
std::cout << "graph: " << std::endl;
for (std::shared_ptr<TrailNode> node : m_allNodes)
{
std::cout << node->id << "\t" << node->level << "\t";
std::cout << node->incomingEdges.size() << "\t" << node->outgoingEdges.size() << "\t";
std::cout << node->name << std::endl;
}
std::cout << std::endl;
for (std::shared_ptr<TrailEdge> edge : m_allEdges)
{
std::cout << edge->id << "\t" << edge->origin->name << "\t" << edge->target->name << std::endl;
}
std::cout << std::endl;
}
void TrailLayouter::addNode(const std::shared_ptr<DummyNode>& dummyNode)
{
std::shared_ptr<TrailNode> node = std::make_shared<TrailNode>();
node->id = dummyNode->tokenId;
node->name = dummyNode->name;
node->dummyNode = dummyNode.get();
node->level = -1;
node->size = dummyNode->size;
m_allNodes.push_back(node);
if (node->id)
{
m_nodesById.emplace(node->id, node.get());
}
if (dummyNode->hasActiveSubNode())
{
m_rootNodes.push_back(node.get());
}
}
void TrailLayouter::addEdge(const std::shared_ptr<DummyEdge> dummyEdge, const std::map<Id, Id>& topLevelAncestorIds)
{
std::shared_ptr<TrailEdge> edge = std::make_shared<TrailEdge>();
if (!dummyEdge->data)
{
return;
}
edge->id = dummyEdge->data->getId();
Id originTopLevelId = topLevelAncestorIds.find(dummyEdge->ownerId)->second;
Id targetTopLevelId = topLevelAncestorIds.find(dummyEdge->targetId)->second;
if (dummyEdge->data->isType(Edge::EDGE_OVERRIDE | Edge::EDGE_INHERITANCE) != invertedLayout())
{
std::swap(originTopLevelId, targetTopLevelId);
}
auto origin = m_nodesById.find(originTopLevelId);
auto target = m_nodesById.find(targetTopLevelId);
if (origin == m_nodesById.end() || target == m_nodesById.end() || origin == target)
{
return;
}
edge->origin = origin->second;
edge->target = target->second;
for (std::shared_ptr<TrailEdge> e : m_allEdges)
{
if ((e->origin == edge->origin && e->target == edge->target) ||
(e->origin == edge->target && e->target == edge->origin))
{
e->dummyEdges.push_back(dummyEdge.get());
return;
}
}
edge->dummyEdges.push_back(dummyEdge.get());
edge->origin->outgoingEdges.insert(edge.get());
edge->target->incomingEdges.insert(edge.get());
m_allEdges.push_back(edge);
}
void TrailLayouter::switchEdge(TrailEdge* edge)
{
edge->origin->outgoingEdges.erase(edge);
edge->origin->incomingEdges.insert(edge);
edge->target->incomingEdges.erase(edge);
edge->target->outgoingEdges.insert(edge);
std::swap(edge->origin, edge->target);
}
bool TrailLayouter::horizontalLayout() const
{
return m_direction == LAYOUT_LEFT_RIGHT || m_direction == LAYOUT_RIGHT_LEFT;
}
bool TrailLayouter::invertedLayout() const
{
return m_direction == LAYOUT_RIGHT_LEFT || m_direction == LAYOUT_BOTTOM_TOP;
}
@@ -0,0 +1,99 @@
#ifndef GRAPH_LAYOUTER_H
#define GRAPH_LAYOUTER_H
#include <map>
#include <set>
#include <vector>
#include "component/controller/helper/DummyEdge.h"
#include "component/controller/helper/DummyNode.h"
// based on Sugiyama dependency graph layouting
class TrailLayouter
{
public:
enum LayoutDirection
{
LAYOUT_LEFT_RIGHT,
LAYOUT_RIGHT_LEFT,
LAYOUT_TOP_BOTTOM,
LAYOUT_BOTTOM_TOP
};
TrailLayouter(LayoutDirection dir);
void layoutGraph(
std::vector<std::shared_ptr<DummyNode>>& dummyNodes,
const std::vector<std::shared_ptr<DummyEdge>>& dummyEdges,
const std::map<Id, Id>& topLevelAncestorIds);
private:
struct TrailEdge;
struct TrailNode
{
Id id;
int level;
std::string name;
Vec2i pos;
Vec2i size;
std::set<TrailEdge*> incomingEdges;
std::set<TrailEdge*> outgoingEdges;
DummyNode* dummyNode;
};
struct TrailEdge
{
Id id;
TrailNode* origin;
TrailNode* target;
std::vector<TrailNode*> virtualNodes;
std::vector<DummyEdge*> dummyEdges;
};
void buildGraph(
std::vector<std::shared_ptr<DummyNode>>& dummyNodes,
const std::vector<std::shared_ptr<DummyEdge>>& dummyEdges,
const std::map<Id, Id>& topLevelAncestorIds);
void makeAcyclic();
void makeAcyclicRecursive(TrailNode* node, std::set<TrailNode*> predecessors);
void assignLongestPathLevels();
void assignRemainingLevels();
void addVirtualNodes();
void buildColumns();
void reduceEdgeCrossings();
void layout();
void moveNodesToAveragePosition(std::vector<TrailNode*> nodes);
void retrievePositions(const std::map<Id, Id>& topLevelAncestorIds);
void print();
void addNode(const std::shared_ptr<DummyNode>& dummyNode);
void addEdge(const std::shared_ptr<DummyEdge> dummyEdge, const std::map<Id, Id>& topLevelAncestorIds);
void switchEdge(TrailEdge* edge);
bool horizontalLayout() const;
bool invertedLayout() const;
LayoutDirection m_direction;
std::vector<std::shared_ptr<TrailNode>> m_allNodes;
std::vector<std::shared_ptr<TrailEdge>> m_allEdges;
std::map<Id, TrailNode*> m_nodesById;
std::vector<TrailNode*> m_rootNodes;
std::vector<std::vector<TrailNode*>> m_nodesPerCol;
};
#endif // GRAPH_LAYOUTER_H
+14 -2
View File
@@ -99,7 +99,6 @@ GraphViewStyle::NodeStyle::NodeStyle()
GraphViewStyle::EdgeStyle::EdgeStyle()
: width(0)
, zValue(0)
, isStraight(false)
, arrowLength(0)
, arrowWidth(0)
, arrowClosed(false)
@@ -550,7 +549,8 @@ GraphViewStyle::NodeStyle GraphViewStyle::getStyleOfTextNode()
return style;
}
GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(Edge::EdgeType type, bool isActive, bool isFocused)
GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(
Edge::EdgeType type, bool isActive, bool isFocused, bool isTrailEdge)
{
EdgeStyle style;
@@ -588,6 +588,13 @@ GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(Edge::EdgeType typ
style.originOffset.y = 1;
style.targetOffset.y = -1;
style.verticalOffset = 4;
if (isTrailEdge && isActive)
{
style.width = 3;
style.color = ColorScheme::getInstance()->getColor(
"graph/edge/" + Edge::getUnderscoredTypeString(type) + "/trail_focus", style.color);
}
break;
case Edge::EDGE_USAGE:
style.originOffset.y = 3;
@@ -605,6 +612,11 @@ GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(Edge::EdgeType typ
break;
}
if (isTrailEdge)
{
style.zValue = isActive ? 5 : 2;
}
return style;
}
+1 -3
View File
@@ -80,8 +80,6 @@ public:
float width;
int zValue;
bool isStraight;
int arrowLength;
int arrowWidth;
bool arrowClosed;
@@ -128,7 +126,7 @@ public:
static NodeStyle getStyleOfQualifier();
static NodeStyle getStyleOfTextNode();
static EdgeStyle getStyleForEdgeType(Edge::EdgeType type, bool isActive, bool isFocused);
static EdgeStyle getStyleForEdgeType(Edge::EdgeType type, bool isActive, bool isFocused, bool isTrailEdge);
static int toGridOffset(int x);
static int toGridSize(int x);
+95 -13
View File
@@ -157,7 +157,8 @@ void PersistentStorage::addError(
Id PersistentStorage::addNodeBookmark(const NodeBookmark& bookmark)
{
const Id categoryId = addBookmarkCategory(bookmark.getCategory().getName());
const Id id = m_sqliteBookmarkStorage.addBookmark(bookmark.getName(), bookmark.getComment(), bookmark.getTimeStamp().toString(), categoryId);
const Id id = m_sqliteBookmarkStorage.addBookmark(
bookmark.getName(), bookmark.getComment(), bookmark.getTimeStamp().toString(), categoryId);
for (const Id& nodeId: bookmark.getNodeIds())
{
@@ -170,7 +171,8 @@ Id PersistentStorage::addNodeBookmark(const NodeBookmark& bookmark)
Id PersistentStorage::addEdgeBookmark(const EdgeBookmark& bookmark)
{
const Id categoryId = addBookmarkCategory(bookmark.getCategory().getName());
const Id id = m_sqliteBookmarkStorage.addBookmark(bookmark.getName(), bookmark.getComment(), bookmark.getTimeStamp().toString(), categoryId);
const Id id = m_sqliteBookmarkStorage.addBookmark(
bookmark.getName(), bookmark.getComment(), bookmark.getTimeStamp().toString(), categoryId);
for (const Id& edgeId: bookmark.getEdgeIds())
{
const StorageEdge storageEdge = m_sqliteIndexStorage.getEdgeById(edgeId);
@@ -178,7 +180,8 @@ Id PersistentStorage::addEdgeBookmark(const EdgeBookmark& bookmark)
bool sourceNodeActive = storageEdge.sourceNodeId == bookmark.getActiveNodeId();
m_sqliteBookmarkStorage.addBookmarkedEdge(
id,
m_sqliteIndexStorage.getNodeById(storageEdge.sourceNodeId).serializedName, // todo: optimization for multiple edges in same bookmark: use a local cache here
// todo: optimization for multiple edges in same bookmark: use a local cache here
m_sqliteIndexStorage.getNodeById(storageEdge.sourceNodeId).serializedName,
m_sqliteIndexStorage.getNodeById(storageEdge.targetNodeId).serializedName,
storageEdge.type,
sourceNodeActive
@@ -202,7 +205,8 @@ Id PersistentStorage::addBookmarkCategory(const std::string& name)
return id;
}
void PersistentStorage::updateBookmark(const Id bookmarkId, const std::string& name, const std::string& comment, const std::string& categoryName)
void PersistentStorage::updateBookmark(
const Id bookmarkId, const std::string& name, const std::string& comment, const std::string& categoryName)
{
const Id categoryId = addBookmarkCategory(categoryName); // only creates category if id didn't exist before;
m_sqliteBookmarkStorage.updateBookmark(bookmarkId, name, comment, categoryId);
@@ -229,7 +233,8 @@ std::vector<NodeBookmark> PersistentStorage::getAllNodeBookmarks() const
std::unordered_map<Id, std::vector<Id>> bookmarkIdToBookmarkedNodeIds;
for (const StorageBookmarkedNode& bookmarkedNode: m_sqliteBookmarkStorage.getAllBookmarkedNodes())
{
bookmarkIdToBookmarkedNodeIds[bookmarkedNode.bookmarkId].push_back(m_sqliteIndexStorage.getNodeBySerializedName(bookmarkedNode.serializedNodeName).id);
bookmarkIdToBookmarkedNodeIds[bookmarkedNode.bookmarkId].push_back(
m_sqliteIndexStorage.getNodeBySerializedName(bookmarkedNode.serializedNodeName).id);
}
std::vector<NodeBookmark> nodeBookmarks;
@@ -272,7 +277,12 @@ std::vector<EdgeBookmark> PersistentStorage::getAllEdgeBookmarks() const
std::vector<EdgeBookmark> edgeBookmarks;
Cache<std::string, Id> nodeIdCache([&](std::string serializedNodeName){ return m_sqliteIndexStorage.getNodeBySerializedName(serializedNodeName).id; });
Cache<std::string, Id> nodeIdCache([&](std::string serializedNodeName)
{
return m_sqliteIndexStorage.getNodeBySerializedName(serializedNodeName).id;
}
);
for (const StorageBookmark& storageBookmark: m_sqliteBookmarkStorage.getAllBookmarks())
{
auto itCategories = bookmarkCategories.find(storageBookmark.categoryId);
@@ -292,7 +302,8 @@ std::vector<EdgeBookmark> PersistentStorage::getAllEdgeBookmarks() const
{
const Id sourceNodeId = nodeIdCache.getValue(bookmarkedEdge.serializedSourceNodeName);
const Id targetNodeId = nodeIdCache.getValue(bookmarkedEdge.serializedTargetNodeName);
const Id edgeId = m_sqliteIndexStorage.getEdgeBySourceTargetType(sourceNodeId, targetNodeId, bookmarkedEdge.edgeType).id;
const Id edgeId =
m_sqliteIndexStorage.getEdgeBySourceTargetType(sourceNodeId, targetNodeId, bookmarkedEdge.edgeType).id;
bookmark.addEdgeId(edgeId);
if (activeNodeId == 0)
@@ -360,7 +371,8 @@ void PersistentStorage::forEachLocalSymbol(std::function<void(
}
}
void PersistentStorage::forEachSourceLocation(std::function<void(const Id /*id*/, const StorageSourceLocation& /*data*/)> callback) const
void PersistentStorage::forEachSourceLocation(
std::function<void(const Id /*id*/, const StorageSourceLocation& /*data*/)> callback) const
{
for (StorageSourceLocation& sourceLocation: m_sqliteIndexStorage.getAll<StorageSourceLocation>())
{
@@ -767,7 +779,8 @@ std::vector<SearchMatch> PersistentStorage::getAutocompletionMatches(const std::
return matches;
}
std::vector<SearchMatch> PersistentStorage::getAutocompletionSymbolMatches(const std::string& query, size_t maxResultsCount) const
std::vector<SearchMatch> PersistentStorage::getAutocompletionSymbolMatches(
const std::string& query, size_t maxResultsCount) const
{
// search in indices
std::vector<SearchResult> results = m_symbolIndex.search(query, maxResultsCount, maxResultsCount);
@@ -985,7 +998,8 @@ std::shared_ptr<Graph> PersistentStorage::getGraphForAll() const
return graph;
}
std::shared_ptr<Graph> PersistentStorage::getGraphForActiveTokenIds(const std::vector<Id>& tokenIds, bool* isActiveNamespace) const
std::shared_ptr<Graph> PersistentStorage::getGraphForActiveTokenIds(
const std::vector<Id>& tokenIds, bool* isActiveNamespace) const
{
TRACE();
@@ -1108,6 +1122,71 @@ std::shared_ptr<Graph> PersistentStorage::getGraphForActiveTokenIds(const std::v
return g;
}
std::shared_ptr<Graph> PersistentStorage::getGraphForTrail(
Id originId, Id targetId, Edge::EdgeTypeMask trailType, size_t depth) const
{
TRACE();
std::set<Id> nodeIds;
std::set<Id> edgeIds;
std::vector<Id> nodeIdsToProcess;
nodeIdsToProcess.push_back(originId ? originId : targetId);
bool forward = originId;
size_t currentDepth = 0;
nodeIds.insert(nodeIdsToProcess.back());
while (nodeIdsToProcess.size() && (!depth || currentDepth < depth))
{
std::vector<StorageEdge> edges =
forward ?
m_sqliteIndexStorage.getEdgesBySourceIds(nodeIdsToProcess) :
m_sqliteIndexStorage.getEdgesByTargetIds(nodeIdsToProcess);
if (trailType & (Edge::EDGE_OVERRIDE | Edge::EDGE_INHERITANCE))
{
utility::append(edges,
forward ?
m_sqliteIndexStorage.getEdgesByTargetIds(nodeIdsToProcess) :
m_sqliteIndexStorage.getEdgesBySourceIds(nodeIdsToProcess)
);
}
nodeIdsToProcess.clear();
for (const StorageEdge& edge : edges)
{
if (Edge::intToType(edge.type) & trailType)
{
bool isForward = forward == !(Edge::intToType(edge.type) & (Edge::EDGE_OVERRIDE | Edge::EDGE_INHERITANCE));
Id nodeId = isForward ? edge.targetNodeId : edge.sourceNodeId;
Id otherNodeId = isForward ? edge.sourceNodeId : edge.targetNodeId;
if (nodeIds.find(nodeId) == nodeIds.end())
{
nodeIdsToProcess.push_back(nodeId);
nodeIds.insert(nodeId);
edgeIds.insert(edge.id);
}
else if (nodeIds.find(otherNodeId) != nodeIds.end())
{
edgeIds.insert(edge.id);
}
}
}
currentDepth++;
}
std::shared_ptr<Graph> graph = std::make_shared<Graph>();
addNodesWithChildrenAndEdgesToGraph(utility::toVector(nodeIds), utility::toVector(edgeIds), graph.get());
addComponentAccessToGraph(graph.get());
return graph;
}
// TODO: rename: getActiveElementIdsForId; TODO: make separate function for declarationId
std::vector<Id> PersistentStorage::getActiveTokenIdsForId(Id tokenId, Id* declarationId) const
{
@@ -1506,7 +1585,8 @@ std::unordered_map<Id, std::set<Id>> PersistentStorage::getFileIdToImportingFile
importedSourceLocationToElementIds[occurrence.sourceLocationId] = occurrence.elementId;
}
for (const StorageSourceLocation& sourceLocation: m_sqliteIndexStorage.getAllByIds<StorageSourceLocation>(importedSourceLocationIds))
for (const StorageSourceLocation& sourceLocation:
m_sqliteIndexStorage.getAllByIds<StorageSourceLocation>(importedSourceLocationIds))
{
auto it = importedSourceLocationToElementIds.find(sourceLocation.id);
if (it != importedSourceLocationToElementIds.end())
@@ -1528,7 +1608,8 @@ std::unordered_map<Id, std::set<Id>> PersistentStorage::getFileIdToImportingFile
return fileIdToImportingFileIdMap;
}
std::set<Id> PersistentStorage::getReferenced(const std::set<Id>& ids, std::unordered_map<Id, std::set<Id>> idToReferencingIdMap) const
std::set<Id> PersistentStorage::getReferenced(
const std::set<Id>& ids, std::unordered_map<Id, std::set<Id>> idToReferencingIdMap) const
{
std::unordered_map<Id, std::set<Id>> idToReferencedIdMap;
for (auto it: idToReferencingIdMap)
@@ -1542,7 +1623,8 @@ std::set<Id> PersistentStorage::getReferenced(const std::set<Id>& ids, std::unor
return getReferencing(ids, idToReferencedIdMap);
}
std::set<Id> PersistentStorage::getReferencing(const std::set<Id>& ids, std::unordered_map<Id, std::set<Id>> idToReferencingIdMap) const
std::set<Id> PersistentStorage::getReferencing(
const std::set<Id>& ids, std::unordered_map<Id, std::set<Id>> idToReferencingIdMap) const
{
std::set<Id> referencingIds;
+1
View File
@@ -117,6 +117,7 @@ public:
virtual std::shared_ptr<Graph> getGraphForAll() const;
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds, bool* isActiveNamespace = nullptr) const;
virtual std::shared_ptr<Graph> getGraphForTrail(Id originId, Id targetId, Edge::EdgeTypeMask trailType, size_t depth) const;
virtual std::vector<Id> getActiveTokenIdsForId(Id tokenId, Id* declarationId) const;
virtual std::vector<Id> getNodeIdsForLocationIds(const std::vector<Id>& locationIds) const;
+1
View File
@@ -52,6 +52,7 @@ public:
virtual std::shared_ptr<Graph> getGraphForAll() const = 0;
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds, bool* isActiveNamespace = nullptr) const = 0;
virtual std::shared_ptr<Graph> getGraphForTrail(Id originId, Id targetId, Edge::EdgeTypeMask trailType, size_t depth) const = 0;
virtual std::vector<Id> getActiveTokenIdsForId(Id tokenId, Id* declarationId) const = 0;
virtual std::vector<Id> getNodeIdsForLocationIds(const std::vector<Id>& locationIds) const = 0;
@@ -184,6 +184,16 @@ std::shared_ptr<Graph> StorageAccessProxy::getGraphForActiveTokenIds(const std::
return std::make_shared<Graph>();
}
std::shared_ptr<Graph> StorageAccessProxy::getGraphForTrail(Id originId, Id targetId, Edge::EdgeTypeMask trailType, size_t depth) const
{
if (hasSubject())
{
return m_subject->getGraphForTrail(originId, targetId, trailType, depth);
}
return std::make_shared<Graph>();
}
std::vector<Id> StorageAccessProxy::getActiveTokenIdsForId(Id tokenId, Id* delcarationId) const
{
if (hasSubject())
+1
View File
@@ -40,6 +40,7 @@ public:
virtual std::shared_ptr<Graph> getGraphForAll() const;
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds, bool* isActiveNamespace = nullptr) const;
virtual std::shared_ptr<Graph> getGraphForTrail(Id originId, Id targetId, Edge::EdgeTypeMask trailType, size_t depth) const;
virtual std::vector<Id> getActiveTokenIdsForId(Id tokenId, Id* declarationId) const;
virtual std::vector<Id> getNodeIdsForLocationIds(const std::vector<Id>& locationIds) const;
+11
View File
@@ -3,6 +3,7 @@
#include "utility/logging/logging.h"
Graph::Graph()
: m_trailMode(TRAIL_NONE)
{
}
@@ -285,6 +286,16 @@ Token* Graph::getTokenById(Id id) const
return token;
}
Graph::TrailMode Graph::getTrailMode() const
{
return m_trailMode;
}
void Graph::setTrailMode(TrailMode trailMode)
{
m_trailMode = trailMode;
}
void Graph::print(std::ostream& ostream) const
{
ostream << "Graph:\n";
+12
View File
@@ -11,6 +11,13 @@
class Graph
{
public:
enum TrailMode
{
TRAIL_NONE,
TRAIL_HORIZONTAL,
TRAIL_VERTICAL
};
Graph();
virtual ~Graph();
@@ -49,6 +56,9 @@ public:
Token* getTokenById(Id id) const;
TrailMode getTrailMode() const;
void setTrailMode(TrailMode trailMode);
void print(std::ostream& ostream) const;
void printBasic(std::ostream& ostream) const;
@@ -60,6 +70,8 @@ private:
std::map<Id, std::shared_ptr<Node>> m_nodes;
std::map<Id, std::shared_ptr<Edge>> m_edges;
TrailMode m_trailMode;
};
std::ostream& operator<<(std::ostream& ostream, const Graph& graph);
@@ -0,0 +1,32 @@
#ifndef MESSAGE_ACTIVATE_TRAIL_H
#define MESSAGE_ACTIVATE_TRAIL_H
#include "utility/messaging/Message.h"
#include "utility/types.h"
class MessageActivateTrail
: public Message<MessageActivateTrail>
{
public:
MessageActivateTrail(Id originId, Id targetId, Edge::EdgeTypeMask trailType, size_t depth, bool horizontalLayout)
: originId(originId)
, targetId(targetId)
, trailType(trailType)
, depth(depth)
, horizontalLayout(horizontalLayout)
{
}
static const std::string getStaticType()
{
return "MessageActivateTrail";
}
const Id originId;
const Id targetId;
const Edge::EdgeTypeMask trailType;
const size_t depth;
const bool horizontalLayout;
};
#endif // MESSAGE_ACTIVATE_TRAIL_H