qcgtoplevel.cpp 61.9 KB
Newer Older
1
/* This file is part of KCachegrind.
Josef Weidendorfer's avatar
Josef Weidendorfer committed
2
   Copyright (c) 2002-2016 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

   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.
*/

/*
 * QCachegrind top level window
 */

#define TRACE_UPDATES 0

25
#include "qcgtoplevel.h"
26 27 28

#include <stdlib.h> // for system()

29
#include <QApplication>
30 31 32 33 34 35 36 37 38 39
#include <QDebug>
#include <QDockWidget>
#include <QTimer>
#include <QByteArray>
#include <QLabel>
#include <QMenuBar>
#include <QProgressBar>
#include <QFile>
#include <QFileDialog>
#include <QEventLoop>
40
#include <QToolBar>
41
#include <QComboBox>
42
#include <QMessageBox>
Laurent Montel's avatar
Laurent Montel committed
43
#include <QStatusBar>
44
#include <QWhatsThis>
45

46
#ifdef QT_DBUS_SUPPORT
Yuri Chornoivan's avatar
Yuri Chornoivan committed
47
#include <QDBusConnection>
48 49
#endif

50
#include "partselection.h"
51
#include "functionselection.h"
52 53
#include "stackselection.h"
#include "stackbrowser.h"
54
#include "tracedata.h"
55
#include "config.h"
56
#include "globalguiconfig.h"
57 58
#include "multiview.h"
#include "callgraphview.h"
59
#include "configdialog.h"
60

61
QCGTopLevel::QCGTopLevel()
62
{
63
#ifdef QT_DBUS_SUPPORT
Josef Weidendorfer's avatar
Josef Weidendorfer committed
64 65
    QDBusConnection con = QDBusConnection::sessionBus();
    con.registerObject("/QCachegrind", this,
66
                       QDBusConnection::ExportScriptableSlots);
Josef Weidendorfer's avatar
Josef Weidendorfer committed
67
#endif
68

Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
69
    _progressBar = nullptr;
70 71 72
    _statusbar = statusBar();
    _statusLabel = new QLabel(_statusbar);
    _statusbar->addWidget(_statusLabel, 1);
73

74 75 76
    _layoutCount = 1;
    _layoutCurrent = 0;

77
    resetState();
78

79
    GlobalGUIConfig::config()->readOptions();
80

81
    createActions();
82 83 84
    createDocks();
    createMenu();
    createToolbar();
85

86
    _multiView = new MultiView(this, this);
87
    _multiView->setObjectName(QStringLiteral("MultiView"));
88
    setCentralWidget(_multiView);
89

90
    // restore current state settings (not configuration options)
91
    restoreCurrentState(QString());
92

93 94
    // restore docks & toolbars from config
    QByteArray state, geometry;
95 96 97 98
    ConfigGroup* topConfig = ConfigStorage::group(QStringLiteral("TopWindow"));
    _forcePartDock = topConfig->value(QStringLiteral("ForcePartDockVisible"), false).toBool();
    state = topConfig->value(QStringLiteral("State"), QByteArray()).toByteArray();
    geometry = topConfig->value(QStringLiteral("Geometry"), QByteArray()).toByteArray();
99
    delete topConfig;
100

101
    if (!geometry.isEmpty())
102
        restoreGeometry(geometry);
103
    if (!state.isEmpty())
104
        restoreState(state);
105

106
    setWindowIcon(QIcon(QStringLiteral(":/app.png")));
107
    setAttribute(Qt::WA_DeleteOnClose);
108 109
}

110
QCGTopLevel::~QCGTopLevel()
111 112 113
{
    delete _data;
}
114 115

// reset the visualization state, e.g. before loading new data
116
void QCGTopLevel::resetState()
117
{
118 119
    _activeParts.clear();
    _hiddenParts.clear();
120

Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
121 122 123 124
    _data = nullptr;
    _function = nullptr;
    _eventType = nullptr;
    _eventType2 = nullptr;
125
    _groupType = ProfileContext::InvalidType;
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
126
    _group = nullptr;
127

128
    // for delayed slots
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
129 130 131
    _traceItemDelayed = nullptr;
    _eventTypeDelayed = nullptr;
    _eventType2Delayed = nullptr;
132
    _groupTypeDelayed = ProfileContext::InvalidType;
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
133
    _groupDelayed = nullptr;
134
    _directionDelayed = TraceItemView::None;
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
135
    _lastSender = nullptr;
136 137
}

138

