qmlprofilereventview.cpp 30.7 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8 9 10 11 12 13 14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23
**
hjk's avatar
hjk committed
24 25
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29 30 31

#include "qmlprofilereventview.h"

32 33
#include <QUrl>
#include <QHash>
34

35 36
#include <QStandardItem>
#include <QHeaderView>
37

38 39
#include <QApplication>
#include <QClipboard>
40

41
#include <QContextMenuEvent>
42 43
#include <QDebug>

44
#include <coreplugin/minisplitter.h>
45 46
#include <QVBoxLayout>
#include <QHBoxLayout>
47

Christiaan Janssen's avatar
Christiaan Janssen committed
48 49 50 51 52
#include "qmlprofilerviewmanager.h"
#include "qmlprofilertool.h"
#include <QMenu>

#include <utils/qtcassert.h>
53

54
using namespace QmlDebug;
55

56 57 58
namespace QmlProfiler {
namespace Internal {

59 60 61 62 63 64 65 66 67 68
struct Colors {
    Colors () {
        this->bindingLoopBackground = QColor("orange").lighter();
    }

    QColor bindingLoopBackground;
};

Q_GLOBAL_STATIC(Colors, colors)

Christiaan Janssen's avatar
Christiaan Janssen committed
69 70 71
////////////////////////////////////////////////////////////////////////////////////


72 73
////////////////////////////////////////////////////////////////////////////////////

74 75 76 77 78 79 80 81 82
class EventsViewItem : public QStandardItem
{
public:
    EventsViewItem(const QString &text) : QStandardItem(text) {}

