28 #include <QApplication>
31 #include <QFileDialog>
32 #include <QTemporaryFile>
33 #include <QTextStream>
39 #include <QResizeEvent>
40 #include <QMouseEvent>
41 #include <QFocusEvent>
43 #include <QStyleOptionGraphicsItem>
44 #include <QContextMenuEvent>
47 #include <QDesktopWidget>
61 #define DEFAULT_FUNCLIMIT .05
62 #define DEFAULT_CALLLIMIT 1.
63 #define DEFAULT_MAXCALLER 2
64 #define DEFAULT_MAXCALLEE -1
65 #define DEFAULT_SHOWSKIPPED false
66 #define DEFAULT_EXPANDCYCLES false
67 #define DEFAULT_CLUSTERGROUPS false
68 #define DEFAULT_DETAILLEVEL 1
69 #define DEFAULT_LAYOUT GraphOptions::TopDown
70 #define DEFAULT_ZOOMPOS Auto
78 class CallerGraphEdgeLessThan
87 if (!ce1)
return true;
88 if (!ce2)
return false;
92 QPoint d1 = p1.point(1) - p1.point(0);
93 QPoint d2 = p2.point(1) - p2.point(0);
94 double angle1 = atan2(
double(d1.y()),
double(d1.x()));
95 double angle2 = atan2(
double(d2.y()),
double(d2.x()));
97 return (angle1 < angle2);
102 class CalleeGraphEdgeLessThan
111 if (!ce1)
return true;
112 if (!ce2)
return false;
116 QPoint d1 = p1.point(p1.count()-2) - p1.point(p1.count()-1);
117 QPoint d2 = p2.point(p2.count()-2) - p2.point(p2.count()-1);
118 double angle1 = atan2(
double(d1.y()),
double(d1.x()));
119 double angle2 = atan2(
double(d2.y()),
double(d2.x()));
122 return (angle2 < angle1);
139 _lastCallerIndex = _lastCalleeIndex = -1;
141 _lastFromCaller =
true;
173 if (e && (callees.count(e) == 0))
179 if (e && (callers.count(e) == 0))
185 callers.removeAll(e);
186 callees.removeAll(e);
233 qDebug(
"GraphNode::visibleCaller %s: last %d, count %d",
234 qPrintable(_f->
prettyName()), _lastCallerIndex, callers.count());
237 GraphEdge* e = callers.value(_lastCallerIndex);
238 if (e && !e->isVisible())
241 double maxCost = 0.0;
243 for(
int i = 0; i<callers.size(); i++) {
245 if (e->isVisible() && (e->cost > maxCost)) {
248 _lastCallerIndex = i;
253 return e ? e->
call() : 0;
259 qDebug(
"GraphNode::visibleCallee %s: last %d, count %d",
260 qPrintable(_f->
prettyName()), _lastCalleeIndex, callees.count());
262 GraphEdge* e = callees.value(_lastCalleeIndex);
263 if (e && !e->isVisible())
267 double maxCost = 0.0;
269 for(
int i = 0; i<callees.size(); i++) {
271 if (e->isVisible() && (e->cost > maxCost)) {
274 _lastCalleeIndex = i;
279 return e ? e->
call() : 0;
284 _lastCalleeIndex = callees.indexOf(e);
285 _lastFromCaller =
false;
290 _lastCallerIndex = callers.indexOf(e);
291 _lastFromCaller =
true;
298 if (_lastFromCaller) {
320 if (_lastFromCaller) {
340 int idx = e ? callers.indexOf(e) : _lastCallerIndex;
342 while(idx < callers.size()) {
344 _lastCallerIndex = idx;
345 return callers[idx]->call();
354 int idx = e ? callees.indexOf(e) : _lastCalleeIndex;
356 while(idx < callees.size()) {
358 _lastCalleeIndex = idx;
359 return callees[idx]->call();
368 int idx = e ? callers.indexOf(e) : _lastCallerIndex;
370 idx = (idx<0) ? callers.size()-1 : idx-1;
373 _lastCallerIndex = idx;
374 return callers[idx]->call();
383 int idx = e ? callees.indexOf(e) : _lastCalleeIndex;
385 idx = (idx<0) ? callees.size()-1 : idx-1;
388 _lastCalleeIndex = idx;
389 return callees[idx]->call();
405 _fromNode = _toNode = 0;
410 _lastFromCaller =
true;
419 return QObject::tr(
"Call(s) from %1").arg(_from->
prettyName());
422 return QObject::tr(
"Call(s) to %1").arg(_to->
prettyName());
424 return QObject::tr(
"(unknown call)");
430 _lastFromCaller =
true;
441 _lastFromCaller =
false;
453 if (_lastFromCaller && _fromNode) {
457 }
else if (_toNode) {
459 if (!res && _fromNode)
469 if (_lastFromCaller && _fromNode) {
473 }
else if (_toNode) {
475 if (!res && _fromNode)
490 return QString(
"Circular");
492 return QString(
"LeftRight");
493 return QString(
"TopDown");
498 if (s == QString(
"Circular"))
500 if (s == QString(
"LeftRight"))
545 reset(d, f, ct, gt, filename);
550 if (_item && _tmpFile) {
552 _tmpFile->setAutoRemove(
true);
562 _graphCreated =
false;
566 if (_item && _tmpFile) {
567 _tmpFile->setAutoRemove(
true);
588 if (filename.isEmpty()) {
589 _tmpFile =
new QTemporaryFile();
591 _tmpFile->setAutoRemove(
false);
593 _dotName = _tmpFile->fileName();
617 _graphCreated =
true;
624 _realFuncLimit = incl * _go->
funcLimit();
625 _realCallLimit = _realFuncLimit * _go->
callLimit();
627 buildGraph(f, 0,
true, 1.0);
633 buildGraph(f, 0,
false, 1.0);
637 double incl = c->
subCost(_eventType);
638 _realFuncLimit = incl * _go->
funcLimit();
639 _realCallLimit = _realFuncLimit * _go->
callLimit();
643 caller = c->
caller(
false);
644 called = c->
called(
false);
645 QPair<TraceFunction*,TraceFunction*> p(caller, called);
654 buildGraph(called, 0,
true, e.
cost / s);
656 buildGraph(caller, 0,
false, e.
cost / s);
667 QTextStream* stream = 0;
670 stream =
new QTextStream(device);
673 stream =
new QTextStream(_tmpFile);
675 file =
new QFile(_dotName);
676 if ( !file->open(QIODevice::WriteOnly ) ) {
677 qDebug() <<
"Can not write dot file '"<< _dotName <<
"'";
681 stream =
new QTextStream(file);
694 *stream <<
"digraph \"callgraph\" {\n";
697 *stream << QString(
" rankdir=LR;\n");
700 switch (_item->
type()) {
712 *stream << QString(
" center=F%1;\n").arg((qptrdiff)f, 0, 16);
713 *stream << QString(
" overlap=false;\n splines=true;\n");
717 QMap<TraceCostItem*,QList<GraphNode*> > nLists;
719 GraphNodeMap::Iterator nit;
720 for (nit = _nodeMap.begin(); nit != _nodeMap.end(); ++nit ) {
723 if (n.
incl <= _realFuncLimit)
729 switch (_groupType) {
746 nLists[g].append(&n);
749 QMap<TraceCostItem*,QList<GraphNode*> >::Iterator lit;
751 for (lit = nLists.begin(); lit != nLists.end(); ++lit, cluster++) {
757 *stream << QString(
"subgraph \"cluster%1\" { label=\"%2\";\n")
758 .arg(cluster).arg(iabr);
765 *stream << QString(
" F%1 [").arg((qptrdiff)f, 0, 16);
768 if ((
int)abr.length() < 8) abr = abr + QString(8 - abr.length(),
'_');
771 *stream << QString(
"shape=box,label=\"** %1 **\\n**\\n%2\"];\n")
775 *stream << QString(
"label=\"%1\\n%2\"];\n")
781 *stream << QString(
"}\n");
784 GraphEdgeMap::Iterator eit;
785 for (eit = _edgeMap.begin(); eit != _edgeMap.end(); ++eit ) {
788 if (e.
cost < _realCallLimit)
802 if ((from.
incl <= _realFuncLimit) ||(to.
incl <= _realFuncLimit))
809 *stream << QString(
" F%1 -> F%2 [weight=%3")
810 .arg((qptrdiff)e.
from(), 0, 16)
811 .arg((qptrdiff)e.
to(), 0, 16)
812 .arg((
long)log(log(e.
cost)));
815 *stream << QString(
",label=\"%1 (%2x)\"")
820 *stream << QString(
",label=\"%3\\n%4 x\"")
824 *stream << QString(
"];\n");
831 double costSum, countSum;
832 for (nit = _nodeMap.begin(); nit != _nodeMap.end(); ++nit ) {
834 if (n.
incl <= _realFuncLimit)
840 if (costSum > _realCallLimit) {
842 QPair<TraceFunction*,TraceFunction*> p(0, n.
function());
848 *stream << QString(
" R%1 [shape=point,label=\"\"];\n")
849 .arg((qptrdiff)n.
function(), 0, 16);
850 *stream << QString(
" R%1 -> F%2 [label=\"%3\\n%4 x\",weight=%5];\n")
855 .arg((
int)log(costSum));
861 if (costSum > _realCallLimit) {
863 QPair<TraceFunction*,TraceFunction*> p(n.
function(), 0);
869 *stream << QString(
" S%1 [shape=point,label=\"\"];\n")
870 .arg((qptrdiff)n.
function(), 0, 16);
871 *stream << QString(
" F%1 -> S%2 [label=\"%3\\n%4 x\",weight=%5];\n")
876 .arg((
int)log(costSum));
883 for (nit = _nodeMap.begin(); nit != _nodeMap.end(); ++nit ) {
904 GraphNodeMap::Iterator nit;
905 for (nit = _nodeMap.begin(); nit != _nodeMap.end(); ++nit ) {
928 GraphNodeMap::Iterator it = _nodeMap.find(f);
929 if (it == _nodeMap.end())
937 GraphEdgeMap::Iterator it = _edgeMap.find(qMakePair(f1, f2));
938 if (it == _edgeMap.end())
953 void GraphExporter::buildGraph(
TraceFunction* f,
int d,
bool toCallees,
957 qDebug() <<
"buildGraph(" << f->
prettyName() <<
"," << d <<
"," << factor
958 <<
") [to " << (toCallees ?
"Callees":
"Callers") <<
"]";
961 double oldIncl = 0.0;
972 qDebug(
" Added Incl. %f, now %f", incl, n.
incl);
977 if ((maxDepth>=0) && (d >= maxDepth)) {
979 qDebug(
" Cutoff, max depth reached");
985 if ((n.
incl >= _realFuncLimit) && (oldIncl < _realFuncLimit))
994 qDebug(
" Cutoff, 2nd visit to Cycle Member");
1000 }
else if (incl <= _realFuncLimit) {
1002 qDebug(
" Cutoff, below limit");
1013 f2 = toCallees ? call->
called(
false) : call->
caller(
false);
1015 double count = call->
callCount() * factor;
1016 double cost = call->
subCost(_eventType) * factor;
1022 double oldCost = 0.0;
1023 QPair<TraceFunction*,TraceFunction*> p(toCallees ? f : f2,
1024 toCallees ? f2 : f);
1026 if (e.
call() == 0) {
1036 qDebug(
" Edge to %s, added cost %f, now %f",
1040 if (f2->
cycle() == f2) {
1042 realF = toCallees ? call->
called(
true) : call->
caller(
true);
1043 QPair<TraceFunction*,TraceFunction*>
1044 realP(toCallees ? f : realF, toCallees ? realF : f);
1046 if (e.
call() == 0) {
1068 if ((e.
cost >= _realCallLimit) && (oldCost < _realCallLimit))
1070 if (cost < _realCallLimit) {
1072 qDebug(
" Edge Cutoff, limit not reached");
1083 buildGraph(f2, d+1, toCallees, factor * v / s);
1096 viewport()->setFocusPolicy(Qt::NoFocus);
1102 viewport()->update();
1110 QColor red(Qt::red);
1111 QPen pen(red.dark());
1112 pen.setWidthF(2.0 / matrix().m11());
1115 QColor c(red.dark());
1117 p->setBrush(QBrush(c));
1125 QPointF sPos = mapToScene(e->pos());
1139 QPointF sPos = mapToScene(e->pos());
1170 if (!_node || !_view)
1188 double inclP = 100.0 * n->
incl/ total;
1196 setToolTip(QString(
"%1 (%2)").arg(
text(0)).arg(
text(1)));
1207 if (!_view || !_node)
1217 const QStyleOptionGraphicsItem* option,
1220 QRect r = rect().toRect(), origRect = r;
1222 r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
1226 r.setRect(r.x()+2, r.y()+2, r.width()-4, r.height()-4);
1230 _view->style().drawPrimitive( QStyle::PE_FocusRect, &p, r,
1231 _view->colorGroup());
1237 p->drawRect(QRect(origRect.x(), origRect.y(), origRect.width()-1,
1238 origRect.height()-1));
1240 #if QT_VERSION >= 0x040600
1241 if (option->levelOfDetailFromTransform(p->transform()) < .5)
1244 if (option->levelOfDetail < .5)
1259 int y,
int w,
int h) :
1279 double inclP = 100.0 * e->
cost/ total;
1291 _percentage = inclP;
1292 if (_percentage > 100.0) _percentage = 100.0;
1295 QString icon =
"edit-undo";
1297 KIconLoader* loader = KIconLoader::global();
1298 QPixmap p= loader->loadIcon(icon, KIconLoader::Small, 0,
1299 KIconLoader::DefaultState, QStringList(), 0,
1305 setToolTip(QString(
"%1 (%2)").arg(
text(0)).arg(
text(1)));
1309 const QStyleOptionGraphicsItem* option,
QWidget*)
1312 #if QT_VERSION >= 0x040600
1313 if (option->levelOfDetailFromTransform(p->transform()) < .5)
1316 if (option->levelOfDetail < .5)
1320 QRect r = rect().toRect();
1337 const QStyleOptionGraphicsItem *,
QWidget *)
1339 p->setRenderHint(QPainter::Antialiasing);
1340 p->setBrush(_ce->isSelected() ? Qt::red : Qt::black);
1341 p->drawPolygon(polygon(), Qt::OddEvenFill);
1356 setFlag(QGraphicsItem::ItemIsSelectable);
1364 QString tip = QString(
"%1 (%2)").arg(l->
text(0)).arg(l->
text(1));
1367 if (_arrow) _arrow->setToolTip(tip);
1370 if (_thickness < .9) _thickness = .9;
1378 if (a && _label) a->setToolTip(QString(
"%1 (%2)")
1379 .arg(_label->
text(0)).arg(_label->
text(1)));
1384 QGraphicsItem::setSelected(s);
1394 for (
int i = 1; i < pa.size(); i += 3)
1395 path.cubicTo(pa[i], pa[(i + 1) % pa.size()], pa[(i + 2) % pa.size()]);
1402 const QStyleOptionGraphicsItem* option,
QWidget*)
1404 p->setRenderHint(QPainter::Antialiasing);
1406 qreal levelOfDetail;
1407 #if QT_VERSION >= 0x040600
1408 levelOfDetail = option->levelOfDetailFromTransform(p->transform());
1410 levelOfDetail = option->levelOfDetail;
1414 mypen.setWidthF(1.0/levelOfDetail * _thickness);
1416 p->drawPath(path());
1419 mypen.setColor(Qt::red);
1420 mypen.setWidthF(1.0/levelOfDetail * _thickness/2.0);
1422 p->drawPath(path());
1431 QPixmap* CanvasFrame::_p = 0;
1438 float v1 = 130.0f, v2 = 10.0f, v = v1, f = 1.03f;
1441 QRect r(0, 0, 30, 30);
1443 r.setRect(r.x()-d, r.y()-d, r.width()+2*d, r.height()+2*d);
1447 _p =
new QPixmap(r.size());
1448 _p->fill(Qt::white);
1450 p.setPen(Qt::NoPen);
1452 r.translate(-r.x(), -r.y());
1456 p.setBrush(QColor(265-(
int)v, 265-(
int)v, 265-(
int)v));
1458 p.drawRect(QRect(r.x(), r.y(), r.width(), d));
1459 p.drawRect(QRect(r.x(), r.bottom()-d, r.width(), d));
1460 p.drawRect(QRect(r.x(), r.y()+d, d, r.height()-2*d));
1461 p.drawRect(QRect(r.right()-d, r.y()+d, d, r.height()-2*d));
1463 r.setRect(r.x()+d, r.y()+d, r.width()-2*d, r.height()-2*d);
1467 setRect(QRectF(n->rect().center().x() - _p->width()/2,
1468 n->rect().center().y() - _p->height()/2, _p->width(), _p->height()) );
1473 const QStyleOptionGraphicsItem* option,
QWidget*)
1475 qreal levelOfDetail;
1476 #if QT_VERSION >= 0x040600
1477 levelOfDetail = option->levelOfDetailFromTransform(p->transform());
1479 levelOfDetail = option->levelOfDetail;
1481 if (levelOfDetail < .5) {
1482 QRadialGradient g(rect().center(), rect().width()/3);
1483 g.setColorAt(0.0, Qt::gray);
1484 g.setColorAt(1.0, Qt::white);
1486 p->setBrush(QBrush(g));
1487 p->setPen(Qt::NoPen);
1488 p->drawRect(rect());
1492 p->drawPixmap(
int( rect().x()),
int( rect().y()), *_p );
1504 setObjectName(name);
1509 _xMargin = _yMargin = 0;
1518 _panningView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1519 _panningView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1520 _panningView->raise();
1521 _panningView->hide();
1523 setFocusPolicy(Qt::StrongFocus);
1524 setAttribute(Qt::WA_NoSystemBackground,
true);
1535 _prevSelectedNode = 0;
1536 connect(&_renderTimer, SIGNAL(timeout()),
1543 delete _panningView;
1548 return tr(
"<b>Call Graph around active Function</b>"
1549 "<p>Depending on configuration, this view shows "
1550 "the call graph environment of the active function. "
1551 "Note: the shown cost is <b>only</b> the cost which is "
1552 "spent while the active function was actually running; "
1553 "i.e. the cost shown for main() - if it is visible - should "
1554 "be the same as the cost of the active function, as that is "
1555 "the part of inclusive cost of main() spent while the active "
1556 "function was running.</p>"
1557 "<p>For cycles, blue call arrows indicate that this is an "
1558 "artificial call added for correct drawing which "
1559 "actually never happened.</p>"
1560 "<p>If the graph is larger than the widget area, an overview "
1561 "panner is shown in one edge. "
1562 "There are similar visualization options to the "
1563 "Call Treemap; the selected function is highlighted.</p>");
1566 void CallGraphView::updateSizes(QSize s)
1571 if (s == QSize(0, 0))
1575 int cWidth = (int)_scene->width() - 2*_xMargin + 100;
1576 int cHeight = (int)_scene->height() - 2*_yMargin + 100;
1580 ((cWidth < s.width()) && (cHeight < s.height())) ) {
1581 _panningView->hide();
1586 double zoom = .33 * s.width() / cWidth;
1587 if (zoom * cHeight < .33 * s.height())
1588 zoom = .33 * s.height() / cHeight;
1591 if (cWidth * zoom > s.width())
1592 zoom = s.width() / (double)cWidth;
1593 if (cHeight * zoom > s.height())
1594 zoom = s.height() / (double)cHeight;
1603 if (zoom != _panningZoom) {
1604 _panningZoom = zoom;
1606 qDebug(
"Canvas Size: %fx%f, Content: %dx%d, Zoom: %f",
1607 _scene->width(), _scene->height(), cWidth, cHeight, zoom);
1610 _panningView->setMatrix(m.scale(zoom, zoom));
1613 _panningView->resize(
int(cWidth * zoom) + 4,
int(cHeight * zoom) + 4);
1619 _panningView->centerOn(_scene->width()/2, _scene->height()/2);
1621 int cvW = _panningView->width();
1622 int cvH = _panningView->height();
1623 int x = width()- cvW - verticalScrollBar()->width() -2;
1624 int y = height()-cvH - horizontalScrollBar()->height() -2;
1625 QPoint oldZoomPos = _panningView->pos();
1626 QPoint newZoomPos = QPoint(0, 0);
1629 int tlCols = items(QRect(0,0, cvW,cvH)).count();
1630 int trCols = items(QRect(x,0, cvW,cvH)).count();
1631 int blCols = items(QRect(0,y, cvW,cvH)).count();
1632 int brCols = items(QRect(x,y, cvW,cvH)).count();
1633 int minCols = tlCols;
1635 zp = _lastAutoPosition;
1652 if (minCols > tlCols) {
1656 if (minCols > trCols) {
1660 if (minCols > blCols) {
1664 if (minCols > brCols) {
1669 _lastAutoPosition = zp;
1674 newZoomPos = QPoint(0, 0);
1677 newZoomPos = QPoint(x, 0);
1680 newZoomPos = QPoint(0, y);
1683 newZoomPos = QPoint(x, y);
1689 if (newZoomPos != oldZoomPos)
1690 _panningView->move(newZoomPos);
1693 _panningView->hide();
1695 _panningView->show();
1700 if (!_scene)
return;
1702 if (_selectedNode && _selectedNode->
canvasNode()) {
1721 if ((e->key() == Qt::Key_Return) ||(e->key() == Qt::Key_Space)) {
1724 else if (_selectedEdge && _selectedEdge->
call())
1730 if (!(e->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier))
1731 &&(_selectedNode || _selectedEdge)&&((e->key() == Qt::Key_Up)
1732 ||(e->key() == Qt::Key_Down)||(e->key() == Qt::Key_Left)||(e->key()
1733 == Qt::Key_Right))) {
1746 key = Qt::Key_Right;
1759 if (_selectedNode) {
1760 if (key == Qt::Key_Up)
1762 if (key == Qt::Key_Down)
1764 if (key == Qt::Key_Right)
1766 if (key == Qt::Key_Left)
1768 }
else if (_selectedEdge) {
1769 if (key == Qt::Key_Up)
1771 if (key == Qt::Key_Down)
1773 if (key == Qt::Key_Right)
1775 if (key == Qt::Key_Left)
1787 QPointF center = mapToScene(viewport()->rect().center());
1788 if (e->key() == Qt::Key_Home)
1789 centerOn(center + QPointF(-_scene->width(), 0));
1790 else if (e->key() == Qt::Key_End)
1791 centerOn(center + QPointF(_scene->width(), 0));
1792 else if (e->key() == Qt::Key_PageUp) {
1793 QPointF dy = mapToScene(0, height()) - mapToScene(0, 0);
1794 centerOn(center + QPointF(-dy.x()/2, -dy.y()/2));
1795 }
else if (e->key() == Qt::Key_PageDown) {
1796 QPointF dy = mapToScene(0, height()) - mapToScene(0, 0);
1797 centerOn(center + QPointF(dy.x()/2, dy.y()/2));
1798 }
else if (e->key() == Qt::Key_Left) {
1799 QPointF dx = mapToScene(width(), 0) - mapToScene(0, 0);
1800 centerOn(center + QPointF(-dx.x()/10, -dx.y()/10));
1801 }
else if (e->key() == Qt::Key_Right) {
1802 QPointF dx = mapToScene(width(), 0) - mapToScene(0, 0);
1803 centerOn(center + QPointF(dx.x()/10, dx.y()/10));
1804 }
else if (e->key() == Qt::Key_Down) {
1805 QPointF dy = mapToScene(0, height()) - mapToScene(0, 0);
1806 centerOn(center + QPointF(dy.x()/10, dy.y()/10));
1807 }
else if (e->key() == Qt::Key_Up) {
1808 QPointF dy = mapToScene(0, height()) - mapToScene(0, 0);
1809 centerOn(center + QPointF(-dy.x()/10, -dy.y()/10));
1816 QGraphicsView::resizeEvent(e);
1818 updateSizes(e->size());
1824 switch (i->
type()) {
1836 void CallGraphView::doUpdate(
int changeType,
bool)
1854 if (n == _selectedNode)
1859 if (e == _selectedEdge)
1864 if (_selectedNode && _selectedNode->
canvasNode()) {
1868 if (_selectedEdge && _selectedEdge->
canvasEdge()) {
1886 #if 0 // do not change position when selecting edge
1890 if (!sNode && _selectedEdge->
toNode())
1896 ensureVisible(sNode);
1912 for (
int i = 0; i < l.size(); ++i)
1930 void CallGraphView::clear()
1935 _panningView->setScene(0);
1941 void CallGraphView::showText(QString s)
1944 _renderTimer.stop();
1946 _scene =
new QGraphicsScene;
1948 _scene->addSimpleText(s);
1952 _panningView->hide();
1960 s = tr(
"Warning: a long lasting graph layouting is in progress.\n"
1961 "Reduce node/edge limits for speedup.\n");
1963 s = tr(
"Layouting stopped.\n");
1965 s.append(tr(
"The call graph has %1 nodes and %2 edges.\n")
1974 err = tr(
"No graph available because the layouting process failed.\n");
1976 err += tr(
"Trying to run the following command did not work:\n"
1977 "'%1'\n").arg(_renderProcessCmdLine);
1978 err += tr(
"Please check that 'dot' is installed (package GraphViz).");
1981 err += QString(
"\n\n%1").arg(s);
1988 if (!_renderProcess)
1991 qDebug(
"CallGraphView::stopRendering: Killing QProcess %p",
1994 _renderProcess->kill();
1997 _renderProcess->deleteLater();
1999 _unparsedOutput = QString();
2001 _renderTimer.setSingleShot(
true);
2002 _renderTimer.start(200);
2005 void CallGraphView::refresh()
2012 _prevSelectedNode = _selectedNode;
2013 _prevSelectedPos = QPoint(-1, -1);
2014 if (_selectedNode) {
2015 QPointF center = _selectedNode->
canvasNode()->rect().center();
2016 _prevSelectedPos = mapFromScene(center);
2020 showText(tr(
"No item activated for which to "
2021 "draw the call graph."));
2032 showText(tr(
"No call graph can be drawn for "
2033 "the active item."));
2038 qDebug() <<
"CallGraphView::refresh";
2058 QString renderProgram;
2059 QStringList renderArgs;
2061 renderProgram =
"twopi";
2063 renderProgram =
"dot";
2064 renderArgs <<
"-Tplain";
2066 _unparsedOutput = QString();
2069 _renderTimer.setSingleShot(
true);
2070 _renderTimer.start(1000);
2072 _renderProcess =
new QProcess(
this);
2073 connect(_renderProcess, SIGNAL(readyReadStandardOutput()),
2075 connect(_renderProcess, SIGNAL(error(QProcess::ProcessError)),
2077 connect(_renderProcess, SIGNAL(finished(
int,QProcess::ExitStatus)),
2080 _renderProcessCmdLine = renderProgram +
" " + renderArgs.join(
" ");
2081 qDebug(
"CallGraphView::refresh: Starting process %p, '%s'",
2082 _renderProcess, qPrintable(_renderProcessCmdLine));
2086 QProcess* p = _renderProcess;
2087 p->start(renderProgram, renderArgs);
2090 p->closeWriteChannel();
2095 QProcess* p = qobject_cast<QProcess*>(sender());
2096 qDebug(
"CallGraphView::readDotOutput: QProcess %p", p);
2099 if ((_renderProcess == 0) || (p != _renderProcess)) {
2104 _unparsedOutput.append(_renderProcess->readAllStandardOutput());
2109 QProcess* p = qobject_cast<QProcess*>(sender());
2110 qDebug(
"CallGraphView::dotError: Got %d from QProcess %p",
2114 if ((_renderProcess == 0) || (p != _renderProcess)) {
2122 _renderProcess->deleteLater();
2129 QProcess* p = qobject_cast<QProcess*>(sender());
2130 qDebug(
"CallGraphView::dotExited: QProcess %p", p);
2133 if ((_renderProcess == 0) || (p != _renderProcess)) {
2138 _unparsedOutput.append(_renderProcess->readAllStandardOutput());
2139 _renderProcess->deleteLater();
2144 QGraphicsEllipseItem* eItem;
2147 QTextStream* dotStream;
2148 double scale = 1.0, scaleX = 1.0, scaleY = 1.0;
2149 double dotWidth = 0, dotHeight = 0;
2153 _renderTimer.stop();
2154 viewport()->setUpdatesEnabled(
false);
2156 dotStream =
new QTextStream(&_unparsedOutput, QIODevice::ReadOnly);
2160 double nodeHeight = 0.0;
2162 line = dotStream->readLine();
2163 if (line.isNull())
break;
2164 if (line.isEmpty())
continue;
2165 QTextStream lineStream(&line, QIODevice::ReadOnly);
2167 if (cmd !=
"node")
continue;
2169 lineStream >> s >> s >> s >> s >> h ;
2170 nodeHeight = h.toDouble();
2173 if (nodeHeight > 0.0) {
2174 scaleY = (8 + (1 + 2 *
_detailLevel) * fontMetrics().height()) / nodeHeight;
2180 line = dotStream->readLine();
2188 QTextStream lineStream(&line, QIODevice::ReadOnly);
2192 qDebug(
"%s:%d - line '%s', cmd '%s'",
2194 lineno, qPrintable(line), qPrintable(cmd));
2199 if (cmd ==
"graph") {
2200 QString dotWidthString, dotHeightString;
2202 lineStream >> scale >> dotWidthString >> dotHeightString;
2203 dotWidth = dotWidthString.toDouble();
2204 dotHeight = dotHeightString.toDouble();
2207 int w = (int)(scaleX * dotWidth);
2208 int h = (int)(scaleY * dotHeight);
2213 if (w < QApplication::desktop()->width())
2214 _xMargin += (QApplication::desktop()->width()-w)/2;
2217 if (h < QApplication::desktop()->height())
2218 _yMargin += (QApplication::desktop()->height()-h)/2;
2220 _scene =
new QGraphicsScene( 0.0, 0.0,
2221 qreal(w+2*_xMargin), qreal(h+2*_yMargin));
2224 _scene->setBackgroundBrush(Qt::white);
2227 qDebug() << qPrintable(_exporter.
filename()) <<
":" << lineno
2228 <<
" - graph (" << dotWidth <<
" x " << dotHeight
2229 <<
") => (" << w <<
" x " << h <<
")";
2232 qDebug() <<
"Ignoring 2nd 'graph' from dot ("
2233 << _exporter.
filename() <<
":"<< lineno <<
")";
2237 if ((cmd !=
"node") && (cmd !=
"edge")) {
2238 qDebug() <<
"Ignoring unknown command '"<< cmd
2239 <<
"' from dot ("<< _exporter.
filename() <<
":"<< lineno
2245 qDebug() <<
"Ignoring '"<< cmd
2246 <<
"' without 'graph' from dot ("<< _exporter.
filename()
2247 <<
":"<< lineno <<
")";
2251 if (cmd ==
"node") {
2253 QString nodeName, label, nodeX, nodeY, nodeWidth, nodeHeight;
2254 double x, y, width, height;
2255 lineStream >> nodeName >> nodeX >> nodeY >> nodeWidth
2257 x = nodeX.toDouble();
2258 y = nodeY.toDouble();
2259 width = nodeWidth.toDouble();
2260 height = nodeHeight.toDouble();
2264 int xx = (int)(scaleX * x + _xMargin);
2265 int yy = (int)(scaleY * (dotHeight - y)+ _yMargin);
2266 int w = (int)(scaleX * width);
2267 int h = (int)(scaleY * height);
2270 qDebug() << _exporter.
filename() <<
":" << lineno
2271 <<
" - node '" << nodeName <<
"' ( "
2272 << x <<
"/" << y <<
" - "
2273 << width <<
"x" << height <<
" ) => ("
2274 << xx-w/2 <<
"/" << yy-h/2 <<
" - "
2275 << w <<
"x" << h <<
")" << endl;
2279 if (nodeName[0] ==
'R'|| nodeName[0] ==
'S') {
2281 eItem =
new QGraphicsEllipseItem( QRectF(xx-w/2, yy-h/2, w, h) );
2282 _scene->addItem(eItem);
2283 eItem->setBrush(Qt::gray);
2284 eItem->setZValue(1.0);
2290 qDebug(
"Warning: Unknown function '%s' ?!",
2291 qPrintable(nodeName));
2296 rItem =
new CanvasNode(
this, n, xx-w/2, yy-h/2, w, h);
2299 _scene->addItem(rItem);
2310 rItem->setZValue(1.0);
2318 QString node1Name, node2Name, label, edgeX, edgeY;
2322 lineStream >> node1Name >> node2Name >> points;
2325 _exporter.
toFunc(node2Name));
2327 qDebug() <<
"Unknown edge '"<< node1Name <<
"'-'"<< node2Name
2328 <<
"' from dot ("<< _exporter.
filename() <<
":"<< lineno
2339 qDebug(
" Edge with %d points:", points);
2341 poly.resize(points);
2342 for (i=0; i<points; i++) {
2343 if (lineStream.atEnd())
2345 lineStream >> edgeX >> edgeY;
2346 x = edgeX.toDouble();
2347 y = edgeY.toDouble();
2349 int xx = (int)(scaleX * x + _xMargin);
2350 int yy = (int)(scaleY * (dotHeight - y)+ _yMargin);
2353 qDebug(
" P %d: ( %f / %f ) => ( %d / %d)", i, x, y, xx, yy);
2355 poly.setPoint(i, xx, yy);
2358 qDebug(
"CallGraphView: Can not read %d spline points (%s:%d)",
2359 points, qPrintable(_exporter.
filename()), lineno);
2364 QColor arrowColor = Qt::black;
2367 if ( (caller && (caller->
cycle() == caller)) ||
2368 (called && (called->
cycle() == called)) ) arrowColor = Qt::blue;
2371 _scene->addItem(sItem);
2375 sItem->setPen(QPen(arrowColor));
2376 sItem->setZValue(0.5);
2393 QPointF toCenter = fromNode->rect().center();
2394 qreal dx0 = poly.point(0).x() - toCenter.x();
2395 qreal dy0 = poly.point(0).y() - toCenter.y();
2396 qreal dx1 = poly.point(points-1).x() - toCenter.x();
2397 qreal dy1 = poly.point(points-1).y() - toCenter.y();
2398 if (dx0*dx0+dy0*dy0 > dx1*dx1+dy1*dy1) {
2401 while (arrowDir.isNull() && (indexHead<points-2)) {
2403 arrowDir = poly.point(indexHead) - poly.point(indexHead+1);
2408 if (arrowDir.isNull()) {
2411 while (arrowDir.isNull() && (indexHead>1)) {
2413 arrowDir = poly.point(indexHead) - poly.point(indexHead-1);
2417 if (!arrowDir.isNull()) {
2419 arrowDir *= 10.0/sqrt(
double(arrowDir.x()*arrowDir.x() +
2420 arrowDir.y()*arrowDir.y()));
2423 a << QPointF(poly.point(indexHead) + arrowDir);
2424 a << QPointF(poly.point(indexHead) + QPoint(arrowDir.y()/2,
2426 a << QPointF(poly.point(indexHead) + QPoint(-arrowDir.y()/2,
2430 qDebug(
" Arrow: ( %f/%f, %f/%f, %f/%f)", a[0].x(), a[0].y(),
2431 a[1].x(), a[1].y(), a[2].x(), a[1].y());
2434 _scene->addItem(aItem);
2435 aItem->setPolygon(a);
2436 aItem->setBrush(arrowColor);
2437 aItem->setZValue(1.5);
2443 if (lineStream.atEnd())
2452 lineStream >> label;
2456 while (!c.isNull() && (c !=
'\"')) {
2463 lineStream >> edgeX >> edgeY;
2464 x = edgeX.toDouble();
2465 y = edgeY.toDouble();
2467 int xx = (int)(scaleX * x + _xMargin);
2468 int yy = (int)(scaleY * (dotHeight - y)+ _yMargin);
2471 qDebug(
" Label '%s': ( %f / %f ) => ( %d / %d)",
2472 qPrintable(label), x, y, xx, yy);
2478 _scene->addItem(lItem);
2480 lItem->setZValue(1.5);
2492 _scene =
new QGraphicsScene;
2494 QString s = tr(
"Error running the graph layouting tool.\n");
2495 s += tr(
"Please check that 'dot' is installed (package GraphViz).");
2496 _scene->addSimpleText(s);
2498 }
else if (!activeNode && !activeEdge) {
2499 QString s = tr(
"There is no call graph available for function\n"
2501 "because it has no cost of the selected event type.")
2503 _scene->addSimpleText(s);
2507 _panningView->setScene(_scene);
2512 if ((!_selectedNode || !_selectedNode->
canvasNode()) &&
2513 (!_selectedEdge || !_selectedEdge->
canvasEdge())) {
2515 _selectedNode = activeNode;
2517 }
else if (activeEdge) {
2518 _selectedEdge = activeEdge;
2526 else if (_selectedEdge) {
2529 if (!sNode && _selectedEdge->
toNode())
2534 if (_prevSelectedNode) {
2535 QPointF prevPos = mapToScene(_prevSelectedPos);
2536 if (rect().contains(_prevSelectedPos)) {
2537 QPointF wCenter = mapToScene(viewport()->rect().center());
2538 centerOn(sNode->rect().center() +
2542 ensureVisible(sNode);
2551 f->setPos(cn->pos());
2559 viewport()->setUpdatesEnabled(
true);
2561 delete _renderProcess;
2570 QGraphicsView::scrollContentsBy(dx, dy);
2572 QPointF topLeft = mapToScene(QPoint(0, 0));
2573 QPointF bottomRight = mapToScene(QPoint(width(), height()));
2575 QRectF z(topLeft, bottomRight);
2577 qDebug(
"CallGraphView::scrollContentsBy(dx %d, dy %d) - to (%f,%f - %f,%f)",
2578 dx, dy, topLeft.x(), topLeft.y(),
2579 bottomRight.x(), bottomRight.y());
2588 QScrollBar *hBar = horizontalScrollBar();
2589 QScrollBar *vBar = verticalScrollBar();
2590 hBar->setValue(hBar->value() + int(dx));
2591 vBar->setValue(vBar->value() + int(dy));
2596 if (_zoomPosition ==
Auto)
2606 if (e->button() == Qt::LeftButton) _isMoving =
true;
2608 QGraphicsItem* i = itemAt(e->pos());
2614 qDebug(
"CallGraphView: Got Node '%s'",
2629 qDebug(
"CallGraphView: Got Edge '%s'",
2636 _lastPos = e->pos();
2642 QPoint delta = e->pos() - _lastPos;
2644 QScrollBar *hBar = horizontalScrollBar();
2645 QScrollBar *vBar = verticalScrollBar();
2646 hBar->setValue(hBar->value() - delta.x());
2647 vBar->setValue(vBar->value() - delta.y());
2649 _lastPos = e->pos();
2656 if (_zoomPosition ==
Auto)
2662 QGraphicsItem* i = itemAt(e->pos());
2669 qDebug(
"CallGraphView: Double Clicked on Node '%s'",
2685 qDebug(
"CallGraphView: Double Clicked On Edge '%s'",
2696 QAction* CallGraphView::addCallerDepthAction(QMenu* m, QString s,
int d)
2700 a = m->addAction(s);
2702 a->setCheckable(
true);
2708 QMenu* CallGraphView::addCallerDepthMenu(QMenu* menu)
2713 m = menu->addMenu(tr(
"Caller Depth"));
2714 a = addCallerDepthAction(m, tr(
"Unlimited"), -1);
2717 addCallerDepthAction(m, tr(
"Depth 0",
"None"), 0);
2718 addCallerDepthAction(m, tr(
"max. 2"), 2);
2719 addCallerDepthAction(m, tr(
"max. 5"), 5);
2720 addCallerDepthAction(m, tr(
"max. 10"), 10);
2721 addCallerDepthAction(m, tr(
"max. 15"), 15);
2723 connect(m, SIGNAL(triggered(QAction*)),
2735 QAction* CallGraphView::addCalleeDepthAction(QMenu* m, QString s,
int d)
2739 a = m->addAction(s);
2741 a->setCheckable(
true);
2747 QMenu* CallGraphView::addCalleeDepthMenu(QMenu* menu)
2752 m = menu->addMenu(tr(
"Callee Depth"));
2753 a = addCalleeDepthAction(m, tr(
"Unlimited"), -1);
2756 addCalleeDepthAction(m, tr(
"Depth 0",
"None"), 0);
2757 addCalleeDepthAction(m, tr(
"max. 2"), 2);
2758 addCalleeDepthAction(m, tr(
"max. 5"), 5);
2759 addCalleeDepthAction(m, tr(
"max. 10"), 10);
2760 addCalleeDepthAction(m, tr(
"max. 15"), 15);
2762 connect(m, SIGNAL(triggered(QAction*)),
2774 QAction* CallGraphView::addNodeLimitAction(QMenu* m, QString s,
double l)
2778 a = m->addAction(s);
2780 a->setCheckable(
true);
2786 QMenu* CallGraphView::addNodeLimitMenu(QMenu* menu)
2791 m = menu->addMenu(tr(
"Min. Node Cost"));
2792 a = addNodeLimitAction(m, tr(
"No Minimum"), 0.0);
2798 addNodeLimitAction(m, tr(
"50 %"), .5);
2799 addNodeLimitAction(m, tr(
"20 %"), .2);
2800 addNodeLimitAction(m, tr(
"10 %"), .1);
2801 addNodeLimitAction(m, tr(
"5 %"), .05);
2802 addNodeLimitAction(m, tr(
"2 %"), .02);
2803 addNodeLimitAction(m, tr(
"1 %"), .01);
2805 connect(m, SIGNAL(triggered(QAction*)),
2817 QAction* CallGraphView::addCallLimitAction(QMenu* m, QString s,
double l)
2821 a = m->addAction(s);
2823 a->setCheckable(
true);
2829 QMenu* CallGraphView::addCallLimitMenu(QMenu* menu)
2833 m = menu->addMenu(tr(
"Min. Call Cost"));
2834 addCallLimitAction(m, tr(
"Same as Node"), 1.0);
2836 addCallLimitAction(m, tr(
"50 % of Node"), .5);
2838 addCallLimitAction(m, tr(
"20 % of Node"), .2);
2840 addCallLimitAction(m, tr(
"10 % of Node"), .1);
2842 connect(m, SIGNAL(triggered(QAction*)),
2854 QAction* CallGraphView::addZoomPosAction(QMenu* m, QString s,
2859 a = m->addAction(s);
2861 a->setCheckable(
true);
2862 a->setChecked(_zoomPosition == p);
2867 QMenu* CallGraphView::addZoomPosMenu(QMenu* menu)
2869 QMenu* m = menu->addMenu(tr(
"Birds-eye View"));
2870 addZoomPosAction(m, tr(
"Top Left"),
TopLeft);
2871 addZoomPosAction(m, tr(
"Top Right"),
TopRight);
2872 addZoomPosAction(m, tr(
"Bottom Left"),
BottomLeft);
2873 addZoomPosAction(m, tr(
"Bottom Right"),
BottomRight);
2874 addZoomPosAction(m, tr(
"Automatic"),
Auto);
2875 addZoomPosAction(m, tr(
"Hide"),
Hide);
2877 connect(m, SIGNAL(triggered(QAction*)),
2890 QAction* CallGraphView::addLayoutAction(QMenu* m, QString s,
2895 a = m->addAction(s);
2897 a->setCheckable(
true);
2903 QMenu* CallGraphView::addLayoutMenu(QMenu* menu)
2905 QMenu* m = menu->addMenu(tr(
"Layout"));
2906 addLayoutAction(m, tr(
"Top to Down"),
TopDown);
2907 addLayoutAction(m, tr(
"Left to Right"),
LeftRight);
2908 addLayoutAction(m, tr(
"Circular"),
Circular);
2910 connect(m, SIGNAL(triggered(QAction*)),
2928 QGraphicsItem* i = itemAt(e->pos());
2934 QAction* activateFunction = 0;
2935 QAction* activateCycle = 0;
2936 QAction* activateCall = 0;
2941 qDebug(
"CallGraphView: Menu on Node '%s'",
2948 QString menuStr = tr(
"Go to '%1'")
2950 activateFunction = popup.addAction(menuStr);
2951 if (cycle && (cycle != f)) {
2953 activateCycle = popup.addAction(tr(
"Go to '%1'").arg(name));
2955 popup.addSeparator();
2967 qDebug(
"CallGraphView: Menu on Edge '%s'",
2973 QString menuStr = tr(
"Go to '%1'")
2975 activateCall = popup.addAction(menuStr);
2977 popup.addSeparator();
2982 QAction* stopLayout = 0;
2983 if (_renderProcess) {
2984 stopLayout = popup.addAction(tr(
"Stop Layouting"));
2985 popup.addSeparator();
2989 popup.addSeparator();
2991 QMenu* epopup = popup.addMenu(tr(
"Export Graph"));
2992 QAction* exportAsDot = epopup->addAction(tr(
"As DOT file..."));
2993 QAction* exportAsImage = epopup->addAction(tr(
"As Image..."));
2994 popup.addSeparator();
2996 QMenu* gpopup = popup.addMenu(tr(
"Graph"));
2997 addCallerDepthMenu(gpopup);
2998 addCalleeDepthMenu(gpopup);
2999 addNodeLimitMenu(gpopup);
3000 addCallLimitMenu(gpopup);
3001 gpopup->addSeparator();
3003 QAction* toggleSkipped;
3004 toggleSkipped = gpopup->addAction(tr(
"Arrows for Skipped Calls"));
3005 toggleSkipped->setCheckable(
true);
3008 QAction* toggleExpand;
3009 toggleExpand = gpopup->addAction(tr(
"Inner-cycle Calls"));
3010 toggleExpand->setCheckable(
true);
3013 QAction* toggleCluster;
3014 toggleCluster = gpopup->addAction(tr(
"Cluster Groups"));
3015 toggleCluster->setCheckable(
true);
3018 QMenu* vpopup = popup.addMenu(tr(
"Visualization"));
3019 QAction* layoutCompact = vpopup->addAction(tr(
"Compact"));
3020 layoutCompact->setCheckable(
true);
3022 QAction* layoutNormal = vpopup->addAction(tr(
"Normal"));
3023 layoutNormal->setCheckable(
true);
3025 QAction* layoutTall = vpopup->addAction(tr(
"Tall"));
3026 layoutTall->setCheckable(
true);
3029 addLayoutMenu(&popup);
3030 addZoomPosMenu(&popup);
3032 QAction* a = popup.exec(e->globalPos());
3034 if (a == activateFunction)
3036 else if (a == activateCycle)
3038 else if (a == activateCall)
3041 else if (a == stopLayout)
3044 else if (a == exportAsDot) {
3049 n = QFileDialog::getSaveFileName(
this,
3050 tr(
"Export Graph As DOT file"),
3051 QString(), tr(
"Graphviz (*.dot)"));
3060 else if (a == exportAsImage) {
3062 if (!_scene)
return;
3065 n = QFileDialog::getSaveFileName(
this,
3066 tr(
"Export Graph As Image"),
3068 tr(
"Images (*.png *.jpg)"));
3071 QRect r = _scene->sceneRect().toRect();
3072 QPixmap pix(r.width(), r.height());
3074 _scene->render( &p );
3079 else if (a == toggleSkipped) {
3083 else if (a == toggleExpand) {
3087 else if (a == toggleCluster) {
3092 else if (a == layoutCompact) {
3096 else if (a == layoutNormal) {
3100 else if (a == layoutTall) {
3109 if (s == QString(
"TopLeft"))
3111 if (s == QString(
"TopRight"))
3113 if (s == QString(
"BottomLeft"))
3115 if (s == QString(
"BottomRight"))
3117 if (s == QString(
"Automatic"))
3119 if (s == QString(
"Hide"))
3128 return QString(
"TopLeft");
3130 return QString(
"TopRight");
3132 return QString(
"BottomLeft");
3134 return QString(
"BottomRight");
3136 return QString(
"Automatic");
3138 return QString(
"Hide");
3182 #include "callgraphview.moc"
virtual int detailLevel()=0
bool drawField(QPainter *, int f, DrawParams *dp=0)
virtual Layout layout()=0
A panner laid over a QGraphicsScene.
static bool showPercentage()
#define DEFAULT_EXPANDCYCLES
void setCallerNode(GraphNode *n)
SubCost subCost(EventType *)
Returns a sub cost.
void setArrow(CanvasEdgeArrow *a)
EventType * eventType() const
GraphEdge * edge(TraceFunction *, TraceFunction *)
TraceCall * priorVisibleCaller(GraphEdge *=0)
virtual int maxCallerDepth()=0
PanningView(QWidget *parent=0)
TraceFunction * visibleCallee()
void addUniqueCaller(GraphEdge *)
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
void setControlPoints(const QPolygon &a)
static QString zoomPosString(ZoomPosition)
void drawBack(QPainter *, DrawParams *dp=0)
CanvasEdge * canvasEdge() const
const TraceCallList & callings(bool skipCycle=false) const
GraphNode * node(TraceFunction *)
void setGraphOptions(GraphOptions *go=0)
#define DEFAULT_CLUSTERGROUPS
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
TraceFunction * caller(bool skipCycle=false) const
ProfileContext::Type type() const
ZoomPosition zoomPos() const
CanvasEdgeLabel(CallGraphView *, CanvasEdge *, int, int, int, int)
static QColor functionColor(ProfileContext::Type gt, TraceFunction *)
void setCanvasEdge(CanvasEdge *ce)
virtual bool clusterGroups()=0
void addCaller(GraphEdge *)
double percentage() const
TraceObject * object() const
virtual void setValue(const QString &key, const QVariant &value, const QVariant &defaultValue=QVariant())
void mousePressEvent(QMouseEvent *)
TraceFunctionCycle * cycle()
Base class for cost items.
TraceFunction * priorVisible()
void setPixmap(int f, const QPixmap &)
void zoomPosTriggered(QAction *)
void contextMenuEvent(QContextMenuEvent *)
void setCallee(TraceFunction *f)
void calleeDepthTriggered(QAction *)
void mouseReleaseEvent(QMouseEvent *)
void keyPressEvent(QKeyEvent *)
TraceFunction * activeFunction()
void setMaxLines(int f, int)
ProfileContext::Type _groupType
TraceCall * visibleCallee()
void mousePressEvent(QMouseEvent *)
QPixmap percentagePixmap(int w, int h, int percent, QColor c, bool framed)
Create a percentage pixmap with a filling rate of p percent (0-100).
void callerDepthTriggered(QAction *)
TraceCallList callers(bool skipCycle=false) const
void setBackColor(const QColor &c)
static ConfigGroup * group(const QString &group, const QString &optSuffix=QString())
Abstract Base Class for KCachegrind Views.
TraceCall * nextVisibleCaller(GraphEdge *=0)
#define DEFAULT_MAXCALLER
void setRect(const QRect &)
void setCaller(TraceFunction *f)
const QPolygon & controlPoints() const
CostItem * selectedItem() const
TraceFunction * from() const
virtual int maxCalleeDepth()=0
An array of basic cost metrics for a trace item.
virtual double funcLimit()=0
#define DEFAULT_DETAILLEVEL
TraceCall * visibleCaller()
TraceCall * priorVisible()
CanvasNode(CallGraphView *, GraphNode *, int, int, int, int)
CanvasEdgeArrow(CanvasEdge *)
TraceFunction * function() const
virtual QString name() const
Returns dynamic name info (without type)
void nodeLimitTriggered(QAction *)
CallerGraphEdgeLessThan callerGraphEdgeLessThan
QString whatsThis() const
void setCallee(GraphEdge *)
static QString layoutString(Layout)
GraphNode * toNode() const
void resizeEvent(QResizeEvent *)
void addCallee(GraphEdge *)
void setCalleeNode(GraphNode *n)
QString prettyName() const
Similar to name, but prettyfied = more descriptive to humans.
virtual TraceData * data()
TraceCall * priorVisibleCallee(GraphEdge *=0)
CallGraphView(TraceItemView *parentView, QWidget *parent=0, const char *name=0)
TraceCall * nextVisibleCallee(GraphEdge *=0)
void setFunction(TraceFunction *f)
void showRenderError(QString)
#define DEFAULT_MAXCALLEE
static QString shortenSymbol(const QString &)
A group of configuration settings.
void mouseMoveEvent(QMouseEvent *)
void addUniqueCallee(GraphEdge *)
void removeEdge(GraphEdge *)
virtual void selected(TraceItemView *sender, CostItem *)
Notification from child views.
void setCanvasNode(CanvasNode *cn)
virtual void activated(TraceItemView *sender, CostItem *)
void mouseDoubleClickEvent(QMouseEvent *)
virtual double callLimit()=0
CalleeGraphEdgeLessThan calleeGraphEdgeLessThan
void setLabel(CanvasEdgeLabel *l)
TraceFunction * nextVisible()
void writeDot(QIODevice *=0)
static bool showExpanded()
void mouseMoveEvent(QMouseEvent *)
CostItem * activeItem() const
static int percentPrecision()
void callLimitTriggered(QAction *)
void setCall(TraceCall *c)
#define DEFAULT_FUNCLIMIT
Cost event counter, simple wrapper around a 64bit entity.
void reset(TraceData *, CostItem *, EventType *, ProfileContext::Type, QString filename=QString())
TraceFunction * called(bool skipCycle=false) const
void drawForeground(QPainter *p, const QRectF &)
void setText(int f, const QString &)
void mouseReleaseEvent(QMouseEvent *)
QString pretty(char sep= ' ') const
Convert SubCost value into a QString, spaced every 3 digits.
void zoomRectMoveFinished()
A QGraphicsView showing a part of the call graph and another zoomed out CanvasView in a border acting...
TraceFunction * toFunc(QString)
QList< TraceCall * > TraceCallList
void focusOutEvent(QFocusEvent *)
#define DEFAULT_SHOWSKIPPED
void focusInEvent(QFocusEvent *)
TraceFunction * to() const
void setPosition(int f, Position)
void setCaller(GraphEdge *)
virtual bool expandCycles()=0
void layoutTriggered(QAction *)
This class holds profiling data of multiple tracefiles generated with cachegrind on one command...
virtual QString prettyName() const
Similar to name, but prettyfied = more descriptive to humans.
A call from one to another function.
void zoomRectMoved(qreal, qreal)
#define DEFAULT_CALLLIMIT
void zoomRectMoved(qreal dx, qreal dy)
ProfileContext::Type groupType() const
void saveOptions(const QString &prefix, const QString &postfix)
void setZoomRect(const QRectF &r)
void restoreOptions(const QString &prefix, const QString &postfix)
void zoomRectMoveFinished()
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
ProfileCostArray * inclusive()
GraphNode * fromNode() const
virtual bool showSkipped()=0
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
CanvasFrame(CanvasNode *)
virtual QVariant value(const QString &key, const QVariant &defaultValue) const
TraceCall * nextVisible()
TraceFunction * visibleCaller()
void scrollContentsBy(int dx, int dy)
CanvasNode * canvasNode() const