139 140 141 142 143 144 145
/**
 * This saves the current state of the main window and
 * sub widgets.
 *
 * No positions are saved. These is done automatically for
 * KToolbar, and manually in queryExit() for QT docks.
 */
146
void QCGTopLevel::saveCurrentState(const QString& postfix)
147
{
148 149 150
    QString eventType, eventType2;
    if (_eventType) eventType = _eventType->name();
    if (_eventType2) eventType2 = _eventType2->name();
151

152
    ConfigGroup* stateConfig = ConfigStorage::group(QLatin1String("CurrentState") + postfix);
153 154 155
    stateConfig->setValue(QStringLiteral("EventType"), eventType);
    stateConfig->setValue(QStringLiteral("EventType2"), eventType2);
    stateConfig->setValue(QStringLiteral("GroupType"), ProfileContext::typeName(_groupType));
156
    delete stateConfig;
157

158 159 160
    _partSelection->saveOptions(QStringLiteral("PartOverview"), postfix);
    _multiView->saveLayout(QStringLiteral("MainView"), postfix);
    _multiView->saveOptions(QStringLiteral("MainView"), postfix);
161 162 163 164 165 166
}

/**
 * This function is called when a trace is closed.
 * Save browsing position for later restoring
 */
167
void QCGTopLevel::saveTraceSettings()
168
{
169
    QString key = traceKey();
170

171 172 173
    ConfigGroup* lConfig = ConfigStorage::group(QStringLiteral("Layouts"));
    lConfig->setValue(QStringLiteral("Count%1").arg(key), _layoutCount);
    lConfig->setValue(QStringLiteral("Current%1").arg(key), _layoutCurrent);
174 175
    delete lConfig;

176
    ConfigGroup* pConfig = ConfigStorage::group(QStringLiteral("TracePositions"));
177 178 179
    QString eventType, eventType2;
    if (_eventType) eventType = _eventType->name();
    if (_eventType2) eventType2 = _eventType2->name();
180 181
    pConfig->setValue(QStringLiteral("EventType%1").arg(key), eventType);
    pConfig->setValue(QStringLiteral("EventType2%1").arg(key), eventType2);
182
    if (_groupType != ProfileContext::InvalidType)
183 184
        pConfig->setValue(QStringLiteral("GroupType%1").arg(key),
                          ProfileContext::typeName(_groupType));
185 186

    if (_data) {
187 188 189
        if (_group)
            pConfig->setValue(QStringLiteral("Group%1").arg(key), _group->name());
        saveCurrentState(key);
190 191
    }
    delete pConfig;
192 193 194
}

/**
195 196
 * This restores the current visualization state of the main window and
 * of the profile views.
197
 */
198
void QCGTopLevel::restoreCurrentState(const QString& postfix)
199
{
200 201 202
    _partSelection->restoreOptions(QStringLiteral("PartOverview"), postfix);
    _multiView->restoreLayout(QStringLiteral("MainView"), postfix);
    _multiView->restoreOptions(QStringLiteral("MainView"), postfix);
203

204 205 206
    _splittedToggleAction->setChecked(_multiView->childCount()>1);
    _splitDirectionToggleAction->setEnabled(_multiView->childCount()>1);
    _splitDirectionToggleAction->setChecked(_multiView->orientation() ==
207
                                            Qt::Horizontal);
208 209
}

210
void QCGTopLevel::sidebarMenuAboutToShow()
211 212 213 214 215 216 217 218 219
{
    QAction* action;
    QMenu *popup = _sidebarMenuAction->menu();

    popup->clear();

    action = popup->addAction(tr("Parts Overview"));
    action->setCheckable(true);
    action->setChecked(_partDock->isVisible());
220
    connect(action, &QAction::triggered, this, &QCGTopLevel::togglePartDock);
221 222 223 224

    action = popup->addAction(tr("Top Cost Call Stack"));
    action->setCheckable(true);
    action->setChecked(_stackDock->isVisible());
225
    connect(action, &QAction::triggered, this, &QCGTopLevel::toggleStackDock);
226 227 228 229

    action = popup->addAction(tr("Flat Profile"));
    action->setCheckable(true);
    action->setChecked(_functionDock->isVisible());
230
    connect(action, &QAction::triggered, this, &QCGTopLevel::toggleFunctionDock);
231 232
}

