You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
814 lines
22 KiB
814 lines
22 KiB
/* This file is part of KCachegrind.
|
|
Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
|
|
|
|
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.
|
|
*/
|
|
|
|
/*
|
|
* Source View
|
|
*/
|
|
|
|
#include <tqdir.h>
|
|
#include <tqfile.h>
|
|
#include <tqwhatsthis.h>
|
|
#include <tqpopupmenu.h>
|
|
#include <tdelocale.h>
|
|
#include <kdebug.h>
|
|
|
|
#include "configuration.h"
|
|
#include "sourceitem.h"
|
|
#include "sourceview.h"
|
|
|
|
|
|
//
|
|
// SourceView
|
|
//
|
|
|
|
|
|
SourceView::SourceView(TraceItemView* parentView,
|
|
TQWidget* parent, const char* name)
|
|
: TQListView(parent, name), TraceItemView(parentView)
|
|
{
|
|
_inSelectionUpdate = false;
|
|
|
|
_arrowLevels = 0;
|
|
_lowList.setSortLow(true);
|
|
_highList.setSortLow(false);
|
|
|
|
addColumn( i18n( "#" ) );
|
|
addColumn( i18n( "Cost" ) );
|
|
addColumn( i18n( "Cost 2" ) );
|
|
addColumn( "" );
|
|
addColumn( i18n( "Source (unknown)" ) );
|
|
|
|
setAllColumnsShowFocus(true);
|
|
setColumnAlignment(0, TQt::AlignRight);
|
|
setColumnAlignment(1, TQt::AlignRight);
|
|
setColumnAlignment(2, TQt::AlignRight);
|
|
setResizeMode(TQListView::LastColumn);
|
|
|
|
connect(this,
|
|
TQT_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint &, int)),
|
|
TQT_SLOT(context(TQListViewItem*, const TQPoint &, int)));
|
|
|
|
connect(this,
|
|
TQT_SIGNAL(selectionChanged(TQListViewItem*)),
|
|
TQT_SLOT(selectedSlot(TQListViewItem*)));
|
|
|
|
connect(this,
|
|
TQT_SIGNAL(doubleClicked(TQListViewItem*)),
|
|
TQT_SLOT(activatedSlot(TQListViewItem*)));
|
|
|
|
connect(this,
|
|
TQT_SIGNAL(returnPressed(TQListViewItem*)),
|
|
TQT_SLOT(activatedSlot(TQListViewItem*)));
|
|
|
|
TQWhatsThis::add( this, whatsThis());
|
|
}
|
|
|
|
void SourceView::paintEmptyArea( TQPainter * p, const TQRect & r)
|
|
{
|
|
TQListView::paintEmptyArea(p, r);
|
|
}
|
|
|
|
|
|
TQString SourceView::whatsThis() const
|
|
{
|
|
return i18n( "<b>Annotated Source</b>"
|
|
"<p>The annotated source list shows the "
|
|
"source lines of the current selected function "
|
|
"together with (self) cost spent while executing the "
|
|
"code of this source line. If there was a call "
|
|
"in a source line, lines with details on the "
|
|
"call happening are inserted into the source: "
|
|
"the cost spent inside of the call, the "
|
|
"number of calls happening, and the call destination.</p>"
|
|
"<p>Select a inserted call information line to "
|
|
"make the destination function current.</p>");
|
|
}
|
|
|
|
void SourceView::context(TQListViewItem* i, const TQPoint & p, int c)
|
|
{
|
|
TQPopupMenu popup;
|
|
|
|
// Menu entry:
|
|
TraceLineCall* lc = i ? ((SourceItem*) i)->lineCall() : 0;
|
|
TraceLineJump* lj = i ? ((SourceItem*) i)->lineJump() : 0;
|
|
TraceFunction* f = lc ? lc->call()->called() : 0;
|
|
TraceLine* line = lj ? lj->lineTo() : 0;
|
|
|
|
if (f) {
|
|
TQString name = f->name();
|
|
if ((int)name.length()>Configuration::maxSymbolLength())
|
|
name = name.left(Configuration::maxSymbolLength()) + "...";
|
|
popup.insertItem(i18n("Go to '%1'").arg(name), 93);
|
|
popup.insertSeparator();
|
|
}
|
|
else if (line) {
|
|
popup.insertItem(i18n("Go to Line %1").arg(line->name()), 93);
|
|
popup.insertSeparator();
|
|
}
|
|
|
|
if ((c == 1) || (c == 2)) {
|
|
addCostMenu(&popup);
|
|
popup.insertSeparator();
|
|
}
|
|
addGoMenu(&popup);
|
|
|
|
int r = popup.exec(p);
|
|
if (r == 93) {
|
|
if (f) activated(f);
|
|
if (line) activated(line);
|
|
}
|
|
}
|
|
|
|
|
|
void SourceView::selectedSlot(TQListViewItem * i)
|
|
{
|
|
if (!i) return;
|
|
// programatically selected items are not signalled
|
|
if (_inSelectionUpdate) return;
|
|
|
|
TraceLineCall* lc = ((SourceItem*) i)->lineCall();
|
|
TraceLineJump* lj = ((SourceItem*) i)->lineJump();
|
|
|
|
if (!lc && !lj) {
|
|
TraceLine* l = ((SourceItem*) i)->line();
|
|
if (l) {
|
|
_selectedItem = l;
|
|
selected(l);
|
|
}
|
|
return;
|
|
}
|
|
|
|
TraceFunction* f = lc ? lc->call()->called() : 0;
|
|
if (f) {
|
|
_selectedItem = f;
|
|
selected(f);
|
|
}
|
|
else {
|
|
TraceLine* line = lj ? lj->lineTo() : 0;
|
|
if (line) {
|
|
_selectedItem = line;
|
|
selected(line);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SourceView::activatedSlot(TQListViewItem * i)
|
|
{
|
|
if (!i) return;
|
|
TraceLineCall* lc = ((SourceItem*) i)->lineCall();
|
|
TraceLineJump* lj = ((SourceItem*) i)->lineJump();
|
|
|
|
if (!lc && !lj) {
|
|
TraceLine* l = ((SourceItem*) i)->line();
|
|
if (l) activated(l);
|
|
return;
|
|
}
|
|
|
|
TraceFunction* f = lc ? lc->call()->called() : 0;
|
|
if (f) activated(f);
|
|
else {
|
|
TraceLine* line = lj ? lj->lineTo() : 0;
|
|
if (line) activated(line);
|
|
}
|
|
}
|
|
|
|
TraceItem* SourceView::canShow(TraceItem* i)
|
|
{
|
|
TraceItem::CostType t = i ? i->type() : TraceItem::NoCostType;
|
|
TraceFunction* f = 0;
|
|
|
|
switch(t) {
|
|
case TraceItem::Function:
|
|
f = (TraceFunction*) i;
|
|
break;
|
|
|
|
case TraceItem::Instr:
|
|
f = ((TraceInstr*)i)->function();
|
|
select(i);
|
|
break;
|
|
|
|
case TraceItem::Line:
|
|
f = ((TraceLine*)i)->functionSource()->function();
|
|
select(i);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
void SourceView::doUpdate(int changeType)
|
|
{
|
|
// Special case ?
|
|
if (changeType == selectedItemChanged) {
|
|
|
|
if (!_selectedItem) {
|
|
clearSelection();
|
|
return;
|
|
}
|
|
|
|
TraceLine* sLine = 0;
|
|
if (_selectedItem->type() == TraceItem::Line)
|
|
sLine = (TraceLine*) _selectedItem;
|
|
if (_selectedItem->type() == TraceItem::Instr)
|
|
sLine = ((TraceInstr*)_selectedItem)->line();
|
|
|
|
SourceItem* si = (SourceItem*)TQListView::selectedItem();
|
|
if (si) {
|
|
if (si->line() == sLine) return;
|
|
if (si->lineCall() &&
|
|
(si->lineCall()->call()->called() == _selectedItem)) return;
|
|
}
|
|
|
|
TQListViewItem *item, *item2;
|
|
for (item = firstChild();item;item = item->nextSibling()) {
|
|
si = (SourceItem*)item;
|
|
if (si->line() == sLine) {
|
|
ensureItemVisible(item);
|
|
_inSelectionUpdate = true;
|
|
setCurrentItem(item);
|
|
_inSelectionUpdate = false;
|
|
break;
|
|
}
|
|
item2 = item->firstChild();
|
|
for (;item2;item2 = item2->nextSibling()) {
|
|
si = (SourceItem*)item2;
|
|
if (!si->lineCall()) continue;
|
|
if (si->lineCall()->call()->called() == _selectedItem) {
|
|
ensureItemVisible(item2);
|
|
_inSelectionUpdate = true;
|
|
setCurrentItem(item2);
|
|
_inSelectionUpdate = false;
|
|
break;
|
|
}
|
|
}
|
|
if (item2) break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (changeType == groupTypeChanged) {
|
|
TQListViewItem *item, *item2;
|
|
for (item = firstChild();item;item = item->nextSibling())
|
|
for (item2 = item->firstChild();item2;item2 = item2->nextSibling())
|
|
((SourceItem*)item2)->updateGroup();
|
|
}
|
|
|
|
refresh();
|
|
}
|
|
|
|
void SourceView::refresh()
|
|
{
|
|
clear();
|
|
setColumnWidth(0, 20);
|
|
setColumnWidth(1, 50);
|
|
setColumnWidth(2, _costType2 ? 50:0);
|
|
setColumnWidth(3, 0); // arrows, defaults to invisible
|
|
setSorting(0); // always reset to line number sort
|
|
if (_costType)
|
|
setColumnText(1, _costType->name());
|
|
if (_costType2)
|
|
setColumnText(2, _costType2->name());
|
|
|
|
_arrowLevels = 0;
|
|
|
|
if (!_data || !_activeItem) {
|
|
setColumnText(4, i18n("(No Source)"));
|
|
return;
|
|
}
|
|
|
|
TraceItem::CostType t = _activeItem->type();
|
|
TraceFunction* f = 0;
|
|
if (t == TraceItem::Function) f = (TraceFunction*) _activeItem;
|
|
if (t == TraceItem::Instr) {
|
|
f = ((TraceInstr*)_activeItem)->function();
|
|
if (!_selectedItem) _selectedItem = _activeItem;
|
|
}
|
|
if (t == TraceItem::Line) {
|
|
f = ((TraceLine*)_activeItem)->functionSource()->function();
|
|
if (!_selectedItem) _selectedItem = _activeItem;
|
|
}
|
|
|
|
if (!f) return;
|
|
|
|
// Allow resizing of column 2
|
|
setColumnWidthMode(2, TQListView::Maximum);
|
|
|
|
TraceFunctionSource* mainSF = f->sourceFile();
|
|
|
|
// skip first source if there's no debug info and there are more sources
|
|
// (this is for a bug in GCC 2.95.x giving unknown source for prologs)
|
|
if (mainSF &&
|
|
(mainSF->firstLineno() == 0) &&
|
|
(mainSF->lastLineno() == 0) &&
|
|
(f->sourceFiles().count()>1) ) {
|
|
// skip
|
|
}
|
|
else
|
|
fillSourceFile(mainSF, 0);
|
|
|
|
TraceFunctionSource* sf;
|
|
int fileno = 1;
|
|
TraceFunctionSourceList l = f->sourceFiles();
|
|
for (sf=l.first();sf;sf=l.next(), fileno++)
|
|
if (sf != mainSF)
|
|
fillSourceFile(sf, fileno);
|
|
|
|
if (!_costType2) {
|
|
setColumnWidthMode(2, TQListView::Manual);
|
|
setColumnWidth(2, 0);
|
|
}
|
|
}
|
|
|
|
|
|
// helper for fillSourceList:
|
|
// search recursive for a file, starting from a base dir
|
|
static bool checkFileExistance(TQString& dir, const TQString& name)
|
|
{
|
|
// we leave this in...
|
|
tqDebug("Checking %s/%s", dir.ascii(), name.ascii());
|
|
|
|
if (TQFile::exists(dir + "/" + name)) return true;
|
|
|
|
// check in subdirectories
|
|
TQDir d(dir);
|
|
d.setFilter( TQDir::Dirs | TQDir::NoSymLinks );
|
|
d.setSorting( TQDir::Unsorted );
|
|
TQStringList subdirs = d.entryList();
|
|
TQStringList::Iterator it =subdirs.begin();
|
|
for(; it != subdirs.end(); ++it ) {
|
|
if (*it == "." || *it == ".." || *it == "CVS") continue;
|
|
|
|
dir = d.filePath(*it);
|
|
if (checkFileExistance(dir, name)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void SourceView::updateJumpArray(uint lineno, SourceItem* si,
|
|
bool ignoreFrom, bool ignoreTo)
|
|
{
|
|
TraceLineJump* lj;
|
|
uint lowLineno, highLineno;
|
|
int iEnd = -1, iStart = -1;
|
|
|
|
if (0) tqDebug("updateJumpArray(line %d, jump to %s)",
|
|
lineno,
|
|
si->lineJump()
|
|
? si->lineJump()->lineTo()->name().ascii() : "?" );
|
|
|
|
|
|
lj=_lowList.current();
|
|
while(lj) {
|
|
lowLineno = lj->lineFrom()->lineno();
|
|
if (lj->lineTo()->lineno() < lowLineno)
|
|
lowLineno = lj->lineTo()->lineno();
|
|
|
|
if (lowLineno > lineno) break;
|
|
|
|
if (ignoreFrom && (lowLineno < lj->lineTo()->lineno())) break;
|
|
if (ignoreTo && (lowLineno < lj->lineFrom()->lineno())) break;
|
|
|
|
if (si->lineJump() && (lj != si->lineJump())) break;
|
|
|
|
int asize = (int)_jump.size();
|
|
#if 0
|
|
for(iStart=0;iStart<asize;iStart++)
|
|
if (_jump[iStart] &&
|
|
(_jump[iStart]->lineTo() == lj->lineTo())) break;
|
|
#else
|
|
iStart = asize;
|
|
#endif
|
|
|
|
if (iStart == asize) {
|
|
for(iStart=0;iStart<asize;iStart++)
|
|
if (_jump[iStart] == 0) break;
|
|
|
|
if (iStart== asize) {
|
|
asize++;
|
|
_jump.resize(asize);
|
|
if (asize > _arrowLevels) _arrowLevels = asize;
|
|
}
|
|
|
|
if (0) tqDebug(" start %d (%s to %s)",
|
|
iStart,
|
|
lj->lineFrom()->name().ascii(),
|
|
lj->lineTo()->name().ascii());
|
|
|
|
_jump[iStart] = lj;
|
|
}
|
|
lj=_lowList.next();
|
|
}
|
|
|
|
si->setJumpArray(_jump);
|
|
|
|
lj=_highList.current();
|
|
while(lj) {
|
|
highLineno = lj->lineFrom()->lineno();
|
|
if (lj->lineTo()->lineno() > highLineno) {
|
|
highLineno = lj->lineTo()->lineno();
|
|
if (ignoreTo) break;
|
|
}
|
|
else if (ignoreFrom) break;
|
|
|
|
if (highLineno > lineno) break;
|
|
|
|
for(iEnd=0;iEnd< (int)_jump.size();iEnd++)
|
|
if (_jump[iEnd] == lj) break;
|
|
if (iEnd == (int)_jump.size()) {
|
|
tqDebug("LineView: no jump start for end at %x ?", highLineno);
|
|
iEnd = -1;
|
|
}
|
|
lj=_highList.next();
|
|
|
|
if (0 && (iEnd>=0))
|
|
tqDebug(" end %d (%s to %s)",
|
|
iEnd,
|
|
_jump[iEnd]->lineFrom()->name().ascii(),
|
|
_jump[iEnd]->lineTo()->name().ascii());
|
|
|
|
if (0 && lj) tqDebug("next end: %s to %s",
|
|
lj->lineFrom()->name().ascii(),
|
|
lj->lineTo()->name().ascii());
|
|
|
|
if (highLineno > lineno)
|
|
break;
|
|
else {
|
|
if (iEnd>=0) _jump[iEnd] = 0;
|
|
iEnd = -1;
|
|
}
|
|
}
|
|
if (iEnd>=0) _jump[iEnd] = 0;
|
|
}
|
|
|
|
|
|
/* If sourceList is empty we set the source file name into the header,
|
|
* else this code is of a inlined function, and we add "inlined from..."
|
|
*/
|
|
void SourceView::fillSourceFile(TraceFunctionSource* sf, int fileno)
|
|
{
|
|
if (!sf) return;
|
|
|
|
if (0) tqDebug("Selected Item %s",
|
|
_selectedItem ? _selectedItem->name().ascii() : "(none)");
|
|
|
|
TraceLineMap::Iterator lineIt, lineItEnd;
|
|
int nextCostLineno = 0, lastCostLineno = 0;
|
|
|
|
bool validSourceFile = (!sf->file()->name().isEmpty());
|
|
|
|
TraceLine* sLine = 0;
|
|
if (_selectedItem) {
|
|
if (_selectedItem->type() == TraceItem::Line)
|
|
sLine = (TraceLine*) _selectedItem;
|
|
if (_selectedItem->type() == TraceItem::Instr)
|
|
sLine = ((TraceInstr*)_selectedItem)->line();
|
|
}
|
|
|
|
if (validSourceFile) {
|
|
TraceLineMap* lineMap = sf->lineMap();
|
|
if (lineMap) {
|
|
lineIt = lineMap->begin();
|
|
lineItEnd = lineMap->end();
|
|
// get first line with cost of selected type
|
|
while(lineIt != lineItEnd) {
|
|
if (&(*lineIt) == sLine) break;
|
|
if ((*lineIt).hasCost(_costType)) break;
|
|
if (_costType2 && (*lineIt).hasCost(_costType2)) break;
|
|
++lineIt;
|
|
}
|
|
|
|
nextCostLineno = (lineIt == lineItEnd) ? 0 : (*lineIt).lineno();
|
|
if (nextCostLineno<0) {
|
|
kdError() << "SourceView::fillSourceFile: Negative line number "
|
|
<< nextCostLineno << endl
|
|
<< " Function '" << sf->function()->name() << "'" << endl
|
|
<< " File '" << sf->file()->name() << "'" << endl;
|
|
nextCostLineno = 0;
|
|
}
|
|
|
|
}
|
|
|
|
if (nextCostLineno == 0) {
|
|
new SourceItem(this, this, fileno, 0, false,
|
|
i18n("There is no cost of current selected type associated"));
|
|
new SourceItem(this, this, fileno, 1, false,
|
|
i18n("with any source line of this function in file"));
|
|
new SourceItem(this, this, fileno, 2, false,
|
|
TQString(" '%1'").arg(sf->function()->prettyName()));
|
|
new SourceItem(this, this, fileno, 3, false,
|
|
i18n("Thus, no annotated source can be shown."));
|
|
return;
|
|
}
|
|
}
|
|
|
|
TQString filename = sf->file()->shortName();
|
|
TQString dir = sf->file()->directory();
|
|
if (!dir.isEmpty())
|
|
filename = dir + "/" + filename;
|
|
|
|
if (nextCostLineno>0) {
|
|
// we have debug info... search for source file
|
|
if (!TQFile::exists(filename)) {
|
|
TQStringList list = Configuration::sourceDirs(_data,
|
|
sf->function()->object());
|
|
TQStringList::Iterator it;
|
|
|
|
for ( it = list.begin(); it != list.end(); ++it ) {
|
|
dir = *it;
|
|
if (checkFileExistance(dir, sf->file()->shortName())) break;
|
|
}
|
|
|
|
if (it == list.end())
|
|
nextCostLineno = 0;
|
|
else {
|
|
filename = dir + "/" + sf->file()->shortName();
|
|
// no need to search again
|
|
sf->file()->setDirectory(dir);
|
|
}
|
|
}
|
|
}
|
|
|
|
// do it here, because the source directory could have been set before
|
|
if (childCount()==0) {
|
|
setColumnText(4, validSourceFile ?
|
|
i18n("Source ('%1')").arg(filename) :
|
|
i18n("Source (unknown)"));
|
|
}
|
|
else {
|
|
new SourceItem(this, this, fileno, 0, true,
|
|
validSourceFile ?
|
|
i18n("--- Inlined from '%1' ---").arg(filename) :
|
|
i18n("--- Inlined from unknown source ---"));
|
|
}
|
|
|
|
if (nextCostLineno == 0) {
|
|
new SourceItem(this, this, fileno, 0, false,
|
|
i18n("There is no source available for the following function:"));
|
|
new SourceItem(this, this, fileno, 1, false,
|
|
TQString(" '%1'").arg(sf->function()->prettyName()));
|
|
if (sf->file()->name().isEmpty()) {
|
|
new SourceItem(this, this, fileno, 2, false,
|
|
i18n("This is because no debug information is present."));
|
|
new SourceItem(this, this, fileno, 3, false,
|
|
i18n("Recompile source and redo the profile run."));
|
|
if (sf->function()->object()) {
|
|
new SourceItem(this, this, fileno, 4, false,
|
|
i18n("The function is located in this ELF object:"));
|
|
new SourceItem(this, this, fileno, 5, false,
|
|
TQString(" '%1'")
|
|
.arg(sf->function()->object()->prettyName()));
|
|
}
|
|
}
|
|
else {
|
|
new SourceItem(this, this, fileno, 2, false,
|
|
i18n("This is because its source file cannot be found:"));
|
|
new SourceItem(this, this, fileno, 3, false,
|
|
TQString(" '%1'").arg(sf->file()->name()));
|
|
new SourceItem(this, this, fileno, 4, false,
|
|
i18n("Add the folder of this file to the source folder list."));
|
|
new SourceItem(this, this, fileno, 5, false,
|
|
i18n("The list can be found in the configuration dialog."));
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// initialisation for arrow drawing
|
|
// create sorted list of jumps (for jump arrows)
|
|
TraceLineMap::Iterator it = lineIt, nextIt;
|
|
_lowList.clear();
|
|
_highList.clear();
|
|
while(1) {
|
|
|
|
nextIt = it;
|
|
++nextIt;
|
|
while(nextIt != lineItEnd) {
|
|
if (&(*nextIt) == sLine) break;
|
|
if ((*nextIt).hasCost(_costType)) break;
|
|
if (_costType2 && (*nextIt).hasCost(_costType2)) break;
|
|
++nextIt;
|
|
}
|
|
|
|
TraceLineJumpList jlist = (*it).lineJumps();
|
|
TraceLineJump* lj;
|
|
for (lj=jlist.first();lj;lj=jlist.next()) {
|
|
if (lj->executedCount()==0) continue;
|
|
// skip jumps to next source line with cost
|
|
//if (lj->lineTo() == &(*nextIt)) continue;
|
|
|
|
_lowList.append(lj);
|
|
_highList.append(lj);
|
|
}
|
|
it = nextIt;
|
|
if (it == lineItEnd) break;
|
|
}
|
|
_lowList.sort();
|
|
_highList.sort();
|
|
_lowList.first(); // iterators to list start
|
|
_highList.first();
|
|
_jump.resize(0);
|
|
|
|
|
|
char buf[256];
|
|
bool inside = false, skipLineWritten = true;
|
|
int readBytes;
|
|
int fileLineno = 0;
|
|
SubCost most = 0;
|
|
|
|
TraceLine* currLine;
|
|
SourceItem *si, *si2, *item = 0, *first = 0, *selected = 0;
|
|
TQFile file(filename);
|
|
if (!file.open(IO_ReadOnly)) return;
|
|
while (1) {
|
|
readBytes=file.readLine(buf, sizeof( buf ));
|
|
if (readBytes<=0) {
|
|
// for nice empty 4 lines after function with EOF
|
|
buf[0] = 0;
|
|
}
|
|
|
|
if (readBytes >= (int) sizeof( buf )) {
|
|
tqDebug("%s:%d Line too long\n",
|
|
sf->file()->name().ascii(), fileLineno);
|
|
}
|
|
else if ((readBytes>0) && (buf[readBytes-1] == '\n'))
|
|
buf[readBytes-1] = 0;
|
|
|
|
|
|
// keep fileLineno inside [lastCostLineno;nextCostLineno]
|
|
fileLineno++;
|
|
if (fileLineno == nextCostLineno) {
|
|
currLine = &(*lineIt);
|
|
|
|
// get next line with cost of selected type
|
|
++lineIt;
|
|
while(lineIt != lineItEnd) {
|
|
if (&(*lineIt) == sLine) break;
|
|
if ((*lineIt).hasCost(_costType)) break;
|
|
if (_costType2 && (*lineIt).hasCost(_costType2)) break;
|
|
++lineIt;
|
|
}
|
|
|
|
lastCostLineno = nextCostLineno;
|
|
nextCostLineno = (lineIt == lineItEnd) ? 0 : (*lineIt).lineno();
|
|
}
|
|
else
|
|
currLine = 0;
|
|
|
|
// update inside
|
|
if (!inside) {
|
|
if (currLine) inside = true;
|
|
}
|
|
else {
|
|
if ( (fileLineno > lastCostLineno) &&
|
|
((nextCostLineno == 0) ||
|
|
(fileLineno < nextCostLineno - Configuration::noCostInside()) ))
|
|
inside = false;
|
|
}
|
|
|
|
int context = Configuration::context();
|
|
|
|
if ( ((lastCostLineno==0) || (fileLineno > lastCostLineno + context)) &&
|
|
((nextCostLineno==0) || (fileLineno < nextCostLineno - context))) {
|
|
if (lineIt == lineItEnd) break;
|
|
|
|
if (!skipLineWritten) {
|
|
skipLineWritten = true;
|
|
// a "skipping" line: print "..." instead of a line number
|
|
strcpy(buf,"...");
|
|
}
|
|
else
|
|
continue;
|
|
}
|
|
else
|
|
skipLineWritten = false;
|
|
|
|
si = new SourceItem(this, this,
|
|
fileno, fileLineno, inside, TQString(buf),
|
|
currLine);
|
|
|
|
if (!currLine) continue;
|
|
|
|
if (!selected && (currLine == sLine)) selected = si;
|
|
if (!first) first = si;
|
|
|
|
if (currLine->subCost(_costType) > most) {
|
|
item = si;
|
|
most = currLine->subCost(_costType);
|
|
}
|
|
|
|
si->setOpen(true);
|
|
TraceLineCallList list = currLine->lineCalls();
|
|
TraceLineCall* lc;
|
|
for (lc=list.first();lc;lc=list.next()) {
|
|
if ((lc->subCost(_costType)==0) &&
|
|
(lc->subCost(_costType2)==0)) continue;
|
|
|
|
if (lc->subCost(_costType) > most) {
|
|
item = si;
|
|
most = lc->subCost(_costType);
|
|
}
|
|
|
|
si2 = new SourceItem(this, si, fileno, fileLineno, currLine, lc);
|
|
|
|
if (!selected && (lc->call()->called() == _selectedItem))
|
|
selected = si2;
|
|
}
|
|
|
|
TraceLineJumpList jlist = currLine->lineJumps();
|
|
TraceLineJump* lj;
|
|
for (lj=jlist.first();lj;lj=jlist.next()) {
|
|
if (lj->executedCount()==0) continue;
|
|
|
|
new SourceItem(this, si, fileno, fileLineno, currLine, lj);
|
|
}
|
|
}
|
|
|
|
if (selected) item = selected;
|
|
if (item) first = item;
|
|
if (first) {
|
|
ensureItemVisible(first);
|
|
_inSelectionUpdate = true;
|
|
setCurrentItem(first);
|
|
_inSelectionUpdate = false;
|
|
}
|
|
|
|
file.close();
|
|
|
|
// for arrows: go down the list according to list sorting
|
|
sort();
|
|
TQListViewItem *item1, *item2;
|
|
for (item1=firstChild();item1;item1 = item1->nextSibling()) {
|
|
si = (SourceItem*)item1;
|
|
updateJumpArray(si->lineno(), si, true, false);
|
|
|
|
for (item2=item1->firstChild();item2;item2 = item2->nextSibling()) {
|
|
si2 = (SourceItem*)item2;
|
|
if (si2->lineJump())
|
|
updateJumpArray(si->lineno(), si2, false, true);
|
|
else
|
|
si2->setJumpArray(_jump);
|
|
}
|
|
}
|
|
|
|
if (arrowLevels())
|
|
setColumnWidth(3, 10 + 6*arrowLevels() + itemMargin() * 2);
|
|
else
|
|
setColumnWidth(3, 0);
|
|
}
|
|
|
|
|
|
void SourceView::updateSourceItems()
|
|
{
|
|
setColumnWidth(1, 50);
|
|
setColumnWidth(2, _costType2 ? 50:0);
|
|
// Allow resizing of column 2
|
|
setColumnWidthMode(2, TQListView::Maximum);
|
|
|
|
if (_costType)
|
|
setColumnText(1, _costType->name());
|
|
if (_costType2)
|
|
setColumnText(2, _costType2->name());
|
|
|
|
SourceItem* si;
|
|
TQListViewItem* item = firstChild();
|
|
for (;item;item = item->nextSibling()) {
|
|
si = (SourceItem*)item;
|
|
TraceLine* l = si->line();
|
|
if (!l) continue;
|
|
|
|
si->updateCost();
|
|
|
|
TQListViewItem *next, *i = si->firstChild();
|
|
for (;i;i = next) {
|
|
next = i->nextSibling();
|
|
((SourceItem*)i)->updateCost();
|
|
}
|
|
}
|
|
|
|
if (!_costType2) {
|
|
setColumnWidthMode(2, TQListView::Manual);
|
|
setColumnWidth(2, 0);
|
|
}
|
|
}
|
|
|
|
#include "sourceview.moc"
|