    virtual bool operator<(const QStandardItem &other) const
    {
        if (data().type() == QVariant::String) {
            // first column
83 84
            if (column() == 0) {
                return data(FilenameRole).toString() == other.data(FilenameRole).toString() ?
85 86
                            data(LineRole).toInt() < other.data(LineRole).toInt() :
                            data(FilenameRole).toString() < other.data(FilenameRole).toString();
87
            } else {
88
                return data().toString().toLower() < other.data().toString().toLower();
89
            }
90 91 92 93 94 95
        }

        return data().toDouble() < other.data().toDouble();
    }
};

96 97
////////////////////////////////////////////////////////////////////////////////////

Christiaan Janssen's avatar
Christiaan Janssen committed
98
class QmlProfilerEventsWidget::QmlProfilerEventsWidgetPrivate
99
{
Christiaan Janssen's avatar
Christiaan Janssen committed
100 101 102 103 104 105
public:
    QmlProfilerEventsWidgetPrivate(QmlProfilerEventsWidget *qq):q(qq) {}
    ~QmlProfilerEventsWidgetPrivate() {}

    QmlProfilerEventsWidget *q;

106
    QmlProfilerTool *m_profilerTool;
Christiaan Janssen's avatar
Christiaan Janssen committed
107 108 109
    QmlProfilerViewManager *m_viewContainer;

    QmlProfilerEventsMainView *m_eventTree;
Christiaan Janssen's avatar
Christiaan Janssen committed
110 111
    QmlProfilerEventRelativesView *m_eventChildren;
    QmlProfilerEventRelativesView *m_eventParents;
112

Christiaan Janssen's avatar
Christiaan Janssen committed
113 114
    QmlProfilerEventsModelProxy *modelProxy;
    bool globalStats;
Christiaan Janssen's avatar
Christiaan Janssen committed
115 116 117
};

QmlProfilerEventsWidget::QmlProfilerEventsWidget(QWidget *parent,
118
                                                 QmlProfilerTool *profilerTool,
119
                                                 QmlProfilerViewManager *container,
Christiaan Janssen's avatar
Christiaan Janssen committed
120 121
                                                 QmlProfilerModelManager *profilerModelManager )

Christiaan Janssen's avatar
Christiaan Janssen committed
122 123
    : QWidget(parent), d(new QmlProfilerEventsWidgetPrivate(this))
{
124
    setObjectName(QLatin1String("QmlProfilerEventsView"));
125

Christiaan Janssen's avatar
Christiaan Janssen committed
126 127
    d->modelProxy = new QmlProfilerEventsModelProxy(profilerModelManager, this);
    connect(profilerModelManager, SIGNAL(stateChanged()),
Christiaan Janssen's avatar
Christiaan Janssen committed
128 129
            this, SLOT(profilerDataModelStateChanged()));

Christiaan Janssen's avatar
Christiaan Janssen committed
130
    d->m_eventTree = new QmlProfilerEventsMainView(this, d->modelProxy);
Christiaan Janssen's avatar
Christiaan Janssen committed
131
    connect(d->m_eventTree, SIGNAL(gotoSourceLocation(QString,int,int)), this, SIGNAL(gotoSourceLocation(QString,int,int)));
Christiaan Janssen's avatar
Christiaan Janssen committed
132 133 134 135 136 137 138 139 140 141 142 143 144 145
    connect(d->m_eventTree, SIGNAL(eventSelected(QString)), this, SIGNAL(eventSelectedByHash(QString)));

    d->m_eventChildren = new QmlProfilerEventRelativesView(
                profilerModelManager,
                new QmlProfilerEventChildrenModelProxy(profilerModelManager, d->modelProxy, this),
                this);
    d->m_eventParents = new QmlProfilerEventRelativesView(
                profilerModelManager,
                new QmlProfilerEventParentsModelProxy(profilerModelManager, d->modelProxy, this),
                this);
    connect(d->m_eventTree, SIGNAL(eventSelected(QString)), d->m_eventChildren, SLOT(displayEvent(QString)));
    connect(d->m_eventTree, SIGNAL(eventSelected(QString)), d->m_eventParents, SLOT(displayEvent(QString)));
    connect(d->m_eventChildren, SIGNAL(eventClicked(QString)), d->m_eventTree, SLOT(selectEvent(QString)));
    connect(d->m_eventParents, SIGNAL(eventClicked(QString)), d->m_eventTree, SLOT(selectEvent(QString)));
146 147 148 149 150

    // widget arrangement
    QVBoxLayout *groupLayout = new QVBoxLayout;
    groupLayout->setContentsMargins(0,0,0,0);
    groupLayout->setSpacing(0);
Christiaan Janssen's avatar
Christiaan Janssen committed
151

152
    Core::MiniSplitter *splitterVertical = new Core::MiniSplitter;
Christiaan Janssen's avatar
Christiaan Janssen committed
153
    splitterVertical->addWidget(d->m_eventTree);
154
    Core::MiniSplitter *splitterHorizontal = new Core::MiniSplitter;
Christiaan Janssen's avatar
Christiaan Janssen committed
155 156
    splitterHorizontal->addWidget(d->m_eventParents);
    splitterHorizontal->addWidget(d->m_eventChildren);
157 158 159 160 161 162 163 164
    splitterHorizontal->setOrientation(Qt::Horizontal);
    splitterVertical->addWidget(splitterHorizontal);
    splitterVertical->setOrientation(Qt::Vertical);
    splitterVertical->setStretchFactor(0,5);
    splitterVertical->setStretchFactor(1,2);
    groupLayout->addWidget(splitterVertical);
    setLayout(groupLayout);

Christiaan Janssen's avatar
Christiaan Janssen committed
165 166
    d->m_profilerTool = profilerTool;
    d->m_viewContainer = container;
Christiaan Janssen's avatar
Christiaan Janssen committed
167
    d->globalStats = true;
168 169 170 171
}

QmlProfilerEventsWidget::~QmlProfilerEventsWidget()
{
Christiaan Janssen's avatar
Christiaan Janssen committed
172
    delete d->modelProxy;
Christiaan Janssen's avatar
Christiaan Janssen committed
173
    delete d;
174 175
}

Christiaan Janssen's avatar
Christiaan Janssen committed
176
void QmlProfilerEventsWidget::profilerDataModelStateChanged()
177
{
178 179 180 181
}

void QmlProfilerEventsWidget::clear()
{
Christiaan Janssen's avatar
Christiaan Janssen committed
182 183 184
    d->m_eventTree->clear();
    d->m_eventChildren->clear();
    d->m_eventParents->clear();
185 186
}

187 188
void QmlProfilerEventsWidget::getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd)
{
Christiaan Janssen's avatar
Christiaan Janssen committed
189 190
    d->modelProxy->limitToRange(rangeStart, rangeEnd);
    d->globalStats = (rangeStart == -1) && (rangeEnd == -1);
191 192
}

193 194
QModelIndex QmlProfilerEventsWidget::selectedItem() const
{
Christiaan Janssen's avatar
Christiaan Janssen committed
195
    return d->m_eventTree->selectedItem();
196 197 198 199
}

void QmlProfilerEventsWidget::contextMenuEvent(QContextMenuEvent *ev)
{
Christiaan Janssen's avatar
Christiaan Janssen committed
200 201 202 203 204 205 206 207 208 209 210
    QTC_ASSERT(d->m_viewContainer, return;);

    QMenu menu;
    QAction *copyRowAction = 0;
    QAction *copyTableAction = 0;
    QAction *showExtendedStatsAction = 0;
    QAction *getLocalStatsAction = 0;
    QAction *getGlobalStatsAction = 0;

    QPoint position = ev->globalPos();

211 212
    if (d->m_profilerTool) {
        QList <QAction *> commonActions = d->m_profilerTool->profilerContextMenuActions();
Christiaan Janssen's avatar
Christiaan Janssen committed
213 214 215 216 217 218 219 220 221 222 223
        foreach (QAction *act, commonActions) {
            menu.addAction(act);
        }
    }

    if (mouseOnTable(position)) {
        menu.addSeparator();
        if (selectedItem().isValid())
            copyRowAction = menu.addAction(tr("Copy Row"));
        copyTableAction = menu.addAction(tr("Copy Table"));

Christiaan Janssen's avatar
Christiaan Janssen committed
224 225 226
        showExtendedStatsAction = menu.addAction(tr("Extended Event Statistics"));
        showExtendedStatsAction->setCheckable(true);
        showExtendedStatsAction->setChecked(showExtendedStatistics());
Christiaan Janssen's avatar
Christiaan Janssen committed
227 228
    }

Christiaan Janssen's avatar
Christiaan Janssen committed
229 230 231 232 233 234 235
    menu.addSeparator();
    getLocalStatsAction = menu.addAction(tr("Limit Events Pane to Current Range"));
    if (!d->m_viewContainer->hasValidSelection())
        getLocalStatsAction->setEnabled(false);
    getGlobalStatsAction = menu.addAction(tr("Reset Events Pane"));
    if (hasGlobalStats())
        getGlobalStatsAction->setEnabled(false);
Christiaan Janssen's avatar
Christiaan Janssen committed
236 237 238 239 240 241 242 243 244 245 246 247

    QAction *selectedAction = menu.exec(position);

    if (selectedAction) {
        if (selectedAction == copyRowAction)
            copyRowToClipboard();
        if (selectedAction == copyTableAction)
            copyTableToClipboard();
        if (selectedAction == getLocalStatsAction) {
            getStatisticsInRange(d->m_viewContainer->selectionStart(),
                                 d->m_viewContainer->selectionEnd());
        }
Christiaan Janssen's avatar
Christiaan Janssen committed
248 249
        if (selectedAction == getGlobalStatsAction)
            getStatisticsInRange(-1, -1);
Christiaan Janssen's avatar
Christiaan Janssen committed
250 251 252
        if (selectedAction == showExtendedStatsAction)
            setShowExtendedStatistics(!showExtendedStatistics());
    }
253 254
}

255 256 257 258 259 260
void QmlProfilerEventsWidget::resizeEvent(QResizeEvent *event)
{
    QWidget::resizeEvent(event);
    emit resized();
}

261 262
bool QmlProfilerEventsWidget::mouseOnTable(const QPoint &position) const
{
Christiaan Janssen's avatar
Christiaan Janssen committed
263 264
    QPoint tableTopLeft = d->m_eventTree->mapToGlobal(QPoint(0,0));
    QPoint tableBottomRight = d->m_eventTree->mapToGlobal(QPoint(d->m_eventTree->width(), d->m_eventTree->height()));
265 266 267 268 269
    return (position.x() >= tableTopLeft.x() && position.x() <= tableBottomRight.x() && position.y() >= tableTopLeft.y() && position.y() <= tableBottomRight.y());
}

void QmlProfilerEventsWidget::copyTableToClipboard() const
{
Christiaan Janssen's avatar
Christiaan Janssen committed
270
    d->m_eventTree->copyTableToClipboard();
271 272 273 274
}

void QmlProfilerEventsWidget::copyRowToClipboard() const
{
Christiaan Janssen's avatar
Christiaan Janssen committed
275
    d->m_eventTree->copyRowToClipboard();
276
}
277

Christiaan Janssen's avatar
Christiaan Janssen committed
278
void QmlProfilerEventsWidget::updateSelectedEvent(const QString &eventHash) const
279
{
Christiaan Janssen's avatar
Christiaan Janssen committed
280 281
    if (d->m_eventTree->selectedEventHash() != eventHash)
        d->m_eventTree->selectEvent(eventHash);
282 283
}

284
void QmlProfilerEventsWidget::selectBySourceLocation(const QString &filename, int line, int column)
285
{
Christiaan Janssen's avatar
Christiaan Janssen committed
286
    d->m_eventTree->selectEventByLocation(filename, line, column);
287 288
}

289 290
bool QmlProfilerEventsWidget::hasGlobalStats() const
{
Christiaan Janssen's avatar
Christiaan Janssen committed
291
    return d->globalStats;
292 293
}

294 295
void QmlProfilerEventsWidget::setShowExtendedStatistics(bool show)
{
Christiaan Janssen's avatar
Christiaan Janssen committed
296
    d->m_eventTree->setShowExtendedStatistics(show);
297 298 299 300
}

bool QmlProfilerEventsWidget::showExtendedStatistics() const
{
Christiaan Janssen's avatar
Christiaan Janssen committed
301 302 303
    return d->m_eventTree->showExtendedStatistics();
}

304 305
////////////////////////////////////////////////////////////////////////////////////

306
class QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate
307 308
{
public:
309
    QmlProfilerEventsMainViewPrivate(QmlProfilerEventsMainView *qq) : q(qq) {}
310 311 312

    int getFieldCount();

Christiaan Janssen's avatar
Christiaan Janssen committed
313
    QString textForItem(QStandardItem *item, bool recursive = false) const;
314

315

316
    QmlProfilerEventsMainView *q;
317

Christiaan Janssen's avatar
Christiaan Janssen committed
318
    QmlProfilerEventsModelProxy *modelProxy;
319 320
    QStandardItemModel *m_model;
    QList<bool> m_fieldShown;
321 322
    QHash<int, int> m_columnIndex; // maps field enum to column index
    bool m_showExtendedStatistics;
323
    int m_firstNumericColumn;
324
    bool m_preventSelectBounce;
325 326 327 328 329
};


////////////////////////////////////////////////////////////////////////////////////

Christiaan Janssen's avatar
Christiaan Janssen committed
330 331 332
QmlProfilerEventsMainView::QmlProfilerEventsMainView(QWidget *parent,
                                   QmlProfilerEventsModelProxy *modelProxy)
: QmlProfilerTreeView(parent), d(new QmlProfilerEventsMainViewPrivate(this))
333
{
334
    setObjectName(QLatin1String("QmlProfilerEventsTable"));
Christiaan Janssen's avatar
Christiaan Janssen committed
335

336 337 338 339 340 341
    setSortingEnabled(false);

    d->m_model = new QStandardItemModel(this);
    setModel(d->m_model);
    connect(this,SIGNAL(clicked(QModelIndex)), this,SLOT(jumpToItem(QModelIndex)));

Christiaan Janssen's avatar
Christiaan Janssen committed
342 343 344 345
    d->modelProxy = modelProxy;
    connect(d->modelProxy,SIGNAL(dataAvailable()), this, SLOT(buildModel()));
//    connect(d->modelProxy,SIGNAL(stateChanged()),
//            this,SLOT(profilerDataModelStateChanged()));
346
    d->m_firstNumericColumn = 0;
347
    d->m_preventSelectBounce = false;
348
    d->m_showExtendedStatistics = false;
349

Christiaan Janssen's avatar
Christiaan Janssen committed
350 351 352 353 354 355 356 357 358 359 360 361 362 363
    setFieldViewable(Name, true);
    setFieldViewable(Type, true);
    setFieldViewable(TimeInPercent, true);
    setFieldViewable(TotalTime, true);
    setFieldViewable(SelfTimeInPercent, false);
    setFieldViewable(SelfTime, false);
    setFieldViewable(CallCount, true);
    setFieldViewable(TimePerCall, true);
    setFieldViewable(MaxTime, true);
    setFieldViewable(MinTime, true);
    setFieldViewable(MedianTime, true);
    setFieldViewable(Details, true);

    buildModel();
364 365
}

366
QmlProfilerEventsMainView::~QmlProfilerEventsMainView()
367 368
{
    clear();
Christiaan Janssen's avatar
Christiaan Janssen committed
369
    //delete d->modelProxy;
370
    delete d->m_model;
Kai Koehne's avatar
Kai Koehne committed
371
    delete d;
372 373
}

Christiaan Janssen's avatar
Christiaan Janssen committed
374
void QmlProfilerEventsMainView::profilerDataModelStateChanged()
375
{
376 377
}

378
void QmlProfilerEventsMainView::setFieldViewable(Fields field, bool show)
379 380 381 382 383 384 385 386 387 388 389 390
{
    if (field < MaxFields) {
        int length = d->m_fieldShown.count();
        if (field >= length) {
            for (int i=length; i<MaxFields; i++)
                d->m_fieldShown << false;
        }
        d->m_fieldShown[field] = show;
    }
}


391
void QmlProfilerEventsMainView::setHeaderLabels()
392 393 394 395
{
    int fieldIndex = 0;
    d->m_firstNumericColumn = 0;

396
    d->m_columnIndex.clear();
397
    if (d->m_fieldShown[Name]) {
398
        d->m_columnIndex[Name] = fieldIndex;
Christiaan Janssen's avatar
Christiaan Janssen committed
399
        d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Location)));
400 401 402
        d->m_firstNumericColumn++;
    }
    if (d->m_fieldShown[Type]) {
403
        d->m_columnIndex[Type] = fieldIndex;
Christiaan Janssen's avatar
Christiaan Janssen committed
404
        d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Type)));
405 406
        d->m_firstNumericColumn++;
    }
Christiaan Janssen's avatar
Christiaan Janssen committed
407 408 409
    if (d->m_fieldShown[TimeInPercent]) {
        d->m_columnIndex[TimeInPercent] = fieldIndex;
        d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TimeInPercent)));
410
    }
Christiaan Janssen's avatar
Christiaan Janssen committed
411 412 413
    if (d->m_fieldShown[TotalTime]) {
        d->m_columnIndex[TotalTime] = fieldIndex;
        d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TotalTime)));
414
    }
Christiaan Janssen's avatar
Christiaan Janssen committed
415
    if (d->m_fieldShown[SelfTimeInPercent]) {
416
        d->m_columnIndex[Type] = fieldIndex;
Christiaan Janssen's avatar
Christiaan Janssen committed
417
        d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(SelfTimeInPercent)));
418
    }
Christiaan Janssen's avatar
Christiaan Janssen committed
419 420 421
    if (d->m_fieldShown[SelfTime]) {
        d->m_columnIndex[SelfTime] = fieldIndex;
        d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(SelfTime)));
