MainView.qml 20.1 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
Kai Koehne's avatar
Kai Koehne committed
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
Kai Koehne's avatar
Kai Koehne committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
Kai Koehne's avatar
Kai Koehne committed
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.
Kai Koehne's avatar
Kai Koehne committed
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
Kai Koehne's avatar
Kai Koehne committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
Kai Koehne's avatar
Kai Koehne committed
29

30
import QtQuick 2.1
Christiaan Janssen's avatar
Christiaan Janssen committed
31
import Monitor 1.0
32
import QtQuick.Controls 1.0
Christiaan Janssen's avatar
Christiaan Janssen committed
33
34
35
36

Rectangle {
    id: root

37
38
    // ***** properties

39
    property int singleRowHeight: 30
40
41
42
43

    property bool dataAvailable: true
    property int eventCount: 0
    property real progress: 0
Christiaan Janssen's avatar
Christiaan Janssen committed
44

45
46
47
    property alias selectionLocked : view.selectionLocked
    signal updateLockButton
    property alias selectedItem: view.selectedItem
Christiaan Janssen's avatar
Christiaan Janssen committed
48
    signal selectedEventChanged(int eventId)
49
    property bool lockItemSelection : false
50

51
    property real mainviewTimePerPixel : 0
52

Christiaan Janssen's avatar
Christiaan Janssen committed
53
54
55
    signal updateCursorPosition
    property string fileName: ""
    property int lineNumber: -1
56
    property int columnNumber: 0
57

58
59
60
    signal updateRangeButton
    property bool selectionRangeMode: false

61
    property bool selectionRangeReady: selectionRange.ready
62
63
    property real selectionRangeStart: selectionRange.startTime
    property real selectionRangeEnd: selectionRange.startTime + selectionRange.duration
64

65
66
    signal changeToolTip(string text)

Christiaan Janssen's avatar
Christiaan Janssen committed
67
68
69
70
71
    property bool recordingEnabled: false
    property bool appKilled : false

    property date recordingStartDate
    property real elapsedTime
72

73
74
75
76
77
78
79
    // ***** connections with external objects
    Connections {
        target: zoomControl
        onRangeChanged: {
            var startTime = zoomControl.startTime();
            var endTime = zoomControl.endTime();

80
            mainviewTimePerPixel = Math.abs(endTime - startTime) / root.width;
81
82
83

            backgroundMarks.updateMarks(startTime, endTime);
            view.updateFlickRange(startTime, endTime);
84
            flick.setContentWidth();
85
86
87
        }
    }

Christiaan Janssen's avatar
Christiaan Janssen committed
88

89
    Connections {
Christiaan Janssen's avatar
Christiaan Janssen committed
90
        target: qmlProfilerModelProxy
91
        onCountChanged: {
Christiaan Janssen's avatar
Christiaan Janssen committed
92
            eventCount = qmlProfilerModelProxy.count();
93
94
95
96
            if (eventCount === 0)
                root.clearAll();
            if (eventCount > 1) {
                root.progress = Math.min(1.0,
Christiaan Janssen's avatar
Christiaan Janssen committed
97
98
                    (qmlProfilerModelProxy.lastTimeMark() -
                    qmlProfilerModelProxy.traceStartTime()) / root.elapsedTime * 1e-9 );
99
100
101
102
            } else {
                root.progress = 0;
            }
        }
103
        onStateChanged: {
Christiaan Janssen's avatar
Christiaan Janssen committed
104
            switch (qmlProfilerModelProxy.getState()) {
105
106
107
108
109
110
111
112
113
114
115
116
            case 0: {
                root.clearAll();
                break;
            }
            case 1: {
                root.dataAvailable = false;
                break;
            }
            case 2: {
                root.progress = 0.9; // jump to 90%
                break;
            }
117
118
            }
        }
Christiaan Janssen's avatar
Christiaan Janssen committed
119
120
121
122
123
124
125
126
127
128
129
        onDataAvailable: {
            view.clearData();
            zoomControl.setRange(0,0);
            progress = 1.0;
            dataAvailable = true;
            view.visible = true;
            view.requestPaint();
            zoomControl.setRange(qmlProfilerModelProxy.traceStartTime(),
                                 qmlProfilerModelProxy.traceStartTime() +
                                 qmlProfilerModelProxy.traceDuration()/10);
        }
130
131
    }

Christiaan Janssen's avatar
Christiaan Janssen committed
132

133
    // ***** functions
134
    function gotoSourceLocation(file,line,column) {
Christiaan Janssen's avatar
Christiaan Janssen committed
135
136
137
138
139
140
        if (file !== undefined) {
            root.fileName = file;
            root.lineNumber = line;
            root.columnNumber = column;
            root.updateCursorPosition();
        }
Christiaan Janssen's avatar
Christiaan Janssen committed
141
142
    }

143
    function clearData() {
144
        view.clearData();
145
        dataAvailable = false;
Christiaan Janssen's avatar
Christiaan Janssen committed
146
        appKilled = false;
147
        eventCount = 0;
148
        hideRangeDetails();
149
150
151
        selectionRangeMode = false;
        updateRangeButton();
        zoomControl.setRange(0,0);
152
153
    }

154
    function clearDisplay() {
155
156
        clearData();
        view.visible = false;
157
158
159
160
    }

    function clearAll() {
        clearDisplay();
161
        elapsedTime = 0;
162
163
    }

164
    function nextEvent() {
165
        view.selectNext();
166
167
168
    }

    function prevEvent() {
169
        view.selectPrev();
170
171
    }

172
173
174
175
176
177
178
179
    function updateZoomCentered(centerX, relativeFactor)
    {
        var min_length = 1e5; // 0.1 ms
        var windowLength = view.endTime - view.startTime;
        if (windowLength < min_length)
            windowLength = min_length;
        var newWindowLength = windowLength * relativeFactor;

Christiaan Janssen's avatar
Christiaan Janssen committed
180
181
        if (newWindowLength > qmlProfilerModelProxy.traceDuration()) {
            newWindowLength = qmlProfilerModelProxy.traceDuration();
182
183
184
185
186
187
188
189
190
            relativeFactor = newWindowLength / windowLength;
        }
        if (newWindowLength < min_length) {
            newWindowLength = min_length;
            relativeFactor = newWindowLength / windowLength;
        }

        var fixedPoint = (centerX - flick.x) * windowLength / flick.width + view.startTime;
        var startTime = fixedPoint - relativeFactor*(fixedPoint - view.startTime);
191
192
193
        zoomControl.setRange(startTime, startTime + newWindowLength);
    }

194
195
196
197
198
    function recenter( centerPoint ) {
        var windowLength = view.endTime - view.startTime;
        var newStart = Math.floor(centerPoint - windowLength/2);
        if (newStart < 0)
            newStart = 0;
Christiaan Janssen's avatar
Christiaan Janssen committed
199
200
        if (newStart + windowLength > qmlProfilerModelProxy.traceEndTime())
            newStart = qmlProfilerModelProxy.traceEndTime() - windowLength;
201
202
203
        zoomControl.setRange(newStart, newStart + windowLength);
    }

Christiaan Janssen's avatar
Christiaan Janssen committed
204
    function recenterOnItem( modelIndex, itemIndex )
205
    {
206
207
208
        if (itemIndex === -1)
            return;

209
        // if item is outside of the view, jump back to its position
Christiaan Janssen's avatar
Christiaan Janssen committed
210
211
212
213
        if (qmlProfilerModelProxy.getEndTime(modelIndex, itemIndex) < view.startTime ||
                qmlProfilerModelProxy.getStartTime(modelIndex, itemIndex) > view.endTime) {
            recenter((qmlProfilerModelProxy.getStartTime(modelIndex, itemIndex) +
                      qmlProfilerModelProxy.getEndTime(modelIndex, itemIndex)) / 2);
214
        }
Christiaan Janssen's avatar
Christiaan Janssen committed
215

216
217
    }

218
    function wheelZoom(wheelCenter, wheelDelta) {
Christiaan Janssen's avatar
Christiaan Janssen committed
219
        if (qmlProfilerModelProxy.traceEndTime() > qmlProfilerModelProxy.traceStartTime() &&
Christiaan Janssen's avatar
Christiaan Janssen committed
220
                wheelDelta !== 0) {
221
222
223
224
225
226
227
            if (wheelDelta>0)
                updateZoomCentered(wheelCenter, 1/1.2);
            else
                updateZoomCentered(wheelCenter, 1.2);
        }
    }

228
229
230
231
    function hideRangeDetails() {
        rangeDetails.visible = false;
        rangeDetails.duration = "";
        rangeDetails.label = "";
Christiaan Janssen's avatar
Christiaan Janssen committed
232
        //rangeDetails.type = "";
233
234
        rangeDetails.file = "";
        rangeDetails.line = -1;
235
        rangeDetails.column = 0;
236
        rangeDetails.isBindingLoop = false;
237
238
    }

Christiaan Janssen's avatar
Christiaan Janssen committed
239
240
241
242
243
244
245
246
    function selectNextByHash(hash) {
        var eventId = qmlProfilerModelProxy.getEventIdForHash(hash);
        if (eventId !== -1) {
            selectNextById(eventId);
        }
    }

    function selectNextById(eventId)
247
    {
Christiaan Janssen's avatar
Christiaan Janssen committed
248
249
        // this is a slot responding to events from the other pane
        // which tracks only events from the basic model
250
251
        if (!lockItemSelection) {
            lockItemSelection = true;
Christiaan Janssen's avatar
Christiaan Janssen committed
252
253
            var modelIndex = qmlProfilerModelProxy.basicModelIndex();
            var itemIndex = view.nextItemFromId( modelIndex, eventId );
254
            // select an item, lock to it, and recenter if necessary
Christiaan Janssen's avatar
Christiaan Janssen committed
255
256
            if (view.selectedItem != itemIndex || view.selectedModel != modelIndex) {
                view.selectedModel = modelIndex;
257
258
259
                view.selectedItem = itemIndex;
                if (itemIndex !== -1) {
                    view.selectionLocked = true;
Christiaan Janssen's avatar
Christiaan Janssen committed
260
                    recenterOnItem(modelIndex, itemIndex);
261
262
263
264
265
266
                }
            }
            lockItemSelection = false;
        }
    }

267
    // ***** slots
268
269
270
271
272
    onSelectionRangeModeChanged: {
        selectionRangeControl.enabled = selectionRangeMode;
        selectionRange.reset(selectionRangeMode);
    }

273
274
275
276
    onSelectionLockedChanged: {
        updateLockButton();
    }

277
278
279
    onSelectedItemChanged: {
        if (selectedItem != -1 && !lockItemSelection) {
            lockItemSelection = true;
Christiaan Janssen's avatar
Christiaan Janssen committed
280
281
282
            // update in other views
            var eventLocation = qmlProfilerModelProxy.getEventLocation(view.selectedModel, view.selectedItem);
            gotoSourceLocation(eventLocation.file, eventLocation.line, eventLocation.column);
283
284
285
286
            lockItemSelection = false;
        }
    }

Christiaan Janssen's avatar
Christiaan Janssen committed
287
288
289
290
291
292
    onRecordingEnabledChanged: {
        if (recordingEnabled) {
            recordingStartDate = new Date();
            elapsedTime = 0;
        } else {
            elapsedTime = (new Date() - recordingStartDate)/1000.0;
Christiaan Janssen's avatar
Christiaan Janssen committed
293
294
295
        }
    }

296
297
298
    Flickable {
        id: vertflick
        flickableDirection: Flickable.VerticalFlick
299
        anchors.fill: parent
300
301
        clip: true
        contentHeight: labels.height
302
303
304
        boundsBehavior: Flickable.StopAtBounds

        // ScrollView will try to deinteractivate it. We don't want that
305
306
307
308
309
        // as the horizontal flickable is interactive, too. We do occasionally
        // switch to non-interactive ourselves, though.
        property bool stayInteractive: true
        onInteractiveChanged: interactive = stayInteractive
        onStayInteractiveChanged: interactive = stayInteractive
Christiaan Janssen's avatar
Christiaan Janssen committed
310

311
312
313
        // ***** child items
        TimeMarks {
            id: backgroundMarks
314
315
            y: vertflick.contentY
            height: vertflick.height
316
            width: root.width - labels.width
317
            anchors.left: labels.right
318
319
        }

320
        Flickable {
321
322
323
324
325
326
            function setContentWidth() {
                var duration = Math.abs(zoomControl.endTime() - zoomControl.startTime());
                if (duration > 0)
                    contentWidth = qmlProfilerModelProxy.traceDuration() * width / duration;
            }

327
328
329
330
331
332
333
334
            id: flick
            anchors.top: parent.top
            anchors.topMargin: labels.y
            anchors.right: parent.right
            anchors.left: labels.right
            contentWidth: 0
            height: labels.height + labelsTail.height
            flickableDirection: Flickable.HorizontalFlick
335
            boundsBehavior: Flickable.StopAtBounds
336

337
            onContentXChanged: view.updateZoomControl()
338
339
            onWidthChanged: setContentWidth()

340
341
342
343
344
345
346
347
            clip:true

            SelectionRange {
                id: selectionRange
                visible: root.selectionRangeMode
                height: parent.height
                z: 2
            }
348

349
350
            TimelineRenderer {
                id: view
Christiaan Janssen's avatar
Christiaan Janssen committed
351

352
                profilerModelProxy: qmlProfilerModelProxy
353

354
                x: flick.contentX
355
                y: vertflick.contentY
356
                width: flick.width
357
                height: vertflick.height
Christiaan Janssen's avatar
Christiaan Janssen committed
358

359
                onEndTimeChanged: requestPaint()
360
361
                onYChanged: requestPaint()
                onHeightChanged: requestPaint()
362

363
364
                function updateZoomControl() {
                    var newStartTime = Math.round(flick.contentX * (endTime - startTime) / flick.width) +
365
366
                            qmlProfilerModelProxy.traceStartTime();
                    if (Math.abs(newStartTime - startTime) > 1) {
367
                        var newEndTime = Math.round((flick.contentX + flick.width) *
368
369
370
371
372
373
                                                    (endTime - startTime) /
                                                    flick.width) +
                                                    qmlProfilerModelProxy.traceStartTime();
                        zoomControl.setRange(newStartTime, newEndTime);
                    }
                }
374

375
376
377
378
379
380
                function updateFlickRange(start, end) {
                    if (start !== startTime || end !== endTime) {
                        startTime = start;
                        endTime = end;
                        var newStartX = (startTime - qmlProfilerModelProxy.traceStartTime()) *
                                flick.width / (endTime-startTime);
381
382
                        if (isFinite(newStartX) && Math.abs(newStartX - flick.contentX) >= 1)
                            flick.contentX = newStartX;
383
                    }
384
                }
385

386
387
388
389
390
                onSelectedItemChanged: {
                    if (selectedItem !== -1) {
                        // display details
                        rangeDetails.showInfo(qmlProfilerModelProxy.getEventDetails(selectedModel, selectedItem));
                        rangeDetails.setLocation(qmlProfilerModelProxy.getEventLocation(selectedModel, selectedItem));
391

392
393
394
395
396
                        // center view (horizontally)
                        var windowLength = view.endTime - view.startTime;
                        var eventStartTime = qmlProfilerModelProxy.getStartTime(selectedModel, selectedItem);
                        var eventEndTime = eventStartTime +
                                qmlProfilerModelProxy.getDuration(selectedModel, selectedItem);
397

398
399
400
401
                        if (eventEndTime < view.startTime || eventStartTime > view.endTime) {
                            var center = (eventStartTime + eventEndTime)/2;
                            var from = Math.min(qmlProfilerModelProxy.traceEndTime()-windowLength,
                                                Math.max(0, Math.floor(center - windowLength/2)));
402

403
                            zoomControl.setRange(from, from + windowLength);
Christiaan Janssen's avatar
Christiaan Janssen committed
404

405
406
407
                        }
                    } else {
                        root.hideRangeDetails();
408
                    }
409
                }
410

411
412
413
414
415
                onItemPressed: {
                    var location = qmlProfilerModelProxy.getEventLocation(modelIndex, pressedItem);
                    if (location.hasOwnProperty("file")) // not empty
                        root.gotoSourceLocation(location.file, location.line, location.column);
                }
416

417
             // hack to pass mouse events to the other mousearea if enabled
418
419
                startDragArea: selectionRange.ready ? selectionRange.getLeft() : -flick.contentX
                endDragArea: selectionRange.ready ? selectionRange.getRight() : -flick.contentX-1
420
            }
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
            MouseArea {
                id: selectionRangeControl
                enabled: false
                width: flick.width
                height: flick.height
                x: flick.contentX
                hoverEnabled: enabled
                z: 2

                onReleased:  {
                    selectionRange.releasedOnCreation();
                }
                onPressed:  {
                    selectionRange.pressedOnCreation();
                }
436
437
438
                onCanceled: {
                    selectionRange.releasedOnCreation();
                }
439
440
441
                onPositionChanged: {
                    selectionRange.movedOnCreation();
                }
442
            }
Christiaan Janssen's avatar
Christiaan Janssen committed
443
444
        }

445
446
447
448
449
450
451
452
453
454
455
456
457
458
        Rectangle {
            id: labels
            width: 150
            color: "#dcdcdc"
            height: col.height

            property int rowCount: qmlProfilerModelProxy.categories();

            Column {
                id: col
                Repeater {
                    model: labels.rowCount
                    delegate: CategoryLabel { }
                }
459
            }
Christiaan Janssen's avatar
Christiaan Janssen committed
460
        }
461

462
        Rectangle {
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
            id: labelsTail
            anchors.top: labels.bottom
            height: Math.max(0, vertflick.height - labels.height)
            width: labels.width
            color: labels.color
        }

        // Gradient borders
        Item {
            anchors.left: labels.right
            anchors.top: labels.top
            anchors.bottom: labelsTail.bottom
            width: 6
            Rectangle {
                x: parent.width
                transformOrigin: Item.TopLeft
                rotation: 90
                width: parent.height
                height: parent.width
                gradient: Gradient {
                    GradientStop { position: 0.0; color: "#00000000"; }
                    GradientStop { position: 1.0; color: "#86000000"; }
                }
486
487
488
            }
        }
    }
489

490
491
492
493
494
    ScrollView {
        contentItem: vertflick
        anchors.fill: parent
    }

495
496
497
498
499
500
    SelectionRangeDetails {
        id: selectionRangeDetails
        visible: root.selectionRangeMode
        startTime: selectionRange.startTimeString
        duration: selectionRange.durationString
        endTime: selectionRange.endTimeString
501
        showDuration: selectionRange.getWidth() > 1
502
503
504
505
506
    }

    RangeDetails {
        id: rangeDetails
    }
507

508
509
510
511
512
513
514
515
516
517
    Rectangle {
        objectName: "zoomSliderToolBar"
        color: "#9b9b9b"
        enabled: false
        visible: false
        width: labels.width
        height: 24
        x: 0
        y: 0

518
519
520
521
522
        function updateZoomLevel() {
            zoomSlider.externalUpdate = true;
            zoomSlider.value = Math.pow((view.endTime - view.startTime) / qmlProfilerModelProxy.traceDuration(), 1 / zoomSlider.exponent) * zoomSlider.maximumValue;
        }

523
524
525
526
527
528
529
530

        Slider {
            id: zoomSlider
            anchors.fill: parent
            minimumValue: 1
            maximumValue: 10000
            stepSize: 100

531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
            property int exponent: 3
            property bool externalUpdate: false
            property int minWindowLength: 1e5 // 0.1 ms

            onValueChanged: {
                if (externalUpdate || qmlProfilerModelProxy.traceEndTime() <= qmlProfilerModelProxy.traceStartTime()) {
                    // Zoom range is independently updated. We shouldn't mess
                    // with it here as otherwise we might introduce rounding
                    // or arithmetic errors.
                    externalUpdate = false;
                    return;
                }

                var windowLength = Math.max(
                            Math.pow(value / maximumValue, exponent) * qmlProfilerModelProxy.traceDuration(),
                            minWindowLength);

                var fixedPoint = (view.startTime + view.endTime) / 2;
                if (view.selectedItem !== -1) {
                    // center on selected item if it's inside the current screen
                    var newFixedPoint = qmlProfilerModelProxy.getStartTime(view.selectedModel, view.selectedItem);
                    if (newFixedPoint >= view.startTime && newFixedPoint < view.endTime)
                        fixedPoint = newFixedPoint;
                }

                var startTime = Math.max(qmlProfilerModelProxy.traceStartTime(), fixedPoint - windowLength / 2)
                zoomControl.setRange(startTime, startTime + windowLength);
            }
559
560
561
        }
    }

562
563
564
565
566
567
568
569
570
571
572
573
    Item {
        anchors.right: root.right
        width: 6
        anchors.top: root.top
        anchors.bottom: root.bottom
        Rectangle {
            x: parent.width
            transformOrigin: Item.TopLeft
            rotation: 90
            width: parent.height
            height: parent.width
            gradient: Gradient {
574
575
                GradientStop { position: 0.0; color: "#86000000"; }
                GradientStop { position: 1.0; color: "#00000000"; }
576
577
578
579
580
            }
        }
    }

    Rectangle {
581
        y: root.height - height
582
583
584
585
        height: 6
        width: root.width
        x: 0
        gradient: Gradient {
586
587
            GradientStop { position: 0.0; color: "#00000000"; }
            GradientStop { position: 1.0; color: "#86000000"; }
588
589
        }
    }
Christiaan Janssen's avatar
Christiaan Janssen committed
590
}