/* This file is part of KCachegrind.
Copyright (C) 2002, 2003 Josef Weidendorfer A trace consists of multiple trace parts when "
"there are several profile data files from one profile run. "
"The Trace Part Overview dockable shows these, "
"horizontally ordered in execution time; "
"the rectangle sizes are proportional to the total "
"cost spent in the parts. You can select one or several "
"parts to constrain all costs shown to these parts only."
" The parts are further subdivided: there is a "
"partitioning and an callee split mode: "
"
This is a purely fictional 'most probable' call stack. " "It is built up by starting with the current selected " "function and adds the callers/callees with highest cost " "at the top and to bottom.
" "The Cost and Calls columns show the " "cost used for all calls from the function in the line " "above.
")); connect(_stackSelection, SIGNAL(functionSelected(TraceItem*)), this, SLOT(setTraceItemDelayed(TraceItem*))); _functionDock = new QDockWindow(QDockWindow::InDock, this); _functionDock->setCaption(i18n("Flat Profile")); _functionDock->setCloseMode( QDockWindow::Always ); _functionSelection = new FunctionSelection(this, _functionDock, "functionSelection"); _functionSelection->setTopLevel(this); _functionDock->setWidget(_functionSelection); _functionDock->setResizeEnabled(true); _functionDock->setFixedExtentWidth(200); QWhatsThis::add( _functionSelection, i18n( "The Flat Profile" "The flat profile contains a group and a function " "selection list. The group list contains all groups " "where costs " "are spent in, depending on the chosen group type. " "The group list is hidden when group type 'Function' " "is selected.
" "
The function list contains the functions of the " "selected group (or all for 'Function' group type), " "ordered by the costs spent therein. Functions with " "costs less than 1% are hidden on default.
")); #if ENABLE_DUMPDOCK _dumpDock = new QDockWindow(QDockWindow::InDock, this); _dumpDock->setCaption(i18n("Profile Dumps")); _dumpDock->setCloseMode( QDockWindow::Always ); _dumpSelection = new DumpSelection(this, _dumpDock, "dumpSelection"); _dumpSelection->setTopLevel(this); _dumpDock->setWidget(_dumpSelection); _dumpDock->setResizeEnabled(true); _dumpDock->setFixedExtentWidth(200); QWhatsThis::add( _dumpSelection, i18n( "Profile Dumps" "This dockable shows in the top part the list of " "loadable profile dumps in all subdirectories of: " "
On selecting a profile dump, information for it " "is shown in the bottom area of the dockable: " "
Make a copy of the current layout.
"); action->setWhatsThis( hint ); action = new KAction( i18n( "&Remove" ), KShortcut(), this, SLOT(layoutRemove()), actionCollection(), "layout_remove" ); hint = i18n("Remove Current Layout" "Delete current layout and make the previous active.
"); action->setWhatsThis( hint ); action = new KAction( i18n( "&Go to Next" ), KShortcut(KKey("Ctrl+Right")), this, SLOT(layoutNext()), actionCollection(), "layout_next" ); hint = i18n("Go to Next Layout"); action->setWhatsThis( hint ); action = new KAction( i18n( "&Go to Previous" ), KShortcut(KKey("Ctrl+Left")), this, SLOT(layoutPrevious()), actionCollection(), "layout_previous" ); hint = i18n("Go to Previous Layout"); action->setWhatsThis( hint ); action = new KAction( i18n( "&Restore to Default" ), KShortcut(), this, SLOT(layoutRestore()), actionCollection(), "layout_restore" ); hint = i18n("Restore Layouts to Default"); action->setWhatsThis( hint ); action = new KAction( i18n( "&Save as Default" ), KShortcut(), this, SLOT(layoutSave()), actionCollection(), "layout_save" ); hint = i18n("Save Layouts as Default"); action->setWhatsThis( hint ); } // TODO: split this up... void TopLevel::createMiscActions() { QString hint; KAction* action; action = KStdAction::openNew(this, SLOT(newWindow()), actionCollection()); hint = i18n("NewOpen new empty KCachegrind window.
"); action->setWhatsThis( hint ); action = new KAction( i18n( "&Add..." ), KShortcut(), this, SLOT(addTrace()), actionCollection(), "file_add" ); hint = i18n("Add Profile Data" "This opens an additional profile data file in the current window.
"); action->setWhatsThis( hint ); action = new KAction( i18n( "&Reload" ), "reload", #if KDE_VERSION > 0x030190 // for KDE 3.2: KStdAccel::key is deprecated KStdAccel::shortcut(KStdAccel::Reload), #else KStdAccel::key(KStdAccel::Reload), #endif this, SLOT( reload() ), actionCollection(), "reload" ); hint = i18n("Reload Profile Data" "This loads any new created parts, too.
"); action->setWhatsThis( hint ); action = new KAction( i18n( "&Export Graph" ), KShortcut(), this, SLOT(exportGraph()), actionCollection(), "export" ); hint = i18n("Export Call Graph" "Generates a file with extension .dot for the tools " "of the GraphViz package.
"); action->setWhatsThis( hint ); _taDump = new KToggleAction( i18n( "&Force Dump" ), "redo", #if KDE_VERSION > 0x030190 // for KDE 3.2: KStdAccel::key is deprecated KStdAccel::shortcut(KStdAccel::Redo), #else KStdAccel::key(KStdAccel::Redo), #endif this, SLOT( forceTrace() ), actionCollection(), "dump" ); hint = i18n("Force Dump" "This forces a dump for a Callgrind profile run " "in the current directory. This action is checked while " "KCachegrind looks for the dump. If the dump is " "finished, it automatically reloads the current trace. " "If this is the one from the running Callgrind, the new " "created trace part will be loaded, too.
" "Force dump creates a file 'callgrind.cmd', and " "checks every second for its existence. A running " "Callgrind will detect this file, dump a trace part, " "and delete 'callgrind.cmd'. " "The deletion is detected by KCachegrind, " "and it does a Reload. If there's no Callgrind " "running, press 'Force Dump' again to cancel the dump " "request. This deletes 'callgrind.cmd' itself and " "stops polling for a new dump.
" "Note: A Callgrind run only detects " "existence of 'callgrind.cmd' when actively running " "a few milliseconds, i.e. " "not sleeping. Tip: For a profiled GUI program, " "you can awake Callgrind e.g. by resizing a window " "of the program.
"); _taDump->setWhatsThis( hint ); action = KStdAction::open(this, SLOT(loadTrace()), actionCollection()); hint = i18n("Open Profile Data" "This opens a profile data file, with possible multiple parts
"); action->setToolTip( hint ); action->setWhatsThis( hint ); _openRecent = KStdAction::openRecent(this, SLOT(loadTrace(const KURL&)), actionCollection()); KStdAction::showStatusbar(this, SLOT(toggleStatusBar()), actionCollection()); _partDockShown = new KToggleAction(i18n("Parts Overview"), KShortcut(), this, SLOT(togglePartDock()), actionCollection(), "settings_show_partdock"); hint = i18n("Show/Hide the Parts Overview Dockable"); _partDockShown->setToolTip( hint ); _partDockShown->setWhatsThis( hint ); _stackDockShown = new KToggleAction(i18n("Call Stack"), KShortcut(), this, SLOT(toggleStackDock()), actionCollection(), "settings_show_stackdock"); hint = i18n("Show/Hide the Call Stack Dockable"); _stackDockShown->setToolTip( hint ); _stackDockShown->setWhatsThis( hint ); _functionDockShown = new KToggleAction(i18n("Function Profile"), KShortcut(), this, SLOT(toggleFunctionDock()), actionCollection(), "settings_show_profiledock"); hint = i18n("Show/Hide the Function Profile Dockable"); _functionDockShown->setToolTip( hint ); _functionDockShown->setWhatsThis( hint ); #if ENABLE_DUMPDOCK _dumpDockShown = new KToggleAction(i18n("Profile Dumps"), KShortcut(), this, SLOT(toggleDumpDock()), actionCollection(), "settings_show_dumpdock"); hint = i18n("Show/Hide the Profile Dumps Dockable"); _dumpDockShown->setToolTip( hint ); _dumpDockShown->setWhatsThis( hint ); #endif _taPercentage = new KToggleAction(i18n("Show Relative Costs"), "percent", KShortcut(), this, SLOT(togglePercentage()), actionCollection(), "view_percentage"); #if KDE_VERSION >= 0x030290 // for KDE 3.3: show another text instead of a checkmark _taPercentage->setCheckedState(i18n("Show Absolute Costs")); #endif hint = i18n("Show relative instead of absolute costs"); _taPercentage->setToolTip( hint ); _taPercentage->setWhatsThis( hint ); _taExpanded = new KToggleAction(i18n("Percentage Relative to Parent"), "move", KShortcut(), this, SLOT(toggleExpanded()), actionCollection(), "view_expanded"); hint = i18n("Show percentage costs relative to parent"); _taExpanded->setToolTip( hint ); _taExpanded->setWhatsThis( hint ); hint = i18n("Show percentage costs relative to parent" "If this is switched off, percentage costs are always shown " "relative to the total cost of the profile part(s) that are " "currently browsed. By turning on this option, percentage cost " "of shown cost items will be relative to the parent cost item." "
Cost Type | Parent Cost |
Function Cumulative | Total |
Function Self | Function Group (*) / Total |
Call | Function Cumulative |
Source Line | Function Cumulative |
(*) Only if function grouping is switched on (e.g. ELF object grouping)."); _taExpanded->setWhatsThis( hint ); _taCycles = new KToggleAction( i18n( "Do Cycle Detection" ), "undo", KShortcut(), this, SLOT( toggleCycles() ), actionCollection(), "view_cycles" ); #if KDE_VERSION >= 0x030290 // for KDE 3.3: show another text instead of a checkmark _taCycles->setCheckedState(i18n("Skip Cycle Detection")); #endif hint = i18n("Detect recursive cycles" "
If this is switched off, the treemap drawing will show " "black areas when a recursive call is made instead of drawing the " "recursion ad infinitum. Note that " "the size of black areas often will be wrong, as inside recursive " "cycles the cost of calls cannot be determined; the error is small, " "however, for false cycles (see documentation)." "
The correct handling for cycles is to detect them and collapse all " "functions of a cycle into a virtual function, which is done when this " "option is selected. Unfortunately, with GUI applications, this often will " "lead to huge false cycles, making the analysis impossible; therefore, there " "is the option to switch this off."); _taCycles->setWhatsThis( hint ); KStdAction::quit(this, SLOT(close()), actionCollection()); KStdAction::preferences(this, SLOT(configure()), actionCollection()); KStdAction::keyBindings(this, SLOT(configureKeys()), actionCollection()); KStdAction::configureToolbars(this,SLOT(configureToolbars()), actionCollection()); #if 0 action = KStdAction::back(_stackSelection, SLOT(browserBack()), actionCollection()); hint = i18n("Go back in function selection history"); action->setToolTip( hint ); action->setWhatsThis( hint ); action = KStdAction::forward(_stackSelection, SLOT(browserForward()), actionCollection()); hint = i18n("Go forward in function selection history"); action->setToolTip( hint ); action->setWhatsThis( hint ); action = KStdAction::up(_stackSelection, SLOT(browserUp()), actionCollection()); hint = i18n("Go Up" "
Go to last selected caller of current function. " "If no caller was visited, use that with highest cost.
"); action->setToolTip( hint ); action->setWhatsThis( hint ); #else _paUp = new KToolBarPopupAction( i18n( "&Up" ), "up", ALT+Key_Up, _stackSelection, SLOT( browserUp() ), actionCollection(), "go_up" ); connect( _paUp->popupMenu(), SIGNAL( aboutToShow() ), this, SLOT( upAboutToShow() ) ); connect( _paUp->popupMenu(), SIGNAL( activated( int ) ), this, SLOT( upActivated( int ) ) ); hint = i18n("Go Up" "Go to last selected caller of current function. " "If no caller was visited, use that with highest cost.
"); _paUp->setToolTip( hint ); _paUp->setWhatsThis( hint ); QPair< KGuiItem, KGuiItem > backForward = KStdGuiItem::backAndForward(); _paBack = new KToolBarPopupAction( backForward.first, ALT+Key_Left, _stackSelection, SLOT(browserBack()), actionCollection(), "go_back" ); connect( _paBack->popupMenu(), SIGNAL( aboutToShow() ), this, SLOT( backAboutToShow() ) ); connect( _paBack->popupMenu(), SIGNAL( activated( int ) ), this, SLOT( backActivated( int ) ) ); hint = i18n("Go back in function selection history"); _paBack->setToolTip( hint ); _paBack->setWhatsThis( hint ); _paForward = new KToolBarPopupAction( backForward.second, ALT+Key_Right, _stackSelection, SLOT(browserForward()), actionCollection(), "go_forward" ); connect( _paForward->popupMenu(), SIGNAL( aboutToShow() ), this, SLOT( forwardAboutToShow() ) ); connect( _paForward->popupMenu(), SIGNAL( activated( int ) ), this, SLOT( forwardActivated( int ) ) ); hint = i18n("Go forward in function selection history"); _paForward->setToolTip( hint ); _paForward->setWhatsThis( hint ); #endif _saCost = new KSelectAction( i18n("Primary Event Type"), KShortcut(), actionCollection(), "view_cost_type"); hint = i18n("Select primary event type of costs"); _saCost->setComboWidth(300); _saCost->setToolTip( hint ); _saCost->setWhatsThis( hint ); // cost types are dependent on loaded data, thus KSelectAction // is filled in setData() connect( _saCost, SIGNAL(activated(const QString&)), this, SLOT(costTypeSelected(const QString&))); _saCost2 = new KSelectAction( i18n("Secondary Event Type"), KShortcut(), actionCollection(), "view_cost_type2"); hint = i18n("Select secondary event type for cost e.g. shown in annotations"); _saCost2->setComboWidth(300); _saCost2->setToolTip( hint ); _saCost2->setWhatsThis( hint ); connect( _saCost2, SIGNAL(activated(const QString&)), this, SLOT(costType2Selected(const QString&))); saGroup = new KSelectAction( i18n("Grouping"), KShortcut(), actionCollection(), "view_group_type"); hint = i18n("Select how functions are grouped into higher level cost items"); saGroup->setToolTip( hint ); saGroup->setWhatsThis( hint ); QStringList args; args << i18n("(No Grouping)") << TraceCost::i18nTypeName(TraceItem::Object) << TraceCost::i18nTypeName(TraceItem::File) << TraceCost::i18nTypeName(TraceItem::Class) << TraceCost::i18nTypeName(TraceItem::FunctionCycle); saGroup->setItems(args); connect( saGroup, SIGNAL(activated(int)), this, SLOT(groupTypeSelected(int))); _taSplit = new KToggleAction(i18n("Split"), "view_left_right", KShortcut(), this, SLOT(splitSlot()), actionCollection(), "view_split"); hint = i18n("Show two information panels"); _taSplit->setToolTip( hint ); _taSplit->setWhatsThis( hint ); _taSplitDir = new KToggleAction(i18n("Split Horizontal"), "view_left_right", KShortcut(), this, SLOT(splitDirSlot()), actionCollection(), "view_split_dir"); hint = i18n("Change Split Orientation when main window is split."); _taSplitDir->setToolTip( hint ); _taSplitDir->setWhatsThis( hint ); // copied from KMail... #if KDE_VERSION >= 308 // KDE 3.1 KStdAction::tipOfDay( this, SLOT( slotShowTip() ), actionCollection() ); #else (void) new KAction( KGuiItem( i18n("Tip of the &Day..."), "idea", i18n("Show \"Tip of the Day\"") ), 0, this, SLOT(slotShowTip()), actionCollection(), "help_show_tip" ); #endif } void TopLevel::createActions() { createMiscActions(); createLayoutActions(); } void TopLevel::toggleStatusBar() { if (statusBar()->isVisible()) statusBar()->hide(); else statusBar()->show(); } void TopLevel::togglePartDock() { if (!_partDock->isVisible()) _partDock->show(); else _partDock->hide(); } void TopLevel::toggleStackDock() { if (!_stackDock->isVisible()) _stackDock->show(); else _stackDock->hide(); } void TopLevel::toggleDumpDock() { #if ENABLE_DUMPDOCK if (!_dumpDock->isVisible()) _dumpDock->show(); else _dumpDock->hide(); #endif } void TopLevel::toggleFunctionDock() { if (!_functionDock->isVisible()) _functionDock->show(); else _functionDock->hide(); } void TopLevel::togglePercentage() { setPercentage(_taPercentage->isChecked()); } void TopLevel::setAbsoluteCost() { setPercentage(false); } void TopLevel::setRelativeCost() { setPercentage(true); } void TopLevel::setPercentage(bool show) { if (_showPercentage == show) return; _showPercentage = show; if (_taPercentage->isChecked() != show) _taPercentage->setChecked(show); // FIXME: Delete when no view gets this config from Configuration Configuration::setShowPercentage(_showPercentage); _partSelection->refresh(); _stackSelection->refresh(); _functionSelection->notifyChange(TraceItemView::configChanged); _functionSelection->updateView(); _multiView->notifyChange(TraceItemView::configChanged); _multiView->updateView(); } void TopLevel::toggleExpanded() { bool show = _taExpanded->isChecked(); if (_showExpanded == show) return; _showExpanded = show; // FIXME: Delete when no view gets this config from Configuration Configuration::setShowExpanded(_showExpanded); _partSelection->refresh(); _stackSelection->refresh(); _functionSelection->notifyChange(TraceItemView::configChanged); _functionSelection->updateView(); _multiView->notifyChange(TraceItemView::configChanged); _multiView->updateView(); } void TopLevel::toggleCycles() { bool show = _taCycles->isChecked(); if (_showCycles == show) return; _showCycles = show; // FIXME: Delete when no view gets this config from Configuration Configuration::setShowCycles(_showCycles); if (!_data) return; _data->invalidateDynamicCost(); _data->updateFunctionCycles(); _partSelection->refresh(); _stackSelection->rebuildStackList(); _functionSelection->notifyChange(TraceItemView::configChanged); _functionSelection->updateView(); _multiView->notifyChange(TraceItemView::configChanged); _multiView->updateView(); } void TopLevel::partVisibilityChanged(bool v) { _partDockShown->setChecked(v); } void TopLevel::stackVisibilityChanged(bool v) { _stackDockShown->setChecked(v); } #if ENABLE_DUMPDOCK void TopLevel::dumpVisibilityChanged(bool v) #else void TopLevel::dumpVisibilityChanged(bool) #endif { #if ENABLE_DUMPDOCK _dumpDockShown->setChecked(v); #endif } void TopLevel::functionVisibilityChanged(bool v) { _functionDockShown->setChecked(v); if (v) _functionSelection->updateView(); } void TopLevel::querySlot() { _functionSelection->query(queryLineEdit->text()); } void TopLevel::configureKeys() { #if KDE_VERSION > 0x030190 // for KDE 3.2: KKeyDialog::configureKeys is deprecated KKeyDialog::configure(actionCollection(), this, true); #else KKeyDialog::configureKeys(actionCollection(), xmlFile(), true, this); #endif } void TopLevel::configureToolbars() { KEditToolbar *dlg = new KEditToolbar(guiFactory(),this); if (dlg->exec()) createGUI(); delete dlg; } void TopLevel::newTrace() { // start cachegrind on command... } void TopLevel::newWindow() { TopLevel* t = new TopLevel(0); t->show(); } void TopLevel::loadTrace() { KURL url = KFileDialog::getOpenURL(":", i18n("cachegrind.out* callgrind.out*|Callgrind Profile Data\n*|All Files"), this, i18n("Select Callgrind Profile Data")); loadTrace(url); } void TopLevel::loadTrace(const KURL& url) { if (url.isEmpty()) return; // network transparancy QString tmpFile; #if KDE_VERSION > 0x030190 // for KDE 3.2: KIO::NetAccess::download with 2 args is deprecated if(KIO::NetAccess::download( url, tmpFile, this )) { #else if(KIO::NetAccess::download( url, tmpFile )) { #endif _openRecent->addURL(url); _openRecent->saveEntries( KGlobal::config() ); loadTrace(tmpFile); KIO::NetAccess::removeTempFile( tmpFile ); } } void TopLevel::loadTrace(QString file) { if (file.isEmpty()) return; if (_data && _data->parts().count()>0) { // In new window TopLevel* t = new TopLevel(); t->show(); t->loadDelayed(file); return; } // this constructor enables progress bar callbacks TraceData* d = new TraceData(this); d->load(file); setData(d); } void TopLevel::addTrace() { KURL url = KFileDialog::getOpenURL(QString::null, i18n("cachegrind.out* callgrind.out*|Callgrind Profile Data\n*|All Files"), this, i18n("Add Callgrind Profile Data")); addTrace(url); } void TopLevel::addTrace(const KURL& url) { if (url.isEmpty()) return; // network transparancy QString tmpFile; #if KDE_VERSION > 0x030190 // for KDE 3.2: KIO::NetAccess::download with 2 args is deprecated if(KIO::NetAccess::download( url, tmpFile, this )) { #else if(KIO::NetAccess::download( url, tmpFile )) { #endif _openRecent->addURL(url); _openRecent->saveEntries( KGlobal::config() ); addTrace(tmpFile); KIO::NetAccess::removeTempFile( tmpFile ); } } void TopLevel::addTrace(QString file) { if (file.isEmpty()) return; if (_data) { _data->load(file); // GUI update for added data configChanged(); return; } // this constructor enables progress bar callbacks TraceData* d = new TraceData(this); d->load(file); setData(d); } void TopLevel::loadDelayed(QString file) { _loadTraceDelayed = file; QTimer::singleShot(0, this, SLOT(loadTraceDelayed())); } void TopLevel::loadTraceDelayed() { if (_loadTraceDelayed.isEmpty()) return; loadTrace(_loadTraceDelayed); _loadTraceDelayed = QString::null; } void TopLevel::reload() { QString trace; if (!_data || _data->parts().count()==0) trace = "."; // open first trace found in dir else trace = _data->traceName(); // this also keeps sure we have the same browsing position... TraceData* d = new TraceData(this); d->load(trace); setData(d); } void TopLevel::exportGraph() { if (!_data || !_function) return; QString n = QString("callgraph.dot"); GraphExporter ge(_data, _function, _costType, _groupType, n); ge.writeDot(); QString cmd = QString("(dot %1 -Tps > %2.ps; kghostview %3.ps)&") .arg(n).arg(n).arg(n); system(QFile::encodeName( cmd )); } bool TopLevel::setCostType(QString s) { TraceCostType* ct; ct = (_data) ? _data->mapping()->type(s) : 0; // if costtype with given name not found, use first available if (!ct && _data) ct = _data->mapping()->type(0); return setCostType(ct); } bool TopLevel::setCostType2(QString s) { TraceCostType* ct; // Special type i18n("(Hidden)") gives 0 ct = (_data) ? _data->mapping()->type(s) : 0; return setCostType2(ct); } void TopLevel::costTypeSelected(const QString& s) { TraceCostType* ct; ct = (_data) ? _data->mapping()->typeForLong(s) : 0; setCostType(ct); } void TopLevel::costType2Selected(const QString& s) { TraceCostType* ct; ct = (_data) ? _data->mapping()->typeForLong(s) : 0; setCostType2(ct); } bool TopLevel::setCostType(TraceCostType* ct) { if (_costType == ct) return false; _costType = ct; if (ct) { int idx=0; QStringList l = _saCost->items(); for (QStringList::Iterator it = l.begin(); it != l.end(); ++it, ++idx ) { if (*it == ct->longName()) _saCost->setCurrentItem(idx); } } _partSelection->setCostType(_costType); _stackSelection->setCostType(_costType); _functionSelection->setCostType(_costType); _functionSelection->updateView(); _multiView->setCostType(_costType); _multiView->updateView(); updateStatusBar(); return true; } bool TopLevel::setCostType2(TraceCostType* ct) { if (_costType2 == ct) return false; _costType2 = ct; QString longName = ct ? ct->longName() : i18n("(Hidden)"); int idx=0; QStringList l = _saCost2->items(); for (QStringList::Iterator it = l.begin(); it != l.end(); ++it, ++idx ) { if (*it == longName) _saCost2->setCurrentItem(idx); } _partSelection->setCostType2(_costType2); _stackSelection->setCostType2(_costType2); _functionSelection->setCostType2(_costType2); _functionSelection->updateView(); _multiView->setCostType2(_costType2); _multiView->updateView(); updateStatusBar(); return true; } void TopLevel::groupTypeSelected(int cg) { switch(cg) { case 0: setGroupType( TraceItem::Function ); break; case 1: setGroupType( TraceItem::Object ); break; case 2: setGroupType( TraceItem::File ); break; case 3: setGroupType( TraceItem::Class ); break; case 4: setGroupType( TraceItem::FunctionCycle ); break; default: break; } } bool TopLevel::setGroupType(QString s) { TraceItem::CostType gt; gt = (_data) ? _data->costType(s) : TraceData::costType(s); // only allow Function/Object/File/Class as grouptype switch(gt) { case TraceItem::Object: case TraceItem::File: case TraceItem::Class: case TraceItem::FunctionCycle: break; default: gt = TraceItem::Function; } return setGroupType(gt); } bool TopLevel::setGroupType(TraceItem::CostType gt) { if (_groupType == gt) return false; _groupType = gt; int idx = -1; switch(gt) { case TraceItem::Function: idx = 0; break; case TraceItem::Object: idx = 1; break; case TraceItem::File: idx = 2; break; case TraceItem::Class: idx = 3; break; case TraceItem::FunctionCycle: idx = 4; break; default: break; } if (idx==-1) return false; if (saGroup->currentItem() != idx) saGroup->setCurrentItem(idx); _stackSelection->setGroupType(_groupType); _partSelection->setGroupType(_groupType); _functionSelection->set(_groupType); _functionSelection->updateView(); _multiView->set(_groupType); _multiView->updateView(); updateStatusBar(); return true; } bool TopLevel::setGroup(QString s) { return true; TraceCostItem* ci = _functionSelection->group(s); if (!ci) return false; return setGroup(ci); } bool TopLevel::setGroup(TraceCostItem* g) { _multiView->activate(g); _multiView->updateView(); _functionSelection->activate(g); _functionSelection->updateView(); if (_group == g) return false; _group = g; updateStatusBar(); return true; } bool TopLevel::setFunction(QString s) { if (!_data) return false; TraceCost* f = _data->search(TraceItem::Function, s, _costType); if (!f) return false; return setFunction((TraceFunction*)f); } bool TopLevel::setFunction(TraceFunction* f) { _multiView->activate(f); _multiView->updateView(); _functionSelection->activate(f); _functionSelection->updateView(); if (_function == f) return false; _function = f; _partSelection->setFunction(_function); _stackSelection->setFunction(_function); StackBrowser* b = _stackSelection->browser(); if (b) { // don't disable up: a press forces stack-up extending... _paForward->setEnabled(b->canGoForward()); _paBack->setEnabled(b->canGoBack()); } #if TRACE_UPDATES qDebug("TopLevel::setFunction(%s), lastSender %s", f ? f->prettyName().ascii() : "0", _lastSender ? _lastSender->name() :"0" ); #endif return true; } /** * Delayed versions. * We always have a pair of slots: One receiver to start the * delay with a singleShot Timer. It stores the parameter into a * temporary variable. And one parameterless slot for * forwarding, using this temporary. */ void TopLevel::setCostTypeDelayed(TraceCostType* ct) { _costTypeDelayed = ct; QTimer::singleShot (0, this, SLOT(setCostTypeDelayed())); } void TopLevel::setCostType2Delayed(TraceCostType* ct) { _costType2Delayed = ct; QTimer::singleShot (0, this, SLOT(setCostType2Delayed())); } void TopLevel::setCostTypeDelayed() { setCostType(_costTypeDelayed); } void TopLevel::setCostType2Delayed() { setCostType2(_costType2Delayed); } void TopLevel::setGroupTypeDelayed(TraceItem::CostType gt) { _groupTypeDelayed = gt; QTimer::singleShot (0, this, SLOT(setGroupTypeDelayed())); } void TopLevel::setGroupTypeDelayed() { setGroupType(_groupTypeDelayed); } void TopLevel::setGroupDelayed(TraceCostItem* g) { #if TRACE_UPDATES qDebug("TopLevel::setGroupDelayed(%s), sender %s", g ? g->prettyName().ascii() : "0", _lastSender ? _lastSender->name() :"0" ); #endif _groupDelayed = g; QTimer::singleShot (0, this, SLOT(setGroupDelayed())); } void TopLevel::setGroupDelayed() { setGroup(_groupDelayed); } void TopLevel::setDirectionDelayed(TraceItemView::Direction d) { _directionDelayed = d; QTimer::singleShot (0, this, SLOT(setDirectionDelayed())); } void TopLevel::setDirectionDelayed() { switch(_directionDelayed) { case TraceItemView::Back: _stackSelection->browserBack(); break; case TraceItemView::Forward: _stackSelection->browserForward(); break; case TraceItemView::Up: { StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0; HistoryItem* hi = b ? b->current() : 0; TraceFunction* f = hi ? hi->function() : 0; if (!f) break; f = hi->stack()->caller(f, false); if (f) setFunction(f); } break; default: break; } _directionDelayed = TraceItemView::None; } void TopLevel::setTraceItemDelayed(TraceItem* i) { // no need to select same item a 2nd time... if (_traceItemDelayed == i) return; _traceItemDelayed = i; _lastSender = sender(); kdDebug() << "Selected " << (i ? i->prettyName() : "(none)") << endl; #if TRACE_UPDATES qDebug("TopLevel::setTraceItemDelayed(%s), sender %s", i ? i->prettyName().ascii() : "0", _lastSender ? _lastSender->name() :"0" ); #endif QTimer::singleShot (0, this, SLOT(setTraceItemDelayed())); } void TopLevel::setTraceItemDelayed() { if (!_traceItemDelayed) return; switch(_traceItemDelayed->type()) { case TraceItem::Function: case TraceItem::FunctionCycle: setFunction((TraceFunction*)_traceItemDelayed); break; case TraceItem::Object: case TraceItem::File: case TraceItem::Class: setGroup((TraceCostItem*)_traceItemDelayed); break; #if 0 // this conflicts with the selection policy of InstrView ?!? case TraceItem::Instr: case TraceItem::Line: // only for multiview _multiView->activate(_traceItemDelayed); _multiView->updateView(); break; #endif default: break; } _traceItemDelayed = 0; _lastSender = 0; } /** * A TraceData object cannot be viewed many times in different * toplevel windows. Thus, this toplevel window takes ownership * of the TraceData object: on closing the window or opening * another trace, the object is destroyed. */ void TopLevel::setData(TraceData* data) { if (data == _data) return; _lastSender = 0; saveTraceSettings(); if (_data) { _partSelection->setData(0); _stackSelection->setData(0); _functionSelection->setData(0); _functionSelection->updateView(); _multiView->setData(0); _multiView->updateView(); // we are the owner... delete _data; } // reset members init(); _data = data; // fill cost type list QStringList types; if (_data) { /* add all supported virtual types */ TraceCostMapping* m = _data->mapping(); m->addKnownVirtualTypes(); /* first, fill selection list with available cost types */ for (int i=0;i