data/logic/ui: added aggregation edges

This change adds the creation of aggregation edges to the StorageGraph, which save the connection counts between
children in their parents. Aggregation edges are displayed using a straight line, that is thicker than more connections
it represents with the connection count in the middle.
This commit is contained in:
Eberhard Graether
2015-01-07 14:42:35 +01:00
parent 8dafd0435f
commit ee85abfc7b
18 changed files with 410 additions and 117 deletions
+1 -1
View File
@@ -246,7 +246,7 @@ std::shared_ptr<QtGraphEdge> QtGraphView::createEdge(QGraphicsView* view, const
}
else
{
LOG_WARNING("Couldn't find owner or target node.");
LOG_WARNING_STREAM(<< "Couldn't find owner or target node for edge: " << edge.data->getName());
return NULL;
}
}
+149 -53
View File
@@ -1,68 +1,86 @@
#include "qt/view/graphElements/QtGraphEdge.h"
#include <cmath>
#include <QGraphicsScene>
#include <QGraphicsSceneEvent>
#include <QPainter>
#include <QPen>
#include "utility/messaging/type/MessageActivateToken.h"
#include "utility/messaging/type/MessageActivateTokens.h"
#include "component/view/graphElements/GraphNode.h"
#include "data/graph/token_component/TokenComponentAggregation.h"
#include "qt/graphics/QtGraphicsRoundedRectItem.h"
QtStraightConnection::QtStraightConnection(Vec4i ownerRect, Vec4i targetRect, QGraphicsItem* parent)
QtStraightConnection::QtStraightConnection(Vec4i ownerRect, Vec4i targetRect, int number, QGraphicsItem* parent)
: QGraphicsLineItem(parent)
{
const Vec4i& o = ownerRect;
const Vec4i& t = targetRect;
Vec2f po[2] = { Vec2f(o.x, (o.y + 2 * o.w) / 3), Vec2f(o.z, (o.y + 2 * o.w) / 3) };
Vec2f pt[2] = { Vec2f(t.x, (2 * t.y + t.w) / 3), Vec2f(t.z, (2 * t.y + t.w) / 3) };
Vec2f a((o.x + o.z) / 2, (o.y + o.w) / 2);
Vec2f b((t.x + t.z) / 2, (t.y + t.w) / 2);
int io = -1;
int it = -1;
float dist = -1;
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
Vec2f diff = po[i] - pt[j];
if (dist < 0 || diff.getLength() < dist)
{
dist = diff.getLength();
io = i;
it = j;
}
}
}
this->setLine(po[io].x, po[io].y, pt[it].x, pt[it].y);
this->setLine(a.x, a.y, b.x, b.y);
this->setAcceptHoverEvents(true);
Vec2f u = b - a;
u.normalize();
float alpha = atan2(u.y, u.x);
Vec2f w;
w.x = (o.z - o.x) / 2 * cos(alpha);
w.y = (o.w - o.y) / 2 * sin(alpha);
a += u * w.getLength();
w.x = (t.z - t.x) / 2 * cos(alpha);
w.y = (t.w - t.y) / 2 * sin(alpha);
b += u * -w.getLength();
Vec2f mid = (a + b) / 2;
m_circle = new QtGraphicsRoundedRectItem(this);
m_circle->setRect(mid.x - 10, mid.y - 10, 20, 20);
m_circle->setRadius(10);
m_circle->setPen(QPen(QColor("#F8F8F8"), 2));
m_circle->setBrush(QBrush(QColor("#FFF")));
m_circle->setAcceptHoverEvents(true);
QFont font;
font.setFamily("Myriad Pro");
font.setWeight(QFont::Normal);
font.setPixelSize(9);
m_number = new QGraphicsSimpleTextItem(this);
m_number->setFont(font);
QString numberStr = QString::number(number);
m_number->setText(numberStr);
m_number->setBrush(QBrush(QColor("#666")));
m_number->setPos(
mid.x - QFontMetrics(m_number->font()).width(numberStr) / 2,
mid.y - QFontMetrics(m_number->font()).height() / 2
);
}
QtStraightConnection::~QtStraightConnection()
{
}
QPainterPath QtStraightConnection::shape() const
void QtStraightConnection::setColor(QColor color)
{
QPainterPath path;
QLineF l = line();
QLineF n = l.normalVector();
n.setLength(5.0f);
QPen p = this->pen();
p.setColor(color);
this->setPen(p);
qreal x = n.x2() - n.x1();
qreal y = n.y2() - n.y1();
path.moveTo(l.x1() + x, l.y1() + y);
path.lineTo(l.x2() + x, l.y2() + y);
path.lineTo(l.x2() - x, l.y2() - y);
path.lineTo(l.x1() - x, l.y1() - y);
path.closeSubpath();
return path;
p = m_circle->pen();
p.setColor(color);
m_circle->setPen(p);
}
QtCorneredConnection::QtCorneredConnection(
Vec4i ownerRect, Vec4i targetRect, Vec4i ownerParentRect, Vec4i targetParentRect, QGraphicsItem* parent
)
@@ -323,7 +341,7 @@ QtGraphEdge::QtGraphEdge(const std::weak_ptr<GraphNode>& owner, const std::weak_
, m_mouseMoved(false)
{
this->setAcceptHoverEvents(true);
this->setZValue(1); // Used to draw edges always on top of nodes.
this->setZValue(getZValue(false)); // Used to draw edges always on top of nodes.
this->updateLine();
}
@@ -358,11 +376,19 @@ void QtGraphEdge::updateLine()
delete m_child;
}
m_child = new QtCorneredConnection(
owner->getBoundingRect(), target->getBoundingRect(),
owner->getParentBoundingRect(), target->getParentBoundingRect(),
this
);
if (isAggregation())
{
m_child =
new QtStraightConnection(owner->getBoundingRect(), target->getBoundingRect(), getAggregationCount(), this);
}
else
{
m_child = new QtCorneredConnection(
owner->getBoundingRect(), target->getBoundingRect(),
owner->getParentBoundingRect(), target->getParentBoundingRect(),
this
);
}
QColor color;
@@ -377,12 +403,17 @@ void QtGraphEdge::updateLine()
case Edge::EDGE_INHERITANCE:
color = QColor("#CC5E89");
break;
case Edge::EDGE_AGGREGATION:
color = QColor("#F8F8F8");
break;
default:
color = QColor("#878787");
break;
}
m_child->setPen(QPen(color, 1));
m_child->setPen(QPen(color, getPenWidth()));
setIsActive(m_isActive);
}
bool QtGraphEdge::getIsActive() const
@@ -394,23 +425,47 @@ void QtGraphEdge::setIsActive(bool isActive)
{
m_isActive = isActive;
QPen p = m_child->pen();
if (isActive)
{
p.setWidth(2);
this->setZValue(5);
if (isAggregation())
{
dynamic_cast<QtStraightConnection*>(m_child)->setColor(QColor("#EEE"));
}
else
{
QPen p = m_child->pen();
p.setWidth(getPenWidth() + 1);
m_child->setPen(p);
}
this->setZValue(getZValue(isActive));
}
else
{
p.setWidth(1);
this->setZValue(1);
if (isAggregation())
{
dynamic_cast<QtStraightConnection*>(m_child)->setColor(QColor("#F8F8F8"));
}
else
{
QPen p = m_child->pen();
p.setWidth(getPenWidth());
m_child->setPen(p);
}
this->setZValue(getZValue(isActive));
}
m_child->setPen(p);
}
void QtGraphEdge::onClick()
{
MessageActivateToken(getData()->getId()).dispatch();
if (isAggregation())
{
const std::set<Id>& ids = getData()->getComponent<TokenComponentAggregation>()->getAggregationIds();
MessageActivateTokens(std::vector<Id>(ids.begin(), ids.end())).dispatch();
}
else
{
MessageActivateToken(getData()->getId()).dispatch();
}
}
void QtGraphEdge::mousePressEvent(QGraphicsSceneMouseEvent* event)
@@ -448,3 +503,44 @@ void QtGraphEdge::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
{
this->setIsActive(m_isActive);
}
bool QtGraphEdge::isAggregation() const
{
return getData()->getType() == Edge::EDGE_AGGREGATION;
}
int QtGraphEdge::getZValue(bool active) const
{
if (isAggregation())
{
if (active)
{
return -1;
}
return -5;
}
if (active)
{
return 5;
}
return 1;
}
int QtGraphEdge::getPenWidth() const
{
if (isAggregation())
{
return getAggregationCount() + 1;
}
return 1;
}
int QtGraphEdge::getAggregationCount() const
{
if (isAggregation())
{
return getData()->getComponent<TokenComponentAggregation>()->getAggregationCount();
}
return 0;
}
+12 -3
View File
@@ -6,20 +6,24 @@
#include <QGraphicsItem>
#include "utility/math/Vector2.h"
#include "utility/messaging/type/MessageActivateToken.h"
#include "component/view/graphElements/GraphEdge.h"
class GraphNode;
class QtGraphicsRoundedRectItem;
class QtStraightConnection
: public QGraphicsLineItem
{
public:
QtStraightConnection(Vec4i ownerRect, Vec4i targetRect, QGraphicsItem* parent);
QtStraightConnection(Vec4i ownerRect, Vec4i targetRect, int number, QGraphicsItem* parent);
virtual ~QtStraightConnection();
virtual QPainterPath shape() const;
void setColor(QColor color);
private:
QtGraphicsRoundedRectItem* m_circle;
QGraphicsSimpleTextItem* m_number;
};
class QtCorneredConnection
@@ -71,6 +75,11 @@ protected:
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event);
private:
bool isAggregation() const;
int getZValue(bool active) const;
int getPenWidth() const;
int getAggregationCount() const;
std::weak_ptr<GraphNode> m_owner;
std::weak_ptr<GraphNode> m_target;
+27 -27
View File
@@ -161,14 +161,14 @@ Vec4i QtGraphNode::getParentBoundingRect() const
bool QtGraphNode::addOutEdge(const std::shared_ptr<GraphEdge>& edge)
{
for (std::list<std::shared_ptr<GraphEdge>>::iterator it = m_outEdges.begin(); it != m_outEdges.end(); it++)
{
if ((*it)->getOwner().lock() == edge->getOwner().lock() &&
(*it)->getTarget().lock() == edge->getTarget().lock())
{
return false;
}
}
// for (std::list<std::shared_ptr<GraphEdge>>::iterator it = m_outEdges.begin(); it != m_outEdges.end(); it++)
// {
// if ((*it)->getOwner().lock() == edge->getOwner().lock() &&
// (*it)->getTarget().lock() == edge->getTarget().lock())
// {
// return false;
// }
// }
m_outEdges.push_back(edge);
return true;
@@ -176,18 +176,18 @@ bool QtGraphNode::addOutEdge(const std::shared_ptr<GraphEdge>& edge)
bool QtGraphNode::addInEdge(const std::weak_ptr<GraphEdge>& edge)
{
for (std::list<std::weak_ptr<GraphEdge>>::iterator it = m_inEdges.begin(); it != m_inEdges.end(); it++)
{
std::shared_ptr<GraphEdge> existingEdge = it->lock();
if (existingEdge != NULL)
{
if (existingEdge->getOwner().lock() == edge.lock()->getOwner().lock() &&
existingEdge->getTarget().lock() == edge.lock()->getTarget().lock())
{
return false;
}
}
}
// for (std::list<std::weak_ptr<GraphEdge>>::iterator it = m_inEdges.begin(); it != m_inEdges.end(); it++)
// {
// std::shared_ptr<GraphEdge> existingEdge = it->lock();
// if (existingEdge != NULL)
// {
// if (existingEdge->getOwner().lock() == edge.lock()->getOwner().lock() &&
// existingEdge->getTarget().lock() == edge.lock()->getTarget().lock())
// {
// return false;
// }
// }
// }
m_inEdges.push_back(edge);
return true;
@@ -258,7 +258,7 @@ void QtGraphNode::setStyle()
QPen p(Qt::transparent);
QFont font(getFontForNodeType(m_data->getType()));
bool undefined = false;
bool useUndefinedPattern = false;
bool useUndefinedColor = false;
Vec2i padding;
@@ -266,9 +266,9 @@ void QtGraphNode::setStyle()
switch (m_data->getType())
{
case Node::NODE_UNDEFINED:
undefined = true;
p.setStyle(Qt::DashLine);
case Node::NODE_NAMESPACE:
color = Qt::white;
color = Qt::transparent;
p.setColor("#cc8d91");
p.setWidth(1);
@@ -279,7 +279,7 @@ void QtGraphNode::setStyle()
break;
case Node::NODE_UNDEFINED_TYPE:
undefined = true;
useUndefinedPattern = true;
case Node::NODE_STRUCT:
case Node::NODE_CLASS:
case Node::NODE_ENUM:
@@ -315,7 +315,7 @@ void QtGraphNode::setStyle()
break;
case Node::NODE_UNDEFINED_FUNCTION:
undefined = true;
useUndefinedPattern = true;
useUndefinedColor = true;
case Node::NODE_FUNCTION:
case Node::NODE_METHOD:
@@ -335,7 +335,7 @@ void QtGraphNode::setStyle()
break;
case Node::NODE_UNDEFINED_VARIABLE:
undefined = true;
useUndefinedPattern = true;
useUndefinedColor = true;
case Node::NODE_GLOBAL_VARIABLE:
case Node::NODE_FIELD:
@@ -365,7 +365,7 @@ void QtGraphNode::setStyle()
m_rect->setBrush(QBrush(color));
m_rect->setRadius(radius);
if (undefined)
if (useUndefinedPattern)
{
QtDeviceScaledPixmap pixmap("data/gui/graph_view/images/pattern.png");
pixmap.scaleToHeight(10);
+2
View File
@@ -87,6 +87,8 @@ add_files(
data/graph/token_component/TokenComponentAbstraction.h
data/graph/token_component/TokenComponentAccess.cpp
data/graph/token_component/TokenComponentAccess.h
data/graph/token_component/TokenComponentAggregation.cpp
data/graph/token_component/TokenComponentAggregation.h
data/graph/token_component/TokenComponentConst.cpp
data/graph/token_component/TokenComponentConst.h
data/graph/token_component/TokenComponentName.cpp
@@ -168,7 +168,14 @@ DummyNode GraphController::createDummyNodeTopDown(Node* node)
return;
}
result.connected = true;
if (edge->isType(Edge::EDGE_AGGREGATION))
{
result.aggregated = true;
}
else
{
result.connected = true;
}
for (const DummyEdge& dummy : m_dummyEdges)
{
@@ -189,7 +196,7 @@ void GraphController::setActiveAndVisibility(const std::vector<Id>& activeTokenI
{
for (DummyNode& node : m_dummyNodes)
{
setNodeActiveAndVisibilityRecursiveBottomUp(node, activeTokenIds);
setNodeActiveAndVisibilityRecursiveBottomUp(node, activeTokenIds, false);
}
for (DummyEdge& edge : m_dummyEdges)
@@ -203,7 +210,7 @@ void GraphController::setActiveAndVisibility(const std::vector<Id>& activeTokenI
}
bool GraphController::setNodeActiveAndVisibilityRecursiveBottomUp(
DummyNode& node, const std::vector<Id>& activeTokenIds
DummyNode& node, const std::vector<Id>& activeTokenIds, bool aggregated
) const {
node.visible = false;
node.active = false;
@@ -216,13 +223,13 @@ bool GraphController::setNodeActiveAndVisibilityRecursiveBottomUp(
bool childVisible = false;
for (DummyNode& subNode : node.subNodes)
{
if (setNodeActiveAndVisibilityRecursiveBottomUp(subNode, activeTokenIds))
if (setNodeActiveAndVisibilityRecursiveBottomUp(subNode, activeTokenIds, aggregated | node.aggregated))
{
childVisible = true;
}
}
if (node.active || node.connected || childVisible)
if (node.active || node.connected || childVisible || (!aggregated && node.aggregated))
{
setNodeVisibilityRecursiveTopDown(node);
}
@@ -59,7 +59,8 @@ private:
DummyNode createDummyNodeTopDown(Node* node);
void setActiveAndVisibility(const std::vector<Id>& activeTokenIds);
bool setNodeActiveAndVisibilityRecursiveBottomUp(DummyNode& node, const std::vector<Id>& activeTokenIds) const;
bool setNodeActiveAndVisibilityRecursiveBottomUp(
DummyNode& node, const std::vector<Id>& activeTokenIds, bool aggregated) const;
void setNodeVisibilityRecursiveTopDown(DummyNode& node) const;
void layoutNesting();
@@ -52,6 +52,7 @@ struct DummyNode
, accessType(TokenComponentAccess::ACCESS_NONE)
, active(false)
, connected(false)
, aggregated(false)
, expanded(false)
, invisibleSubNodeCount(0)
, visible(false)
@@ -63,6 +64,7 @@ struct DummyNode
, accessType(accessType)
, active(false)
, connected(false)
, aggregated(false)
, expanded(false)
, invisibleSubNodeCount(0)
, visible(false)
@@ -77,6 +79,7 @@ struct DummyNode
bool active;
bool connected;
bool aggregated;
bool expanded;
size_t invisibleSubNodeCount;
+9 -2
View File
@@ -481,9 +481,16 @@ std::shared_ptr<Graph> Storage::getGraphForActiveTokenIds(const std::vector<Id>&
graph->addNodeAndAllChildrenAsPlainCopy(node->getLastParentNode());
node->forEachEdge(
[graph](Edge* edge)
[graph, node](Edge* edge)
{
graph->addEdgeAndAllChildrenAsPlainCopy(edge);
const Node::NodeTypeMask varFuncMask =
Node::NODE_UNDEFINED_FUNCTION | Node::NODE_FUNCTION | Node::NODE_METHOD |
Node::NODE_UNDEFINED_VARIABLE | Node::NODE_GLOBAL_VARIABLE | Node::NODE_FIELD;
if (!node->isType(varFuncMask) || !edge->isType(Edge::EDGE_AGGREGATION))
{
graph->addEdgeAndAllChildrenAsPlainCopy(edge);
}
}
);
}
+35 -3
View File
@@ -3,6 +3,7 @@
#include <sstream>
#include "data/graph/Node.h"
#include "data/graph/token_component/TokenComponentAggregation.h"
#include "data/graph/token_component/TokenComponentAccess.h"
#include "utility/logging/logging.h"
@@ -76,6 +77,22 @@ bool Edge::isEdge() const
return true;
}
void Edge::addComponentAggregation(std::shared_ptr<TokenComponentAggregation> component)
{
if (getComponent<TokenComponentAggregation>())
{
LOG_ERROR("TokenComponentAggregation has been set before!");
}
else if (m_type != EDGE_AGGREGATION)
{
LOG_ERROR("TokenComponentAggregation can't be set on edge of type: " + getTypeString());
}
else
{
addComponent(component);
}
}
void Edge::addComponentAccess(std::shared_ptr<TokenComponentAccess> component)
{
if (getComponent<TokenComponentAccess>())
@@ -118,6 +135,8 @@ std::string Edge::getTypeString(EdgeType type) const
return "template parameter";
case EDGE_TEMPLATE_SPECIALIZATION_OF:
return "template specialization";
case EDGE_AGGREGATION:
return "aggregation";
}
return "";
}
@@ -132,10 +151,16 @@ std::string Edge::getAsString() const
std::stringstream str;
str << "[" << getId() << "] " << getTypeString() << ": \"" << m_from->getName() << "\" -> \"" + m_to->getName() << "\"";
TokenComponentAccess* component = getComponent<TokenComponentAccess>();
if (component)
TokenComponentAccess* access = getComponent<TokenComponentAccess>();
if (access)
{
str << " " << component->getAccessString();
str << " " << access->getAccessString();
}
TokenComponentAggregation* aggregation = getComponent<TokenComponentAggregation>();
if (aggregation)
{
str << " " << aggregation->getAggregationCount();
}
return str.str();
@@ -222,6 +247,13 @@ bool Edge::checkType() const
break;
}
return true;
case EDGE_AGGREGATION:
if (!m_from->isType(typeMask | variableMask | functionMask) || !m_to->isType(typeMask | variableMask | functionMask))
{
break;
}
return true;
}
LOG_ERROR_STREAM(
+5 -1
View File
@@ -7,6 +7,7 @@
#include "data/graph/Token.h"
class Node;
class TokenComponentAggregation;
class TokenComponentAccess;
class TokenComponentDataType;
@@ -26,7 +27,9 @@ public:
EDGE_INHERITANCE = 0x80,
EDGE_TYPEDEF_OF = 0x100,
EDGE_TEMPLATE_PARAMETER_OF = 0x200,
EDGE_TEMPLATE_SPECIALIZATION_OF = 0x400
EDGE_TEMPLATE_SPECIALIZATION_OF = 0x400,
EDGE_AGGREGATION = 0x800
};
Edge(EdgeType type, Node* from, Node* to);
@@ -46,6 +49,7 @@ public:
virtual bool isEdge() const;
// Component setters
void addComponentAggregation(std::shared_ptr<TokenComponentAggregation> component);
void addComponentAccess(std::shared_ptr<TokenComponentAccess> component);
// Logging.
+47 -1
View File
@@ -1,5 +1,6 @@
#include "data/graph/StorageGraph.h"
#include "data/graph/token_component/TokenComponentAggregation.h"
#include "data/graph/token_component/TokenComponentName.h"
#include "utility/logging/logging.h"
#include "utility/utilityString.h"
@@ -87,7 +88,16 @@ Edge* StorageGraph::createEdge(Edge::EdgeType type, Node* from, Node* to)
return edge;
}
return insertEdge(type, from, to);
edge = insertEdge(type, from, to);
if (from->getLastParentNode() != to->getLastParentNode())
{
Id edgeId = edge->getId();
updateAggregationEdges(from->getParentNode(), to, edgeId);
updateAggregationEdges(from, to->getParentNode(), edgeId);
}
return edge;
}
Node* StorageGraph::insertNodeHierarchy(Node::NodeType type, SearchNode* searchNode)
@@ -140,3 +150,39 @@ Edge* StorageGraph::insertEdge(Edge::EdgeType type, Node* from, Node* to)
m_edges.emplace(edgePtr->getId(), edgePtr);
return edgePtr.get();
}
void StorageGraph::updateAggregationEdges(Node* from, Node* to, Id edgeId)
{
if (!from || !to || from == to)
{
return;
}
const Node::NodeTypeMask mask = Node::NODE_UNDEFINED_TYPE | Node::NODE_CLASS | Node::NODE_STRUCT | Node::NODE_ENUM;
const Node::NodeTypeMask varFuncMask =
Node::NODE_UNDEFINED_FUNCTION | Node::NODE_FUNCTION | Node::NODE_UNDEFINED_VARIABLE | Node::NODE_GLOBAL_VARIABLE;
if ((from->isType(mask) && to->isType(mask | varFuncMask)) ||
(from->isType(mask | varFuncMask) && to->isType(mask)))
{
Edge* edge = from->findEdgeOfType(Edge::EDGE_AGGREGATION,
[from, to](Edge* e)
{
const Node* f = e->getFrom();
const Node* t = e->getTo();
return (f == from && t == to) || (f == to && t == from);
}
);
if (!edge)
{
edge = insertEdge(Edge::EDGE_AGGREGATION, from, to);
edge->addComponentAggregation(std::make_shared<TokenComponentAggregation>());
}
edge->getComponent<TokenComponentAggregation>()->addAggregationId(edgeId);
}
updateAggregationEdges(from->getParentNode(), to, edgeId);
updateAggregationEdges(from, to->getParentNode(), edgeId);
}
+2
View File
@@ -21,6 +21,8 @@ private:
Node* insertNodeHierarchy(Node::NodeType type, SearchNode* searchNode);
Node* insertNode(Node::NodeType type, Node* parentNode, SearchNode* searchNode);
Edge* insertEdge(Edge::EdgeType type, Node* from, Node* to);
void updateAggregationEdges(Node* from, Node* to, Id edgeId);
};
#endif // STORAGE_GRAPH_H
@@ -0,0 +1,29 @@
#include "data/graph/token_component/TokenComponentAggregation.h"
TokenComponentAggregation::TokenComponentAggregation()
{
}
TokenComponentAggregation::~TokenComponentAggregation()
{
}
std::shared_ptr<TokenComponent> TokenComponentAggregation::copy() const
{
return std::make_shared<TokenComponentAggregation>(*this);
}
int TokenComponentAggregation::getAggregationCount() const
{
return m_ids.size();
}
void TokenComponentAggregation::addAggregationId(Id id)
{
m_ids.insert(id);
}
const std::set<Id>& TokenComponentAggregation::getAggregationIds() const
{
return m_ids;
}
@@ -0,0 +1,27 @@
#ifndef TOKEN_COMPONENT_AGGREGATION_H
#define TOKEN_COMPONENT_AGGREGATION_H
#include <set>
#include "utility/types.h"
#include "data/graph/token_component/TokenComponent.h"
class TokenComponentAggregation
: public TokenComponent
{
public:
TokenComponentAggregation();
virtual ~TokenComponentAggregation();
virtual std::shared_ptr<TokenComponent> copy() const;
int getAggregationCount() const;
void addAggregationId(Id id);
const std::set<Id>& getAggregationIds() const;
private:
std::set<Id> m_ids;
};
#endif // TOKEN_COMPONENT_AGGREGATION_H
+14 -14
View File
@@ -39,11 +39,11 @@ public:
void assign(const VectorBase<U, N>& other);
template<class U>
VectorBase<T, N> add(const VectorBase<U, N>& other);
VectorBase<T, N>& add(const VectorBase<U, N>& other);
template<class U>
VectorBase<T, N> subtract(const VectorBase<U, N>& other);
VectorBase<T, N>& subtract(const VectorBase<U, N>& other);
template<class U>
VectorBase<T, N> scalarMultiplication(const U& scalar);
VectorBase<T, N>& scalarMultiplication(const U& scalar);
template<class U>
T dotProduct(const VectorBase<U, N>& other);
@@ -71,13 +71,13 @@ public:
VectorBase<T, N> operator/(const U& scalar) const;
template<class U>
VectorBase<T, N> operator+=(const VectorBase<U, N>& other);
VectorBase<T, N>& operator+=(const VectorBase<U, N>& other);
template<class U>
VectorBase<T, N> operator-=(const VectorBase<U, N>& other);
VectorBase<T, N>& operator-=(const VectorBase<U, N>& other);
template<class U>
VectorBase<T, N> operator*=(const U& scalar);
VectorBase<T, N>& operator*=(const U& scalar);
template<class U>
VectorBase<T, N> operator/=(const U& scalar);
VectorBase<T, N>& operator/=(const U& scalar);
// Checks whether all values are the same.
template<class U>
@@ -238,7 +238,7 @@ void VectorBase<T, N>::assign(const VectorBase<U, N>& other)
template<class T, unsigned int N>
template<class U>
VectorBase<T, N> VectorBase<T, N>::add(const VectorBase<U, N>& other)
VectorBase<T, N>& VectorBase<T, N>::add(const VectorBase<U, N>& other)
{
T tmpValues[N];
for (unsigned int i = 0; i < N; i++)
@@ -253,7 +253,7 @@ VectorBase<T, N> VectorBase<T, N>::add(const VectorBase<U, N>& other)
template<class T, unsigned int N>
template<class U>
VectorBase<T, N> VectorBase<T, N>::subtract(const VectorBase<U, N>& other)
VectorBase<T, N>& VectorBase<T, N>::subtract(const VectorBase<U, N>& other)
{
T tmpValues[N];
for (unsigned int i = 0; i < N; i++)
@@ -268,7 +268,7 @@ VectorBase<T, N> VectorBase<T, N>::subtract(const VectorBase<U, N>& other)
template<class T, unsigned int N>
template<class U>
VectorBase<T, N> VectorBase<T, N>::scalarMultiplication(const U& scalar)
VectorBase<T, N>& VectorBase<T, N>::scalarMultiplication(const U& scalar)
{
T tmpValues[N];
for (unsigned int i = 0; i < N; i++)
@@ -371,28 +371,28 @@ VectorBase<T, N> VectorBase<T, N>::operator/(const U& scalar) const
template<class T, unsigned int N>
template<class U>
VectorBase<T, N> VectorBase<T, N>::operator+=(const VectorBase<U, N>& other)
VectorBase<T, N>& VectorBase<T, N>::operator+=(const VectorBase<U, N>& other)
{
return add(other);
}
template<class T, unsigned int N>
template<class U>
VectorBase<T, N> VectorBase<T, N>::operator-=(const VectorBase<U, N>& other)
VectorBase<T, N>& VectorBase<T, N>::operator-=(const VectorBase<U, N>& other)
{
return subtract(other);
}
template<class T, unsigned int N>
template<class U>
VectorBase<T, N> VectorBase<T, N>::operator*=(const U& scalar)
VectorBase<T, N>& VectorBase<T, N>::operator*=(const U& scalar)
{
return scalarMultiplication(scalar);
}
template<class T, unsigned int N>
template<class U>
VectorBase<T, N> VectorBase<T, N>::operator/=(const U& scalar)
VectorBase<T, N>& VectorBase<T, N>::operator/=(const U& scalar)
{
return scalarMultiplication(1.0f / scalar);
}
+4 -3
View File
@@ -99,9 +99,10 @@ public:
"7 nodes: "
"class:A field:A::count undefined_type:int undefined_type:void class:B function:main "
"undefined_function:B::B\n"
"7 edges: "
"child:A->A::count type_use:A::count->int inheritance:B->A return_type:main->int type_usage:main->B "
"child:B->B::B call:main->B::B\n"
"13 edges: "
"child:A->A::count aggregation:A->int aggregation:A->void type_use:A::count->int inheritance:B->A "
"aggregation:B->void aggregation:B->int return_type:main->int type_usage:main->B child:B->B::B "
"call:main->B::B aggregation:main->B aggregation:main->A\n"
);
}
+30 -3
View File
@@ -1,5 +1,6 @@
#include "cxxtest/TestSuite.h"
#include "data/graph/token_component/TokenComponentAggregation.h"
#include "data/graph/StorageGraph.h"
#include "data/search/SearchIndex.h"
@@ -74,6 +75,32 @@ public:
TS_ASSERT_EQUALS(ab->getParentNode(), a);
}
void test_graph_creates_aggregation_edges()
{
TestStorageGraph graph;
Node* a = graph.createNodeHierarchy(Node::NODE_CLASS, "A");
Node* ab = graph.createNodeHierarchy(Node::NODE_CLASS, "A::B");
Node* c = graph.createNodeHierarchy(Node::NODE_CLASS, "C");
Node* cd = graph.createNodeHierarchy(Node::NODE_CLASS, "C::D");
Node* cdd = graph.createNodeHierarchy(Node::NODE_METHOD, "C::D::D");
Edge* i = graph.createEdge(Edge::EDGE_INHERITANCE, ab, cd);
Edge* t = graph.createEdge(Edge::EDGE_TYPE_USAGE, cdd, a);
TS_ASSERT_EQUALS(5, graph.getNodeCount());
TS_ASSERT_EQUALS(8, graph.getEdgeCount());
Edge* e1 = graph.getEdge(Edge::EDGE_AGGREGATION, a, c);
TS_ASSERT(e1);
TS_ASSERT_EQUALS(2, e1->getComponent<TokenComponentAggregation>()->getAggregationCount());
TS_ASSERT_EQUALS(i->getId(), *e1->getComponent<TokenComponentAggregation>()->getAggregationIds().begin());
TS_ASSERT_EQUALS(t->getId(), *(++e1->getComponent<TokenComponentAggregation>()->getAggregationIds().begin()));
Edge* e2 = graph.getEdge(Edge::EDGE_AGGREGATION, ab, c);
TS_ASSERT(e2);
TS_ASSERT_EQUALS(1, e2->getComponent<TokenComponentAggregation>()->getAggregationCount());
TS_ASSERT_EQUALS(i->getId(), *e2->getComponent<TokenComponentAggregation>()->getAggregationIds().begin());
}
void test_graph_removes_nodes()
{
TestStorageGraph graph;
@@ -278,14 +305,14 @@ public:
}
);
TS_ASSERT_EQUALS(4, plainGraph.getNodeCount());
TS_ASSERT_EQUALS(3, plainGraph.getEdgeCount());
TS_ASSERT_EQUALS(5, plainGraph.getNodeCount());
TS_ASSERT_EQUALS(4, plainGraph.getEdgeCount());
TS_ASSERT(plainGraph.getNode("A"));
TS_ASSERT(plainGraph.getNode("A::B"));
TS_ASSERT(plainGraph.getNode("A::B::C"));
TS_ASSERT(plainGraph.getNode("D"));
TS_ASSERT(!plainGraph.getNode("E"));
TS_ASSERT(plainGraph.getNode("E"));
}
private: