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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user