233
void QCGTopLevel::recentFilesMenuAboutToShow()
234 235 236 237 238 239
{
    QStringList recentFiles;
    QMenu *popup = _recentFilesMenuAction->menu();

    popup->clear();

240 241
    ConfigGroup* generalConfig = ConfigStorage::group(QStringLiteral("GeneralSettings"));
    recentFiles = generalConfig->value(QStringLiteral("RecentFiles"),
242
                                       QStringList()).toStringList();
243 244
    delete generalConfig;

245
    if (recentFiles.isEmpty())
246
        popup->addAction(tr("(No recent files)"));
247
    else {
248 249 250 251
        foreach(const QString& file, recentFiles) {
            // paths shown to user should use OS-native separators
            popup->addAction(QDir::toNativeSeparators(file));
        }
252 253 254
    }
}

255
void QCGTopLevel::recentFilesTriggered(QAction* action)
256 257
{
    if (action)
258
        load(QStringList(QDir::fromNativeSeparators(action->text())));
259
}
260

261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
void QCGTopLevel::primaryAboutToShow()
{
    updateEventTypeMenu(_primaryMenuAction->menu(), false);
}

void QCGTopLevel::secondaryAboutToShow()
{
    updateEventTypeMenu(_secondaryMenuAction->menu(), true);
}

void QCGTopLevel::groupingAboutToShow()
{
    if (!_functionSelection) return;
    _functionSelection->updateGroupingMenu(_groupingMenuAction->menu());
}



279
void QCGTopLevel::createDocks()
280
{
281 282
    // part visualization/selection side bar
    _partDock = new QDockWidget(this);
283
    _partDock->setObjectName(QStringLiteral("part-dock"));
284 285 286 287
    _partDock->setWindowTitle(tr("Parts Overview"));
    _partSelection = new PartSelection(this, _partDock);
    _partDock->setWidget(_partSelection);

288
    connect(_partSelection, &PartSelection::partsHideSelected,
289
            this, &QCGTopLevel::partsHideSelectedSlotDelayed);
290
    connect(_partSelection, &PartSelection::partsUnhideAll,
291
            this, &QCGTopLevel::partsUnhideAllSlotDelayed);
292 293 294

    // stack selection side bar
    _stackDock = new QDockWidget(this);
295
    _stackDock->setObjectName(QStringLiteral("stack-dock"));
296 297 298 299
    _stackSelection = new StackSelection(_stackDock);
    _stackDock->setWidget(_stackSelection);
    _stackDock->setWindowTitle(tr("Top Cost Call Stack"));
    _stackSelection->setWhatsThis( tr(
300 301 302 303 304 305 306 307
                                       "<b>The Top Cost Call Stack</b>"
                                       "<p>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.</p>"
                                       "<p>The <b>Cost</b> and <b>Calls</b> columns show the "
                                       "cost used for all calls from the function in the line "
                                       "above.</p>"));
308
    connect(_stackSelection, SIGNAL(functionSelected(CostItem*)),
309
            this, SLOT(setTraceItemDelayed(CostItem*)));
310
    // actions are already created
311
    connect(_upAction, &QAction::triggered,
312
            _stackSelection, &StackSelection::browserUp );
313
    connect(_backAction, &QAction::triggered,
314
            _stackSelection, &StackSelection::browserBack );
315
    connect(_forwardAction, &QAction::triggered,
316
            _stackSelection, &StackSelection::browserForward);
317 318 319

    // flat function profile side bar
    _functionDock = new QDockWidget(this);
320
    _functionDock->setObjectName(QStringLiteral("function-dock"));
321 322 323 324
    _functionDock->setWindowTitle(tr("Flat Profile"));
    _functionSelection = new FunctionSelection(this, _functionDock);
    _functionDock->setWidget(_functionSelection);
    // functionDock needs call to updateView() when getting visible
325
    connect(_functionDock, &QDockWidget::visibilityChanged,
326
            this, &QCGTopLevel::functionVisibilityChanged);
327

328
    // defaults (later to be adjusted from stored state in config)
Josef Weidendorfer's avatar
Cleanup  
Josef Weidendorfer committed
329 330 331 332
    addDockWidget(Qt::LeftDockWidgetArea, _partDock );
    addDockWidget(Qt::LeftDockWidgetArea, _stackDock );
    addDockWidget(Qt::LeftDockWidgetArea, _functionDock );
    _stackDock->hide();
333
    _partDock->hide();
334 335 336 337 338
}




339
void QCGTopLevel::createActions()
340
{
341 342 343 344 345 346 347
    QString hint;
    QIcon icon;

    // file menu actions
    _newAction = new QAction(tr("&New"), this);
    _newAction->setShortcuts(QKeySequence::New);
    _newAction->setStatusTip(tr("Open new empty window"));
348
    connect(_newAction, &QAction::triggered, this, &QCGTopLevel::newWindow);
349 350 351 352 353

    icon = QApplication::style()->standardIcon(QStyle::SP_DialogOpenButton);
    _openAction = new QAction(icon, tr("&Open..."), this);
    _openAction->setShortcuts(QKeySequence::Open);
    _openAction->setStatusTip(tr("Open profile data file"));
354
    connect(_openAction, SIGNAL(triggered()), this, SLOT(load()));
355 356 357

    _addAction = new QAction(tr( "&Add..." ), this);
    _addAction->setStatusTip(tr("Add profile data to current window"));
358
    connect(_addAction, SIGNAL(triggered(bool)), SLOT(add()));
359 360 361

    _exportAction = new QAction(tr("Export Graph"), this);
    _exportAction->setStatusTip(tr("Generate GraphViz file 'callgraph.dot'"));
362
    connect(_exportAction, &QAction::triggered, this, &QCGTopLevel::exportGraph);
363 364 365

    _recentFilesMenuAction = new QAction(tr("Open &Recent"), this);
    _recentFilesMenuAction->setMenu(new QMenu(this));
366
    connect(_recentFilesMenuAction->menu(), &QMenu::aboutToShow,
367
            this, &QCGTopLevel::recentFilesMenuAboutToShow);
368
    connect(_recentFilesMenuAction->menu(), &QMenu::triggered,
369
            this, &QCGTopLevel::recentFilesTriggered);
370 371 372 373

    _exitAction = new QAction(tr("E&xit"), this);
    _exitAction->setShortcut(tr("Ctrl+Q"));
    _exitAction->setStatusTip(tr("Exit the application"));
374
    connect(_exitAction, &QAction::triggered, this, &QWidget::close);
375 376

    // view menu actions
377 378 379 380

    _primaryMenuAction = new QAction(tr( "Primary Event Type" ), this );
    _primaryMenuAction->setMenu(new QMenu(this));
    connect(_primaryMenuAction->menu(), &QMenu::aboutToShow,
381
            this, &QCGTopLevel::primaryAboutToShow );
382 383 384
    _secondaryMenuAction = new QAction(tr( "Secondary Event Type" ), this );
    _secondaryMenuAction->setMenu(new QMenu(this));
    connect(_secondaryMenuAction->menu(), &QMenu::aboutToShow,
385
            this, &QCGTopLevel::secondaryAboutToShow );
386 387 388
    _groupingMenuAction = new QAction(tr( "Grouping" ), this );
    _groupingMenuAction->setMenu(new QMenu(this));
    connect(_groupingMenuAction->menu(), &QMenu::aboutToShow,
389
            this, &QCGTopLevel::groupingAboutToShow );
390

391 392 393 394 395 396 397
    icon = QApplication::style()->standardIcon(QStyle::SP_BrowserReload);
    _cyclesToggleAction = new QAction(icon, tr("Detect Cycles"), this);
    _cyclesToggleAction->setCheckable(true);
    _cyclesToggleAction->setStatusTip(tr("Do Cycle Detection"));
    hint = tr("<b>Detect recursive cycles</b>"
              "<p>If this is switched off, the treemap drawing will show "
              "black areas when a recursive call is made instead of drawing "
398
              "the recursion ad infinitum. Note that "
399
              "the size of black areas often will be wrong, as inside "
400 401
              "recursive cycles the cost of calls cannot be determined; "
              "the error is small, "
402 403
              "however, for false cycles (see documentation).</p>"
              "<p>The correct handling for cycles is to detect them and "
404 405 406
              "collapse all functions of a cycle into an artificial "
              "function, which is done when this option is selected. "
              "Unfortunately, with GUI applications, this often will "
407
              "lead to huge false cycles, making the analysis impossible; "
408
              "therefore, there is the option to switch this off.</p>");
409
    _cyclesToggleAction->setWhatsThis(hint);
410
    connect(_cyclesToggleAction, &QAction::triggered,
411
            this, &QCGTopLevel::toggleCycles);
412 413
    _cyclesToggleAction->setChecked(GlobalConfig::showCycles());

414
    _percentageToggleAction = new QAction(QIcon(QStringLiteral(":/percent.png")),
415
                                          tr("Relative Cost"), this);
416 417
    _percentageToggleAction->setCheckable(true);
    _percentageToggleAction->setStatusTip(tr("Show Relative Costs"));
418
    connect(_percentageToggleAction, &QAction::triggered,
419
            this, &QCGTopLevel::togglePercentage);
420 421
    _percentageToggleAction->setChecked(GlobalConfig::showPercentage());

422
    _hideTemplatesToggleAction = new QAction(QIcon(QStringLiteral(":/hidetemplates.png")),
423 424 425 426
                                             tr("Shorten Templates"), this);
    _hideTemplatesToggleAction->setCheckable(true);
    _hideTemplatesToggleAction->setStatusTip(tr("Hide Template Parameters "
                                                "in C++ Symbols"));
427 428
    connect(_hideTemplatesToggleAction, &QAction::triggered,
            this, &QCGTopLevel::toggleHideTemplates);
429 430 431 432 433 434 435 436 437 438
    _hideTemplatesToggleAction->setChecked(GlobalConfig::hideTemplates());
    hint = tr("<b>Hide Template Parameters in C++ Symbols</b>"
              "<p>If this is switched on, every symbol displayed will have "
              "any C++ template parameters hidden, just showing &lt;&gt; "
              "instead of a potentially nested template parameter.</p>"
              "<p>In this mode, you can hover the mouse pointer over the "
              "activated symbol label to show a tooltip with the "
              "unabbreviated symbol.</p>");
    _hideTemplatesToggleAction->setWhatsThis(hint);

439
    _expandedToggleAction = new QAction(QIcon(QStringLiteral(":/move.png")),
440
                                        tr("Relative to Parent"), this);
441 442
    _expandedToggleAction->setCheckable(true);
    _expandedToggleAction->setStatusTip(
443
                tr("Show Percentage relative to Parent"));
444 445
    hint = tr("<b>Show percentage costs relative to parent</b>"
              "<p>If this is switched off, percentage costs are always "
446 447 448 449
              "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.</p>"
450 451
              "<ul><table>"
              "<tr><td><b>Cost Type</b></td><td><b>Parent Cost</b></td></tr>"
452 453
              "<tr><td>Function Inclusive</td><td>Total</td></tr>"
              "<tr><td>Function Self</td><td>Function Group (*)/Total</td></tr>"
454 455 456
              "<tr><td>Call</td><td>Function Inclusive</td></tr>"
              "<tr><td>Source Line</td><td>Function Inclusive</td></tr>"
              "</table></ul>"
457
              "<p>(*) Only if function grouping is switched on "
458
              "(e.g. ELF object grouping).</p>");
459
    _expandedToggleAction->setWhatsThis( hint );
460
    connect(_expandedToggleAction, &QAction::triggered,
461
            this, &QCGTopLevel::toggleExpanded);
462 463
    _expandedToggleAction->setChecked(GlobalConfig::showExpanded());

Yuri Chornoivan's avatar
Yuri Chornoivan committed
464
    _splittedToggleAction = new QAction(tr("Split Visualization"), this);
465 466
    _splittedToggleAction->setCheckable(true);
    _splittedToggleAction->setStatusTip(
467
                tr("Show visualization of two cost items"));
468
    connect(_splittedToggleAction, &QAction::triggered,
469
            this, &QCGTopLevel::toggleSplitted);
470 471 472 473

    _splitDirectionToggleAction = new QAction(tr("Split Horizontal"), this);
    _splitDirectionToggleAction->setCheckable(true);
    _splitDirectionToggleAction->setStatusTip(
474
                tr("Split visualization area horizontally"));
475
    connect(_splitDirectionToggleAction, &QAction::triggered,
476
            this, &QCGTopLevel::toggleSplitDirection);
477 478 479

    _sidebarMenuAction = new QAction(tr("Sidebars"), this);
    _sidebarMenuAction->setMenu(new QMenu(this));
480
    connect( _sidebarMenuAction->menu(), &QMenu::aboutToShow,
481
             this, &QCGTopLevel::sidebarMenuAboutToShow);
482

483
    _layoutDup = new QAction(tr("&Duplicate"), this);
484
    connect(_layoutDup, &QAction::triggered, this, &QCGTopLevel::layoutDuplicate);
485 486
    _layoutDup->setShortcut(Qt::CTRL + Qt::Key_Plus);
    _layoutDup->setStatusTip(tr("Duplicate current layout"));
487

488
    _layoutRemove = new QAction(tr("&Remove"), this);
489
    connect(_layoutRemove, &QAction::triggered, this, &QCGTopLevel::layoutRemove);
490
    _layoutRemove->setStatusTip(tr("Remove current layout"));
491

492
    _layoutNext = new QAction(tr("Go to &Next"), this);
493
    connect(_layoutNext, &QAction::triggered, this, &QCGTopLevel::layoutNext);
494 495
    _layoutNext->setShortcut(Qt::CTRL + Qt::Key_Right);
    _layoutNext->setStatusTip(tr("Switch to next layout"));
496

497
    _layoutPrev = new QAction(tr("Go to &Previous"), this);
498
    connect(_layoutPrev, &QAction::triggered, this, &QCGTopLevel::layoutPrevious);
499 500 501 502
    _layoutPrev->setShortcut(Qt::CTRL + Qt::Key_Left);
    _layoutPrev->setStatusTip(tr("Switch to previous layout"));

    _layoutRestore = new QAction(tr("&Restore to Default"), this);
503
    connect(_layoutRestore, &QAction::triggered, this, &QCGTopLevel::layoutRestore);
504 505 506
    _layoutRestore->setStatusTip(tr("Restore layouts to default"));

    _layoutSave = new QAction(tr("&Save as Default"), this);
507
    connect(_layoutSave, &QAction::triggered, this, &QCGTopLevel::layoutSave);
508 509 510 511 512 513 514 515
    _layoutSave->setStatusTip(tr("Save layouts as default"));

    // go menu actions
    icon = QApplication::style()->standardIcon(QStyle::SP_ArrowUp);
    _upAction = new QAction(icon, tr( "Up" ), this );
    _upAction->setShortcut( QKeySequence(Qt::ALT+Qt::Key_Up) );
    _upAction->setStatusTip(tr("Go Up in Call Stack"));
    _upAction->setMenu(new QMenu(this));
516
    connect(_upAction->menu(), &QMenu::aboutToShow,
517
            this, &QCGTopLevel::upAboutToShow );
518
    connect(_upAction->menu(), &QMenu::triggered,
519
            this, &QCGTopLevel::upTriggered );
520 521 522 523 524 525 526 527
    hint = tr("Go to last selected caller of current function");
    _upAction->setToolTip(hint);

    icon = QApplication::style()->standardIcon(QStyle::SP_ArrowBack);
    _backAction = new QAction(icon, tr("Back"), this);
    _backAction->setShortcut( QKeySequence(Qt::ALT+Qt::Key_Left) );
    _backAction->setStatusTip(tr("Go Back"));
    _backAction->setMenu(new QMenu(this));
528
    connect(_backAction->menu(), &QMenu::aboutToShow,
529
            this, &QCGTopLevel::backAboutToShow );
530
    connect(_backAction->menu(), &QMenu::triggered,
531
            this, &QCGTopLevel::backTriggered );
532 533 534 535 536 537 538 539
    hint = tr("Go back in function selection history");
    _backAction->setToolTip(hint);

    icon = QApplication::style()->standardIcon(QStyle::SP_ArrowForward);
    _forwardAction = new QAction(icon, tr("Forward"), this);
    _forwardAction->setShortcut( QKeySequence(Qt::ALT+Qt::Key_Right) );
    _forwardAction->setStatusTip(tr("Go Forward"));
    _forwardAction->setMenu(new QMenu(this));
540
    connect(_forwardAction->menu(), &QMenu::aboutToShow,
541
            this, &QCGTopLevel::forwardAboutToShow );
542
    connect(_forwardAction->menu(), &QMenu::triggered,
543
            this, &QCGTopLevel::forwardTriggered );
544 545 546
    hint = tr("Go forward in function selection history");
    _forwardAction->setToolTip( hint );

547
    // settings menu actions
548
    _configureAction = new QAction(tr("&Configure..."), this);
549 550 551
    _configureAction->setStatusTip(tr("Configure QCachegrind"));
    connect(_configureAction, SIGNAL(triggered()), this, SLOT(configure()));

552
    // help menu actions
553
    _aboutAction = new QAction(tr("&About QCachegrind..."), this);
554
    _aboutAction->setStatusTip(tr("Show the application's About box"));
555
    connect(_aboutAction, &QAction::triggered, this, &QCGTopLevel::about);
556

557
    _aboutQtAction = new QAction(tr("About Qt..."), this);
558
    connect(_aboutQtAction, &QAction::triggered, qApp, &QApplication::aboutQt);
559

560 561 562 563 564
    // toolbar actions
    _eventTypeBox = new QComboBox(this);
    _eventTypeBox->setMinimumContentsLength(25);
    hint = tr("Select primary event type of costs");
    _eventTypeBox->setToolTip( hint );
Yuri Chornoivan's avatar
Yuri Chornoivan committed
565 566
    connect( _eventTypeBox, SIGNAL(activated(QString)),
             this, SLOT(eventTypeSelected(QString)));
567 568
}

569
void QCGTopLevel::createMenu()
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
{
    QMenuBar* mBar = menuBar();

    QMenu* fileMenu = mBar->addMenu(tr("&File"));
    fileMenu->addAction(_newAction);
    fileMenu->addAction(_openAction);
    fileMenu->addAction(_recentFilesMenuAction);
    fileMenu->addAction(_addAction);
    fileMenu->addSeparator();
    fileMenu->addAction(_exportAction);
    fileMenu->addSeparator();
    fileMenu->addAction(_exitAction);

    QMenu* layoutMenu = new QMenu(tr("&Layout"), this);
    layoutMenu->addAction(_layoutDup);
    layoutMenu->addAction(_layoutRemove);
    layoutMenu->addSeparator();
    layoutMenu->addAction(_layoutPrev);
    layoutMenu->addAction(_layoutNext);
    layoutMenu->addSeparator();
    layoutMenu->addAction(_layoutSave);
    layoutMenu->addAction(_layoutRestore);

    QMenu* viewMenu = mBar->addMenu(tr("&View"));
594 595 596 597 598 599 600 601
    viewMenu->addAction(_primaryMenuAction);
    viewMenu->addAction(_secondaryMenuAction);
    viewMenu->addAction(_groupingMenuAction);
    viewMenu->addSeparator();
    viewMenu->addMenu(layoutMenu);
    viewMenu->addAction(_splittedToggleAction);
    viewMenu->addAction(_splitDirectionToggleAction);
    viewMenu->addSeparator();
602 603 604
    viewMenu->addAction(_cyclesToggleAction);
    viewMenu->addAction(_percentageToggleAction);
    viewMenu->addAction(_expandedToggleAction);
605
    viewMenu->addAction(_hideTemplatesToggleAction);
606

607
    QMenu* goMenu = mBar->addMenu(tr("&Go"));
608 609 610 611
    goMenu->addAction(_backAction);
    goMenu->addAction(_forwardAction);
    goMenu->addAction(_upAction);

612 613
    QMenu* settingsMenu = mBar->addMenu(tr("&Settings"));
    settingsMenu->addAction(_sidebarMenuAction);
614 615
    settingsMenu->addSeparator();
    settingsMenu->addAction(_configureAction);
616 617

    QMenu* helpMenu = mBar->addMenu(tr("&Help"));
618 619
    helpMenu->addAction(QWhatsThis::createAction(this));
    helpMenu->addSeparator();
620
    helpMenu->addAction(_aboutAction);
621
    helpMenu->addAction(_aboutQtAction);
622 623
}

624
void QCGTopLevel::createToolbar()
625 626
{
    QToolBar* tb = new QToolBar(tr("Main Toolbar"), this);
627
    tb->setObjectName(QStringLiteral("main-toolbar"));
628 629 630 631 632 633 634 635
    addToolBar(Qt::TopToolBarArea, tb);

    tb->addAction(_openAction);
    tb->addSeparator();

    tb->addAction(_cyclesToggleAction);
    tb->addAction(_percentageToggleAction);
    tb->addAction(_expandedToggleAction);
636
    tb->addAction(_hideTemplatesToggleAction);
637 638 639 640 641 642 643 644
    tb->addSeparator();

    tb->addAction(_backAction);
    tb->addAction(_forwardAction);
    tb->addAction(_upAction);
    tb->addSeparator();

    tb->addWidget(_eventTypeBox);
645 646
}

647

648
void QCGTopLevel::about()
649
{
650
    QString text, version;
Josef Weidendorfer's avatar
Josef Weidendorfer committed
651
    version = QStringLiteral("0.8.0kde");
652
    text = QStringLiteral("<h3>QCachegrind %1</h3>").arg(version);
653
    text += tr("<p>QCachegrind is a graphical user interface for analysing "
654 655 656 657 658 659 660 661 662 663
               "profiling data, which helps in the performance optimization "
               "phase of developing a computer program. "
               "QCachegrind is open-source, and it is distributed under the "
               "terms of the GPL v2. For details and source code, see the "
               "<a href=\"https://kcachegrind.github.io\">homepage</a> of the "
               "KCachegrind project.</p>"
               "Main author and maintainer: "
               "<a href=\"mailto:Josef.Weidendorfer@gmx.de\">"
               "Josef Weidendorfer</a><br>"
               "(with lots of bug fixes/porting help by the KDE community)");
664 665 666
    QMessageBox::about(this, tr("About QCachegrind"), text);
}

