/* This file is part of KCachegrind. Copyright (C) 2002, 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. */ /* * KCachegrind top level window */ #define TRACE_UPDATES 0 #define ENABLE_DUMPDOCK 0 #include // for system() #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if ENABLE_DUMPDOCK #include "dumpselection.h" #endif #include "toplevel.h" #include "partselection.h" #include "functionselection.h" #include "stactdeselection.h" #include "stackbrowser.h" #include "tracedata.h" #include "configuration.h" #include "configdlg.h" #include "multiview.h" #include "callgraphview.h" TopLevel::TopLevel(const char *name) : TDEMainWindow(0, name), DCOPObject("KCachegrindIface") { init(); createDocks(); _multiView = new MultiView(this, this, "MultiView"); setCentralWidget(_multiView); createActions(); _partDockShown->setChecked(!_partDock->isHidden()); _stackDockShown->setChecked(!_stackDock->isHidden()); _functionDockShown->setChecked(!_functionDock->isHidden()); connect(_partDock, TQT_SIGNAL(visibilityChanged(bool)), TQT_TQOBJECT(this), TQT_SLOT(partVisibilityChanged(bool))); connect(_stackDock, TQT_SIGNAL(visibilityChanged(bool)), TQT_TQOBJECT(this), TQT_SLOT(stackVisibilityChanged(bool))); connect(_functionDock, TQT_SIGNAL(visibilityChanged(bool)), TQT_TQOBJECT(this), TQT_SLOT(functionVisibilityChanged(bool))); #if ENABLE_DUMPDOCK _dumpDockShown->setChecked(!_dumpDock->isHidden()); connect(_dumpDock, TQT_SIGNAL(visibilityChanged(bool)), TQT_TQOBJECT(this), TQT_SLOT(dumpVisibilityChanged(bool))); #endif _statusbar = statusBar(); _statusLabel = new TQLabel(_statusbar); #if 0 // how to do avoid main window resizing on large statusbar label? TQSizePolicy p(TQSizePolicy::Fixed, TQSizePolicy::Expanding); _statusLabel->setSizePolicy(p); _statusbar->setSizePolicy(p); #endif _statusbar->addWidget(_statusLabel, 1); TDEConfig* tdeconfig = TDEGlobal::config(); Configuration::readOptions( tdeconfig ); _openRecent->loadEntries( tdeconfig ); // set toggle after reading configuration _showPercentage = Configuration::showPercentage(); _showExpanded = Configuration::showExpanded(); _showCycles = Configuration::showCycles(); _taPercentage->setChecked(_showPercentage); _taExpanded->setChecked(_showExpanded); _taCycles->setChecked(_showCycles); setupPartSelection(_partSelection); // KCachegrind for KDE 3.0.x does not allow to hide toolbars... #if TDE_VERSION >= 308 // KDE 3.1 setStandardToolBarMenuEnabled(true); #endif // QT dock windows are created before (using QT position restoring) createGUI(); setAutoSaveSettings(); // restore current state settings (not configuration options) restoreCurrentState(TQString()); // if this is the first toplevel, show tip of day if (memberList->count() == 1) TQTimer::singleShot( 200, TQT_TQOBJECT(this), TQT_SLOT(slotShowTipOnStart()) ); } void TopLevel::init() { _activeParts.clear(); _hiddenParts.clear(); _progressBar = 0; _data = 0; _function = 0; _costType = 0; _costType2 = 0; _groupType = TraceCost::NoCostType; _group = 0; _layoutCurrent = 0; _layoutCount = 1; // for delayed slots _traceItemDelayed = 0; _costTypeDelayed = 0; _costType2Delayed = 0; _groupTypeDelayed = TraceCost::NoCostType; _groupDelayed = 0; _directionDelayed = TraceItemView::None; _lastSender = 0; } /** * Setup the part selection widget. * Statusbar has to be created before. */ void TopLevel::setupPartSelection(PartSelection* ps) { // setup connections from the part selection widget connect(ps, TQT_SIGNAL(activePartsChanged(const TracePartList&)), TQT_TQOBJECT(this), TQT_SLOT(activePartsChangedSlot(const TracePartList&))); connect(ps, TQT_SIGNAL(groupChanged(TraceCostItem*)), TQT_TQOBJECT(this), TQT_SLOT(setGroupDelayed(TraceCostItem*))); connect(ps, TQT_SIGNAL(functionChanged(TraceItem*)), TQT_TQOBJECT(this), TQT_SLOT(setTraceItemDelayed(TraceItem*))); connect(ps, TQT_SIGNAL(goBack()), _stackSelection, TQT_SLOT(browserBack())); connect(ps, TQT_SIGNAL(partsHideSelected()), TQT_TQOBJECT(this), TQT_SLOT(partsHideSelectedSlotDelayed())); connect(ps, TQT_SIGNAL(partsUnhideAll()), TQT_TQOBJECT(this), TQT_SLOT(partsUnhideAllSlotDelayed())); connect(ps, TQT_SIGNAL(showMessage(const TQString&, int)), _statusbar, TQT_SLOT(message(const TQString&, int))); } /** * This saves the current state of the main window and * sub widgets. * * No positions are saved. These is done automatically for * TDEToolbar, and manually in queryExit() for QT docks. */ void TopLevel::saveCurrentState(TQString postfix) { TDEConfig* tdeconfig = TDEGlobal::config(); TQCString pf = postfix.ascii(); TDEConfigGroup psConfig(tdeconfig, TQCString("PartOverview")+pf); _partSelection->saveVisualisationConfig(&psConfig); TDEConfigGroup stateConfig(tdeconfig, TQCString("CurrentState")+pf); stateConfig.writeEntry("CostType", _costType ? _costType->name() : TQString("?")); stateConfig.writeEntry("CostType2", _costType2 ? _costType2->name() : TQString("?")); stateConfig.writeEntry("GroupType", TraceItem::typeName(_groupType)); _multiView->saveViewConfig(tdeconfig, TQString("MainView"), postfix, true); } /** * This function is called when a trace is closed. * Save browsing position for later restoring */ void TopLevel::saveTraceSettings() { TQString key = traceKey(); TDEConfigGroup pConfig(TDEGlobal::config(), TQCString("TracePositions")); pConfig.writeEntry(TQString("CostType%1").arg(key), _costType ? _costType->name() : TQString("?")); pConfig.writeEntry(TQString("CostType2%1").arg(key), _costType2 ? _costType2->name() : TQString("?")); pConfig.writeEntry(TQString("GroupType%1").arg(key), TraceItem::typeName(_groupType)); if (!_data) return; TDEConfigGroup aConfig(TDEGlobal::config(), TQCString("Layouts")); aConfig.writeEntry(TQString("Count%1").arg(key), _layoutCount); aConfig.writeEntry(TQString("Current%1").arg(key), _layoutCurrent); saveCurrentState(key); pConfig.writeEntry(TQString("Group%1").arg(key), _group ? _group->name() : TQString()); } /** * This restores the current state of the main window and * sub widgets. * * This does NOT restore any positions. This is done automatically for * TDEToolbar, and manually in the createDocks() for QT docks.. */ void TopLevel::restoreCurrentState(TQString postfix) { TDEConfig* tdeconfig = TDEGlobal::config(); TQStringList gList = tdeconfig->groupList(); TQCString pf = postfix.ascii(); // dock properties (not position, this should be have done before) TQCString group = TQCString("PartOverview"); if (gList.contains(group+pf)) group += pf; TDEConfigGroup psConfig(tdeconfig, group); _partSelection->readVisualisationConfig(&psConfig); _multiView->readViewConfig(tdeconfig, TQString("MainView"), postfix, true); _taSplit->setChecked(_multiView->childCount()>1); _taSplitDir->setEnabled(_multiView->childCount()>1); _taSplitDir->setChecked(_multiView->orientation() == Qt::Horizontal); } void TopLevel::createDocks() { _partDock = new TQDockWindow(TQDockWindow::InDock, this); _partDock->setCaption(i18n("Parts Overview")); _partDock->setCloseMode( TQDockWindow::Always ); _partSelection = new PartSelection(_partDock, "partSelection"); _partDock->setWidget(_partSelection); _partDock->setResizeEnabled(true); _partDock->setFixedExtentWidth(200); TQWhatsThis::add( _partSelection, i18n( "The Parts Overview" "

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: " "

  • Partitioning: You see the " "partitioning into groups for a trace part, according to " "the group type selected. E.g. if ELF object groups are " "selected, you see colored rectangles for each " "used ELF object (shared library or executable), sized " "according to the cost spent therein.
  • " "
  • Callee: A rectangle showing the inclusive " "cost of the current selected function in the trace part " "is shown. " "This is split up into smaller rectangles to show the costs of its " "callees.

")); _stackDock = new TQDockWindow(TQDockWindow::InDock, this); _stackDock->setResizeEnabled(true); // Why is the caption only correct with a close button? _stackDock->setCloseMode( TQDockWindow::Always ); _stackSelection = new StackSelection(_stackDock, "stackSelection"); _stackDock->setWidget(_stackSelection); _stackDock->setFixedExtentWidth(200); _stackDock->setCaption(i18n("Top Cost Call Stack")); TQWhatsThis::add( _stackSelection, i18n( "The Top Cost Call Stack" "

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, TQT_SIGNAL(functionSelected(TraceItem*)), TQT_TQOBJECT(this), TQT_SLOT(setTraceItemDelayed(TraceItem*))); _functionDock = new TQDockWindow(TQDockWindow::InDock, this); _functionDock->setCaption(i18n("Flat Profile")); _functionDock->setCloseMode( TQDockWindow::Always ); _functionSelection = new FunctionSelection(this, _functionDock, "functionSelection"); _functionSelection->setTopLevel(this); _functionDock->setWidget(_functionSelection); _functionDock->setResizeEnabled(true); _functionDock->setFixedExtentWidth(200); TQWhatsThis::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 TQDockWindow(TQDockWindow::InDock, this); _dumpDock->setCaption(i18n("Profile Dumps")); _dumpDock->setCloseMode( TQDockWindow::Always ); _dumpSelection = new DumpSelection(this, _dumpDock, "dumpSelection"); _dumpSelection->setTopLevel(this); _dumpDock->setWidget(_dumpSelection); _dumpDock->setResizeEnabled(true); _dumpDock->setFixedExtentWidth(200); TQWhatsThis::add( _dumpSelection, i18n( "Profile Dumps" "

This dockable shows in the top part the list of " "loadable profile dumps in all subdirectories of: " "

  • current working directory of KCachegrind, " "i.e. where it was started from, and " "
  • the default profile dump directory given in the " "configuration.
" "The list is sorted according the the target command " "profiled in the corresponding dump.

" "

On selecting a profile dump, information for it " "is shown in the bottom area of the dockable: " "

  • Options allows you to view the profiled " "command and profile options of this dump. By changing " "any item, a new (yet unexisting) profile template " "is created. Press Run Profile to start a" "profile run with these options in the background. " "
  • Info gives detailed info on the selected " "dump like event cost summary and properties of the " "simulated cache. " "
  • State is only available for current happening " "profiles runs. Press Update to see different " "counters of the run, and a stack trace of the current " "position in the program profiled. Check the Every " "option to let KCachegrind regularly poll these data. " "Check the Sync option to let the dockable activate " "the top function in the current loaded dump.

")); #endif // Restore QT Dock positions... TDEConfigGroup dockConfig(TDEGlobal::config(), TQCString("Docks")); TQString str = dockConfig.readEntry("Position", TQString()); if (0) tqDebug("Docks/Position: '%s'", str.ascii()); if (str.isEmpty()) { // default positions addDockWindow(_partDock, DockLeft); addDockWindow(_stackDock, DockLeft); addDockWindow(_functionDock, DockLeft); _stackDock->hide(); #if ENABLE_DUMPDOCK addDockWindow(_dumpDock, DockLeft); _dumpDock->hide(); #endif } else { TQTextStream ts( &str, IO_ReadOnly ); ts >> *this; } _forcePartDock = dockConfig.readBoolEntry("ForcePartDockVisible", false); #if 0 // dock context menu setAppropriate(_partDock, true); setAppropriate(_stackDock, true); setAppropriate(_dumpDock, true); setAppropriate(_functionDock, true); connect( _partDock, TQT_SIGNAL(contextMenuRequested(const TQPoint &)), TQT_TQOBJECT(this), TQT_SLOT(showDockMenu(const TQPoint &))); #endif } TopLevel::~TopLevel() { delete _data; } void TopLevel::saveProperties(TDEConfig* c) { c->writeEntry("TraceName", _data->traceName()); } void TopLevel::readProperties(TDEConfig* c) { TQString traceName = c->readEntry("TraceName"); if (!traceName.isEmpty()) { TraceData* d = new TraceData(this); d->load(traceName); setData(d); } } void TopLevel::createLayoutActions() { TQString hint; TDEAction* action; action = new TDEAction( i18n( "&Duplicate" ), TDEShortcut(KKey("Ctrl+Plus")), TQT_TQOBJECT(this), TQT_SLOT(layoutDuplicate()), actionCollection(), "layout_duplicate" ); hint = i18n("Duplicate Current Layout" "

Make a copy of the current layout.

"); action->setWhatsThis( hint ); action = new TDEAction( i18n( "&Remove" ), TDEShortcut(), TQT_TQOBJECT(this), TQT_SLOT(layoutRemove()), actionCollection(), "layout_remove" ); hint = i18n("Remove Current Layout" "

Delete current layout and make the previous active.

"); action->setWhatsThis( hint ); action = new TDEAction( i18n( "&Go to Next" ), TDEShortcut(KKey("Ctrl+Right")), TQT_TQOBJECT(this), TQT_SLOT(layoutNext()), actionCollection(), "layout_next" ); hint = i18n("Go to Next Layout"); action->setWhatsThis( hint ); action = new TDEAction( i18n( "&Go to Previous" ), TDEShortcut(KKey("Ctrl+Left")), TQT_TQOBJECT(this), TQT_SLOT(layoutPrevious()), actionCollection(), "layout_previous" ); hint = i18n("Go to Previous Layout"); action->setWhatsThis( hint ); action = new TDEAction( i18n( "&Restore to Default" ), TDEShortcut(), TQT_TQOBJECT(this), TQT_SLOT(layoutRestore()), actionCollection(), "layout_restore" ); hint = i18n("Restore Layouts to Default"); action->setWhatsThis( hint ); action = new TDEAction( i18n( "&Save as Default" ), TDEShortcut(), TQT_TQOBJECT(this), TQT_SLOT(layoutSave()), actionCollection(), "layout_save" ); hint = i18n("Save Layouts as Default"); action->setWhatsThis( hint ); } // TODO: split this up... void TopLevel::createMiscActions() { TQString hint; TDEAction* action; action = KStdAction::openNew(TQT_TQOBJECT(this), TQT_SLOT(newWindow()), actionCollection()); hint = i18n("New

Open new empty KCachegrind window.

"); action->setWhatsThis( hint ); action = new TDEAction( i18n( "&Add..." ), TDEShortcut(), TQT_TQOBJECT(this), TQT_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 TDEAction( i18n( "&Reload" ), "reload", #if TDE_VERSION > 0x030190 // for KDE 3.2: TDEStdAccel::key is deprecated TDEStdAccel::shortcut(TDEStdAccel::Reload), #else TDEStdAccel::key(TDEStdAccel::Reload), #endif TQT_TQOBJECT(this), TQT_SLOT( reload() ), actionCollection(), "reload" ); hint = i18n("Reload Profile Data" "

This loads any new created parts, too.

"); action->setWhatsThis( hint ); action = new TDEAction( i18n( "&Export Graph" ), TDEShortcut(), TQT_TQOBJECT(this), TQT_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 TDEToggleAction( i18n( "&Force Dump" ), "redo", #if TDE_VERSION > 0x030190 // for KDE 3.2: TDEStdAccel::key is deprecated TDEStdAccel::shortcut(TDEStdAccel::Redo), #else TDEStdAccel::key(TDEStdAccel::Redo), #endif TQT_TQOBJECT(this), TQT_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(TQT_TQOBJECT(this), TQT_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(TQT_TQOBJECT(this), TQT_SLOT(loadTrace(const KURL&)), actionCollection()); KStdAction::showStatusbar(TQT_TQOBJECT(this), TQT_SLOT(toggleStatusBar()), actionCollection()); _partDockShown = new TDEToggleAction(i18n("Parts Overview"), TDEShortcut(), TQT_TQOBJECT(this), TQT_SLOT(togglePartDock()), actionCollection(), "settings_show_partdock"); hint = i18n("Show/Hide the Parts Overview Dockable"); _partDockShown->setToolTip( hint ); _partDockShown->setWhatsThis( hint ); _stackDockShown = new TDEToggleAction(i18n("Call Stack"), TDEShortcut(), TQT_TQOBJECT(this), TQT_SLOT(toggleStackDock()), actionCollection(), "settings_show_stackdock"); hint = i18n("Show/Hide the Call Stack Dockable"); _stackDockShown->setToolTip( hint ); _stackDockShown->setWhatsThis( hint ); _functionDockShown = new TDEToggleAction(i18n("Function Profile"), TDEShortcut(), TQT_TQOBJECT(this), TQT_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 TDEToggleAction(i18n("Profile Dumps"), TDEShortcut(), TQT_TQOBJECT(this), TQT_SLOT(toggleDumpDock()), actionCollection(), "settings_show_dumpdock"); hint = i18n("Show/Hide the Profile Dumps Dockable"); _dumpDockShown->setToolTip( hint ); _dumpDockShown->setWhatsThis( hint ); #endif _taPercentage = new TDEToggleAction(i18n("Show Relative Costs"), "percent", TDEShortcut(), TQT_TQOBJECT(this), TQT_SLOT(togglePercentage()), actionCollection(), "view_percentage"); #if TDE_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 TDEToggleAction(i18n("Percentage Relative to Parent"), "move", TDEShortcut(), TQT_TQOBJECT(this), TQT_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 TypeParent Cost
    Function CumulativeTotal
    Function SelfFunction Group (*) / Total
    CallFunction Cumulative
    Source LineFunction Cumulative
    " "

    (*) Only if function grouping is switched on (e.g. ELF object grouping)."); _taExpanded->setWhatsThis( hint ); _taCycles = new TDEToggleAction( i18n( "Do Cycle Detection" ), "undo", TDEShortcut(), TQT_TQOBJECT(this), TQT_SLOT( toggleCycles() ), actionCollection(), "view_cycles" ); #if TDE_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(TQT_TQOBJECT(this), TQT_SLOT(close()), actionCollection()); KStdAction::preferences(TQT_TQOBJECT(this), TQT_SLOT(configure()), actionCollection()); KStdAction::keyBindings(TQT_TQOBJECT(this), TQT_SLOT(configureKeys()), actionCollection()); KStdAction::configureToolbars(TQT_TQOBJECT(this),TQT_SLOT(configureToolbars()), actionCollection()); #if 0 action = KStdAction::back(_stackSelection, TQT_SLOT(browserBack()), actionCollection()); hint = i18n("Go back in function selection history"); action->setToolTip( hint ); action->setWhatsThis( hint ); action = KStdAction::forward(_stackSelection, TQT_SLOT(browserForward()), actionCollection()); hint = i18n("Go forward in function selection history"); action->setToolTip( hint ); action->setWhatsThis( hint ); action = KStdAction::up(_stackSelection, TQT_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 TDEToolBarPopupAction( i18n( "&Up" ), "up", ALT+Key_Up, TQT_TQOBJECT(_stackSelection), TQT_SLOT( browserUp() ), actionCollection(), "go_up" ); connect( _paUp->popupMenu(), TQT_SIGNAL( aboutToShow() ), TQT_TQOBJECT(this), TQT_SLOT( upAboutToShow() ) ); connect( _paUp->popupMenu(), TQT_SIGNAL( activated( int ) ), TQT_TQOBJECT(this), TQT_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 ); TQPair< KGuiItem, KGuiItem > backForward = KStdGuiItem::backAndForward(); _paBack = new TDEToolBarPopupAction( backForward.first, ALT+Key_Left, TQT_TQOBJECT(_stackSelection), TQT_SLOT(browserBack()), actionCollection(), "go_back" ); connect( _paBack->popupMenu(), TQT_SIGNAL( aboutToShow() ), TQT_TQOBJECT(this), TQT_SLOT( backAboutToShow() ) ); connect( _paBack->popupMenu(), TQT_SIGNAL( activated( int ) ), TQT_TQOBJECT(this), TQT_SLOT( backActivated( int ) ) ); hint = i18n("Go back in function selection history"); _paBack->setToolTip( hint ); _paBack->setWhatsThis( hint ); _paForward = new TDEToolBarPopupAction( backForward.second, ALT+Key_Right, TQT_TQOBJECT(_stackSelection), TQT_SLOT(browserForward()), actionCollection(), "go_forward" ); connect( _paForward->popupMenu(), TQT_SIGNAL( aboutToShow() ), this, TQT_SLOT( forwardAboutToShow() ) ); connect( _paForward->popupMenu(), TQT_SIGNAL( activated( int ) ), this, TQT_SLOT( forwardActivated( int ) ) ); hint = i18n("Go forward in function selection history"); _paForward->setToolTip( hint ); _paForward->setWhatsThis( hint ); #endif _saCost = new TDESelectAction( i18n("Primary Event Type"), TDEShortcut(), 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 TDESelectAction // is filled in setData() connect( _saCost, TQT_SIGNAL(activated(const TQString&)), TQT_TQOBJECT(this), TQT_SLOT(costTypeSelected(const TQString&))); _saCost2 = new TDESelectAction( i18n("Secondary Event Type"), TDEShortcut(), 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, TQT_SIGNAL(activated(const TQString&)), TQT_TQOBJECT(this), TQT_SLOT(costType2Selected(const TQString&))); saGroup = new TDESelectAction( i18n("Grouping"), TDEShortcut(), actionCollection(), "view_group_type"); hint = i18n("Select how functions are grouped into higher level cost items"); saGroup->setToolTip( hint ); saGroup->setWhatsThis( hint ); TQStringList 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, TQT_SIGNAL(activated(int)), TQT_TQOBJECT(this), TQT_SLOT(groupTypeSelected(int))); _taSplit = new TDEToggleAction(i18n("Split"), "view_left_right", TDEShortcut(), TQT_TQOBJECT(this), TQT_SLOT(splitSlot()), actionCollection(), "view_split"); hint = i18n("Show two information panels"); _taSplit->setToolTip( hint ); _taSplit->setWhatsThis( hint ); _taSplitDir = new TDEToggleAction(i18n("SplitQt::Horizontal"), "view_left_right", TDEShortcut(), TQT_TQOBJECT(this), TQT_SLOT(splitDirSlot()), actionCollection(), "view_split_dir"); hint = i18n("Change Split Qt::Orientation when main window is split."); _taSplitDir->setToolTip( hint ); _taSplitDir->setWhatsThis( hint ); // copied from KMail... #if TDE_VERSION >= 308 // KDE 3.1 KStdAction::tipOfDay( TQT_TQOBJECT(this), TQT_SLOT( slotShowTip() ), actionCollection() ); #else (void) new TDEAction( KGuiItem( i18n("Tip of the &Day..."), "idea", i18n("Show \"Tip of the Day\"") ), 0, TQT_TQOBJECT(this), TQT_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 TDE_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 TQString tmpFile; #if TDE_VERSION > 0x030190 // for KDE 3.2: TDEIO::NetAccess::download with 2 args is deprecated if(TDEIO::NetAccess::download( url, tmpFile, this )) { #else if(TDEIO::NetAccess::download( url, tmpFile )) { #endif _openRecent->addURL(url); _openRecent->saveEntries( TDEGlobal::config() ); loadTrace(tmpFile); TDEIO::NetAccess::removeTempFile( tmpFile ); } } void TopLevel::loadTrace(TQString 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(TQString(), 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 TQString tmpFile; #if TDE_VERSION > 0x030190 // for KDE 3.2: TDEIO::NetAccess::download with 2 args is deprecated if(TDEIO::NetAccess::download( url, tmpFile, this )) { #else if(TDEIO::NetAccess::download( url, tmpFile )) { #endif _openRecent->addURL(url); _openRecent->saveEntries( TDEGlobal::config() ); addTrace(tmpFile); TDEIO::NetAccess::removeTempFile( tmpFile ); } } void TopLevel::addTrace(TQString 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(TQString file) { _loadTraceDelayed = file; TQTimer::singleShot(0, TQT_TQOBJECT(this), TQT_SLOT(loadTraceDelayed())); } void TopLevel::loadTraceDelayed() { if (_loadTraceDelayed.isEmpty()) return; loadTrace(_loadTraceDelayed); _loadTraceDelayed = TQString(); } void TopLevel::reload() { TQString 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; TQString n = TQString("callgraph.dot"); GraphExporter ge(_data, _function, _costType, _groupType, n); ge.writeDot(); TQString cmd = TQString("(dot %1 -Tps > %2.ps; kghostview %3.ps)&") .arg(n).arg(n).arg(n); system(TQFile::encodeName( cmd )); } bool TopLevel::setCostType(TQString 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(TQString s) { TraceCostType* ct; // Special type i18n("(Hidden)") gives 0 ct = (_data) ? _data->mapping()->type(s) : 0; return setCostType2(ct); } void TopLevel::costTypeSelected(const TQString& s) { TraceCostType* ct; ct = (_data) ? _data->mapping()->typeForLong(s) : 0; setCostType(ct); } void TopLevel::costType2Selected(const TQString& 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; TQStringList l = _saCost->items(); for (TQStringList::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; TQString longName = ct ? ct->longName() : i18n("(Hidden)"); int idx=0; TQStringList l = _saCost2->items(); for (TQStringList::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(TQString 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(TQString 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(TQString 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 tqDebug("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; TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_SLOT(setCostTypeDelayed())); } void TopLevel::setCostType2Delayed(TraceCostType* ct) { _costType2Delayed = ct; TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_SLOT(setCostType2Delayed())); } void TopLevel::setCostTypeDelayed() { setCostType(_costTypeDelayed); } void TopLevel::setCostType2Delayed() { setCostType2(_costType2Delayed); } void TopLevel::setGroupTypeDelayed(TraceItem::CostType gt) { _groupTypeDelayed = gt; TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_SLOT(setGroupTypeDelayed())); } void TopLevel::setGroupTypeDelayed() { setGroupType(_groupTypeDelayed); } void TopLevel::setGroupDelayed(TraceCostItem* g) { #if TRACE_UPDATES tqDebug("TopLevel::setGroupDelayed(%s), sender %s", g ? g->prettyName().ascii() : "0", _lastSender ? _lastSender->name() :"0" ); #endif _groupDelayed = g; TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_SLOT(setGroupDelayed())); } void TopLevel::setGroupDelayed() { setGroup(_groupDelayed); } void TopLevel::setDirectionDelayed(TraceItemView::Direction d) { _directionDelayed = d; TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_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 = TQT_TQOBJECT(const_cast(sender())); kdDebug() << "Selected " << (i ? i->prettyName() : "(none)") << endl; #if TRACE_UPDATES tqDebug("TopLevel::setTraceItemDelayed(%s), sender %s", i ? i->prettyName().ascii() : "0", _lastSender ? _lastSender->name() :"0" ); #endif TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_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 TQStringList 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;irealCount();i++) types << m->realType(i)->longName(); for (int i=0;ivirtualCount();i++) types << m->virtualType(i)->longName(); } _saCost->setItems(types); _saCost->setComboWidth(300); if (types.count()>0) { // second type list gets an additional "(Hidden)" types.prepend(i18n("(Hidden)")); } _saCost2->setItems(types); _saCost2->setComboWidth(300); // default is hidden if (types.count()>0) _saCost2->setCurrentItem(0); _partSelection->setData(_data); _stackSelection->setData(_data); _functionSelection->setData(_data); _functionSelection->updateView(); _multiView->setData(_data); _multiView->updateView(); /* this is needed to let the other widgets know the types */ restoreTraceTypes(); restoreTraceSettings(); TQString caption; if (_data) { caption = _data->traceName(); if (!_data->command().isEmpty()) caption += " [" + _data->command() + "]"; } setCaption(caption); if (!_data || (!_forcePartDock && _data->parts().count()<2)) { _partDock->hide(); _partDockShown->setChecked(false); } else { _partDock->show(); _partDockShown->setChecked(true); } updateStatusBar(); } void TopLevel::addCostMenu(TQPopupMenu* popup, bool withCost2) { if (_data) { TQPopupMenu *popup1 = new TQPopupMenu(popup); TQPopupMenu *popup2 = 0; popup1->setCheckable(true); if (withCost2) { popup2 = new TQPopupMenu(popup); popup2->setCheckable(true); if (_costType2) { popup2->insertItem(i18n("Hide"),199); popup2->insertSeparator(); } } TraceCostMapping* m = _data->mapping(); TraceCostType* ct; for (int i=0;irealCount();i++) { ct = m->realType(i); popup1->insertItem(ct->longName(), 100+i); if (_costType == ct) popup1->setItemChecked(100+i,true); if (popup2) { popup2->insertItem(ct->longName(), 100+i); if (_costType2 == ct) popup2->setItemChecked(100+i,true); } } for (int i=0;ivirtualCount();i++) { ct = m->virtualType(i); popup1->insertItem(ct->longName(), 200+i); if (_costType == ct) popup1->setItemChecked(200+i,true); if (popup2) { popup2->insertItem(ct->longName(), 200+i); if (_costType2 == ct) popup2->setItemChecked(200+i,true); } } popup->insertItem(i18n("Primary Event Type"), popup1); connect(popup1,TQT_SIGNAL(activated(int)),this,TQT_SLOT(setCostType(int))); if (popup2) { popup->insertItem(i18n("Secondary Event Type"), popup2); connect(popup2,TQT_SIGNAL(activated(int)),this,TQT_SLOT(setCostType2(int))); } } if (_showPercentage) popup->insertItem(i18n("Show Absolute Cost"), TQT_TQOBJECT(this), TQT_SLOT(setAbsoluteCost())); else popup->insertItem(i18n("Show Relative Cost"), TQT_TQOBJECT(this), TQT_SLOT(setRelativeCost())); } bool TopLevel::setCostType(int id) { if (!_data) return false; TraceCostMapping* m = _data->mapping(); TraceCostType* ct=0; if (id >=100 && id<199) ct = m->realType(id-100); if (id >=200 && id<299) ct = m->virtualType(id-200); return ct ? setCostType(ct) : false; } bool TopLevel::setCostType2(int id) { if (!_data) return false; TraceCostMapping* m = _data->mapping(); TraceCostType* ct=0; if (id >=100 && id<199) ct = m->realType(id-100); if (id >=200 && id<299) ct = m->virtualType(id-200); return setCostType2(ct); } void TopLevel::addGoMenu(TQPopupMenu* popup) { popup->insertItem(i18n("Go Back"), TQT_TQOBJECT(this), TQT_SLOT(goBack())); popup->insertItem(i18n("Go Forward"), TQT_TQOBJECT(this), TQT_SLOT(goForward())); popup->insertItem(i18n("Go Up"), TQT_TQOBJECT(this), TQT_SLOT(goUp())); } void TopLevel::goBack() { setDirectionDelayed(TraceItemView::Back); } void TopLevel::goForward() { setDirectionDelayed(TraceItemView::Forward); } void TopLevel::goUp() { setDirectionDelayed(TraceItemView::Up); } TQString TopLevel::traceKey() { if (!_data || _data->command().isEmpty()) return TQString(); TQString name = _data->command(); TQString key; for (unsigned int l=0;litems().isEmpty()) costTypeSelected(_saCost->items().first()); TDEConfigGroup aConfig(TDEGlobal::config(), TQCString("Layouts")); _layoutCount = aConfig.readNumEntry(TQString("Count%1").arg(key), 0); _layoutCurrent = aConfig.readNumEntry(TQString("Current%1").arg(key), 0); if (_layoutCount == 0) layoutRestore(); updateLayoutActions(); } /** * This must be called after setting group/cost types in the function * selection widget, because the group/function choosing depends on * filled lists in the function selection widget */ void TopLevel::restoreTraceSettings() { if (!_data) return; TQString key = traceKey(); TDEConfigGroup pConfig(TDEGlobal::config(), TQCString("TracePositions")); TQString group = pConfig.readEntry(TQString("Group%1").arg(key)); if (!group.isEmpty()) setGroup(group); restoreCurrentState(key); // restoreCurrentState() usually leads to a call to setTraceItemDelayed() // to restore last active item... if (!_traceItemDelayed) { // function not available any more.. try with "main" if (!setFunction("main")) _functionSelection->setTopFunction(); } } /* Layout */ void TopLevel::layoutDuplicate() { // save current and allocate a new slot _multiView->saveViewConfig(TDEGlobal::config(), TQString("Layout%1-MainView").arg(_layoutCurrent), traceKey(), false); _layoutCurrent = _layoutCount; _layoutCount++; updateLayoutActions(); kdDebug() << "TopLevel::layoutDuplicate: count " << _layoutCount << endl; } void TopLevel::layoutRemove() { if (_layoutCount <2) return; int from = _layoutCount-1; if (_layoutCurrent == from) { _layoutCurrent--; from--; } // restore from last and decrement count _multiView->readViewConfig(TDEGlobal::config(), TQString("Layout%1-MainView").arg(from), traceKey(), false); _layoutCount--; updateLayoutActions(); } void TopLevel::layoutNext() { if (_layoutCount <2) return; TDEConfig* config = TDEGlobal::config(); TQString key = traceKey(); _multiView->saveViewConfig(config, TQString("Layout%1-MainView").arg(_layoutCurrent), key, false); _layoutCurrent++; if (_layoutCurrent == _layoutCount) _layoutCurrent = 0; _multiView->readViewConfig(config, TQString("Layout%1-MainView").arg(_layoutCurrent), key, false); if (0) kdDebug() << "TopLevel::layoutNext: current " << _layoutCurrent << endl; } void TopLevel::layoutPrevious() { if (_layoutCount <2) return; TDEConfig* config = TDEGlobal::config(); TQString key = traceKey(); _multiView->saveViewConfig(config, TQString("Layout%1-MainView").arg(_layoutCurrent), key, false); _layoutCurrent--; if (_layoutCurrent <0) _layoutCurrent = _layoutCount-1; _multiView->readViewConfig(config, TQString("Layout%1-MainView").arg(_layoutCurrent), key, false); if (0) kdDebug() << "TopLevel::layoutPrevious: current " << _layoutCurrent << endl; } void TopLevel::layoutSave() { TDEConfig* config = TDEGlobal::config(); TQString key = traceKey(); _multiView->saveViewConfig(config, TQString("Layout%1-MainView").arg(_layoutCurrent), key, false); for(int i=0;i<_layoutCount;i++) { _multiView->readViewConfig(config, TQString("Layout%1-MainView").arg(i), key, false); _multiView->saveViewConfig(config, TQString("Layout%1-MainView").arg(i), TQString(), false); } _multiView->readViewConfig(config, TQString("Layout%1-MainView").arg(_layoutCurrent), key, false); TDEConfigGroup aConfig(config, TQCString("Layouts")); aConfig.writeEntry("DefaultCount", _layoutCount); aConfig.writeEntry("DefaultCurrent", _layoutCurrent); } void TopLevel::layoutRestore() { TDEConfig* config = TDEGlobal::config(); TDEConfigGroup aConfig(config, TQCString("Layouts")); _layoutCount = aConfig.readNumEntry("DefaultCount", 0); _layoutCurrent = aConfig.readNumEntry("DefaultCurrent", 0); if (_layoutCount == 0) { _layoutCount++; return; } TQString key = traceKey(); for(int i=0;i<_layoutCount;i++) { _multiView->readViewConfig(config, TQString("Layout%1-MainView").arg(i), TQString(), false); _multiView->saveViewConfig(config, TQString("Layout%1-MainView").arg(i), key, false); } _multiView->readViewConfig(config, TQString("Layout%1-MainView").arg(_layoutCurrent), key, false); updateLayoutActions(); } void TopLevel::updateLayoutActions() { TDEAction* ka; ka = actionCollection()->action("layout_next"); if (ka) ka->setEnabled(_layoutCount>1); ka = actionCollection()->action("layout_previous"); if (ka) ka->setEnabled(_layoutCount>1); ka = actionCollection()->action("layout_remove"); if (ka) ka->setEnabled(_layoutCount>1); _statusbar->message(i18n("Layout Count: %1").arg(_layoutCount), 1000); } void TopLevel::updateStatusBar() { if (!_data || _data->parts().count()==0) { _statusLabel->setText(i18n("No profile data file loaded.")); return; } TQString status = TQString("%1 [%2] - ") .arg(_data->shortTraceName()) .arg(_data->activePartRange()); if (_costType) { status += i18n("Total %1 Cost: %2") .arg(_costType->longName()) .arg(_data->prettySubCost(_costType)); /* this gets too long... if (_costType2 && (_costType2 != _costType)) status += i18n(", %1 Cost: %2") .arg(_costType2->longName()) .arg(_data->prettySubCost(_costType2)); */ } else status += i18n("No event type selected"); /* Not working... should give group of selected function if (_groupType != TraceItem::Function) { status += TQString(" - %1 '%2'") .arg(TraceItem::i18nTypeName(_groupType)) .arg(_group ? _group->prettyName() : i18n("(None)")); } */ _statusLabel->setText(status); } void TopLevel::configure() { if (ConfigDlg::configure(Configuration::config(), _data, this)) { Configuration::saveOptions(TDEGlobal::config()); configChanged(); } else Configuration::readOptions(TDEGlobal::config()); } bool TopLevel::queryClose() { saveTraceSettings(); return true; } bool TopLevel::queryExit() { // save current toplevel options as defaults... Configuration::setShowPercentage(_showPercentage); Configuration::setShowExpanded(_showExpanded); Configuration::setShowCycles(_showCycles); Configuration::saveOptions(TDEGlobal::config()); saveCurrentState(TQString()); // save QT dock positions... // We don't want to save the TDEToolbar position here. // Its already stored. delete toolBar(); TDEConfigGroup dockConfig(TDEGlobal::config(), TQCString("Docks")); TQString str; TQTextStream ts( &str, IO_WriteOnly ); ts << *this; #if 1 dockConfig.writeEntry("Position", str); #else /* We store this with a localized key because for dock positions, * QT uses the localized captions of docks. * This way, when changing languages, you don't loose dock position * settings. * For the retrieval to work, we need to store a non-localized. */ dockConfig.writeEntry("Position", str, true, false, true); #endif // if part dock was chosen visible even for only 1 part loaded, // keep this choice... _forcePartDock = false; if (_data && (_data->parts().count()<2) && _partDock->isVisible()) _forcePartDock=true; dockConfig.writeEntry("ForcePartDockVisible", _forcePartDock); return true; } void TopLevel::splitSlot() { int count = _multiView->childCount(); if (count<1) count = 1; if (count>2) count = 2; count = 3-count; _multiView->setChildCount(count); _taSplit->setChecked(count>1); _taSplitDir->setEnabled(count>1); _taSplitDir->setChecked(_multiView->orientation() == Qt::Horizontal); } void TopLevel::splitDirSlot() { _multiView->setOrientation( _taSplitDir->isChecked() ? Qt::Horizontal : Qt::Vertical ); } // this is called after a config change in the dialog void TopLevel::configChanged() { //tqDebug("TopLevel::configChanged"); //_showPercentage->setChecked(Configuration::showPercentage()); // invalidate found/cached dirs of source files _data->resetSourceDirs(); _partSelection->refresh(); _stackSelection->refresh(); _functionSelection->notifyChange(TraceItemView::configChanged); _functionSelection->updateView(); _multiView->notifyChange(TraceItemView::configChanged); _multiView->updateView(); } void TopLevel::slotShowTipOnStart() { KTipDialog::showTip(this); } void TopLevel::slotShowTip() { KTipDialog::showTip( this, TQString(), true ); } void TopLevel::dummySlot() { } void TopLevel::activePartsChangedSlot(const TracePartList& list) { if (!_data) return; if (!_data->activateParts(list)) { // tqDebug("TopLevel::activePartsChangedSlot: No Change!"); return; } _activeParts = list; _partSelection->activePartsChangedSlot(list); _multiView->set(list); _multiView->updateView(); _functionSelection->set(list); _functionSelection->updateView(); _stackSelection->refresh(); updateStatusBar(); } void TopLevel::partsHideSelectedSlotDelayed() { TQTimer::singleShot( 0, TQT_TQOBJECT(this), TQT_SLOT(partsHideSelectedSlot()) ); } // this puts selected parts into hidden list, // deselects them and makes the remaining parts selected void TopLevel::partsHideSelectedSlot() { if (!_data) return; TracePart* part; TracePartList newHidden, newActive; TracePartList l = _data->parts(); for (part=l.first();part;part=l.next()) { if ((_activeParts.findRef(part)>=0) || (_hiddenParts.findRef(part)>=0)) newHidden.append(part); else newActive.append(part); } _hiddenParts = newHidden; _partSelection->hiddenPartsChangedSlot(_hiddenParts); #if 0 _mainWidget1->hiddenPartsChangedSlot(_hiddenParts); _mainWidget2->hiddenPartsChangedSlot(_hiddenParts); #endif activePartsChangedSlot(newActive); } void TopLevel::partsUnhideAllSlotDelayed() { TQTimer::singleShot( 0, TQT_TQOBJECT(this), TQT_SLOT(partsUnhideAllSlot()) ); } // this unhides all hidden parts. Does NOT change selection void TopLevel::partsUnhideAllSlot() { if (!_data) return; _hiddenParts.clear(); _partSelection->hiddenPartsChangedSlot(_hiddenParts); #if 0 _mainWidget1->hiddenPartsChangedSlot(_hiddenParts); _mainWidget2->hiddenPartsChangedSlot(_hiddenParts); #endif } void TopLevel::forceTrace() { // tqDebug("forceTrace"); // Needs Callgrind now... TQFile cmd("callgrind.cmd"); if (!cmd.exists()) { cmd.open(IO_WriteOnly); cmd.writeBlock("DUMP\n", 5); cmd.close(); } if (_taDump->isChecked()) TQTimer::singleShot( 1000, TQT_TQOBJECT(this), TQT_SLOT(forceTraceReload()) ); else { // cancel request cmd.remove(); } } void TopLevel::forceTraceReload() { // tqDebug("forceTraceReload"); TQFile cmd("callgrind.cmd"); if (cmd.exists()) { if (_taDump->isChecked()) TQTimer::singleShot( 1000, TQT_TQOBJECT(this), TQT_SLOT(forceTraceReload()) ); return; } _taDump->setChecked(false); reload(); } void TopLevel::forwardAboutToShow() { TQPopupMenu *popup = _paForward->popupMenu(); popup->clear(); StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0; HistoryItem* hi = b ? b->current() : 0; TraceFunction* f; if (!hi) { popup->insertItem(i18n("(No Stack)")); return; } hi = hi->next(); if (!hi) { popup->insertItem(i18n("(No next function)")); return; } int count = 1; while (countfunction(); if (!f) break; TQString name = f->prettyName(); if ((int)name.length()>Configuration::maxSymbolLength()) name = name.left(Configuration::maxSymbolLength()) + "..."; //tqDebug("forward: Adding %s", name.ascii()); popup->insertItem(name, count); hi = hi->next(); count++; } } void TopLevel::backAboutToShow() { TQPopupMenu *popup = _paBack->popupMenu(); popup->clear(); StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0; HistoryItem* hi = b ? b->current() : 0; TraceFunction* f; if (!hi) { popup->insertItem(i18n("(No Stack)")); return; } hi = hi->last(); if (!hi) { popup->insertItem(i18n("(No previous function)")); return; } int count = 1; while (countfunction(); if (!f) break; TQString name = f->prettyName(); if ((int)name.length()>Configuration::maxSymbolLength()) name = name.left(Configuration::maxSymbolLength()) + "..."; //tqDebug("back: Adding %s", name.ascii()); popup->insertItem(name, count); hi = hi->last(); count++; } } void TopLevel::upAboutToShow() { TQPopupMenu *popup = _paUp->popupMenu(); popup->clear(); StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0; HistoryItem* hi = b ? b->current() : 0; TraceFunction* f = hi ? hi->function() : 0; if (!f) { popup->insertItem(i18n("(No Stack)")); return; } f = hi->stack()->caller(f, false); if (!f) { popup->insertItem(i18n("(No Function Up)")); return; } int count = 1; while (countprettyName(); if ((int)name.length()>Configuration::maxSymbolLength()) name = name.left(Configuration::maxSymbolLength()) + "..."; popup->insertItem(name, count); f = hi->stack()->caller(f, false); count++; } } void TopLevel::forwardActivated(int id) { //tqDebug("forwardActivated: %d", id); StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0; if (!b) return; while (id>1) { b->goForward(); id--; } _stackSelection->browserForward(); } void TopLevel::backActivated(int id) { //tqDebug("backActivated: %d", id); StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0; if (!b) return; while (id>1) { b->goBack(); id--; } _stackSelection->browserBack(); } void TopLevel::upActivated(int id) { //tqDebug("upActivated: %d", id); StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0; HistoryItem* hi = b ? b->current() : 0; if (!hi) return; TraceFunction* f = hi->function(); while (id>0 && f) { f = hi->stack()->caller(f, false); id--; } //tqDebug("upActivated: %s", f ? f->prettyName().ascii() : "??" ); if (f) setFunction(f); } void TopLevel::showMessage(const TQString& msg, int ms) { if (_statusbar) _statusbar->message(msg, ms); } void TopLevel::showStatus(TQString msg, int progress) { static bool msgUpdateNeeded = true; if (msg.isEmpty()) { if (_progressBar) { _statusbar->removeWidget(_progressBar); delete _progressBar; _progressBar = 0; } _statusbar->clear(); _progressMsg = msg; return; } if (_progressMsg.isEmpty()) _progressStart.start(); if (msg != _progressMsg) { _progressMsg = msg; msgUpdateNeeded = true; } // do nothing if last change was less than 0.5 seconds ago if (_progressStart.elapsed() < 500) return; if (!_progressBar) { _progressBar = new TQProgressBar(_statusbar); _progressBar->setMaximumSize(200, _statusbar->height()-4); _statusbar->addWidget(_progressBar, 1, true); _progressBar->show(); msgUpdateNeeded = true; } _progressStart.restart(); if (msgUpdateNeeded) { _statusbar->message(msg); msgUpdateNeeded = false; } _progressBar->setProgress(progress); // let the progress bar update itself TQEventLoop* l = tqApp->eventLoop(); if (l) l->processEvents(TQEventLoop::ExcludeUserInput); } #include "toplevel.moc"