422 423 424
    }
    if (d->m_fieldShown[CallCount]) {
        d->m_columnIndex[CallCount] = fieldIndex;
Christiaan Janssen's avatar
Christiaan Janssen committed
425
        d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(CallCount)));
426 427 428
    }
    if (d->m_fieldShown[TimePerCall]) {
        d->m_columnIndex[TimePerCall] = fieldIndex;
Christiaan Janssen's avatar
Christiaan Janssen committed
429
        d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TimePerCall)));
430 431 432
    }
    if (d->m_fieldShown[MedianTime]) {
        d->m_columnIndex[MedianTime] = fieldIndex;
Christiaan Janssen's avatar
Christiaan Janssen committed
433
        d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MedianTime)));
434 435 436
    }
    if (d->m_fieldShown[MaxTime]) {
        d->m_columnIndex[MaxTime] = fieldIndex;
Christiaan Janssen's avatar
Christiaan Janssen committed
437
        d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MaxTime)));
438 439 440
    }
    if (d->m_fieldShown[MinTime]) {
        d->m_columnIndex[MinTime] = fieldIndex;
Christiaan Janssen's avatar
Christiaan Janssen committed
441
        d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MinTime)));
442
    }
443
    if (d->m_fieldShown[Details]) {
444
        d->m_columnIndex[Details] = fieldIndex;
Christiaan Janssen's avatar
Christiaan Janssen committed
445
        d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Details)));
446
    }
447 448
}

449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
void QmlProfilerEventsMainView::setShowExtendedStatistics(bool show)
{
    // Not checking if already set because we don't want the first call to skip
    d->m_showExtendedStatistics = show;
    if (show) {
        if (d->m_fieldShown[MedianTime])
            showColumn(d->m_columnIndex[MedianTime]);
        if (d->m_fieldShown[MaxTime])
            showColumn(d->m_columnIndex[MaxTime]);
        if (d->m_fieldShown[MinTime])
            showColumn(d->m_columnIndex[MinTime]);
    } else{
        if (d->m_fieldShown[MedianTime])
            hideColumn(d->m_columnIndex[MedianTime]);
        if (d->m_fieldShown[MaxTime])
            hideColumn(d->m_columnIndex[MaxTime]);
        if (d->m_fieldShown[MinTime])
            hideColumn(d->m_columnIndex[MinTime]);
    }
}

bool QmlProfilerEventsMainView::showExtendedStatistics() const
{
    return d->m_showExtendedStatistics;
}

475
void QmlProfilerEventsMainView::clear()
476 477 478 479 480 481 482 483
{
    d->m_model->clear();
    d->m_model->setColumnCount(d->getFieldCount());

    setHeaderLabels();
    setSortingEnabled(false);
}

484
int QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::getFieldCount()
485 486 487
{
    int count = 0;
    for (int i=0; i < m_fieldShown.count(); ++i)
488
        if (m_fieldShown[i])
489 490 491 492
            count++;
    return count;
}

493
void QmlProfilerEventsMainView::buildModel()
494
{
Christiaan Janssen's avatar
Christiaan Janssen committed
495 496 497
    clear();
    parseModelProxy();
    setShowExtendedStatistics(d->m_showExtendedStatistics);
498

Christiaan Janssen's avatar
Christiaan Janssen committed
499 500 501
    setRootIsDecorated(false);
    setSortingEnabled(true);
    sortByColumn(d->m_firstNumericColumn,Qt::DescendingOrder);
502

Christiaan Janssen's avatar
Christiaan Janssen committed
503 504 505
    expandAll();
    if (d->m_fieldShown[Name])
        resizeColumnToContents(0);
506

Christiaan Janssen's avatar
Christiaan Janssen committed
507 508 509
    if (d->m_fieldShown[Type])
        resizeColumnToContents(d->m_fieldShown[Name]?1:0);
    collapseAll();
510 511
}

Christiaan Janssen's avatar
Christiaan Janssen committed
512
void QmlProfilerEventsMainView::parseModelProxy()
513
{
Christiaan Janssen's avatar
Christiaan Janssen committed
514 515 516
    const QList <QmlProfilerEventsModelProxy::QmlEventStats> eventList = d->modelProxy->getData();
    foreach (const QmlProfilerEventsModelProxy::QmlEventStats &event, eventList) {
        QStandardItem *parentItem = d->m_model->invisibleRootItem();
517 518
        QList<QStandardItem *> newRow;

Christiaan Janssen's avatar
Christiaan Janssen committed
519 520 521 522 523
        if (d->m_fieldShown[Name])
            newRow << new EventsViewItem(event.displayName);

        if (d->m_fieldShown[Type]) {
            QString typeString = QmlProfilerEventsMainView::nameForType(event.eventType);
524
            QString toolTipText;
Christiaan Janssen's avatar
Christiaan Janssen committed
525 526
            if (event.eventType == Binding) {
                if (event.bindingType == (int)OptimizedBinding) {
527
                    typeString = typeString + QLatin1Char(' ') +  tr("(Opt)");
528
                    toolTipText = tr("Binding is evaluated by the optimized engine.");
Christiaan Janssen's avatar
Christiaan Janssen committed
529
                } else if (event.bindingType == (int)V8Binding) {
530
                    toolTipText = tr("Binding not optimized (e.g. has side effects or assignments,\n"
531 532 533
                                     "references to elements in other files, loops, etc.)");

                }
534 535 536 537 538
            }
            newRow << new EventsViewItem(typeString);
            newRow.last()->setData(QVariant(typeString));
            if (!toolTipText.isEmpty())
                newRow.last()->setToolTip(toolTipText);
539 540
        }

Christiaan Janssen's avatar
Christiaan Janssen committed
541 542 543
        if (d->m_fieldShown[TimeInPercent]) {
            newRow << new EventsViewItem(QString::number(event.percentOfTime,'f',2)+QLatin1String(" %"));
            newRow.last()->setData(QVariant(event.percentOfTime));
544 545
        }

Christiaan Janssen's avatar
Christiaan Janssen committed
546 547 548
        if (d->m_fieldShown[TotalTime]) {
            newRow << new EventsViewItem(displayTime(event.duration));
            newRow.last()->setData(QVariant(event.duration));
549 550
        }

Christiaan Janssen's avatar
Christiaan Janssen committed
551 552 553
        if (d->m_fieldShown[CallCount]) {
            newRow << new EventsViewItem(QString::number(event.calls));
            newRow.last()->setData(QVariant(event.calls));
554 555
        }

Christiaan Janssen's avatar
Christiaan Janssen committed
556 557 558
        if (d->m_fieldShown[TimePerCall]) {
            newRow << new EventsViewItem(displayTime(event.timePerCall));
            newRow.last()->setData(QVariant(event.timePerCall));
559 560
        }

Christiaan Janssen's avatar
Christiaan Janssen committed
561 562 563
        if (d->m_fieldShown[MedianTime]) {
            newRow << new EventsViewItem(displayTime(event.medianTime));
            newRow.last()->setData(QVariant(event.medianTime));
564 565
        }

Christiaan Janssen's avatar
Christiaan Janssen committed
566 567 568
        if (d->m_fieldShown[MaxTime]) {
            newRow << new EventsViewItem(displayTime(event.maxTime));
            newRow.last()->setData(QVariant(event.maxTime));
569 570
        }

Christiaan Janssen's avatar
Christiaan Janssen committed
571 572 573
        if (d->m_fieldShown[MinTime]) {
            newRow << new EventsViewItem(displayTime(event.minTime));
            newRow.last()->setData(QVariant(event.minTime));
574 575
        }

Christiaan Janssen's avatar
Christiaan Janssen committed
576 577 578
        if (d->m_fieldShown[Details]) {
            newRow << new EventsViewItem(event.details);
            newRow.last()->setData(QVariant(event.details));
579 580
        }

581 582


583 584 585 586 587 588
        if (!newRow.isEmpty()) {
            // no edit
            foreach (QStandardItem *item, newRow)
                item->setEditable(false);

            // metadata
Christiaan Janssen's avatar
Christiaan Janssen committed
589 590 591 592 593 594
            newRow.at(0)->setData(QVariant(event.eventHashStr),EventHashStrRole);
            newRow.at(0)->setData(QVariant(event.location.filename),FilenameRole);
            newRow.at(0)->setData(QVariant(event.location.line),LineRole);
            newRow.at(0)->setData(QVariant(event.location.column),ColumnRole);

            if (event.isBindingLoop) {
595 596
                foreach (QStandardItem *item, newRow) {
                    item->setBackground(colors()->bindingLoopBackground);
597
                    item->setToolTip(tr("Binding loop detected."));
598
                }
Christiaan Janssen's avatar
Christiaan Janssen committed
599
            }
600 601 602 603 604 605 606

            // append
            parentItem->appendRow(newRow);
        }
    }
}

607
QString QmlProfilerEventsMainView::displayTime(double time)
608 609
{
    if (time < 1e6)
610
        return QString::number(time/1e3,'f',3) + trUtf8(" \xc2\xb5s");
611
    if (time < 1e9)
612
        return QString::number(time/1e6,'f',3) + tr(" ms");
613

614
    return QString::number(time/1e9,'f',3) + tr(" s");
615 616
}

617
QString QmlProfilerEventsMainView::nameForType(int typeNumber)
618 619
{
    switch (typeNumber) {
620 621 622 623 624
    case 0: return QmlProfilerEventsMainView::tr("Paint");
    case 1: return QmlProfilerEventsMainView::tr("Compile");
    case 2: return QmlProfilerEventsMainView::tr("Create");
    case 3: return QmlProfilerEventsMainView::tr("Binding");
    case 4: return QmlProfilerEventsMainView::tr("Signal");
625
    case 5: return QmlProfilerEventsMainView::tr("Javascript");
626 627 628 629
    }
    return QString();
}

630 631
void QmlProfilerEventsMainView::getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd)
{
Christiaan Janssen's avatar
Christiaan Janssen committed
632
    d->modelProxy->limitToRange(rangeStart, rangeEnd);
633 634
}

Christiaan Janssen's avatar
Christiaan Janssen committed
635
QString QmlProfilerEventsMainView::selectedEventHash() const
636 637 638
{
    QModelIndex index = selectedItem();
    if (!index.isValid())
Christiaan Janssen's avatar
Christiaan Janssen committed
639
        return QString();
640
    QStandardItem *item = d->m_model->item(index.row(), 0);
Christiaan Janssen's avatar
Christiaan Janssen committed
641
    return item->data(EventHashStrRole).toString();
642 643 644
}


645
void QmlProfilerEventsMainView::jumpToItem(const QModelIndex &index)
646
{
647 648 649 650
    if (d->m_preventSelectBounce)
        return;

    d->m_preventSelectBounce = true;
651 652 653 654 655 656 657
    QStandardItem *clickedItem = d->m_model->itemFromIndex(index);
    QStandardItem *infoItem;
    if (clickedItem->parent())
        infoItem = clickedItem->parent()->child(clickedItem->row(), 0);
    else
        infoItem = d->m_model->item(index.row(), 0);

658
    // show in editor
659
    int line = infoItem->data(LineRole).toInt();
660
    int column = infoItem->data(ColumnRole).toInt();
661
    QString fileName = infoItem->data(FilenameRole).toString();
662
    if (line!=-1 && !fileName.isEmpty())
663
        emit gotoSourceLocation(fileName, line, column);
664

665
    // show in callers/callees subwindow
Christiaan Janssen's avatar
Christiaan Janssen committed
666
    emit eventSelected(infoItem->data(EventHashStrRole).toString());
667 668

    d->m_preventSelectBounce = false;
669 670
}

Christiaan Janssen's avatar
Christiaan Janssen committed
671
void QmlProfilerEventsMainView::selectEvent(const QString &eventHash)
672
{
673 674
    for (int i=0; i<d->m_model->rowCount(); i++) {
        QStandardItem *infoItem = d->m_model->item(i, 0);
Christiaan Janssen's avatar
Christiaan Janssen committed
675
        if (infoItem->data(EventHashStrRole).toString() == eventHash) {
676 677 678 679 680
            setCurrentIndex(d->m_model->indexFromItem(infoItem));
            jumpToItem(currentIndex());
            return;
        }
    }
681 682
}

Christiaan Janssen's avatar
Christiaan Janssen committed
683
void QmlProfilerEventsMainView::selectEventByLocation(const QString &filename, int line, int column)
684
{
685 686 687
    if (d->m_preventSelectBounce)
        return;

688 689
    for (int i=0; i<d->m_model->rowCount(); i++) {
        QStandardItem *infoItem = d->m_model->item(i, 0);
Christiaan Janssen's avatar
Christiaan Janssen committed
690 691 692 693 694
        if (currentIndex() != d->m_model->indexFromItem(infoItem) &&
                infoItem->data(FilenameRole).toString() == filename &&
                infoItem->data(LineRole).toInt() == line &&
                (column == -1 ||
                infoItem->data(ColumnRole).toInt() == column)) {
695 696 697 698 699 700 701
            setCurrentIndex(d->m_model->indexFromItem(infoItem));
            jumpToItem(currentIndex());
            return;
        }
    }
}

702
QModelIndex QmlProfilerEventsMainView::selectedItem() const
703 704 705 706 707 708 709 710
{
    QModelIndexList sel = selectedIndexes();
    if (sel.isEmpty())
        return QModelIndex();
    else
        return sel.first();
}

Christiaan Janssen's avatar
Christiaan Janssen committed
711
QString QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::textForItem(QStandardItem *item, bool recursive) const
712 713 714 715 716 717 718
{
    QString str;

    if (recursive) {
        // indentation
        QStandardItem *itemParent = item->parent();
        while (itemParent) {
719
            str += QLatin1String("    ");
720 721 722 723 724 725 726 727 728
            itemParent = itemParent->parent();
        }
    }

    // item's data
    int colCount = m_model->columnCount();
    for (int j = 0; j < colCount; ++j) {
        QStandardItem *colItem = item->parent() ? item->parent()->child(item->row(),j) : m_model->item(item->row(),j);
        str += colItem->data(Qt::DisplayRole).toString();
729
        if (j < colCount-1) str += QLatin1Char('\t');
730
    }
731
    str += QLatin1Char('\n');
732 733 734 735 736 737 738 739 740

    // recursively print children
    if (recursive && item->child(0))
        for (int j = 0; j != item->rowCount(); j++)
            str += textForItem(item->child(j));

    return str;
}

741
void QmlProfilerEventsMainView::copyTableToClipboard() const
742 743
{
    QString str;
744 745 746 747 748
    // headers
    int columnCount = d->m_model->columnCount();
    for (int i = 0; i < columnCount; ++i) {
        str += d->m_model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
        if (i < columnCount - 1)
749
            str += QLatin1Char('\t');
750
        else
751
            str += QLatin1Char('\n');
752 753 754 755
    }
    // data
    int rowCount = d->m_model->rowCount();
    for (int i = 0; i != rowCount; ++i) {
756 757 758 759 760 761 762
        str += d->textForItem(d->m_model->item(i));
    }
    QClipboard *clipboard = QApplication::clipboard();
    clipboard->setText(str, QClipboard::Selection);
    clipboard->setText(str, QClipboard::Clipboard);
}

763
void QmlProfilerEventsMainView::copyRowToClipboard() const
764 765 766 767 768 769 770 771 772
{
    QString str;
    str = d->textForItem(d->m_model->itemFromIndex(selectedItem()), false);

    QClipboard *clipboard = QApplication::clipboard();
    clipboard->setText(str, QClipboard::Selection);
    clipboard->setText(str, QClipboard::Clipboard);
}

773 774
////////////////////////////////////////////////////////////////////////////////////

Christiaan Janssen's avatar
Christiaan Janssen committed
775 776 777 778 779 780 781 782 783 784 785 786 787
class QmlProfilerEventRelativesView::QmlProfilerEventParentsViewPrivate
{
public:
    QmlProfilerEventParentsViewPrivate(QmlProfilerEventRelativesView *qq):q(qq) {}
    ~QmlProfilerEventParentsViewPrivate() {}

    QmlProfilerEventRelativesModelProxy *modelProxy;

    QmlProfilerEventRelativesView *q;
};

QmlProfilerEventRelativesView::QmlProfilerEventRelativesView(QmlProfilerModelManager *modelManager, QmlProfilerEventRelativesModelProxy *modelProxy, QWidget *parent)
    : QmlProfilerTreeView(parent), d(new QmlProfilerEventParentsViewPrivate(this))
788
{
Christiaan Janssen's avatar
Christiaan Janssen committed
789 790 791
    Q_UNUSED(modelManager);
    setSortingEnabled(false);
    d->modelProxy = modelProxy;
792 793 794 795 796 797 798
    setModel(new QStandardItemModel(this));
    setRootIsDecorated(false);
    updateHeader();

    connect(this,SIGNAL(clicked(QModelIndex)), this,SLOT(jumpToItem(QModelIndex)));
}

Christiaan Janssen's avatar
Christiaan Janssen committed
799
QmlProfilerEventRelativesView::~QmlProfilerEventRelativesView()
800
{
Christiaan Janssen's avatar
Christiaan Janssen committed
801
    delete d;
802 803
}

