From ec42ef708d586b4fe5f0458402fd4275cb550899 Mon Sep 17 00:00:00 2001 From: Manuel Dobusch Date: Tue, 15 Jul 2014 16:40:52 +0200 Subject: [PATCH] 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. --- bin/app/data/src/header.h | 67 +++- bin/app/data/src/main.cpp | 9 + src/app/CMakeLists.txt | 4 +- src/app/qt/view/QtGraphView.cpp | 128 +++++++- src/app/qt/view/QtGraphView.h | 10 +- src/app/qt/view/graphElements/QtGraphNode.cpp | 62 +++- src/app/qt/view/graphElements/QtGraphNode.h | 10 +- .../graphElements/QtGraphNodeMouseMovable.cpp | 29 ++ .../graphElements/QtGraphNodeMouseMovable.h | 19 ++ .../view/graphElements/QtGraphNodeMovable.cpp | 48 --- .../view/graphElements/QtGraphNodeMovable.h | 19 -- src/lib/CMakeLists.txt | 2 + .../component/controller/GraphController.cpp | 286 ++++++++++++++---- .../component/controller/GraphController.h | 17 ++ .../component/controller/GraphLayouter.cpp | 48 +++ src/lib/component/controller/GraphLayouter.h | 17 ++ .../component/view/graphElements/GraphEdge.h | 24 +- .../view/graphElements/GraphNode.cpp | 2 +- .../component/view/graphElements/GraphNode.h | 54 +++- src/lib/data/Storage.cpp | 58 +++- src/lib/data/Storage.h | 10 +- src/lib/data/access/GraphAccess.h | 9 +- src/lib/data/access/GraphAccessProxy.cpp | 64 +++- src/lib/data/access/GraphAccessProxy.h | 8 +- 24 files changed, 839 insertions(+), 165 deletions(-) create mode 100644 src/app/qt/view/graphElements/QtGraphNodeMouseMovable.cpp create mode 100644 src/app/qt/view/graphElements/QtGraphNodeMouseMovable.h delete mode 100644 src/app/qt/view/graphElements/QtGraphNodeMovable.cpp delete mode 100644 src/app/qt/view/graphElements/QtGraphNodeMovable.h create mode 100644 src/lib/component/controller/GraphLayouter.cpp create mode 100644 src/lib/component/controller/GraphLayouter.h diff --git a/bin/app/data/src/header.h b/bin/app/data/src/header.h index b14f1759..bd6cb688 100644 --- a/bin/app/data/src/header.h +++ b/bin/app/data/src/header.h @@ -13,10 +13,6 @@ y fooy(); z fooz(); */ -class A {}; -class B : public A {}; -typedef A* C; - const bool *ab(int a, int b); bool const *abc(int a, int b); @@ -27,3 +23,66 @@ int main(); void foo(); int sum(int a, int b); int diff(int a, int b); + +void funk(); + +class A +{ +public: + A() + : m_importantValue(42) + , m_importanterValue('r') + , m_importantestValue(3.14159265359f) + { + } + + ~A() + { + } + + void doImportantStuff() + { + m_importantValue *= 1; + } + + void doModeratelyImportantStuff() + { + m_importanterValue = 'R'; + + sum(21, 21); + } + +private: + int m_importantValue; + char m_importanterValue; + float m_importantestValue; +}; + +class B : public A {}; + +class C +{ +public: + C() + : m_valuable(0) + { + } + + ~C() + { + } + + void solveAllProblems() + { + A aInstance; + aInstance.doImportantStuff(); + aInstance.doModeratelyImportantStuff(); + } + +private: + int m_valuable; +}; + +A globalA; + +typedef A* C; diff --git a/bin/app/data/src/main.cpp b/bin/app/data/src/main.cpp index 0dd91d90..c122ff93 100644 --- a/bin/app/data/src/main.cpp +++ b/bin/app/data/src/main.cpp @@ -7,6 +7,9 @@ int diff(int a, int b); int main() { + A aInstance; + aInstance.doImportantStuff(); + int a = sum(1, 2); int b = diff(a, 3); int c = a * b; @@ -33,3 +36,9 @@ int diff(int a, int b) { return a - b; } + +void funk() +{ + A aInstance; + aInstance.doModeratelyImportantStuff(); +} diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 6a49ccad..872ec856 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -22,8 +22,8 @@ add_files( qt/view/graphElements/QtGraphEdge.h qt/view/graphElements/QtGraphNode.cpp qt/view/graphElements/QtGraphNode.h - qt/view/graphElements/QtGraphNodeMovable.cpp - qt/view/graphElements/QtGraphNodeMovable.h + qt/view/graphElements/QtGraphNodeMouseMovable.cpp + qt/view/graphElements/QtGraphNodeMouseMovable.h qt/view/QtCodeView.cpp qt/view/QtCodeView.h diff --git a/src/app/qt/view/QtGraphView.cpp b/src/app/qt/view/QtGraphView.cpp index 647afb68..0ea56f71 100644 --- a/src/app/qt/view/QtGraphView.cpp +++ b/src/app/qt/view/QtGraphView.cpp @@ -12,7 +12,7 @@ #include "qt/QtWidgetWrapper.h" #include "qt/view/graphElements/QtGraphEdge.h" #include "qt/view/graphElements/QtGraphNode.h" -#include "qt/view/graphElements/QtGraphNodeMovable.h" +#include "qt/view/graphElements/QtGraphNodeMouseMovable.h" QtGraphView::QtGraphView(ViewLayout* viewLayout) : GraphView(viewLayout) @@ -83,6 +83,7 @@ void QtGraphView::doRebuildGraph(const std::vector& nodes, const std: for(unsigned int i = 0; i < nodes.size(); i++) { std::shared_ptr newNode = findOrCreateNode(view, nodes[i]); + newNode->setPosition(nodes[i].position); newNodes.push_back(newNode); weakNodes[nodes[i].tokenId] = newNode; } @@ -90,8 +91,17 @@ void QtGraphView::doRebuildGraph(const std::vector& nodes, const std: doClear(); m_nodes = newNodes; - // create edges for(unsigned int i = 0; i < edges.size(); i++) + { + std::shared_ptr edge = createEdge(view, edges[i]); + if(edge != NULL) + { + m_edges.push_back(edge); + } + } + + // create edges + /*for(unsigned int i = 0; i < edges.size(); i++) { if (weakNodes.find(edges[i].ownerId) != weakNodes.end() && weakNodes.find(edges[i].targetId) != weakNodes.end()) { @@ -106,7 +116,7 @@ void QtGraphView::doRebuildGraph(const std::vector& nodes, const std: } } } - } + }*/ } else { @@ -124,7 +134,7 @@ std::shared_ptr QtGraphView::findOrCreateNode(QGraphicsView* view, co { std::shared_ptr result; - result = findNode(node); + result = findNode(node.tokenId); if(result == NULL) { @@ -134,41 +144,131 @@ std::shared_ptr QtGraphView::findOrCreateNode(QGraphicsView* view, co return result; } -std::shared_ptr QtGraphView::findNode(const DummyNode& node) +std::shared_ptr QtGraphView::findNode(const Id id) { std::list>::iterator it = m_nodes.begin(); for(it; it != m_nodes.end(); it++) { - if((*it)->getTokenId() == node.tokenId) + if((*it)->getTokenId() == id) { return *it; } + else + { + std::shared_ptr result = findSubNode(*it, id); + if(result != NULL) + { + return result; + } + } } - return NULL; + return std::shared_ptr(); +} + +std::shared_ptr QtGraphView::findSubNode(const std::shared_ptr node, const Id id) +{ + std::list> subNodes = node->getSubNodes(); + + std::list>::iterator it = subNodes.begin(); + for(it; it != subNodes.end(); it++) + { + if((*it)->getTokenId() == id) + { + return *it; + } + else + { + std::shared_ptr result = findSubNode(*it, id); + if(result != NULL) + { + return result; + } + } + } + + return std::shared_ptr(); } std::shared_ptr QtGraphView::createNode(QGraphicsView* view, const DummyNode& node) { if(view != NULL) { - std::shared_ptr newNode = std::make_shared(node.position, node.name, node.tokenId); + std::shared_ptr newNode = std::make_shared(Vec2i(0, 0), node.name, node.tokenId); view->scene()->addItem(newNode.get()); m_nodes.push_back(newNode); - // create debug sub node - std::shared_ptr subNode = std::make_shared(Vec2i(10, 30), node.name + " member", 666); - subNode->setParentItem(newNode.get()); - view->scene()->addItem(subNode.get()); - newNode->addSubNode(subNode); + for(unsigned int i = 0; i < node.subNodes.size(); i++) + { + std::shared_ptr subNode = createSubNode(view, node.subNodes[i]); + subNode->setParentItem(newNode.get()); + newNode->addSubNode(subNode); + subNode->setRect(0, 0, 80, 20); + subNode->moveBy(10, (i+1)*30); + } - subNode->setRect(0, 0, 80, 20); + newNode->setRect(0, 0, 100, 40 + (node.subNodes.size() * 30)); return newNode; } else { LOG_WARNING("Received pointer to QGraphicsView was NULL. No node created."); + return std::shared_ptr(); + } +} + +std::shared_ptr QtGraphView::createSubNode(QGraphicsView* view, const DummyNode& node) +{ + if(view != NULL) + { + std::shared_ptr newNode = std::make_shared(Vec2i(0, 0), node.name, node.tokenId); + view->scene()->addItem(newNode.get()); + + for(unsigned int i = 0; i < node.subNodes.size(); i++) + { + std::shared_ptr subNode = createSubNode(view, node.subNodes[i]); + subNode->setParentItem(newNode.get()); + newNode->addSubNode(subNode); + subNode->setRect(0, 0, 80, 20); + subNode->moveBy(10, (i+1)*30); + } + + return newNode; + } + else + { + LOG_WARNING("Received pointer to QGraphicsView was NULL. No node created."); + return std::shared_ptr(); + } +} + +std::shared_ptr QtGraphView::createEdge(QGraphicsView* view, const DummyEdge& edge) +{ + if(view != NULL) + { + std::shared_ptr owner = findNode(edge.ownerId); + std::shared_ptr target = findNode(edge.targetId); + + if(owner != NULL && target != NULL) + { + std::shared_ptr edge = std::make_shared(owner, target); + owner->addOutEdge(edge); + target->addInEdge(edge); + view->scene()->addItem(edge.get()); + + return edge; + } + else + { + LOG_WARNING("Couldn't find owner or target node."); + return std::shared_ptr(); + } + } + else + { + LOG_WARNING("Received pointer to QGraphicsView was NULL. No node created."); + return std::shared_ptr(); } } diff --git a/src/app/qt/view/QtGraphView.h b/src/app/qt/view/QtGraphView.h index 9c94f402..d07d2319 100644 --- a/src/app/qt/view/QtGraphView.h +++ b/src/app/qt/view/QtGraphView.h @@ -3,11 +3,15 @@ #include "qt/utility/QtThreadedFunctor.h" +#include "utility/types.h" + #include "component/view/GraphView.h" struct DummyEdge; struct DummyNode; class QGraphicsView; +class QtGraphEdge; +class QtGraphNode; class QtGraphView : public GraphView { @@ -30,8 +34,12 @@ private: void doClear(); std::shared_ptr findOrCreateNode(QGraphicsView* view, const DummyNode& node); - std::shared_ptr findNode(const DummyNode& node); + std::shared_ptr findNode(const Id id); + std::shared_ptr findSubNode(const std::shared_ptr node, const Id id); std::shared_ptr createNode(QGraphicsView* view, const DummyNode& node); + std::shared_ptr createSubNode(QGraphicsView* view, const DummyNode& node); + + std::shared_ptr createEdge(QGraphicsView* view, const DummyEdge& edge); QtThreadedFunctor&, const std::vector&> m_rebuildGraph; QtThreadedFunctor m_clear; diff --git a/src/app/qt/view/graphElements/QtGraphNode.cpp b/src/app/qt/view/graphElements/QtGraphNode.cpp index 621ed802..3935b0ef 100644 --- a/src/app/qt/view/graphElements/QtGraphNode.cpp +++ b/src/app/qt/view/graphElements/QtGraphNode.cpp @@ -1,5 +1,7 @@ #include "qt/view/graphElements/QtGraphNode.h" +#include + #include "qgraphicsscene.h" #include "qgraphicssceneevent.h" @@ -15,7 +17,9 @@ QtGraphNode::QtGraphNode(const Vec2i& position, const std::string& name, const I m_text = new QGraphicsTextItem(this); m_text->setPos(0, 0); - m_text->setPlainText(QString(name.c_str())); + std::stringstream text; + text << m_tokenId << " -> " << name; + m_text->setPlainText(QString(text.str().c_str())); } QtGraphNode::~QtGraphNode() @@ -31,16 +35,28 @@ QtGraphNode::~QtGraphNode() } } -std::string QtGraphNode::getName() +std::string QtGraphNode::getName() const { return m_text->toPlainText().toStdString(); } -Vec2i QtGraphNode::getPosition() +Vec2i QtGraphNode::getPosition() const { return Vec2i(this->scenePos().x(), this->scenePos().y()); } +void QtGraphNode::setPosition(const Vec2i& position) +{ + Vec2i currentPosition = getPosition(); + Vec2i offset = position - currentPosition; + + if(offset.getLength() > 0.0f) + { + this->moveBy(offset.x, offset.y); + notifyEdgesAfterMove(); + } +} + bool QtGraphNode::addOutEdge(const std::shared_ptr& edge) { std::list >::iterator it = m_outEdges.begin(); @@ -91,6 +107,11 @@ void QtGraphNode::removeOutEdge(GraphEdge* edge) } } +std::list > QtGraphNode::getSubNodes() const +{ + return m_subNodes; +} + void QtGraphNode::addSubNode(const std::shared_ptr& node) { m_subNodes.push_back(node); @@ -101,3 +122,38 @@ void QtGraphNode::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) MessageActivateToken message(m_tokenId); message.dispatch(); } + +void QtGraphNode::notifyParentMoved() +{ + notifyEdgesAfterMove(); +} + +void QtGraphNode::notifyEdgesAfterMove() +{ + std::list >::iterator it = m_outEdges.begin(); + for(it; it != m_outEdges.end(); it++) + { + (*it)->ownerMoved(); + } + + std::list >::iterator it2 = m_inEdges.begin(); + while(it2 != m_inEdges.end()) + { + std::shared_ptr edge = it2->lock(); + if(edge.get() != NULL) + { + edge->targetMoved(); + ++it2; + } + else + { + m_inEdges.erase(it2++); + } + } + + std::list >::iterator it3 = m_subNodes.begin(); + for(it3; it3 != m_subNodes.end(); it3++) + { + (*it3)->notifyParentMoved(); + } +} diff --git a/src/app/qt/view/graphElements/QtGraphNode.h b/src/app/qt/view/graphElements/QtGraphNode.h index da8e5e03..bbde5eed 100644 --- a/src/app/qt/view/graphElements/QtGraphNode.h +++ b/src/app/qt/view/graphElements/QtGraphNode.h @@ -18,19 +18,25 @@ public: QtGraphNode(const Vec2i& position, const std::string& name, const Id tokenId); virtual ~QtGraphNode(); - virtual std::string getName(); - virtual Vec2i getPosition(); + virtual std::string getName() const; + virtual Vec2i getPosition() const; + virtual void setPosition(const Vec2i& position); virtual bool addOutEdge(const std::shared_ptr& edge); virtual bool addInEdge(const std::weak_ptr& edge); virtual void removeOutEdge(GraphEdge* edge); + virtual std::list > getSubNodes() const; virtual void addSubNode(const std::shared_ptr& node); void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event); + virtual void notifyParentMoved(); + protected: + void notifyEdgesAfterMove(); + std::list > m_outEdges; std::list > m_inEdges; diff --git a/src/app/qt/view/graphElements/QtGraphNodeMouseMovable.cpp b/src/app/qt/view/graphElements/QtGraphNodeMouseMovable.cpp new file mode 100644 index 00000000..c0f6f319 --- /dev/null +++ b/src/app/qt/view/graphElements/QtGraphNodeMouseMovable.cpp @@ -0,0 +1,29 @@ +#include "qt/view/graphElements/QtGraphNodeMouseMovable.h" + +#include "qgraphicssceneevent.h" + +#include "qt/view/graphElements/QtGraphEdge.h" + +QtGraphNodeMouseMovable::QtGraphNodeMouseMovable(const Vec2i& position, const std::string& name, const Id tokenId) + : QtGraphNode(position, name, tokenId) +{ +} + +QtGraphNodeMouseMovable::~QtGraphNodeMouseMovable() +{ +} + +void QtGraphNodeMouseMovable::mousePressEvent(QGraphicsSceneMouseEvent* event) +{ + m_mouseOffset.x = event->pos().x(); + m_mouseOffset.y = event->pos().y(); +} + +void QtGraphNodeMouseMovable::mouseMoveEvent(QGraphicsSceneMouseEvent* event) +{ + this->setPos(event->scenePos().x() - m_mouseOffset.x, event->scenePos().y() - m_mouseOffset.y); + + Vec2i p(event->scenePos().x(), event->scenePos().y()); + + notifyEdgesAfterMove(); +} \ No newline at end of file diff --git a/src/app/qt/view/graphElements/QtGraphNodeMouseMovable.h b/src/app/qt/view/graphElements/QtGraphNodeMouseMovable.h new file mode 100644 index 00000000..40d9011e --- /dev/null +++ b/src/app/qt/view/graphElements/QtGraphNodeMouseMovable.h @@ -0,0 +1,19 @@ +#ifndef QT_GRAPH_NODE_MOUSE_MOVABLE_H +#define QT_GRAPH_NODE_MOUSE_MOVABLE_H + +#include "qt/view/graphElements/QtGraphNode.h" + +class QtGraphNodeMouseMovable : public QtGraphNode +{ +public: + QtGraphNodeMouseMovable(const Vec2i& position, const std::string& name, const Id tokenId); + virtual ~QtGraphNodeMouseMovable(); + + void mousePressEvent(QGraphicsSceneMouseEvent* event); + void mouseMoveEvent(QGraphicsSceneMouseEvent* event); + +private: + Vec2i m_mouseOffset; +}; + +#endif // QT_GRAPH_NODE_MOUSE_MOVABLE_H \ No newline at end of file diff --git a/src/app/qt/view/graphElements/QtGraphNodeMovable.cpp b/src/app/qt/view/graphElements/QtGraphNodeMovable.cpp deleted file mode 100644 index f01250a7..00000000 --- a/src/app/qt/view/graphElements/QtGraphNodeMovable.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "qt/view/graphElements/QtGraphNodeMovable.h" - -#include "qgraphicssceneevent.h" - -#include "qt/view/graphElements/QtGraphEdge.h" - -QtGraphNodeMovable::QtGraphNodeMovable(const Vec2i& position, const std::string& name, const Id tokenId) - : QtGraphNode(position, name, tokenId) -{ -} - -QtGraphNodeMovable::~QtGraphNodeMovable() -{ -} - -void QtGraphNodeMovable::mousePressEvent(QGraphicsSceneMouseEvent* event) -{ - m_mouseOffset.x = event->pos().x(); - m_mouseOffset.y = event->pos().y(); -} - -void QtGraphNodeMovable::mouseMoveEvent(QGraphicsSceneMouseEvent* event) -{ - this->setPos(event->scenePos().x() - m_mouseOffset.x, event->scenePos().y() - m_mouseOffset.y); - - Vec2i p(event->scenePos().x(), event->scenePos().y()); - - std::list >::iterator it = m_outEdges.begin(); - for(it; it != m_outEdges.end(); it++) - { - (*it)->ownerMoved(); - } - - std::list >::iterator it2 = m_inEdges.begin(); - while(it2 != m_inEdges.end()) - { - std::shared_ptr edge = it2->lock(); - if(edge.get() != NULL) - { - edge->targetMoved(); - ++it2; - } - else - { - m_inEdges.erase(it2++); - } - } -} \ No newline at end of file diff --git a/src/app/qt/view/graphElements/QtGraphNodeMovable.h b/src/app/qt/view/graphElements/QtGraphNodeMovable.h deleted file mode 100644 index 97ce2f2c..00000000 --- a/src/app/qt/view/graphElements/QtGraphNodeMovable.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef QT_GRAPH_NODE_MOVABLE_H -#define QT_GRAPH_NODE_MOVABLE_H - -#include "qt/view/graphElements/QtGraphNode.h" - -class QtGraphNodeMovable : public QtGraphNode -{ -public: - QtGraphNodeMovable(const Vec2i& position, const std::string& name, const Id tokenId); - virtual ~QtGraphNodeMovable(); - - void mousePressEvent(QGraphicsSceneMouseEvent* event); - void mouseMoveEvent(QGraphicsSceneMouseEvent* event); - -private: - Vec2i m_mouseOffset; -}; - -#endif // QT_GRAPH_NODE_MOVABLE_H \ No newline at end of file diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 7c7ced5d..9048d9db 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -28,6 +28,8 @@ add_files( component/controller/Controller.h component/controller/GraphController.cpp component/controller/GraphController.h + component/controller/GraphLayouter.cpp + component/controller/GraphLayouter.h component/controller/SearchController.cpp component/controller/SearchController.h diff --git a/src/lib/component/controller/GraphController.cpp b/src/lib/component/controller/GraphController.cpp index 829a59dc..fb80678d 100644 --- a/src/lib/component/controller/GraphController.cpp +++ b/src/lib/component/controller/GraphController.cpp @@ -1,5 +1,7 @@ #include "component/controller/GraphController.h" +#include + #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 > rawEdges = m_graphAccess->getConnectedEdges(message->tokenId); - std::vector neighbourIds = m_graphAccess->getIdsOfNeighbours(message->tokenId); - - DummyNode node(name, message->tokenId, Vec2i(0,0)); - - std::vector nodes; - nodes.push_back(node); - - std::vector 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> 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(); } + +void GraphController::createDummyGraph(const Id activeId, const LayoutFunction layoutFunction) +{ + GraphView* view = getView(); + if (view != NULL) + { + std::vector nodes; + std::vector edges; + + nodes.push_back(createDummyNode(activeId)); + + std::vector 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> 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> 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 GraphController::createNeighbourNodes(const Id nodeId) +{ + std::vector result; + + std::vector> edges; + std::vector> callEdges = m_graphAccess->getCallEdgesOfNode(nodeId); + std::vector> usageEdges = m_graphAccess->getUsageEdgesOfNode(nodeId); + std::vector> typeOfEdges = m_graphAccess->getTypeOfEdgesOfNode(nodeId); + std::vector> returnTypeEdges = m_graphAccess->getReturnTypeOfEdgesOfNode(nodeId); + std::vector> 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 GraphController::createNeighbourNodes(const DummyNode& node) +{ + std::vector result; + + std::set 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 tmpNeighbours = createNeighbourNodes(node.subNodes[i].tokenId); + for(unsigned int j = 0; j < tmpNeighbours.size(); j++) + { + tmpNodes.insert(tmpNeighbours[j]); + } + } + + result.clear(); + std::set::iterator it = tmpNodes.begin(); + for(it; it != tmpNodes.end(); it++) + { + result.push_back(*it); + } + + return result; +} + +std::vector GraphController::createEdges(const std::vector& nodes) +{ + std::vector result; + + std::unordered_set 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 tmpEdges; // to make it easier to keep the edges unique + for(unsigned int i = 0; i < nodes.size(); i++) + { + std::set tmp = getNeighbourEdgesOfNode(nodes[i]); + + std::set::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::iterator it = tmpEdges.begin(); + for(it; it != tmpEdges.end(); it++) + { + result.push_back(*it); + } + + return result; +} + +std::set GraphController::getNeighbourEdgesOfNode(const DummyNode& node) +{ + std::set result; + + std::vector> rawEdges; + std::vector> callEdges = m_graphAccess->getCallEdgesOfNode(node.tokenId); + std::vector> usageEdges = m_graphAccess->getUsageEdgesOfNode(node.tokenId); + std::vector> typeOfEdges = m_graphAccess->getTypeOfEdgesOfNode(node.tokenId); + std::vector> returnTypeEdges = m_graphAccess->getReturnTypeOfEdgesOfNode(node.tokenId); + std::vector> 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 tmpNeighbours = getNeighbourEdgesOfNode(node.subNodes[i]); + result.insert(tmpNeighbours.begin(), tmpNeighbours.end()); + } + + return result; +} diff --git a/src/lib/component/controller/GraphController.h b/src/lib/component/controller/GraphController.h index a0a01a01..17e4f999 100644 --- a/src/lib/component/controller/GraphController.h +++ b/src/lib/component/controller/GraphController.h @@ -1,11 +1,17 @@ #ifndef GRAPH_CONTROLLER_H #define GRAPH_CONTROLLER_H +#include +#include + #include "utility/messaging/MessageListener.h" #include "utility/messaging/type/MessageActivateToken.h" #include "component/controller/Controller.h" +#include "component/controller/GraphLayouter.h" +struct DummyNode; +struct DummyEdge; class GraphView; class GraphAccess; @@ -20,6 +26,17 @@ public: private: virtual void handleMessage(MessageActivateToken* message); GraphView* getView(); + void createDummyGraph(const Id activeId, const LayoutFunction layoutFunction); + + DummyNode createDummyNode(const Id nodeId); + Id findTopLevelNode(const Id nodeId); + DummyNode buildNodeTopDown(const Id nodeId); + + std::vector createNeighbourNodes(const Id nodeId); + std::vector createNeighbourNodes(const DummyNode& node); + + std::vector createEdges(const std::vector& nodes); + std::set getNeighbourEdgesOfNode(const DummyNode& node); GraphAccess* m_graphAccess; }; diff --git a/src/lib/component/controller/GraphLayouter.cpp b/src/lib/component/controller/GraphLayouter.cpp new file mode 100644 index 00000000..578f0dc7 --- /dev/null +++ b/src/lib/component/controller/GraphLayouter.cpp @@ -0,0 +1,48 @@ +#include "component/controller/GraphLayouter.h" + +#include "component/view/graphElements/GraphNode.h" + +void GraphLayouter::layoutSimpleRaster(std::vector& nodes) +{ + int x = 0; + int y = 0; + int offset = 150; + + for(unsigned int i = 0; i < nodes.size(); i++) + { + nodes[i].position = Vec2i(x, y); + + if(x > 0) + { + y += offset; + x = 0; + } + else + { + x += offset; + } + } +} + +void GraphLayouter::layoutSimpleRing(std::vector& nodes) +{ + if(nodes.size() >= 1) + { + nodes[0].position = Vec2i(0, 0); + + if(nodes.size() > 1) + { + int offset = 150; + + for(unsigned int i = 1; i < nodes.size(); i++) + { + float rad = ((2.0f*3.14159265359f) / float(nodes.size()-1)) * i-1; + + int x = (int)((float)offset * std::cos(rad)); + int y = (int)((float)offset * std::sin(rad)); + + nodes[i].position = Vec2i(x, y); + } + } + } +} diff --git a/src/lib/component/controller/GraphLayouter.h b/src/lib/component/controller/GraphLayouter.h new file mode 100644 index 00000000..58e5a284 --- /dev/null +++ b/src/lib/component/controller/GraphLayouter.h @@ -0,0 +1,17 @@ +#ifndef GRAPH_LAYOUTER_H +#define GRAPH_LAYOUTER_H + +#include + +class DummyNode; + +typedef void (*LayoutFunction)(std::vector&); + +class GraphLayouter +{ +public: + static void layoutSimpleRaster(std::vector& nodes); + static void layoutSimpleRing(std::vector& nodes); +}; + +#endif // GRAPH_LAYOUTER_H \ No newline at end of file diff --git a/src/lib/component/view/graphElements/GraphEdge.h b/src/lib/component/view/graphElements/GraphEdge.h index 246caf2d..7598bbc4 100644 --- a/src/lib/component/view/graphElements/GraphEdge.h +++ b/src/lib/component/view/graphElements/GraphEdge.h @@ -32,9 +32,6 @@ public: { } - Id ownerId; - Id targetId; - bool operator==(const DummyEdge& other) const { if(ownerId == other.ownerId && targetId == other.targetId) @@ -48,6 +45,27 @@ public: { return !(*this == other); } + + bool operator<(const DummyEdge& other) const + { + if(ownerId < other.ownerId ) + { + return true; + } + else if(ownerId == other.ownerId) + { + return (targetId < other.targetId); + } + return false; + } + + bool operator>(const DummyEdge& other) const + { + return !(*this < other); + } + + Id ownerId; + Id targetId; }; #endif // GRAPH_EDGE_H \ No newline at end of file diff --git a/src/lib/component/view/graphElements/GraphNode.cpp b/src/lib/component/view/graphElements/GraphNode.cpp index bcc33ded..437aef97 100644 --- a/src/lib/component/view/graphElements/GraphNode.cpp +++ b/src/lib/component/view/graphElements/GraphNode.cpp @@ -9,7 +9,7 @@ GraphNode::~GraphNode() { } -Id GraphNode::getTokenId() +Id GraphNode::getTokenId() const { return m_tokenId; } diff --git a/src/lib/component/view/graphElements/GraphNode.h b/src/lib/component/view/graphElements/GraphNode.h index ed70c4a7..9281579b 100644 --- a/src/lib/component/view/graphElements/GraphNode.h +++ b/src/lib/component/view/graphElements/GraphNode.h @@ -1,6 +1,7 @@ #ifndef GRAPH_NODE_H #define GRAPH_NODE_H +#include #include #include "utility/math/Vector2.h" @@ -14,17 +15,21 @@ public: GraphNode(const Id tokenId); virtual ~GraphNode(); - virtual std::string getName() = 0; - Id getTokenId(); - virtual Vec2i getPosition() = 0; + virtual std::string getName() const = 0; + Id getTokenId() const; + virtual Vec2i getPosition() const = 0; + virtual void setPosition(const Vec2i& position) = 0; virtual bool addOutEdge(const std::shared_ptr& edge) = 0; virtual bool addInEdge(const std::weak_ptr& edge) = 0; virtual void removeOutEdge(GraphEdge* edge) = 0; + virtual std::list > getSubNodes() const = 0; virtual void addSubNode(const std::shared_ptr& node) = 0; + virtual void notifyParentMoved() = 0; + protected: Id m_tokenId; }; @@ -36,13 +41,56 @@ public: : name(n) , tokenId(tId) , position(p) + , subNodes() + , actualNode() { } + bool operator==(const DummyNode& other) const + { + if(tokenId == other.tokenId + && name == other.name + && position == position) + { + return true; + } + return false; + } + + bool operator!=(const DummyNode& other) const + { + return !(*this == other); + } + + bool operator<(const DummyNode& other) const + { + if(tokenId < other.tokenId) + { + return true; + } + return false; + } + + bool operator>(const DummyNode& other) const + { + return !(*this < other); + } + + void operator=(DummyNode& other) + { + name = other.name; + tokenId = other.tokenId; + position = other.position; + subNodes = other.subNodes; + actualNode = other.actualNode; + } + std::string name; Id tokenId; Vec2i position; + std::vector subNodes; + std::weak_ptr actualNode; }; diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 80cc1bf5..c54c2551 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -289,7 +289,7 @@ std::vector Storage::getIdsOfNeighbours(const Id id) const return result; } -std::vector> Storage::getConnectedEdges(const Id id) const +std::vector> Storage::getNeighbourEdgesOfNode(const Id id) const { std::vector> result; @@ -300,7 +300,7 @@ std::vector> Storage::getConnectedEdges(const Id id) const if (node != NULL) { node->forEachEdge( - [&result, &id](Edge* e) + [&result](Edge* e) { result.push_back(std::pair(e->getFrom()->getId(), e->getTo()->getId())); } @@ -310,6 +310,36 @@ std::vector> Storage::getConnectedEdges(const Id id) const return result; } +std::vector> Storage::getMemberEdgesOfNode(const Id id) const +{ + return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_MEMBER); +} + +std::vector> Storage::getUsageEdgesOfNode(const Id id) const +{ + return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_USAGE); +} + +std::vector> Storage::getCallEdgesOfNode(const Id id) const +{ + return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_CALL); +} + +std::vector> Storage::getTypeOfEdgesOfNode(const Id id) const +{ + return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_TYPE_OF); +} + +std::vector> Storage::getReturnTypeOfEdgesOfNode(const Id id) const +{ + return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_RETURN_TYPE_OF); +} + +std::vector> Storage::getParameterOfEdgesOfNode(const Id id) const +{ + return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_PARAMETER_TYPE_OF); +} + TokenLocationCollection Storage::getTokenLocationsForTokenId(Id id) const { TokenLocationCollection ret; @@ -430,3 +460,27 @@ void Storage::log(std::string type, std::string str, const ParseLocation& locati info << location.endLineNumber << ":" << location.endColumnNumber << ">"; LOG_INFO(info.str()); } + +std::vector> Storage::getEdgesOfTypeOfNode(const Id id, const Edge::EdgeType type) const +{ + std::vector> result; + + Node* node = m_graph.findNode([&](Node* node){ + return node->getId() == id; + }); + + if (node != NULL) + { + node->forEachEdge( + [&result, &type](Edge* e) + { + if(e->getType() == type) + { + result.push_back(std::pair(e->getFrom()->getId(), e->getTo()->getId())); + } + } + ); + } + + return result; +} diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index fefc8f7d..61130ab0 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -62,7 +62,13 @@ public: virtual std::string getNameForNodeWithId(Id id) const; virtual std::vector getNamesForNodesWithNamePrefix(const std::string& prefix) const; virtual std::vector getIdsOfNeighbours(const Id id) const; - virtual std::vector> getConnectedEdges(const Id id) const; + virtual std::vector> getNeighbourEdgesOfNode(const Id id) const; + virtual std::vector> getMemberEdgesOfNode(const Id id) const; + virtual std::vector> getUsageEdgesOfNode(const Id id) const; + virtual std::vector> getCallEdgesOfNode(const Id id) const; + virtual std::vector> getTypeOfEdgesOfNode(const Id id) const; + virtual std::vector> getReturnTypeOfEdgesOfNode(const Id id) const; + virtual std::vector> getParameterOfEdgesOfNode(const Id id) const; // LocationAccess implementation virtual TokenLocationCollection getTokenLocationsForTokenId(Id locationId) const; @@ -78,6 +84,8 @@ private: void log(std::string type, std::string str, const ParseLocation& location) const; + std::vector> getEdgesOfTypeOfNode(const Id id, const Edge::EdgeType type) const; + Graph m_graph; TokenLocationCollection m_locationCollection; }; diff --git a/src/lib/data/access/GraphAccess.h b/src/lib/data/access/GraphAccess.h index eafe50e8..c068032b 100644 --- a/src/lib/data/access/GraphAccess.h +++ b/src/lib/data/access/GraphAccess.h @@ -6,6 +6,7 @@ #include "utility/types.h" +class Edge; class Token; class GraphAccess @@ -17,7 +18,13 @@ public: virtual std::string getNameForNodeWithId(Id id) const = 0; virtual std::vector getNamesForNodesWithNamePrefix(const std::string& prefix) const = 0; virtual std::vector getIdsOfNeighbours(const Id id) const = 0; - virtual std::vector> getConnectedEdges(const Id id) const = 0; + virtual std::vector> getNeighbourEdgesOfNode(const Id id) const = 0; + virtual std::vector> getMemberEdgesOfNode(const Id id) const = 0; + virtual std::vector> getUsageEdgesOfNode(const Id id) const = 0; + virtual std::vector> getCallEdgesOfNode(const Id id) const = 0; + virtual std::vector> getTypeOfEdgesOfNode(const Id id) const = 0; + virtual std::vector> getReturnTypeOfEdgesOfNode(const Id id) const = 0; + virtual std::vector> getParameterOfEdgesOfNode(const Id id) const = 0; }; diff --git a/src/lib/data/access/GraphAccessProxy.cpp b/src/lib/data/access/GraphAccessProxy.cpp index a1271744..42925352 100644 --- a/src/lib/data/access/GraphAccessProxy.cpp +++ b/src/lib/data/access/GraphAccessProxy.cpp @@ -67,11 +67,71 @@ std::vector GraphAccessProxy::getIdsOfNeighbours(const Id id) const return std::vector(); } -std::vector> GraphAccessProxy::getConnectedEdges(const Id id) const +std::vector> GraphAccessProxy::getNeighbourEdgesOfNode(const Id id) const { if (hasSubject()) { - return m_subject->getConnectedEdges(id); + return m_subject->getNeighbourEdgesOfNode(id); + } + + return std::vector>(); +} + +std::vector> GraphAccessProxy::getMemberEdgesOfNode(const Id id) const +{ + if (hasSubject()) + { + return m_subject->getMemberEdgesOfNode(id); + } + + return std::vector>(); +} + +std::vector> GraphAccessProxy::getUsageEdgesOfNode(const Id id) const +{ + if (hasSubject()) + { + return m_subject->getUsageEdgesOfNode(id); + } + + return std::vector>(); +} + +std::vector> GraphAccessProxy::getCallEdgesOfNode(const Id id) const +{ + if (hasSubject()) + { + return m_subject->getCallEdgesOfNode(id); + } + + return std::vector>(); +} + +std::vector> GraphAccessProxy::getTypeOfEdgesOfNode(const Id id) const +{ + if (hasSubject()) + { + return m_subject->getTypeOfEdgesOfNode(id); + } + + return std::vector>(); +} + +std::vector> GraphAccessProxy::getReturnTypeOfEdgesOfNode(const Id id) const +{ + if (hasSubject()) + { + return m_subject->getReturnTypeOfEdgesOfNode(id); + } + + return std::vector>(); +} + +std::vector> GraphAccessProxy::getParameterOfEdgesOfNode(const Id id) const +{ + if (hasSubject()) + { + return m_subject->getParameterOfEdgesOfNode(id); } return std::vector>(); diff --git a/src/lib/data/access/GraphAccessProxy.h b/src/lib/data/access/GraphAccessProxy.h index c376161a..4cea39be 100644 --- a/src/lib/data/access/GraphAccessProxy.h +++ b/src/lib/data/access/GraphAccessProxy.h @@ -17,7 +17,13 @@ public: virtual std::string getNameForNodeWithId(Id id) const; virtual std::vector getNamesForNodesWithNamePrefix(const std::string& prefix) const; virtual std::vector getIdsOfNeighbours(const Id id) const; - virtual std::vector> getConnectedEdges(const Id id) const; + virtual std::vector> getNeighbourEdgesOfNode(const Id id) const; + virtual std::vector> getMemberEdgesOfNode(const Id id) const; + virtual std::vector> getUsageEdgesOfNode(const Id id) const; + virtual std::vector> getCallEdgesOfNode(const Id id) const; + virtual std::vector> getTypeOfEdgesOfNode(const Id id) const; + virtual std::vector> getReturnTypeOfEdgesOfNode(const Id id) const; + virtual std::vector> getParameterOfEdgesOfNode(const Id id) const; private: GraphAccess* m_subject;