/* This file is part of KCachegrind. Copyright (C) 2003 Josef Weidendorfer KCachegrind is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Items of source view. */ #include #include #include #include #include #include #include "configuration.h" #include "listutils.h" #include "sourceview.h" #include "sourceitem.h" // SourceItem // for source lines SourceItem::SourceItem(SourceView* sv, TQListView* parent, int fileno, unsigned int lineno, bool inside, const TQString& src, TraceLine* line) : TQListViewItem(parent) { _view = sv; _lineno = lineno; _fileno = fileno; _inside = inside; _line = line; _lineCall = 0; _lineJump = 0; if (src == "...") setText(0, src); else setText(0, TQString::number(lineno)); TQString s = src; setText(4, s.replace( TQRegExp("\t"), " " )); updateGroup(); updateCost(); } // for call lines SourceItem::SourceItem(SourceView* sv, TQListViewItem* parent, int fileno, unsigned int lineno, TraceLine* line, TraceLineCall* lineCall) : TQListViewItem(parent) { _view = sv; _lineno = lineno; _fileno = fileno; _inside = true; _line = line; _lineCall = lineCall; _lineJump = 0; //tqDebug("SourceItem: (file %d, line %d) Linecall to %s", // fileno, lineno, _lineCall->call()->called()->prettyName().ascii()); SubCost cc = _lineCall->callCount(); TQString templ = " "; if (cc==0) templ += i18n("Active call to '%1'"); else templ += i18n("%n call to '%1'", "%n calls to '%1'", cc); TQString callStr = templ.arg(_lineCall->call()->calledName()); TraceFunction* calledF = _lineCall->call()->called(); calledF->addPrettyLocation(callStr); setText(4, callStr); updateGroup(); updateCost(); } // for jump lines SourceItem::SourceItem(SourceView* sv, TQListViewItem* parent, int fileno, unsigned int lineno, TraceLine* line, TraceLineJump* lineJump) : TQListViewItem(parent) { _view = sv; _lineno = lineno; _fileno = fileno; _inside = true; _line = line; _lineCall = 0; _lineJump = lineJump; //tqDebug("SourceItem: (file %d, line %d) Linecall to %s", // fileno, lineno, _lineCall->call()->called()->prettyName().ascii()); TQString to; if (_lineJump->lineTo()->functionSource() == _line->functionSource()) to = _lineJump->lineTo()->name(); else to = _lineJump->lineTo()->prettyName(); TQString jStr; if (_lineJump->isCondJump()) jStr = i18n("Jump %1 of %2 times to %3") .arg(_lineJump->followedCount().pretty()) .arg(_lineJump->executedCount().pretty()) .arg(to); else jStr = i18n("Jump %1 times to %2") .arg(_lineJump->executedCount().pretty()) .arg(to); setText(4, jStr); } void SourceItem::updateGroup() { if (!_lineCall) return; TraceFunction* f = _lineCall->call()->called(); TQColor c = Configuration::functionColor(_view->groupType(), f); setPixmap(4, colorPixmap(10, 10, c)); } void SourceItem::updateCost() { _pure = SubCost(0); _pure2 = SubCost(0); if (!_line) return; if (_lineJump) return; TraceCost* lineCost = _lineCall ? (TraceCost*)_lineCall : (TraceCost*)_line; // don't show any cost inside of cycles if (_lineCall && ((_lineCall->call()->inCycle()>0) || (_lineCall->call()->isRecursion()>0))) { TQString str; TQPixmap p; TQString icon = "edit-undo"; TDEIconLoader* loader = TDEApplication::kApplication()->iconLoader(); p= loader->loadIcon(icon, TDEIcon::Small, 0, TDEIcon::DefaultState, 0, true); if (p.isNull()) str = i18n("(cycle)"); setText(1, str); setPixmap(1, p); setText(2, str); setPixmap(2, p); return; } TraceCost* totalCost; if (Configuration::showExpanded()) totalCost = _line->functionSource()->function()->inclusive(); else totalCost = _line->functionSource()->function()->data(); TraceCostType* ct = _view->costType(); _pure = ct ? lineCost->subCost(ct) : SubCost(0); if (_pure == 0) { setText(1, TQString()); setPixmap(1, TQPixmap()); } else { double total = totalCost->subCost(ct); double pure = 100.0 * _pure / total; if (Configuration::showPercentage()) setText(1, TQString("%1") .arg(pure, 0, 'f', Configuration::percentPrecision())); else setText(1, _pure.pretty()); setPixmap(1, costPixmap(ct, lineCost, total, false)); } TraceCostType* ct2 = _view->costType2(); _pure2 = ct2 ? lineCost->subCost(ct2) : SubCost(0); if (_pure2 == 0) { setText(2, TQString()); setPixmap(2, TQPixmap()); } else { double total = totalCost->subCost(ct2); double pure2 = 100.0 * _pure2 / total; if (Configuration::showPercentage()) setText(2, TQString("%1") .arg(pure2, 0, 'f', Configuration::percentPrecision())); else setText(2, _pure2.pretty()); setPixmap(2, costPixmap(ct2, lineCost, total, false)); } } int SourceItem::compare(TQListViewItem * i, int col, bool ascending ) const { const SourceItem* si1 = this; const SourceItem* si2 = (SourceItem*) i; // we always want descending order if (((col>0) && ascending) || ((col==0) && !ascending) ) { si1 = si2; si2 = this; } if (col==1) { if (si1->_pure < si2->_pure) return -1; if (si1->_pure > si2->_pure) return 1; return 0; } if (col==2) { if (si1->_pure2 < si2->_pure2) return -1; if (si1->_pure2 > si2->_pure2) return 1; return 0; } if (col==0) { // Sort file numbers if (si1->_fileno < si2->_fileno) return -1; if (si1->_fileno > si2->_fileno) return 1; // Sort line numbers if (si1->_lineno < si2->_lineno) return -1; if (si1->_lineno > si2->_lineno) return 1; // Same line: code gets above calls/jumps if (!si1->_lineCall && !si1->_lineJump) return -1; if (!si2->_lineCall && !si2->_lineJump) return 1; // calls above jumps if (si1->_lineCall && !si2->_lineCall) return -1; if (si2->_lineCall && !si1->_lineCall) return 1; if (si1->_lineCall && si2->_lineCall) { // Two calls: desending sort according costs if (si1->_pure < si2->_pure) return 1; if (si1->_pure > si2->_pure) return -1; // Two calls: sort according function names TraceFunction* f1 = si1->_lineCall->call()->called(); TraceFunction* f2 = si2->_lineCall->call()->called(); if (f1->prettyName() > f2->prettyName()) return 1; return -1; } // Two jumps: descending sort according target line if (si1->_lineJump->lineTo()->lineno() < si2->_lineJump->lineTo()->lineno()) return -1; if (si1->_lineJump->lineTo()->lineno() > si2->_lineJump->lineTo()->lineno()) return 1; return 0; } return TQListViewItem::compare(i, col, ascending); } void SourceItem::paintCell( TQPainter *p, const TQColorGroup &cg, int column, int width, int alignment ) { TQColorGroup _cg( cg ); if ( !_inside || ((column==1) || (column==2))) _cg.setColor( TQColorGroup::Base, cg.button() ); else if ((_lineCall || _lineJump) && column>2) _cg.setColor( TQColorGroup::Base, cg.midlight() ); if (column == 3) paintArrows(p, _cg, width); else TQListViewItem::paintCell( p, _cg, column, width, alignment ); } void SourceItem::setJumpArray(const TQMemArray& a) { _jump.duplicate(a); } void SourceItem::paintArrows(TQPainter *p, const TQColorGroup &cg, int width) { TQListView *lv = listView(); if ( !lv ) return; SourceView* sv = (SourceView*) lv; const BackgroundMode bgmode = lv->viewport()->backgroundMode(); const TQColorGroup::ColorRole crole = TQPalette::backgroundRoleFromMode( bgmode ); if ( cg.brush( crole ) != lv->colorGroup().brush( crole ) ) p->fillRect( 0, 0, width, height(), cg.brush( crole ) ); else sv->paintEmptyArea( p, TQRect( 0, 0, width, height() ) ); if ( isSelected() && lv->allColumnsShowFocus() ) p->fillRect( 0, 0, width, height(), cg.brush( TQColorGroup::Highlight ) ); int marg = lv->itemMargin(); int yy = height()/2, y1, y2; TQColor c; int start = -1, end = -1; // draw line borders, detect start/stop of a line for(int i=0;i< (int)_jump.size();i++) { if (_jump[i] == 0) continue; y1 = 0; y2 = height(); if (_lineJump && (_lineJump->lineTo() == _jump[i]->lineTo()) && (_jump[i]->lineFrom()->lineno() == _lineno)) { if (start<0) start = i; if (_lineJump == _jump[i]) { if (_jump[i]->lineTo()->lineno() <= _lineno) y2 = yy; else y1 = yy; } } else if (!_lineJump && !_lineCall && (_jump[i]->lineTo()->lineno() == _lineno)) { if (end<0) end = i; if (_jump[i]->lineFrom()->lineno() < _lineno) y2 = yy; else y1 = yy; } c = _jump[i]->isCondJump() ? red : blue; p->fillRect( marg + 6*i, y1, 4, y2, c); p->setPen(c.light()); p->drawLine( marg + 6*i, y1, marg + 6*i, y2); p->setPen(c.dark()); p->drawLine( marg + 6*i +3, y1, marg + 6*i +3, y2); } // draw start/stop horizontal line int x, y = yy-2, w, h = 4; if (start >= 0) { c = _jump[start]->isCondJump() ? red : blue; x = marg + 6*start; w = 6*(sv->arrowLevels() - start) + 10; p->fillRect( x, y, w, h, c); p->setPen(c.light()); p->drawLine(x, y, x+w-1, y); p->drawLine(x, y, x, y+h-1); p->setPen(c.dark()); p->drawLine(x+w-1, y, x+w-1, y+h-1); p->drawLine(x+1, y+h-1, x+w-1, y+h-1); } if (end >= 0) { c = _jump[end]->isCondJump() ? red : blue; x = marg + 6*end; w = 6*(sv->arrowLevels() - end) + 10; TQPointArray a; a.putPoints(0, 7, x, y+h, x,y, x+w-8, y, x+w-8, y-2, x+w, yy, x+w-8, y+h+2, x+w-8, y+h); p->setBrush(c); p->drawConvexPolygon(a); p->setPen(c.light()); p->drawPolyline(a, 0, 5); p->setPen(c.dark()); p->drawPolyline(a, 4, 2); p->setPen(c.light()); p->drawPolyline(a, 5, 2); p->setPen(c.dark()); p->drawPolyline(a, 6, 2); } // draw inner vertical line for start/stop // this overwrites borders of horizontal line for(int i=0;i< (int)_jump.size();i++) { if (_jump[i] == 0) continue; c = _jump[i]->isCondJump() ? red : blue; if (_jump[i]->lineFrom()->lineno() == _lineno) { bool drawUp = true; if (_jump[i]->lineTo()->lineno() == _lineno) if (start<0) drawUp = false; if (_jump[i]->lineTo()->lineno() > _lineno) drawUp = false; if (drawUp) p->fillRect( marg + 6*i +1, 0, 2, yy, c); else p->fillRect( marg + 6*i +1, yy, 2, height()-yy, c); } else if (_jump[i]->lineTo()->lineno() == _lineno) { if (end<0) end = i; if (_jump[i]->lineFrom()->lineno() < _lineno) p->fillRect( marg + 6*i +1, 0, 2, yy, c); else p->fillRect( marg + 6*i +1, yy, 2, height()-yy, c); } } } int SourceItem::width( const TQFontMetrics& fm, const TQListView* lv, int c ) const { if (c != 3) return TQListViewItem::width(fm, lv, c); SourceView* sv = (SourceView*) lv; int levels = sv->arrowLevels(); if (levels == 0) return 0; // 10 pixels for the arrow return 10 + 6*levels + lv->itemMargin() * 2; }