667 668
void QCGTopLevel::configure(QString s)
{
669
    static QString lastPage;
670

Yuri Chornoivan's avatar
Yuri Chornoivan committed
671
    // if no specific config item should be focused, use last page
672
    if (s.isEmpty()) s = lastPage;
673 674 675
    ConfigDialog d(_data, this, s);

    if (d.exec() == QDialog::Accepted) {
676 677
        GlobalConfig::config()->saveOptions();
        configChanged();
678
    }
679
    lastPage = d.currentPage();
680
}
681

682
void QCGTopLevel::togglePartDock()
683
{
684 685 686 687
    if (!_partDock->isVisible())
        _partDock->show();
    else
        _partDock->hide();
688 689
}

690
void QCGTopLevel::toggleStackDock()
691
{
692 693 694 695
    if (!_stackDock->isVisible())
        _stackDock->show();
    else
        _stackDock->hide();
696 697
}

698
void QCGTopLevel::toggleFunctionDock()
699
{
700 701 702 703
    if (!_functionDock->isVisible())
        _functionDock->show();
    else
        _functionDock->hide();
704 705
}

706
void QCGTopLevel::togglePercentage()
707
{
708
    setPercentage(_percentageToggleAction->isChecked());
709 710
}

711

712
void QCGTopLevel::setAbsoluteCost()
713
{
714
    setPercentage(false);
715 716
}