Christiaan Janssen's avatar
Christiaan Janssen committed
804
void QmlProfilerEventRelativesView::displayEvent(const QString &eventHash)
805
{
Christiaan Janssen's avatar
Christiaan Janssen committed
806
    rebuildTree(d->modelProxy->getData(eventHash));
807 808 809

    updateHeader();
    resizeColumnToContents(0);
810
    setSortingEnabled(true);
Christiaan Janssen's avatar
Christiaan Janssen committed
811
    sortByColumn(2);
812 813
}

Christiaan Janssen's avatar
Christiaan Janssen committed
814
void QmlProfilerEventRelativesView::rebuildTree(QmlProfilerEventRelativesModelProxy::QmlEventRelativesMap eventMap)
815 816 817 818 819 820
{
    Q_ASSERT(treeModel());
    treeModel()->clear();

    QStandardItem *topLevelItem = treeModel()->invisibleRootItem();

Christiaan Janssen's avatar
Christiaan Janssen committed
821 822 823
    //foreach (const QmlProfilerEventParentsModelProxy::QmlEventParentData &event, eventMap.values()) {
    foreach (const QString &key, eventMap.keys()) {
        const QmlProfilerEventRelativesModelProxy::QmlEventRelativesData &event = eventMap[key];
824
        QList<QStandardItem *> newRow;
Christiaan Janssen's avatar
Christiaan Janssen committed
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848

        // ToDo: here we were going to search for the data in the other modelproxy
        // maybe we should store the data in this proxy and get it here
        // no indirections at this level of abstraction!
        newRow << new EventsViewItem(event.displayName);
        newRow << new EventsViewItem(QmlProfilerEventsMainView::nameForType(event.eventType));
        newRow << new EventsViewItem(QmlProfilerEventsMainView::displayTime(event.duration));
        newRow << new EventsViewItem(QString::number(event.calls));
        newRow << new EventsViewItem(event.details);

//        newRow << new EventsViewItem(event->reference->displayName);
//        newRow << new EventsViewItem(QmlProfilerEventsMainView::nameForType(event->reference->eventType));
//        newRow << new EventsViewItem(QmlProfilerEventsMainView::displayTime(event->duration));
//        newRow << new EventsViewItem(QString::number(event->calls));
//        newRow << new EventsViewItem(event->reference->details);
        newRow.at(0)->setData(QVariant(key), EventHashStrRole);
        newRow.at(2)->setData(QVariant(event.duration));
        newRow.at(3)->setData(QVariant(event.calls));

        if (event.isBindingLoop) {
            foreach (QStandardItem *item, newRow) {
                item->setBackground(colors()->bindingLoopBackground);
                item->setToolTip(tr("Part of binding loop."));
            }
849
        }
Christiaan Janssen's avatar
Christiaan Janssen committed
850

851 852 853 854 855 856 857
        foreach (QStandardItem *item, newRow)
            item->setEditable(false);

        topLevelItem->appendRow(newRow);
    }
}

Christiaan Janssen's avatar
Christiaan Janssen committed
858
void QmlProfilerEventRelativesView::clear()
859 860 861 862 863 864 865
{
    if (treeModel()) {
        treeModel()->clear();
        updateHeader();
    }
}

Christiaan Janssen's avatar
Christiaan Janssen committed
866
void QmlProfilerEventRelativesView::updateHeader()
867
{
Christiaan Janssen's avatar
Christiaan Janssen committed
868
    bool calleesView = qobject_cast<QmlProfilerEventChildrenModelProxy *>(d->modelProxy) != 0;
869 870

    if (treeModel()) {
Christiaan Janssen's avatar
Christiaan Janssen committed
871
        treeModel()->setColumnCount(5);
872 873

        int columnIndex = 0;
Christiaan Janssen's avatar
Christiaan Janssen committed
874 875
        if (calleesView)
            treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(Callee)));
876
        else
Christiaan Janssen's avatar
Christiaan Janssen committed
877 878 879
            treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(Caller)));

        treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(Type)));
880

Christiaan Janssen's avatar
Christiaan Janssen committed
881
        treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(TotalTime)));
882

Christiaan Janssen's avatar
Christiaan Janssen committed
883
        treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(CallCount)));
884 885


Christiaan Janssen's avatar
Christiaan Janssen committed
886 887
        if (calleesView)
            treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(CalleeDescription)));
888
        else
Christiaan Janssen's avatar
Christiaan Janssen committed
889
            treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(CallerDescription)));
890 891 892
    }
}

Christiaan Janssen's avatar
Christiaan Janssen committed
893
QStandardItemModel *QmlProfilerEventRelativesView::treeModel()
894 895 896 897
{
    return qobject_cast<QStandardItemModel *>(model());
}

Christiaan Janssen's avatar
Christiaan Janssen committed
898
void QmlProfilerEventRelativesView::jumpToItem(const QModelIndex &index)
899 900 901
{
    if (treeModel()) {
        QStandardItem *infoItem = treeModel()->item(index.row(), 0);
Christiaan Janssen's avatar
Christiaan Janssen committed
902
        emit eventClicked(infoItem->data(EventHashStrRole).toString());
903 904 905
    }
}

906 907
} // namespace Internal
} // namespace QmlProfiler