ui: graph view layouting and member rendering

Added simple layouting functions (implementations for simple grid and circle layout).
Also the graph displays class members and connections (edges) to or from them "correctly" now.

fortune cookie message = Your exotic ideas will lead you to many exciting new adventures.
This commit is contained in:
Manuel Dobusch
2014-07-15 16:40:52 +02:00
parent 61cb4afd91
commit ec42ef708d
24 changed files with 839 additions and 165 deletions
+228 -58
View File
@@ -1,5 +1,7 @@
#include "component/controller/GraphController.h"
#include <unordered_set>
#include "component/view/graphElements/GraphEdge.h"
#include "component/view/graphElements/GraphNode.h"
#include "component/view/GraphView.h"
@@ -18,67 +20,235 @@ GraphController::~GraphController()
void GraphController::handleMessage(MessageActivateToken* message)
{
GraphView* view = getView();
if (view != NULL)
{
std::string name = m_graphAccess->getNameForNodeWithId(message->tokenId);
std::vector<std::pair<Id, Id> > rawEdges = m_graphAccess->getConnectedEdges(message->tokenId);
std::vector<Id> neighbourIds = m_graphAccess->getIdsOfNeighbours(message->tokenId);
DummyNode node(name, message->tokenId, Vec2i(0,0));
std::vector<DummyNode> nodes;
nodes.push_back(node);
std::vector<DummyEdge> edges;
int offset = 20; // temporary
for(unsigned int i = 0; i < rawEdges.size(); i++)
{
edges.push_back(DummyEdge(rawEdges[i].first, rawEdges[i].second));
Id newId = 0;
if (rawEdges[i].first != message->tokenId)
{
name = m_graphAccess->getNameForNodeWithId(rawEdges[i].first);
newId = rawEdges[i].first;
}
else
{
name = m_graphAccess->getNameForNodeWithId(rawEdges[i].second);
newId = rawEdges[i].second;
}
nodes.push_back(DummyNode(name, newId, Vec2i(0, offset)));
offset += 20;
}
// find edges between neighbour nodes
for(unsigned int i = 1; i < nodes.size(); i++)
{
std::vector<std::pair<Id, Id>> newEdges = m_graphAccess->getConnectedEdges(nodes[i].tokenId);
for(unsigned int j = 0; j < newEdges.size(); j++)
{
if (std::find(neighbourIds.begin(), neighbourIds.end(), newEdges[j].first) != neighbourIds.end() &&
std::find(neighbourIds.begin(), neighbourIds.end(), newEdges[j].second) != neighbourIds.end())
{
DummyEdge newEdge(newEdges[j].first, newEdges[j].second);
if (std::find(edges.begin(), edges.end(), newEdge) == edges.end())
{
edges.push_back(newEdge);
}
}
}
}
view->rebuildGraph(nodes, edges);
}
createDummyGraph(message->tokenId, &GraphLayouter::layoutSimpleRing);
}
GraphView* GraphController::getView()
{
return Controller::getView<GraphView>();
}
void GraphController::createDummyGraph(const Id activeId, const LayoutFunction layoutFunction)
{
GraphView* view = getView();
if (view != NULL)
{
std::vector<DummyNode> nodes;
std::vector<DummyEdge> edges;
nodes.push_back(createDummyNode(activeId));
std::vector<DummyNode> neighbours = createNeighbourNodes(nodes[0]);
nodes.insert(nodes.end(), neighbours.begin(), neighbours.end());
layoutFunction(nodes);
edges = createEdges(nodes);
view->rebuildGraph(nodes, edges);
}
}
DummyNode GraphController::createDummyNode(const Id nodeId)
{
DummyNode result("invalid", 0, Vec2i());
Id topLevelId = findTopLevelNode(nodeId);
result = buildNodeTopDown(topLevelId);
return result;
}
Id GraphController::findTopLevelNode(const Id nodeId)
{
std::vector<std::pair<Id, Id>> memberEdges = m_graphAccess->getMemberEdgesOfNode(nodeId);
for(unsigned int i = 0; i < memberEdges.size(); i++)
{
if(memberEdges[i].first != nodeId)
{
return findTopLevelNode(memberEdges[i].first);
}
}
return nodeId;
}
DummyNode GraphController::buildNodeTopDown(const Id nodeId)
{
DummyNode result("invalid", 0, Vec2i());
result.name = m_graphAccess->getNameForNodeWithId(nodeId);
result.tokenId = nodeId;
std::vector<std::pair<Id, Id>> memberEdges = m_graphAccess->getMemberEdgesOfNode(nodeId);
for(unsigned int i = 0; i < memberEdges.size(); i++)
{
if(memberEdges[i].second != nodeId)
{
result.subNodes.push_back(buildNodeTopDown(memberEdges[i].second));
}
}
return result;
}
std::vector<DummyNode> GraphController::createNeighbourNodes(const Id nodeId)
{
std::vector<DummyNode> result;
std::vector<std::pair<Id, Id>> edges;
std::vector<std::pair<Id, Id>> callEdges = m_graphAccess->getCallEdgesOfNode(nodeId);
std::vector<std::pair<Id, Id>> usageEdges = m_graphAccess->getUsageEdgesOfNode(nodeId);
std::vector<std::pair<Id, Id>> typeOfEdges = m_graphAccess->getTypeOfEdgesOfNode(nodeId);
std::vector<std::pair<Id, Id>> returnTypeEdges = m_graphAccess->getReturnTypeOfEdgesOfNode(nodeId);
std::vector<std::pair<Id, Id>> parameterEdges = m_graphAccess->getParameterOfEdgesOfNode(nodeId);
if(callEdges.size() > 0)
{
edges.insert(edges.end(), callEdges.begin(), callEdges.end());
}
if(usageEdges.size() > 0)
{
edges.insert(edges.end(), usageEdges.begin(), usageEdges.end());
}
if(typeOfEdges.size() > 0)
{
edges.insert(edges.end(), typeOfEdges.begin(), typeOfEdges.end());
}
if(returnTypeEdges.size() > 0)
{
edges.insert(edges.end(), returnTypeEdges.begin(), returnTypeEdges.end());
}
if(parameterEdges.size() > 0)
{
edges.insert(edges.end(), parameterEdges.begin(), parameterEdges.end());
}
for(unsigned int i = 0; i < edges.size(); i++)
{
if(edges[i].first == nodeId)
{
result.push_back(createDummyNode(edges[i].second));
}
else
{
result.push_back(createDummyNode(edges[i].first));
}
}
return result;
}
std::vector<DummyNode> GraphController::createNeighbourNodes(const DummyNode& node)
{
std::vector<DummyNode> result;
std::set<DummyNode> tmpNodes; // to make it easier to keep the nodes unique
result = createNeighbourNodes(node.tokenId);
for(unsigned int i = 0; i < result.size(); i++)
{
tmpNodes.insert(result[i]);
}
for(unsigned int i = 0; i < node.subNodes.size(); i++)
{
std::vector<DummyNode> tmpNeighbours = createNeighbourNodes(node.subNodes[i].tokenId);
for(unsigned int j = 0; j < tmpNeighbours.size(); j++)
{
tmpNodes.insert(tmpNeighbours[j]);
}
}
result.clear();
std::set<DummyNode>::iterator it = tmpNodes.begin();
for(it; it != tmpNodes.end(); it++)
{
result.push_back(*it);
}
return result;
}
std::vector<DummyEdge> GraphController::createEdges(const std::vector<DummyNode>& nodes)
{
std::vector<DummyEdge> result;
std::unordered_set<Id> nodeIds; // to help discard edges that point to non-existing nodes in the sub-graph
for(unsigned int i = 0; i < nodes.size(); i++)
{
nodeIds.insert(nodes[i].tokenId);
}
std::set<DummyEdge> tmpEdges; // to make it easier to keep the edges unique
for(unsigned int i = 0; i < nodes.size(); i++)
{
std::set<DummyEdge> tmp = getNeighbourEdgesOfNode(nodes[i]);
std::set<DummyEdge>::iterator it = tmp.begin();
for(it; it != tmp.end(); it++)
{
if(nodeIds.find(it->ownerId) != nodeIds.end() && nodeIds.find(it->targetId) != nodeIds.end())
{
tmpEdges.insert(tmp.begin(), tmp.end());
}
}
}
std::set<DummyEdge>::iterator it = tmpEdges.begin();
for(it; it != tmpEdges.end(); it++)
{
result.push_back(*it);
}
return result;
}
std::set<DummyEdge> GraphController::getNeighbourEdgesOfNode(const DummyNode& node)
{
std::set<DummyEdge> result;
std::vector<std::pair<Id, Id>> rawEdges;
std::vector<std::pair<Id, Id>> callEdges = m_graphAccess->getCallEdgesOfNode(node.tokenId);
std::vector<std::pair<Id, Id>> usageEdges = m_graphAccess->getUsageEdgesOfNode(node.tokenId);
std::vector<std::pair<Id, Id>> typeOfEdges = m_graphAccess->getTypeOfEdgesOfNode(node.tokenId);
std::vector<std::pair<Id, Id>> returnTypeEdges = m_graphAccess->getReturnTypeOfEdgesOfNode(node.tokenId);
std::vector<std::pair<Id, Id>> parameterEdges = m_graphAccess->getParameterOfEdgesOfNode(node.tokenId);
if(callEdges.size() > 0)
{
rawEdges.insert(rawEdges.end(), callEdges.begin(), callEdges.end());
}
if(usageEdges.size() > 0)
{
rawEdges.insert(rawEdges.end(), usageEdges.begin(), usageEdges.end());
}
if(typeOfEdges.size() > 0)
{
rawEdges.insert(rawEdges.end(), typeOfEdges.begin(), typeOfEdges.end());
}
if(returnTypeEdges.size() > 0)
{
rawEdges.insert(rawEdges.end(), returnTypeEdges.begin(), returnTypeEdges.end());
}
if(parameterEdges.size() > 0)
{
rawEdges.insert(rawEdges.end(), parameterEdges.begin(), parameterEdges.end());
}
for(unsigned int i = 0; i < rawEdges.size(); i++)
{
result.insert(DummyEdge(rawEdges[i].first, rawEdges[i].second));
}
for(unsigned int i = 0; i < node.subNodes.size(); i++)
{
std::set<DummyEdge> tmpNeighbours = getNeighbourEdgesOfNode(node.subNodes[i]);
result.insert(tmpNeighbours.begin(), tmpNeighbours.end());
}
return result;
}