717
void QCGTopLevel::setRelativeCost()
718
{
719
    setPercentage(true);
720 721
}

722
void QCGTopLevel::setPercentage(bool show)
723
{
724 725
    if (GlobalConfig::showPercentage() == show) return;
    if (_percentageToggleAction->isChecked() != show)
726
        _percentageToggleAction->setChecked(show);
727 728
    _expandedToggleAction->setEnabled(show);
    GlobalConfig::setShowPercentage(show);
729

730 731 732 733
    _partSelection->notifyChange(TraceItemView::configChanged);
    _stackSelection->refresh();
    _functionSelection->notifyChange(TraceItemView::configChanged);
    _multiView->notifyChange(TraceItemView::configChanged);
734 735
}

736 737 738 739 740 741 742 743 744 745 746 747
void QCGTopLevel::toggleHideTemplates()
{
    bool show = _hideTemplatesToggleAction->isChecked();
    if (GlobalConfig::hideTemplates() == show) return;
    GlobalConfig::setHideTemplates(show);

    _partSelection->notifyChange(TraceItemView::configChanged);
    _stackSelection->refresh();
    _functionSelection->notifyChange(TraceItemView::configChanged);
    _multiView->notifyChange(TraceItemView::configChanged);
}

748
void QCGTopLevel::toggleExpanded()
749
{
750 751 752
    bool show = _expandedToggleAction->isChecked();
    if (GlobalConfig::showExpanded() == show) return;
    GlobalConfig::setShowExpanded(show);
753

754 755 756 757
    _partSelection->notifyChange(TraceItemView::configChanged);
    _stackSelection->refresh();
    _functionSelection->notifyChange(TraceItemView::configChanged);
    _multiView->notifyChange(TraceItemView::configChanged);
758 759
}

760
void QCGTopLevel::toggleCycles()
761
{
762 763 764
    bool show = _cyclesToggleAction->isChecked();
    if (GlobalConfig::showCycles() == show) return;
    GlobalConfig::setShowCycles(show);
765

766
    if (!_data) return;
767

768 769
    _data->invalidateDynamicCost();
    _data->updateFunctionCycles();
770

771 772 773 774
    _partSelection->notifyChange(TraceItemView::configChanged);
    _stackSelection->rebuildStackList();
    _functionSelection->notifyChange(TraceItemView::configChanged);
    _multiView->notifyChange(TraceItemView::configChanged);
775 776 777
}


778
void QCGTopLevel::functionVisibilityChanged(bool v)
779
{
780
    if (v)
781
        _functionSelection->updateView();
782 783 784
}


785
void QCGTopLevel::newWindow()
786
{