forked from qt-creator/qt-creator
QmlProfiler: Refactor
The code of the qmlprofiler client has become a bit too complex, this patch reorganizes the modules in a more sensible way, having the modules communicate with each other through a state machine instead of the excess of signals and slots from before. Change-Id: I76f7313779888a1bd07a1cdb1acbf2e47aacf42a Reviewed-by: Kai Koehne <kai.koehne@nokia.com>
This commit is contained in:
@@ -7,11 +7,11 @@ contains(CONFIG, dll) {
|
||||
INCLUDEPATH += $$PWD/..
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/qmlprofilereventlocation.h \
|
||||
$$PWD/qdeclarativedebugclient.h \
|
||||
$$PWD/qdeclarativeenginedebug.h \
|
||||
$$PWD/qdeclarativeoutputparser.h \
|
||||
$$PWD/qmljsdebugclient_global.h \
|
||||
$$PWD/qmlprofilereventlist.h \
|
||||
$$PWD/qmlprofilereventtypes.h \
|
||||
$$PWD/qmlprofilertraceclient.h \
|
||||
$$PWD/qpacketprotocol.h \
|
||||
@@ -23,7 +23,6 @@ SOURCES += \
|
||||
$$PWD/qdeclarativedebugclient.cpp \
|
||||
$$PWD/qdeclarativeenginedebug.cpp \
|
||||
$$PWD/qdeclarativeoutputparser.cpp \
|
||||
$$PWD/qmlprofilereventlist.cpp \
|
||||
$$PWD/qmlprofilertraceclient.cpp \
|
||||
$$PWD/qpacketprotocol.cpp \
|
||||
$$PWD/qv8profilerclient.cpp \
|
||||
|
@@ -11,6 +11,3 @@ OTHER_FILES += \
|
||||
qmljsdebugclient.pri \
|
||||
qmljsdebugclient-lib.pri
|
||||
|
||||
HEADERS += \
|
||||
qmlprofilereventlocation.h
|
||||
|
||||
|
@@ -24,7 +24,7 @@ DynamicLibrary {
|
||||
"qdeclarativeoutputparser.h",
|
||||
"qmljsdebugclient_global.h",
|
||||
"qmljsdebugclientconstants.h",
|
||||
"qmlprofilereventlist.h",
|
||||
"qmlprofilereventlocation.h",
|
||||
"qmlprofilertraceclient.cpp",
|
||||
"qpacketprotocol.cpp",
|
||||
"qv8profilerclient.cpp",
|
||||
@@ -36,7 +36,6 @@ DynamicLibrary {
|
||||
"qmlprofilertraceclient.h",
|
||||
"qpacketprotocol.h",
|
||||
"qdebugmessageclient.cpp",
|
||||
"qmlprofilereventlist.cpp",
|
||||
"qdebugmessageclient.h"
|
||||
]
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,8 @@
|
||||
|
||||
#include "qmljsdebugclient_global.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace QmlJsDebugClient {
|
||||
|
||||
struct QMLJSDEBUGCLIENT_EXPORT QmlEventLocation
|
||||
|
@@ -33,8 +33,6 @@
|
||||
#ifndef QMLPROFILEREVENTTYPES_H
|
||||
#define QMLPROFILEREVENTTYPES_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace QmlJsDebugClient {
|
||||
|
||||
enum QmlEventType {
|
||||
@@ -47,8 +45,15 @@ enum QmlEventType {
|
||||
MaximumQmlEventType
|
||||
};
|
||||
|
||||
QString qmlEventType(QmlEventType typeEnum);
|
||||
QmlEventType qmlEventType(const QString &typeString);
|
||||
namespace Constants {
|
||||
const char TYPE_PAINTING_STR[] = "Painting";
|
||||
const char TYPE_COMPILING_STR[] = "Compiling";
|
||||
const char TYPE_CREATING_STR[] = "Creating";
|
||||
const char TYPE_BINDING_STR[] = "Binding";
|
||||
const char TYPE_HANDLINGSIGNAL_STR[] = "HandlingSignal";
|
||||
const char PROFILER_FILE_VERSION[] = "1.02";
|
||||
const int QML_MIN_LEVEL = 1;
|
||||
}
|
||||
|
||||
} // namespace QmlJsDebugClient
|
||||
|
||||
|
@@ -159,6 +159,12 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
|
||||
int event;
|
||||
stream >> event;
|
||||
|
||||
// stop with the first data
|
||||
if (d->recording && event != StartTrace)
|
||||
setRecordingFromServer(false);
|
||||
else if ((!d->recording) && event == StartTrace)
|
||||
setRecordingFromServer(true);
|
||||
|
||||
if (event == EndTrace) {
|
||||
emit this->traceFinished(time);
|
||||
d->maximumTime = time;
|
||||
@@ -169,9 +175,6 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
|
||||
emit this->frame(time, frameRate, animationCount);
|
||||
d->maximumTime = qMax(time, d->maximumTime);
|
||||
} else if (event == StartTrace) {
|
||||
// special: StartTrace is now asynchronous
|
||||
if (!d->recording)
|
||||
setRecordingFromServer(true);
|
||||
emit this->traceStarted(time);
|
||||
d->maximumTime = time;
|
||||
} else if (event < MaximumEventType) {
|
||||
@@ -191,6 +194,9 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
|
||||
d->rangeStartTimes[range].push(time);
|
||||
d->inProgressRanges |= (static_cast<qint64>(1) << range);
|
||||
++d->rangeCount[range];
|
||||
// stop with the first data
|
||||
if (d->recording)
|
||||
setRecordingFromServer(false);
|
||||
} else if (messageType == RangeData) {
|
||||
QString data;
|
||||
stream >> data;
|
||||
|
@@ -80,10 +80,9 @@ public:
|
||||
|
||||
bool isEnabled() const;
|
||||
bool isRecording() const;
|
||||
void setRecording(bool);
|
||||
|
||||
public slots:
|
||||
void setRecording(bool);
|
||||
void setRecordingFromServer(bool);
|
||||
void clearData();
|
||||
void sendRecordingStatus();
|
||||
|
||||
@@ -106,6 +105,9 @@ protected:
|
||||
virtual void statusChanged(Status);
|
||||
virtual void messageReceived(const QByteArray &);
|
||||
|
||||
private:
|
||||
void setRecordingFromServer(bool);
|
||||
|
||||
private:
|
||||
class QmlProfilerTraceClientPrivate *d;
|
||||
};
|
||||
|
@@ -118,6 +118,16 @@ void QV8ProfilerClient::setRecording(bool v)
|
||||
emit recordingChanged(v);
|
||||
}
|
||||
|
||||
void QV8ProfilerClient::setRecordingFromServer(bool v)
|
||||
{
|
||||
if (v == d->recording)
|
||||
return;
|
||||
|
||||
d->recording = v;
|
||||
|
||||
emit recordingChanged(v);
|
||||
}
|
||||
|
||||
void QV8ProfilerClient::statusChanged(Status /*status*/)
|
||||
{
|
||||
emit enabledChanged();
|
||||
@@ -133,7 +143,10 @@ void QV8ProfilerClient::messageReceived(const QByteArray &data)
|
||||
stream >> messageType;
|
||||
|
||||
if (messageType == V8Complete) {
|
||||
setRecordingFromServer(false);
|
||||
emit complete();
|
||||
} else if (messageType == V8ProfilingStarted) {
|
||||
setRecordingFromServer(true);
|
||||
} else if (messageType == V8Entry) {
|
||||
QString filename;
|
||||
QString function;
|
||||
|
@@ -52,6 +52,9 @@ public:
|
||||
enum Message {
|
||||
V8Entry,
|
||||
V8Complete,
|
||||
V8SnapshotChunk,
|
||||
V8SnapshotComplete,
|
||||
V8ProfilingStarted,
|
||||
|
||||
V8MaximumMessage
|
||||
};
|
||||
@@ -61,9 +64,9 @@ public:
|
||||
|
||||
bool isEnabled() const;
|
||||
bool isRecording() const;
|
||||
void setRecording(bool);
|
||||
|
||||
public slots:
|
||||
void setRecording(bool);
|
||||
void clearData();
|
||||
void sendRecordingStatus();
|
||||
|
||||
@@ -77,6 +80,9 @@ signals:
|
||||
void enabledChanged();
|
||||
void cleared();
|
||||
|
||||
private:
|
||||
void setRecordingFromServer(bool);
|
||||
|
||||
protected:
|
||||
virtual void statusChanged(Status);
|
||||
virtual void messageReceived(const QByteArray &);
|
||||
|
@@ -60,17 +60,19 @@ Item {
|
||||
|
||||
function updateHeight() {
|
||||
height = root.singleRowHeight * (1 +
|
||||
(expanded ? qmlEventList.uniqueEventsOfType(typeIndex) : qmlEventList.maxNestingForType(typeIndex)));
|
||||
(expanded ? qmlProfilerDataModel.uniqueEventsOfType(typeIndex) :
|
||||
qmlProfilerDataModel.maxNestingForType(typeIndex)));
|
||||
}
|
||||
|
||||
function getDescriptions() {
|
||||
var desc=[];
|
||||
var ids=[];
|
||||
var extdesc=[];
|
||||
for (var i=0; i<qmlEventList.uniqueEventsOfType(typeIndex); i++) {
|
||||
desc[i] = qmlEventList.eventTextForType(typeIndex, i);
|
||||
ids[i] = qmlEventList.eventIdForType(typeIndex, i);
|
||||
extdesc[i] = qmlEventList.eventDisplayNameForType(typeIndex, i) + " : " + desc[i];
|
||||
for (var i=0; i<qmlProfilerDataModel.uniqueEventsOfType(typeIndex); i++) {
|
||||
desc[i] = qmlProfilerDataModel.eventTextForType(typeIndex, i);
|
||||
ids[i] = qmlProfilerDataModel.eventIdForType(typeIndex, i);
|
||||
extdesc[i] = qmlProfilerDataModel.eventDisplayNameForType(typeIndex, i) +
|
||||
" : " + desc[i];
|
||||
}
|
||||
descriptions = desc;
|
||||
eventIds = ids;
|
||||
@@ -79,18 +81,18 @@ Item {
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: qmlEventList
|
||||
target: qmlProfilerDataModel
|
||||
onReloadDetailLabels: getDescriptions();
|
||||
onStateChanged: {
|
||||
// Empty
|
||||
if (qmlEventList.getCurrentStateFromQml() == 0) {
|
||||
if (qmlProfilerDataModel.getCurrentStateFromQml() == 0) {
|
||||
descriptions = [];
|
||||
eventIds = [];
|
||||
extdescriptions = [];
|
||||
updateHeight();
|
||||
} else
|
||||
// Done
|
||||
if (qmlEventList.getCurrentStateFromQml() == 3) {
|
||||
if (qmlProfilerDataModel.getCurrentStateFromQml() == 3) {
|
||||
getDescriptions();
|
||||
}
|
||||
}
|
||||
|
@@ -51,11 +51,16 @@ Rectangle {
|
||||
property alias selectionLocked : view.selectionLocked
|
||||
signal updateLockButton
|
||||
property alias selectedItem: view.selectedItem
|
||||
signal selectedEventIdChanged(int eventId)
|
||||
signal selectedEventChanged(int eventId)
|
||||
property bool lockItemSelection : false
|
||||
|
||||
property variant names: [ qsTr("Painting"), qsTr("Compiling"), qsTr("Creating"), qsTr("Binding"), qsTr("Handling Signal")]
|
||||
property variant colors : [ "#99CCB3", "#99CCCC", "#99B3CC", "#9999CC", "#CC99B3", "#CC99CC", "#CCCC99", "#CCB399" ]
|
||||
property variant names: [ qsTr("Painting"),
|
||||
qsTr("Compiling"),
|
||||
qsTr("Creating"),
|
||||
qsTr("Binding"),
|
||||
qsTr("Handling Signal")]
|
||||
property variant colors : [ "#99CCB3", "#99CCCC", "#99B3CC",
|
||||
"#9999CC", "#CC99B3", "#CC99CC", "#CCCC99", "#CCB399" ]
|
||||
|
||||
property variant mainviewTimePerPixel : 0
|
||||
|
||||
@@ -64,9 +69,6 @@ Rectangle {
|
||||
property int lineNumber: -1
|
||||
property int columnNumber: 0
|
||||
|
||||
property real elapsedTime
|
||||
signal updateTimer
|
||||
|
||||
signal updateRangeButton
|
||||
property bool selectionRangeMode: false
|
||||
|
||||
@@ -77,7 +79,11 @@ Rectangle {
|
||||
signal changeToolTip(string text)
|
||||
signal updateVerticalScroll(int newPosition)
|
||||
|
||||
property bool applicationDied : false
|
||||
property bool recordingEnabled: false
|
||||
property bool appKilled : false
|
||||
|
||||
property date recordingStartDate
|
||||
property real elapsedTime
|
||||
|
||||
// ***** connections with external objects
|
||||
Connections {
|
||||
@@ -92,7 +98,8 @@ Rectangle {
|
||||
backgroundMarks.updateMarks(startTime, endTime);
|
||||
view.updateFlickRange(startTime, endTime);
|
||||
if (duration > 0) {
|
||||
var candidateWidth = qmlEventList.traceDuration() * flick.width / duration;
|
||||
var candidateWidth = qmlProfilerDataModel.traceDuration() *
|
||||
flick.width / duration;
|
||||
if (flick.contentWidth !== candidateWidth)
|
||||
flick.contentWidth = candidateWidth;
|
||||
}
|
||||
@@ -101,20 +108,21 @@ Rectangle {
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: qmlEventList
|
||||
target: qmlProfilerDataModel
|
||||
onCountChanged: {
|
||||
eventCount = qmlEventList.count();
|
||||
eventCount = qmlProfilerDataModel.count();
|
||||
if (eventCount === 0)
|
||||
root.clearAll();
|
||||
if (eventCount > 1) {
|
||||
root.progress = Math.min(1.0,
|
||||
(qmlEventList.lastTimeMark() - qmlEventList.traceStartTime()) / root.elapsedTime * 1e-9 );
|
||||
(qmlProfilerDataModel.lastTimeMark() -
|
||||
qmlProfilerDataModel.traceStartTime()) / root.elapsedTime * 1e-9 );
|
||||
} else {
|
||||
root.progress = 0;
|
||||
}
|
||||
}
|
||||
onStateChanged: {
|
||||
switch (qmlEventList.getCurrentStateFromQml()) {
|
||||
switch (qmlProfilerDataModel.getCurrentStateFromQml()) {
|
||||
case 0: {
|
||||
root.clearAll();
|
||||
break;
|
||||
@@ -133,7 +141,9 @@ Rectangle {
|
||||
dataAvailable = true;
|
||||
view.visible = true;
|
||||
view.requestPaint();
|
||||
zoomControl.setRange(qmlEventList.traceStartTime(), qmlEventList.traceStartTime() + qmlEventList.traceDuration()/10);
|
||||
zoomControl.setRange(qmlProfilerDataModel.traceStartTime(),
|
||||
qmlProfilerDataModel.traceStartTime() +
|
||||
qmlProfilerDataModel.traceDuration()/10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -151,7 +161,7 @@ Rectangle {
|
||||
function clearData() {
|
||||
view.clearData();
|
||||
dataAvailable = false;
|
||||
applicationDied = false;
|
||||
appKilled = false;
|
||||
eventCount = 0;
|
||||
hideRangeDetails();
|
||||
selectionRangeMode = false;
|
||||
@@ -166,8 +176,6 @@ Rectangle {
|
||||
|
||||
function clearAll() {
|
||||
clearDisplay();
|
||||
root.elapsedTime = 0;
|
||||
root.updateTimer();
|
||||
}
|
||||
|
||||
function nextEvent() {
|
||||
@@ -180,9 +188,10 @@ Rectangle {
|
||||
|
||||
function updateWindowLength(absoluteFactor) {
|
||||
var windowLength = view.endTime - view.startTime;
|
||||
if (qmlEventList.traceEndTime() <= qmlEventList.traceStartTime() || windowLength <= 0)
|
||||
if (qmlProfilerDataModel.traceEndTime() <= qmlProfilerDataModel.traceStartTime() ||
|
||||
windowLength <= 0)
|
||||
return;
|
||||
var currentFactor = windowLength / qmlEventList.traceDuration();
|
||||
var currentFactor = windowLength / qmlProfilerDataModel.traceDuration();
|
||||
updateZoom(absoluteFactor / currentFactor);
|
||||
}
|
||||
|
||||
@@ -193,8 +202,8 @@ Rectangle {
|
||||
windowLength = min_length;
|
||||
var newWindowLength = windowLength * relativeFactor;
|
||||
|
||||
if (newWindowLength > qmlEventList.traceDuration()) {
|
||||
newWindowLength = qmlEventList.traceDuration();
|
||||
if (newWindowLength > qmlProfilerDataModel.traceDuration()) {
|
||||
newWindowLength = qmlProfilerDataModel.traceDuration();
|
||||
relativeFactor = newWindowLength / windowLength;
|
||||
}
|
||||
if (newWindowLength < min_length) {
|
||||
@@ -205,7 +214,7 @@ Rectangle {
|
||||
var fixedPoint = (view.startTime + view.endTime) / 2;
|
||||
if (view.selectedItem !== -1) {
|
||||
// center on selected item if it's inside the current screen
|
||||
var newFixedPoint = qmlEventList.getStartTime(view.selectedItem);
|
||||
var newFixedPoint = qmlProfilerDataModel.getStartTime(view.selectedItem);
|
||||
if (newFixedPoint >= view.startTime && newFixedPoint < view.endTime)
|
||||
fixedPoint = newFixedPoint;
|
||||
}
|
||||
@@ -222,8 +231,8 @@ Rectangle {
|
||||
windowLength = min_length;
|
||||
var newWindowLength = windowLength * relativeFactor;
|
||||
|
||||
if (newWindowLength > qmlEventList.traceDuration()) {
|
||||
newWindowLength = qmlEventList.traceDuration();
|
||||
if (newWindowLength > qmlProfilerDataModel.traceDuration()) {
|
||||
newWindowLength = qmlProfilerDataModel.traceDuration();
|
||||
relativeFactor = newWindowLength / windowLength;
|
||||
}
|
||||
if (newWindowLength < min_length) {
|
||||
@@ -241,8 +250,8 @@ Rectangle {
|
||||
var newStart = Math.floor(centerPoint - windowLength/2);
|
||||
if (newStart < 0)
|
||||
newStart = 0;
|
||||
if (newStart + windowLength > qmlEventList.traceEndTime())
|
||||
newStart = qmlEventList.traceEndTime() - windowLength;
|
||||
if (newStart + windowLength > qmlProfilerDataModel.traceEndTime())
|
||||
newStart = qmlProfilerDataModel.traceEndTime() - windowLength;
|
||||
zoomControl.setRange(newStart, newStart + windowLength);
|
||||
}
|
||||
|
||||
@@ -252,17 +261,16 @@ Rectangle {
|
||||
return;
|
||||
|
||||
// if item is outside of the view, jump back to its position
|
||||
if (qmlEventList.getEndTime(itemIndex) < view.startTime || qmlEventList.getStartTime(itemIndex) > view.endTime) {
|
||||
recenter((qmlEventList.getStartTime(itemIndex) + qmlEventList.getEndTime(itemIndex)) / 2);
|
||||
if (qmlProfilerDataModel.getEndTime(itemIndex) < view.startTime ||
|
||||
qmlProfilerDataModel.getStartTime(itemIndex) > view.endTime) {
|
||||
recenter((qmlProfilerDataModel.getStartTime(itemIndex) +
|
||||
qmlProfilerDataModel.getEndTime(itemIndex)) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
function globalZoom() {
|
||||
zoomControl.setRange(qmlEventList.traceStartTime(), qmlEventList.traceEndTime());
|
||||
}
|
||||
|
||||
function wheelZoom(wheelCenter, wheelDelta) {
|
||||
if (qmlEventList.traceEndTime() > qmlEventList.traceStartTime() && wheelDelta !== 0) {
|
||||
if (qmlProfilerDataModel.traceEndTime() > qmlProfilerDataModel.traceStartTime() &&
|
||||
wheelDelta !== 0) {
|
||||
if (wheelDelta>0)
|
||||
updateZoomCentered(wheelCenter, 1/1.2);
|
||||
else
|
||||
@@ -311,34 +319,22 @@ Rectangle {
|
||||
onSelectedItemChanged: {
|
||||
if (selectedItem != -1 && !lockItemSelection) {
|
||||
lockItemSelection = true;
|
||||
selectedEventIdChanged( qmlEventList.getEventId(selectedItem) );
|
||||
selectedEventChanged( qmlProfilerDataModel.getEventId(selectedItem) );
|
||||
lockItemSelection = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ***** child items
|
||||
Timer {
|
||||
id: elapsedTimer
|
||||
property date startDate
|
||||
property bool reset: true
|
||||
running: connection.recording && connection.enabled
|
||||
repeat: true
|
||||
onRunningChanged: {
|
||||
if (running) reset = true;
|
||||
}
|
||||
interval: 100
|
||||
triggeredOnStart: true
|
||||
onTriggered: {
|
||||
if (reset) {
|
||||
startDate = new Date();
|
||||
reset = false;
|
||||
}
|
||||
var time = (new Date() - startDate)/1000;
|
||||
root.elapsedTime = time.toFixed(1);
|
||||
root.updateTimer();
|
||||
onRecordingEnabledChanged: {
|
||||
if (recordingEnabled) {
|
||||
recordingStartDate = new Date();
|
||||
elapsedTime = 0;
|
||||
} else {
|
||||
elapsedTime = (new Date() - recordingStartDate)/1000.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ***** child items
|
||||
TimeMarks {
|
||||
id: backgroundMarks
|
||||
y: labels.y
|
||||
@@ -380,7 +376,8 @@ Rectangle {
|
||||
selectionRange.isDragging = false;
|
||||
}
|
||||
onDoubleClicked: {
|
||||
zoomControl.setRange(selectionRange.startTime, selectionRange.startTime + selectionRange.duration);
|
||||
zoomControl.setRange(selectionRange.startTime,
|
||||
selectionRange.startTime + selectionRange.duration);
|
||||
root.selectionRangeMode = false;
|
||||
root.updateRangeButton();
|
||||
}
|
||||
@@ -394,10 +391,10 @@ Rectangle {
|
||||
z: 2
|
||||
}
|
||||
|
||||
TimelineView {
|
||||
TimelineRenderer {
|
||||
id: view
|
||||
|
||||
eventList: qmlEventList
|
||||
profilerDataModel: qmlProfilerDataModel
|
||||
|
||||
x: flick.contentX
|
||||
width: flick.width
|
||||
@@ -405,9 +402,13 @@ Rectangle {
|
||||
|
||||
property variant startX: 0
|
||||
onStartXChanged: {
|
||||
var newStartTime = Math.round(startX * (endTime - startTime) / flick.width) + qmlEventList.traceStartTime();
|
||||
var newStartTime = Math.round(startX * (endTime - startTime) / flick.width) +
|
||||
qmlProfilerDataModel.traceStartTime();
|
||||
if (Math.abs(newStartTime - startTime) > 1) {
|
||||
var newEndTime = Math.round((startX+flick.width)* (endTime - startTime) / flick.width) + qmlEventList.traceStartTime();
|
||||
var newEndTime = Math.round((startX+flick.width) *
|
||||
(endTime - startTime) /
|
||||
flick.width) +
|
||||
qmlProfilerDataModel.traceStartTime();
|
||||
zoomControl.setRange(newStartTime, newEndTime);
|
||||
}
|
||||
|
||||
@@ -419,7 +420,8 @@ Rectangle {
|
||||
if (start !== startTime || end !== endTime) {
|
||||
startTime = start;
|
||||
endTime = end;
|
||||
var newStartX = (startTime - qmlEventList.traceStartTime()) * flick.width / (endTime-startTime);
|
||||
var newStartX = (startTime - qmlProfilerDataModel.traceStartTime()) *
|
||||
flick.width / (endTime-startTime);
|
||||
if (Math.abs(newStartX - startX) >= 1)
|
||||
startX = newStartX;
|
||||
}
|
||||
@@ -428,24 +430,25 @@ Rectangle {
|
||||
onSelectedItemChanged: {
|
||||
if (selectedItem !== -1) {
|
||||
// display details
|
||||
rangeDetails.duration = qmlEventList.getDuration(selectedItem)/1000.0;
|
||||
rangeDetails.label = qmlEventList.getDetails(selectedItem);
|
||||
rangeDetails.file = qmlEventList.getFilename(selectedItem);
|
||||
rangeDetails.line = qmlEventList.getLine(selectedItem);
|
||||
rangeDetails.column = qmlEventList.getColumn(selectedItem);
|
||||
rangeDetails.type = root.names[qmlEventList.getType(selectedItem)];
|
||||
rangeDetails.isBindingLoop = qmlEventList.getBindingLoopDest(selectedItem)!==-1;
|
||||
rangeDetails.duration = qmlProfilerDataModel.getDuration(selectedItem)/1000.0;
|
||||
rangeDetails.label = qmlProfilerDataModel.getDetails(selectedItem);
|
||||
rangeDetails.file = qmlProfilerDataModel.getFilename(selectedItem);
|
||||
rangeDetails.line = qmlProfilerDataModel.getLine(selectedItem);
|
||||
rangeDetails.column = qmlProfilerDataModel.getColumn(selectedItem);
|
||||
rangeDetails.type = root.names[qmlProfilerDataModel.getType(selectedItem)];
|
||||
rangeDetails.isBindingLoop = qmlProfilerDataModel.getBindingLoopDest(selectedItem)!==-1;
|
||||
|
||||
rangeDetails.visible = true;
|
||||
|
||||
// center view (horizontally)
|
||||
var windowLength = view.endTime - view.startTime;
|
||||
var eventStartTime = qmlEventList.getStartTime(selectedItem);
|
||||
var eventEndTime = eventStartTime + qmlEventList.getDuration(selectedItem);
|
||||
var eventStartTime = qmlProfilerDataModel.getStartTime(selectedItem);
|
||||
var eventEndTime = eventStartTime +
|
||||
qmlProfilerDataModel.getDuration(selectedItem);
|
||||
|
||||
if (eventEndTime < view.startTime || eventStartTime > view.endTime) {
|
||||
var center = (eventStartTime + eventEndTime)/2;
|
||||
var from = Math.min(qmlEventList.traceEndTime()-windowLength,
|
||||
var from = Math.min(qmlProfilerDataModel.traceEndTime()-windowLength,
|
||||
Math.max(0, Math.floor(center - windowLength/2)));
|
||||
|
||||
zoomControl.setRange(from, from + windowLength);
|
||||
@@ -456,8 +459,10 @@ Rectangle {
|
||||
if (itemY < root.scrollY) {
|
||||
root.updateVerticalScroll(itemY);
|
||||
} else
|
||||
if (itemY + root.singleRowHeight > root.scrollY + root.candidateHeight) {
|
||||
root.updateVerticalScroll(itemY + root.singleRowHeight - root.candidateHeight);
|
||||
if (itemY + root.singleRowHeight >
|
||||
root.scrollY + root.candidateHeight) {
|
||||
root.updateVerticalScroll(itemY + root.singleRowHeight -
|
||||
root.candidateHeight);
|
||||
}
|
||||
} else {
|
||||
root.hideRangeDetails();
|
||||
@@ -466,14 +471,18 @@ Rectangle {
|
||||
|
||||
onItemPressed: {
|
||||
if (pressedItem !== -1) {
|
||||
root.gotoSourceLocation(qmlEventList.getFilename(pressedItem), qmlEventList.getLine(pressedItem), qmlEventList.getColumn(pressedItem));
|
||||
root.gotoSourceLocation(qmlProfilerDataModel.getFilename(pressedItem),
|
||||
qmlProfilerDataModel.getLine(pressedItem),
|
||||
qmlProfilerDataModel.getColumn(pressedItem));
|
||||
}
|
||||
}
|
||||
|
||||
// hack to pass mouse events to the other mousearea if enabled
|
||||
startDragArea: selectionRangeDrag.enabled ? selectionRangeDrag.x : -flick.contentX
|
||||
startDragArea: selectionRangeDrag.enabled ? selectionRangeDrag.x :
|
||||
-flick.contentX
|
||||
endDragArea: selectionRangeDrag.enabled ?
|
||||
selectionRangeDrag.x + selectionRangeDrag.width : -flick.contentX-1
|
||||
selectionRangeDrag.x + selectionRangeDrag.width :
|
||||
-flick.contentX-1
|
||||
}
|
||||
MouseArea {
|
||||
id: selectionRangeControl
|
||||
|
@@ -32,7 +32,7 @@
|
||||
|
||||
.pragma library
|
||||
|
||||
var qmlEventList = 0;
|
||||
var qmlProfilerDataModel = 0;
|
||||
|
||||
//draw background of the graph
|
||||
function drawGraph(canvas, ctxt, region)
|
||||
@@ -44,7 +44,7 @@ function drawGraph(canvas, ctxt, region)
|
||||
//draw the actual data to be graphed
|
||||
function drawData(canvas, ctxt, region)
|
||||
{
|
||||
if ((!qmlEventList) || qmlEventList.count() == 0)
|
||||
if ((!qmlProfilerDataModel) || qmlProfilerDataModel.count() == 0)
|
||||
return;
|
||||
|
||||
var typeCount = 5;
|
||||
@@ -53,17 +53,18 @@ function drawData(canvas, ctxt, region)
|
||||
var height = canvas.height - bump;
|
||||
var blockHeight = height / typeCount;
|
||||
|
||||
var spacing = width / qmlEventList.traceDuration();
|
||||
var spacing = width / qmlProfilerDataModel.traceDuration();
|
||||
|
||||
var highest = [0,0,0,0,0]; // note: change if typeCount changes
|
||||
|
||||
for (var ii = 0; ii < qmlEventList.count(); ++ii) {
|
||||
for (var ii = 0; ii < qmlProfilerDataModel.count(); ++ii) {
|
||||
|
||||
var xx = (qmlEventList.getStartTime(ii) - qmlEventList.traceStartTime()) * spacing;
|
||||
var xx = (qmlProfilerDataModel.getStartTime(ii) -
|
||||
qmlProfilerDataModel.traceStartTime()) * spacing;
|
||||
if (xx > region.x + region.width)
|
||||
continue;
|
||||
|
||||
var eventWidth = qmlEventList.getDuration(ii) * spacing;
|
||||
var eventWidth = qmlProfilerDataModel.getDuration(ii) * spacing;
|
||||
if (xx + eventWidth < region.x)
|
||||
continue;
|
||||
|
||||
@@ -71,24 +72,26 @@ function drawData(canvas, ctxt, region)
|
||||
eventWidth = 1;
|
||||
|
||||
xx = Math.round(xx);
|
||||
var ty = qmlEventList.getType(ii);
|
||||
var ty = qmlProfilerDataModel.getType(ii);
|
||||
if (xx + eventWidth > highest[ty]) {
|
||||
// special: animations
|
||||
if (ty === 0 && qmlEventList.getAnimationCount(ii) >= 0) {
|
||||
var vertScale = qmlEventList.getMaximumAnimationCount() - qmlEventList.getMinimumAnimationCount();
|
||||
if (ty === 0 && qmlProfilerDataModel.getAnimationCount(ii) >= 0) {
|
||||
var vertScale = qmlProfilerDataModel.getMaximumAnimationCount() -
|
||||
qmlProfilerDataModel.getMinimumAnimationCount();
|
||||
if (vertScale < 1)
|
||||
vertScale = 1;
|
||||
var fraction = (qmlEventList.getAnimationCount(ii) - qmlEventList.getMinimumAnimationCount()) / vertScale;
|
||||
var fraction = (qmlProfilerDataModel.getAnimationCount(ii) -
|
||||
qmlProfilerDataModel.getMinimumAnimationCount()) / vertScale;
|
||||
var eventHeight = blockHeight * (fraction * 0.85 + 0.15);
|
||||
var yy = bump + ty*blockHeight + blockHeight - eventHeight;
|
||||
|
||||
var fpsFraction = qmlEventList.getFramerate(ii) / 60.0;
|
||||
var fpsFraction = qmlProfilerDataModel.getFramerate(ii) / 60.0;
|
||||
if (fpsFraction > 1.0)
|
||||
fpsFraction = 1.0;
|
||||
ctxt.fillStyle = "hsl("+(fpsFraction*0.27+0.028)+",0.3,0.65)";
|
||||
ctxt.fillRect(xx, yy, eventWidth, eventHeight);
|
||||
} else {
|
||||
var hue = ( qmlEventList.getEventId(ii) * 25 ) % 360;
|
||||
var hue = ( qmlProfilerDataModel.getEventId(ii) * 25 ) % 360;
|
||||
ctxt.fillStyle = "hsl("+(hue/360.0+0.001)+",0.3,0.65)";
|
||||
ctxt.fillRect(xx, bump + ty*blockHeight, eventWidth, blockHeight);
|
||||
}
|
||||
@@ -100,12 +103,13 @@ function drawData(canvas, ctxt, region)
|
||||
ctxt.strokeStyle = "orange";
|
||||
ctxt.lineWidth = 2;
|
||||
var radius = 1;
|
||||
for (var ii = 0; ii < qmlEventList.count(); ++ii) {
|
||||
if (qmlEventList.getBindingLoopDest(ii) >= 0) {
|
||||
var xcenter = Math.round(qmlEventList.getStartTime(ii) +
|
||||
qmlEventList.getDuration(ii) -
|
||||
qmlEventList.traceStartTime()) * spacing;
|
||||
var ycenter = Math.round(bump + qmlEventList.getType(ii) * blockHeight + blockHeight/2);
|
||||
for (var ii = 0; ii < qmlProfilerDataModel.count(); ++ii) {
|
||||
if (qmlProfilerDataModel.getBindingLoopDest(ii) >= 0) {
|
||||
var xcenter = Math.round(qmlProfilerDataModel.getStartTime(ii) +
|
||||
qmlProfilerDataModel.getDuration(ii) -
|
||||
qmlProfilerDataModel.traceStartTime()) * spacing;
|
||||
var ycenter = Math.round(bump + qmlProfilerDataModel.getType(ii) *
|
||||
blockHeight + blockHeight/2);
|
||||
ctxt.arc(xcenter, ycenter, radius, 0, 2*Math.PI, true);
|
||||
ctxt.stroke();
|
||||
}
|
||||
@@ -114,19 +118,20 @@ function drawData(canvas, ctxt, region)
|
||||
|
||||
function drawTimeBar(canvas, ctxt, region)
|
||||
{
|
||||
if (!qmlEventList)
|
||||
if (!qmlProfilerDataModel)
|
||||
return;
|
||||
|
||||
var width = canvas.width;
|
||||
var height = 10;
|
||||
var startTime = qmlEventList.traceStartTime();
|
||||
var endTime = qmlEventList.traceEndTime();
|
||||
var startTime = qmlProfilerDataModel.traceStartTime();
|
||||
var endTime = qmlProfilerDataModel.traceEndTime();
|
||||
|
||||
var totalTime = qmlEventList.traceDuration();
|
||||
var totalTime = qmlProfilerDataModel.traceDuration();
|
||||
var spacing = width / totalTime;
|
||||
|
||||
var initialBlockLength = 120;
|
||||
var timePerBlock = Math.pow(2, Math.floor( Math.log( totalTime / width * initialBlockLength ) / Math.LN2 ) );
|
||||
var timePerBlock = Math.pow(2, Math.floor( Math.log( totalTime / width *
|
||||
initialBlockLength ) / Math.LN2 ) );
|
||||
var pixelsPerBlock = timePerBlock * spacing;
|
||||
var pixelsPerSection = pixelsPerBlock / 5;
|
||||
var blockCount = width / pixelsPerBlock;
|
||||
|
@@ -51,8 +51,8 @@ Canvas2D {
|
||||
}
|
||||
|
||||
function updateRange() {
|
||||
var newStartTime = Math.round(rangeMover.x * qmlEventList.traceDuration() / width) + qmlEventList.traceStartTime();
|
||||
var newEndTime = Math.round((rangeMover.x + rangeMover.width) * qmlEventList.traceDuration() / width) + qmlEventList.traceStartTime();
|
||||
var newStartTime = Math.round(rangeMover.x * qmlProfilerDataModel.traceDuration() / width) + qmlProfilerDataModel.traceStartTime();
|
||||
var newEndTime = Math.round((rangeMover.x + rangeMover.width) * qmlProfilerDataModel.traceDuration() / width) + qmlProfilerDataModel.traceStartTime();
|
||||
if (startTime !== newStartTime || endTime !== newEndTime) {
|
||||
zoomControl.setRange(newStartTime, newEndTime);
|
||||
}
|
||||
@@ -62,13 +62,13 @@ Canvas2D {
|
||||
Connections {
|
||||
target: zoomControl
|
||||
onRangeChanged: {
|
||||
if (qmlEventList) {
|
||||
if (qmlProfilerDataModel) {
|
||||
startTime = zoomControl.startTime();
|
||||
endTime = zoomControl.endTime();
|
||||
var newRangeX = (startTime - qmlEventList.traceStartTime()) * width / qmlEventList.traceDuration();
|
||||
var newRangeX = (startTime - qmlProfilerDataModel.traceStartTime()) * width / qmlProfilerDataModel.traceDuration();
|
||||
if (rangeMover.x !== newRangeX)
|
||||
rangeMover.x = newRangeX;
|
||||
var newWidth = (endTime-startTime) * width / qmlEventList.traceDuration();
|
||||
var newWidth = (endTime-startTime) * width / qmlProfilerDataModel.traceDuration();
|
||||
if (rangeMover.width !== newWidth)
|
||||
rangeMover.width = newWidth;
|
||||
}
|
||||
@@ -76,10 +76,10 @@ Canvas2D {
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: qmlEventList
|
||||
target: qmlProfilerDataModel
|
||||
onStateChanged: {
|
||||
// State is "done"
|
||||
if (qmlEventList.getCurrentStateFromQml() == 3) {
|
||||
if (qmlProfilerDataModel.getCurrentStateFromQml() == 3) {
|
||||
dataAvailable = true;
|
||||
requestRedraw();
|
||||
}
|
||||
@@ -88,7 +88,7 @@ Canvas2D {
|
||||
|
||||
// ***** slots
|
||||
onDrawRegion: {
|
||||
Plotter.qmlEventList = qmlEventList;
|
||||
Plotter.qmlProfilerDataModel = qmlProfilerDataModel;
|
||||
if (dataAvailable) {
|
||||
Plotter.plot(canvas, ctxt, region);
|
||||
} else {
|
||||
|
@@ -50,7 +50,7 @@ Rectangle {
|
||||
property string endTimeString: detailedPrintTime(startTime+duration)
|
||||
property string durationString: detailedPrintTime(duration)
|
||||
|
||||
property variant startTime: x * selectionRange.viewTimePerPixel + qmlEventList.traceStartTime()
|
||||
property variant startTime: x * selectionRange.viewTimePerPixel + qmlProfilerDataModel.traceStartTime()
|
||||
property variant duration: width * selectionRange.viewTimePerPixel
|
||||
property variant viewTimePerPixel: 1
|
||||
property variant creationState : 0
|
||||
|
@@ -69,7 +69,7 @@ Item {
|
||||
states: [
|
||||
// no data available
|
||||
State {
|
||||
when: (root.eventCount == 0) && !elapsedTimer.running
|
||||
when: (root.eventCount == 0) && !root.recordingEnabled
|
||||
PropertyChanges {
|
||||
target: statusDisplay
|
||||
visible: true
|
||||
@@ -85,7 +85,7 @@ Item {
|
||||
},
|
||||
// running app
|
||||
State {
|
||||
when: elapsedTimer.running
|
||||
when: root.recordingEnabled
|
||||
PropertyChanges {
|
||||
target: statusDisplay
|
||||
visible: true
|
||||
@@ -99,7 +99,7 @@ Item {
|
||||
// loading data
|
||||
State {
|
||||
name: "loading"
|
||||
when: (!root.dataAvailable) && (root.eventCount > 0) && !root.applicationDied
|
||||
when: !root.dataAvailable && (root.eventCount > 0) && !root.appKilled
|
||||
PropertyChanges {
|
||||
target: statusDisplay
|
||||
visible: true
|
||||
@@ -118,7 +118,7 @@ Item {
|
||||
// application died
|
||||
State {
|
||||
name: "deadApp"
|
||||
when: (!root.dataAvailable) && (root.eventCount > 0) && root.applicationDied
|
||||
when: !root.dataAvailable && (root.eventCount > 0) && root.appKilled
|
||||
PropertyChanges {
|
||||
target: statusDisplay
|
||||
visible: true
|
||||
|
@@ -91,15 +91,15 @@ Canvas2D {
|
||||
|
||||
// gray off out-of-bounds areas
|
||||
var rectWidth;
|
||||
if (startTime < qmlEventList.traceStartTime()) {
|
||||
if (startTime < qmlProfilerDataModel.traceStartTime()) {
|
||||
ctxt.fillStyle = "rgba(127,127,127,0.2)";
|
||||
rectWidth = (qmlEventList.traceStartTime() - startTime) * spacing;
|
||||
rectWidth = (qmlProfilerDataModel.traceStartTime() - startTime) * spacing;
|
||||
ctxt.fillRect(0, 0, rectWidth, height);
|
||||
}
|
||||
if (endTime > qmlEventList.traceEndTime()) {
|
||||
if (endTime > qmlProfilerDataModel.traceEndTime()) {
|
||||
ctxt.fillStyle = "rgba(127,127,127,0.2)";
|
||||
var rectX = (qmlEventList.traceEndTime() - startTime) * spacing;
|
||||
rectWidth = (endTime - qmlEventList.traceEndTime()) * spacing;
|
||||
var rectX = (qmlProfilerDataModel.traceEndTime() - startTime) * spacing;
|
||||
rectWidth = (endTime - qmlProfilerDataModel.traceEndTime()) * spacing;
|
||||
ctxt.fillRect(rectX, 0, rectWidth, height);
|
||||
}
|
||||
}
|
||||
@@ -126,8 +126,8 @@ Canvas2D {
|
||||
var cumulatedHeight = 0;
|
||||
for (var i=0; i<labels.rowCount; i++) {
|
||||
cumulatedHeight += root.singleRowHeight + (labels.rowExpanded[i] ?
|
||||
qmlEventList.uniqueEventsOfType(i) * root.singleRowHeight :
|
||||
qmlEventList.maxNestingForType(i) * root.singleRowHeight);
|
||||
qmlProfilerDataModel.uniqueEventsOfType(i) * root.singleRowHeight :
|
||||
qmlProfilerDataModel.maxNestingForType(i) * root.singleRowHeight);
|
||||
|
||||
ctxt.strokeStyle = "#B0B0B0";
|
||||
ctxt.beginPath();
|
||||
|
@@ -24,14 +24,19 @@ SOURCES += \
|
||||
qmlprofilerplugin.cpp \
|
||||
qmlprofilertool.cpp \
|
||||
qmlprofilerengine.cpp \
|
||||
tracewindow.cpp \
|
||||
timelineview.cpp \
|
||||
qmlprofilerattachdialog.cpp \
|
||||
localqmlprofilerrunner.cpp \
|
||||
codaqmlprofilerrunner.cpp \
|
||||
remotelinuxqmlprofilerrunner.cpp \
|
||||
qmlprofilereventview.cpp \
|
||||
qmlprofilerdetailsrewriter.cpp
|
||||
qmlprofilerdetailsrewriter.cpp \
|
||||
qmlprofilertraceview.cpp \
|
||||
timelinerenderer.cpp \
|
||||
qmlprofilerstatemanager.cpp \
|
||||
qv8profilerdatamodel.cpp \
|
||||
qmlprofilerdatamodel.cpp \
|
||||
qmlprofilerclientmanager.cpp \
|
||||
qmlprofilerviewmanager.cpp
|
||||
|
||||
HEADERS += \
|
||||
qmlprofilerconstants.h \
|
||||
@@ -39,22 +44,26 @@ HEADERS += \
|
||||
qmlprofilerplugin.h \
|
||||
qmlprofilertool.h \
|
||||
qmlprofilerengine.h \
|
||||
tracewindow.h \
|
||||
timelineview.h \
|
||||
qmlprofilerattachdialog.h \
|
||||
abstractqmlprofilerrunner.h \
|
||||
localqmlprofilerrunner.h \
|
||||
codaqmlprofilerrunner.h \
|
||||
remotelinuxqmlprofilerrunner.h \
|
||||
qmlprofilereventview.h \
|
||||
qmlprofilerdetailsrewriter.h
|
||||
qmlprofilerdetailsrewriter.h \
|
||||
qmlprofilertraceview.h \
|
||||
timelinerenderer.h \
|
||||
qmlprofilerstatemanager.h \
|
||||
qv8profilerdatamodel.h \
|
||||
qmlprofilerdatamodel.h \
|
||||
qmlprofilerclientmanager.h \
|
||||
qmlprofilerviewmanager.h
|
||||
|
||||
RESOURCES += \
|
||||
qml/qmlprofiler.qrc
|
||||
|
||||
OTHER_FILES += \
|
||||
qml/Detail.qml \
|
||||
qml/Elapsed.qml \
|
||||
qml/Label.qml \
|
||||
qml/MainView.qml \
|
||||
qml/RangeDetails.qml \
|
||||
@@ -64,8 +73,7 @@ OTHER_FILES += \
|
||||
qml/StatusDisplay.qml \
|
||||
qml/SelectionRange.qml \
|
||||
qml/SelectionRangeDetails.qml \
|
||||
qml/Overview.qml \
|
||||
qml/Overview.js
|
||||
qml/Overview.qml
|
||||
|
||||
FORMS += \
|
||||
qmlprofilerattachdialog.ui
|
||||
|
@@ -35,27 +35,37 @@ QtcPlugin {
|
||||
"codaqmlprofilerrunner.h",
|
||||
"localqmlprofilerrunner.cpp",
|
||||
"localqmlprofilerrunner.h",
|
||||
"qmlprofiler_global.h",
|
||||
"qmlprofilerattachdialog.cpp",
|
||||
"qmlprofilerattachdialog.h",
|
||||
"qmlprofilerattachdialog.ui",
|
||||
"qmlprofilerclientmanager.cpp",
|
||||
"qmlprofilerclientmanager.h",
|
||||
"qmlprofilerconstants.h",
|
||||
"qmlprofilerdatamodel.cpp",
|
||||
"qmlprofilerdatamodel.h",
|
||||
"qmlprofilerdetailsrewriter.cpp",
|
||||
"qmlprofilerdetailsrewriter.h",
|
||||
"qmlprofilerengine.cpp",
|
||||
"qmlprofilerengine.h",
|
||||
"qmlprofilereventview.cpp",
|
||||
"qmlprofilereventview.h",
|
||||
"qmlprofiler_global.h",
|
||||
"qmlprofilerplugin.cpp",
|
||||
"qmlprofilerplugin.h",
|
||||
"qmlprofilerstatemanager.cpp",
|
||||
"qmlprofilerstatemanager.h",
|
||||
"qmlprofilertool.cpp",
|
||||
"qmlprofilertool.h",
|
||||
"qmlprofilertraceview.cpp",
|
||||
"qmlprofilertraceview.h",
|
||||
"qmlprofilerviewmanager.cpp",
|
||||
"qmlprofilerviewmanager.h",
|
||||
"qv8profilerdatamodel.cpp",
|
||||
"qv8profilerdatamodel.h",
|
||||
"remotelinuxqmlprofilerrunner.cpp",
|
||||
"remotelinuxqmlprofilerrunner.h",
|
||||
"timelineview.cpp",
|
||||
"timelineview.h",
|
||||
"tracewindow.cpp",
|
||||
"tracewindow.h",
|
||||
"timelinerenderer.cpp",
|
||||
"timelinerenderer.h",
|
||||
"canvas/qdeclarativecanvas.cpp",
|
||||
"canvas/qdeclarativecanvas_p.h",
|
||||
"canvas/qdeclarativecanvastimer.cpp",
|
||||
@@ -75,7 +85,8 @@ QtcPlugin {
|
||||
"qml/StatusDisplay.qml",
|
||||
"qml/TimeDisplay.qml",
|
||||
"qml/TimeMarks.qml",
|
||||
"qml/qmlprofiler.qrc"
|
||||
"qml/qmlprofiler.qrc",
|
||||
"qml/Overview.js"
|
||||
]
|
||||
}
|
||||
|
||||
|
426
src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp
Normal file
426
src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp
Normal file
@@ -0,0 +1,426 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** 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, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlprofilerclientmanager.h"
|
||||
#include "qmlprofilertool.h"
|
||||
#include "qmlprofilerplugin.h"
|
||||
|
||||
#include <qmljsdebugclient/qdeclarativedebugclient.h>
|
||||
#include <qmljsdebugclient/qmlprofilertraceclient.h>
|
||||
#include <qmljsdebugclient/qv8profilerclient.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <QWeakPointer>
|
||||
#include <QTimer>
|
||||
#include <QMessageBox>
|
||||
|
||||
using namespace QmlJsDebugClient;
|
||||
using namespace Core;
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerClientManager::QmlProfilerClientManagerPrivate {
|
||||
public:
|
||||
QmlProfilerClientManagerPrivate(QmlProfilerClientManager *qq) { Q_UNUSED(qq); }
|
||||
|
||||
QmlProfilerStateManager* profilerState;
|
||||
|
||||
QDeclarativeDebugConnection *connection;
|
||||
QWeakPointer<QmlProfilerTraceClient> qmlclientplugin;
|
||||
QWeakPointer<QV8ProfilerClient> v8clientplugin;
|
||||
|
||||
QTimer connectionTimer;
|
||||
int connectionAttempts;
|
||||
|
||||
enum ConnectMode {
|
||||
TcpConnection, OstConnection
|
||||
};
|
||||
ConnectMode connectMode;
|
||||
QString tcpHost;
|
||||
quint64 tcpPort;
|
||||
QString ostDevice;
|
||||
QString sysroot;
|
||||
|
||||
bool v8DataReady;
|
||||
bool qmlDataReady;
|
||||
};
|
||||
|
||||
QmlProfilerClientManager::QmlProfilerClientManager(QObject *parent) :
|
||||
QObject(parent), d(new QmlProfilerClientManagerPrivate(this))
|
||||
{
|
||||
setObjectName("QML Profiler Connections");
|
||||
|
||||
d->profilerState = 0;
|
||||
|
||||
d->connection = 0;
|
||||
d->connectionAttempts = 0;
|
||||
d->v8DataReady = false;
|
||||
d->qmlDataReady = false;
|
||||
|
||||
d->connectionTimer.setInterval(200);
|
||||
connect(&d->connectionTimer, SIGNAL(timeout()), SLOT(tryToConnect()));
|
||||
}
|
||||
|
||||
QmlProfilerClientManager::~QmlProfilerClientManager()
|
||||
{
|
||||
disconnectClientSignals();
|
||||
delete d->connection;
|
||||
delete d->qmlclientplugin.data();
|
||||
delete d->v8clientplugin.data();
|
||||
|
||||
delete d;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Interface
|
||||
void QmlProfilerClientManager::setTcpConnection(QString host, quint64 port)
|
||||
{
|
||||
d->connectMode = QmlProfilerClientManagerPrivate::TcpConnection;
|
||||
d->tcpHost = host;
|
||||
d->tcpPort = port;
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::setOstConnection(QString ostDevice)
|
||||
{
|
||||
d->connectMode = QmlProfilerClientManagerPrivate::OstConnection;
|
||||
d->ostDevice = ostDevice;
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::clearBufferedData()
|
||||
{
|
||||
if (d->qmlclientplugin)
|
||||
d->qmlclientplugin.data()->clearData();
|
||||
if (d->v8clientplugin)
|
||||
d->v8clientplugin.data()->clearData();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Internal
|
||||
void QmlProfilerClientManager::connectClient(quint16 port)
|
||||
{
|
||||
if (d->connection)
|
||||
delete d->connection;
|
||||
d->connection = new QDeclarativeDebugConnection;
|
||||
enableServices();
|
||||
connect(d->connection, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
|
||||
this, SLOT(connectionStateChanged()));
|
||||
d->connectionTimer.start();
|
||||
d->tcpPort = port;
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::enableServices()
|
||||
{
|
||||
QTC_ASSERT(d->profilerState, return);
|
||||
|
||||
disconnectClientSignals();
|
||||
d->profilerState->setServerRecording(false); // false by default (will be set to true when connected)
|
||||
delete d->qmlclientplugin.data();
|
||||
d->qmlclientplugin = new QmlProfilerTraceClient(d->connection);
|
||||
delete d->v8clientplugin.data();
|
||||
d->v8clientplugin = new QV8ProfilerClient(d->connection);
|
||||
connectClientSignals();
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::connectClientSignals()
|
||||
{
|
||||
QTC_ASSERT(d->profilerState, return);
|
||||
if (d->qmlclientplugin) {
|
||||
connect(d->qmlclientplugin.data(), SIGNAL(complete()),
|
||||
this, SLOT(qmlComplete()));
|
||||
connect(d->qmlclientplugin.data(),
|
||||
SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)),
|
||||
this,
|
||||
SIGNAL(addRangedEvent(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)));
|
||||
connect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64)),
|
||||
this, SIGNAL(traceFinished(qint64)));
|
||||
connect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64)),
|
||||
this, SIGNAL(traceStarted(qint64)));
|
||||
connect(d->qmlclientplugin.data(), SIGNAL(frame(qint64,int,int)),
|
||||
this, SIGNAL(addFrameEvent(qint64,int,int)));
|
||||
connect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
|
||||
d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
|
||||
// fixme: this should be unified for both clients
|
||||
connect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
|
||||
d->profilerState, SLOT(setServerRecording(bool)));
|
||||
}
|
||||
if (d->v8clientplugin) {
|
||||
connect(d->v8clientplugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
|
||||
connect(d->v8clientplugin.data(),
|
||||
SIGNAL(v8range(int,QString,QString,int,double,double)),
|
||||
this,
|
||||
SIGNAL(addV8Event(int,QString,QString,int,double,double)));
|
||||
connect(d->v8clientplugin.data(), SIGNAL(enabledChanged()),
|
||||
d->v8clientplugin.data(), SLOT(sendRecordingStatus()));
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::disconnectClientSignals()
|
||||
{
|
||||
if (d->qmlclientplugin) {
|
||||
disconnect(d->qmlclientplugin.data(), SIGNAL(complete()),
|
||||
this, SLOT(qmlComplete()));
|
||||
disconnect(d->qmlclientplugin.data(),
|
||||
SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)),
|
||||
this,
|
||||
SIGNAL(addRangedEvent(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)));
|
||||
disconnect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64)),
|
||||
this, SIGNAL(traceFinished(qint64)));
|
||||
disconnect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64)),
|
||||
this, SIGNAL(traceStarted(qint64)));
|
||||
disconnect(d->qmlclientplugin.data(), SIGNAL(frame(qint64,int,int)),
|
||||
this, SIGNAL(addFrameEvent(qint64,int,int)));
|
||||
disconnect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
|
||||
d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
|
||||
// fixme: this should be unified for both clients
|
||||
disconnect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
|
||||
d->profilerState, SLOT(setServerRecording(bool)));
|
||||
}
|
||||
if (d->v8clientplugin) {
|
||||
disconnect(d->v8clientplugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
|
||||
disconnect(d->v8clientplugin.data(),
|
||||
SIGNAL(v8range(int,QString,QString,int,double,double)),
|
||||
this,
|
||||
SIGNAL(addV8Event(int,QString,QString,int,double,double)));
|
||||
disconnect(d->v8clientplugin.data(), SIGNAL(enabledChanged()),
|
||||
d->v8clientplugin.data(), SLOT(sendRecordingStatus()));
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::connectToClient()
|
||||
{
|
||||
if (!d->connection || d->connection->state() != QAbstractSocket::UnconnectedState)
|
||||
return;
|
||||
|
||||
if (d->connectMode == QmlProfilerClientManagerPrivate::TcpConnection) {
|
||||
QmlProfilerTool::logStatus(QString("QML Profiler: Connecting to %1:%2 ...").arg(d->tcpHost, QString::number(d->tcpPort)));
|
||||
d->connection->connectToHost(d->tcpHost, d->tcpPort);
|
||||
} else {
|
||||
QmlProfilerTool::logStatus(QString("QML Profiler: Connecting to %1 ...").arg(d->tcpHost));
|
||||
d->connection->connectToOst(d->ostDevice);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::disconnectClient()
|
||||
{
|
||||
// this might be actually be called indirectly by QDDConnectionPrivate::readyRead(), therefore allow
|
||||
// method to complete before deleting object
|
||||
if (d->connection) {
|
||||
d->connection->deleteLater();
|
||||
d->connection = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::tryToConnect()
|
||||
{
|
||||
++d->connectionAttempts;
|
||||
|
||||
if (d->connection && d->connection->isConnected()) {
|
||||
d->connectionTimer.stop();
|
||||
d->connectionAttempts = 0;
|
||||
} else if (d->connectionAttempts == 50) {
|
||||
d->connectionTimer.stop();
|
||||
d->connectionAttempts = 0;
|
||||
|
||||
QMessageBox *infoBox = QmlProfilerTool::requestMessageBox();
|
||||
infoBox->setIcon(QMessageBox::Critical);
|
||||
infoBox->setWindowTitle(tr("Qt Creator"));
|
||||
infoBox->setText(tr("Could not connect to the in-process QML profiler.\n"
|
||||
"Do you want to retry?"));
|
||||
infoBox->setStandardButtons(QMessageBox::Retry |
|
||||
QMessageBox::Cancel |
|
||||
QMessageBox::Help);
|
||||
infoBox->setDefaultButton(QMessageBox::Retry);
|
||||
infoBox->setModal(true);
|
||||
|
||||
connect(infoBox, SIGNAL(finished(int)),
|
||||
this, SLOT(retryMessageBoxFinished(int)));
|
||||
|
||||
infoBox->show();
|
||||
} else {
|
||||
connectToClient();
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::connectionStateChanged()
|
||||
{
|
||||
if (!d->connection)
|
||||
return;
|
||||
switch (d->connection->state()) {
|
||||
case QAbstractSocket::UnconnectedState:
|
||||
{
|
||||
if (QmlProfilerPlugin::debugOutput)
|
||||
qWarning("QML Profiler: disconnected");
|
||||
break;
|
||||
}
|
||||
case QAbstractSocket::HostLookupState:
|
||||
break;
|
||||
case QAbstractSocket::ConnectingState: {
|
||||
if (QmlProfilerPlugin::debugOutput)
|
||||
qWarning("QML Profiler: Connecting to debug server ...");
|
||||
break;
|
||||
}
|
||||
case QAbstractSocket::ConnectedState:
|
||||
{
|
||||
if (QmlProfilerPlugin::debugOutput)
|
||||
qWarning("QML Profiler: connected and running");
|
||||
// notify the client recording status
|
||||
clientRecordingChanged();
|
||||
break;
|
||||
}
|
||||
case QAbstractSocket::ClosingState:
|
||||
if (QmlProfilerPlugin::debugOutput)
|
||||
qWarning("QML Profiler: closing ...");
|
||||
break;
|
||||
case QAbstractSocket::BoundState:
|
||||
case QAbstractSocket::ListeningState:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::retryMessageBoxFinished(int result)
|
||||
{
|
||||
switch (result) {
|
||||
case QMessageBox::Retry: {
|
||||
d->connectionAttempts = 0;
|
||||
d->connectionTimer.start();
|
||||
break;
|
||||
}
|
||||
case QMessageBox::Help: {
|
||||
QmlProfilerTool::handleHelpRequest(QString("qthelp://com.nokia.qtcreator/doc/creator-debugging-qml.html"));
|
||||
// fall through
|
||||
}
|
||||
default: {
|
||||
if (d->connection) {
|
||||
QmlProfilerTool::logStatus("QML Profiler: Failed to connect! " + d->connection->errorString());
|
||||
} else {
|
||||
QmlProfilerTool::logStatus("QML Profiler: Failed to connect!");
|
||||
}
|
||||
|
||||
emit connectionFailed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::qmlComplete()
|
||||
{
|
||||
d->qmlDataReady = true;
|
||||
if (!d->v8clientplugin || d->v8clientplugin.data()->status() != QDeclarativeDebugClient::Enabled || d->v8DataReady) {
|
||||
emit dataReadyForProcessing();
|
||||
// once complete is sent, reset the flags
|
||||
d->qmlDataReady = false;
|
||||
d->v8DataReady = false;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::v8Complete()
|
||||
{
|
||||
d->v8DataReady = true;
|
||||
if (!d->qmlclientplugin || d->qmlclientplugin.data()->status() != QDeclarativeDebugClient::Enabled || d->qmlDataReady) {
|
||||
emit dataReadyForProcessing();
|
||||
// once complete is sent, reset the flags
|
||||
d->v8DataReady = false;
|
||||
d->qmlDataReady = false;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::stopClientsRecording()
|
||||
{
|
||||
if (d->qmlclientplugin)
|
||||
d->qmlclientplugin.data()->setRecording(false);
|
||||
if (d->v8clientplugin)
|
||||
d->v8clientplugin.data()->setRecording(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Profiler State
|
||||
void QmlProfilerClientManager::registerProfilerStateManager( QmlProfilerStateManager *profilerState )
|
||||
{
|
||||
if (d->profilerState) {
|
||||
disconnect(d->profilerState, SIGNAL(stateChanged()),
|
||||
this, SLOT(profilerStateChanged()));
|
||||
disconnect(d->profilerState, SIGNAL(clientRecordingChanged()),
|
||||
this, SLOT(clientRecordingChanged()));
|
||||
disconnect(d->profilerState, SIGNAL(serverRecordingChanged()),
|
||||
this, SLOT(serverRecordingChanged()));
|
||||
}
|
||||
|
||||
d->profilerState = profilerState;
|
||||
|
||||
// connect
|
||||
if (d->profilerState) {
|
||||
connect(d->profilerState, SIGNAL(stateChanged()),
|
||||
this, SLOT(profilerStateChanged()));
|
||||
connect(d->profilerState, SIGNAL(clientRecordingChanged()),
|
||||
this, SLOT(clientRecordingChanged()));
|
||||
connect(d->profilerState, SIGNAL(serverRecordingChanged()),
|
||||
this, SLOT(serverRecordingChanged()));
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::profilerStateChanged()
|
||||
{
|
||||
QTC_ASSERT(d->profilerState, return);
|
||||
switch (d->profilerState->currentState()) {
|
||||
case QmlProfilerStateManager::AppStopRequested :
|
||||
if (d->profilerState->serverRecording()) {
|
||||
stopClientsRecording();
|
||||
}
|
||||
else
|
||||
d->profilerState->setCurrentState(QmlProfilerStateManager::AppReadyToStop);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::clientRecordingChanged()
|
||||
{
|
||||
QTC_ASSERT(d->profilerState, return);
|
||||
if (d->profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
|
||||
if (d->qmlclientplugin)
|
||||
d->qmlclientplugin.data()->setRecording(d->profilerState->clientRecording());
|
||||
if (d->v8clientplugin)
|
||||
d->v8clientplugin.data()->setRecording(d->profilerState->clientRecording());
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::serverRecordingChanged()
|
||||
{
|
||||
if (d->profilerState->serverRecording()) {
|
||||
d->v8DataReady = false;
|
||||
d->qmlDataReady = false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
102
src/plugins/qmlprofiler/qmlprofilerclientmanager.h
Normal file
102
src/plugins/qmlprofiler/qmlprofilerclientmanager.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** 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, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLPROFILERCLIENTMANAGER_H
|
||||
#define QMLPROFILERCLIENTMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
#include "qmlprofilerstatemanager.h"
|
||||
#include <qmljsdebugclient/qmlprofilereventlocation.h>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerClientManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QmlProfilerClientManager(QObject *parent = 0);
|
||||
~QmlProfilerClientManager();
|
||||
|
||||
void registerProfilerStateManager(QmlProfilerStateManager *profilerState);
|
||||
|
||||
void setTcpConnection(QString host, quint64 port);
|
||||
void setOstConnection(QString ostDevice);
|
||||
|
||||
void clearBufferedData();
|
||||
|
||||
signals:
|
||||
void connectionFailed();
|
||||
|
||||
// data
|
||||
void addRangedEvent(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation);
|
||||
void addV8Event(int,QString,QString,int,double,double);
|
||||
void addFrameEvent(qint64,int,int);
|
||||
void traceStarted(qint64);
|
||||
void traceFinished(qint64);
|
||||
void dataReadyForProcessing();
|
||||
|
||||
public slots:
|
||||
void connectClient(quint16 port);
|
||||
void disconnectClient();
|
||||
|
||||
private slots:
|
||||
void tryToConnect();
|
||||
void connectionStateChanged();
|
||||
void retryMessageBoxFinished(int result);
|
||||
|
||||
void qmlComplete();
|
||||
void v8Complete();
|
||||
|
||||
void profilerStateChanged();
|
||||
void clientRecordingChanged();
|
||||
void serverRecordingChanged();
|
||||
|
||||
private:
|
||||
class QmlProfilerClientManagerPrivate;
|
||||
QmlProfilerClientManagerPrivate *d;
|
||||
|
||||
void connectToClient();
|
||||
|
||||
void enableServices();
|
||||
void connectClientSignals();
|
||||
void disconnectClientSignals();
|
||||
|
||||
void stopClientsRecording();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // QMLPROFILERCLIENTMANAGER_H
|
@@ -37,6 +37,7 @@ namespace QmlProfiler {
|
||||
namespace Constants {
|
||||
|
||||
const char ATTACH[] = "Menu.Analyzer.Attach";
|
||||
const char TraceFileExtension[] = ".qtd";
|
||||
|
||||
} // namespace Constants
|
||||
} // namespace QmlProfiler
|
||||
|
1652
src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp
Normal file
1652
src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -30,33 +30,37 @@
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLPROFILEREVENTLIST_H
|
||||
#define QMLPROFILEREVENTLIST_H
|
||||
#ifndef QMLPROFILERDATAMODEL_H
|
||||
#define QMLPROFILERDATAMODEL_H
|
||||
|
||||
#include "qmlprofilereventtypes.h"
|
||||
#include "qmlprofilereventlocation.h"
|
||||
#include "qmljsdebugclient_global.h"
|
||||
#include <qmljsdebugclient/qmlprofilereventtypes.h>
|
||||
#include <qmljsdebugclient/qmlprofilereventlocation.h>
|
||||
#include "qv8profilerdatamodel.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
|
||||
namespace QmlJsDebugClient {
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
struct QmlEventSub;
|
||||
struct QV8EventSub;
|
||||
// used for parents and children
|
||||
struct QmlRangeEventRelative;
|
||||
|
||||
struct QMLJSDEBUGCLIENT_EXPORT QmlEventData
|
||||
struct QmlRangeEventData
|
||||
{
|
||||
QmlEventData();
|
||||
~QmlEventData();
|
||||
QmlRangeEventData();
|
||||
~QmlRangeEventData();
|
||||
|
||||
QString displayname;
|
||||
int eventId;
|
||||
QString displayName;
|
||||
QString eventHashStr;
|
||||
QString details;
|
||||
QmlEventLocation location;
|
||||
QmlJsDebugClient::QmlEventLocation location;
|
||||
QmlJsDebugClient::QmlEventType eventType;
|
||||
QHash <QString, QmlEventSub *> parentHash;
|
||||
QHash <QString, QmlEventSub *> childrenHash;
|
||||
|
||||
QHash <QString, QmlRangeEventRelative *> parentHash;
|
||||
QHash <QString, QmlRangeEventRelative *> childrenHash;
|
||||
|
||||
qint64 duration;
|
||||
qint64 calls;
|
||||
qint64 minTime;
|
||||
@@ -64,54 +68,22 @@ struct QMLJSDEBUGCLIENT_EXPORT QmlEventData
|
||||
double timePerCall;
|
||||
double percentOfTime;
|
||||
qint64 medianTime;
|
||||
int eventId;
|
||||
|
||||
bool isBindingLoop;
|
||||
|
||||
QmlEventData &operator=(const QmlEventData &ref);
|
||||
QmlRangeEventData &operator=(const QmlRangeEventData &ref);
|
||||
};
|
||||
|
||||
struct QMLJSDEBUGCLIENT_EXPORT QmlEventSub {
|
||||
QmlEventSub(QmlEventData *from) : reference(from), duration(0), calls(0), inLoopPath(false) {}
|
||||
QmlEventSub(QmlEventSub *from) : reference(from->reference), duration(from->duration), calls(from->calls), inLoopPath(from->inLoopPath) {}
|
||||
QmlEventData *reference;
|
||||
struct QmlRangeEventRelative {
|
||||
QmlRangeEventRelative(QmlRangeEventData *from) : reference(from), duration(0), calls(0), inLoopPath(false) {}
|
||||
QmlRangeEventRelative(QmlRangeEventRelative *from) : reference(from->reference), duration(from->duration), calls(from->calls), inLoopPath(from->inLoopPath) {}
|
||||
QmlRangeEventData *reference;
|
||||
qint64 duration;
|
||||
qint64 calls;
|
||||
bool inLoopPath;
|
||||
};
|
||||
|
||||
struct QMLJSDEBUGCLIENT_EXPORT QV8EventData
|
||||
{
|
||||
QV8EventData();
|
||||
~QV8EventData();
|
||||
|
||||
QString displayName;
|
||||
QString filename;
|
||||
QString functionName;
|
||||
int line;
|
||||
double totalTime; // given in milliseconds
|
||||
double totalPercent;
|
||||
double selfTime;
|
||||
double selfPercent;
|
||||
QHash <QString, QV8EventSub *> parentHash;
|
||||
QHash <QString, QV8EventSub *> childrenHash;
|
||||
int eventId;
|
||||
|
||||
QV8EventData &operator=(const QV8EventData &ref);
|
||||
};
|
||||
|
||||
struct QMLJSDEBUGCLIENT_EXPORT QV8EventSub {
|
||||
QV8EventSub(QV8EventData *from) : reference(from), totalTime(0) {}
|
||||
QV8EventSub(QV8EventSub *from) : reference(from->reference), totalTime(from->totalTime) {}
|
||||
|
||||
QV8EventData *reference;
|
||||
qint64 totalTime;
|
||||
};
|
||||
|
||||
typedef QHash<QString, QmlEventData *> QmlEventHash;
|
||||
typedef QList<QmlEventData *> QmlEventDescriptions;
|
||||
typedef QList<QV8EventData *> QV8EventDescriptions;
|
||||
|
||||
class QMLJSDEBUGCLIENT_EXPORT QmlProfilerEventList : public QObject
|
||||
class QmlProfilerDataModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -122,23 +94,30 @@ public:
|
||||
Done
|
||||
};
|
||||
|
||||
explicit QmlProfilerEventList(QObject *parent = 0);
|
||||
~QmlProfilerEventList();
|
||||
explicit QmlProfilerDataModel(QObject *parent = 0);
|
||||
~QmlProfilerDataModel();
|
||||
|
||||
QmlEventDescriptions getEventDescriptions() const;
|
||||
QmlEventData *eventDescription(int eventId) const;
|
||||
const QV8EventDescriptions& getV8Events() const;
|
||||
QList<QmlRangeEventData *> getEventDescriptions() const;
|
||||
QmlRangeEventData *eventDescription(int eventId) const;
|
||||
QList<QV8EventData *> getV8Events() const;
|
||||
QV8EventData *v8EventDescription(int eventId) const;
|
||||
|
||||
static QString getHashStringForQmlEvent(const QmlJsDebugClient::QmlEventLocation &location, int eventType);
|
||||
static QString getHashStringForV8Event(const QString &displayName, const QString &function);
|
||||
static QString rootEventName();
|
||||
static QString rootEventDescription();
|
||||
static QString qmlEventTypeAsString(QmlJsDebugClient::QmlEventType typeEnum);
|
||||
static QmlJsDebugClient::QmlEventType qmlEventTypeAsEnum(const QString &typeString);
|
||||
|
||||
int findFirstIndex(qint64 startTime) const;
|
||||
int findFirstIndexNoParents(qint64 startTime) const;
|
||||
int findLastIndex(qint64 endTime) const;
|
||||
Q_INVOKABLE qint64 firstTimeMark() const;
|
||||
Q_INVOKABLE qint64 lastTimeMark() const;
|
||||
|
||||
Q_INVOKABLE int count() const;
|
||||
|
||||
// data access
|
||||
Q_INVOKABLE int count() const;
|
||||
Q_INVOKABLE bool isEmpty() const;
|
||||
Q_INVOKABLE qint64 getStartTime(int index) const;
|
||||
Q_INVOKABLE qint64 getEndTime(int index) const;
|
||||
Q_INVOKABLE qint64 getDuration(int index) const;
|
||||
@@ -171,7 +150,6 @@ public:
|
||||
Q_INVOKABLE qint64 qmlMeasuredTime() const;
|
||||
Q_INVOKABLE qint64 v8MeasuredTime() const;
|
||||
|
||||
void showErrorDialog(const QString &st ) const;
|
||||
void compileStatistics(qint64 startTime, qint64 endTime);
|
||||
State currentState() const;
|
||||
Q_INVOKABLE int getCurrentStateFromQml() const;
|
||||
@@ -188,44 +166,37 @@ signals:
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
|
||||
void addRangedEvent(int type, qint64 startTime, qint64 length,
|
||||
const QStringList &data, const QmlJsDebugClient::QmlEventLocation &location);
|
||||
void complete();
|
||||
|
||||
void addV8Event(int depth,const QString &function,const QString &filename, int lineNumber, double totalTime, double selfTime);
|
||||
void addFrameEvent(qint64 time, int framerate, int animationcount);
|
||||
void setTraceStartTime(qint64 time);
|
||||
void setTraceEndTime(qint64 time);
|
||||
|
||||
void complete();
|
||||
|
||||
bool save(const QString &filename);
|
||||
void load(const QString &filename);
|
||||
void setFilename(const QString &filename);
|
||||
void load();
|
||||
|
||||
void setTraceEndTime( qint64 time );
|
||||
void setTraceStartTime( qint64 time );
|
||||
|
||||
void rewriteDetailsString(int eventType, const QmlJsDebugClient::QmlEventLocation &location, const QString &newString);
|
||||
void finishedRewritingDetails();
|
||||
|
||||
private:
|
||||
void postProcess();
|
||||
void sortEndTimes();
|
||||
void findAnimationLimits();
|
||||
void sortStartTimes();
|
||||
void computeLevels();
|
||||
void computeNestingLevels();
|
||||
void computeNestingDepth();
|
||||
void prepareForDisplay();
|
||||
void linkEndsToStarts();
|
||||
void reloadDetails();
|
||||
void findBindingLoops(qint64 startTime, qint64 endTime);
|
||||
bool checkBindingLoop(QmlEventData *from, QmlEventData *current, QList<QmlEventData *>visited);
|
||||
void setState(State state);
|
||||
void reloadDetails();
|
||||
|
||||
private:
|
||||
class QmlProfilerEventListPrivate;
|
||||
QmlProfilerEventListPrivate *d;
|
||||
class QmlProfilerDataModelPrivate;
|
||||
QmlProfilerDataModelPrivate *d;
|
||||
|
||||
friend class QV8ProfilerDataModel;
|
||||
};
|
||||
|
||||
|
||||
} // namespace QmlJsDebugClient
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
#endif // QMLPROFILEREVENTLIST_H
|
||||
#endif // QMLPROFILERDATAMODEL_H
|
@@ -35,7 +35,7 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "qmljsdebugclient/qmlprofilereventlocation.h"
|
||||
#include <qmljsdebugclient/qmlprofilereventlocation.h>
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
|
||||
namespace QmlProfiler {
|
||||
|
@@ -35,8 +35,6 @@
|
||||
#include "codaqmlprofilerrunner.h"
|
||||
#include "localqmlprofilerrunner.h"
|
||||
#include "remotelinuxqmlprofilerrunner.h"
|
||||
#include "qmlprofilerplugin.h"
|
||||
#include "qmlprofilertool.h"
|
||||
|
||||
#include <analyzerbase/analyzermanager.h>
|
||||
#include <coreplugin/icore.h>
|
||||
@@ -76,16 +74,11 @@ public:
|
||||
|
||||
QmlProfilerEngine *q;
|
||||
|
||||
//AnalyzerStartParameters m_params;
|
||||
QmlProfilerStateManager *m_profilerState;
|
||||
|
||||
AbstractQmlProfilerRunner *m_runner;
|
||||
bool m_running;
|
||||
bool m_fetchingData;
|
||||
bool m_hasData;
|
||||
bool m_fetchDataFromStart;
|
||||
bool m_delayedDelete;
|
||||
QTimer m_noDebugOutputTimer;
|
||||
QmlJsDebugClient::QDeclarativeOutputParser m_outputParser;
|
||||
QTimer m_runningTimer;
|
||||
};
|
||||
|
||||
AbstractQmlProfilerRunner *
|
||||
@@ -137,10 +130,7 @@ QmlProfilerEngine::QmlProfilerEngine(IAnalyzerTool *tool,
|
||||
: IAnalyzerEngine(tool, sp, runConfiguration)
|
||||
, d(new QmlProfilerEnginePrivate(this))
|
||||
{
|
||||
d->m_running = false;
|
||||
d->m_fetchingData = false;
|
||||
d->m_fetchDataFromStart = false;
|
||||
d->m_delayedDelete = false;
|
||||
d->m_profilerState = 0;
|
||||
|
||||
// Only wait 4 seconds for the 'Waiting for connection' on application ouput, then just try to connect
|
||||
// (application output might be redirected / blocked)
|
||||
@@ -157,29 +147,31 @@ QmlProfilerEngine::QmlProfilerEngine(IAnalyzerTool *tool,
|
||||
this, SLOT(processIsRunning()));
|
||||
connect(&d->m_outputParser, SIGNAL(errorMessage(QString)),
|
||||
this, SLOT(wrongSetupMessageBox(QString)));
|
||||
|
||||
d->m_runningTimer.setInterval(100); // ten times per second
|
||||
connect(&d->m_runningTimer, SIGNAL(timeout()), this, SIGNAL(timeUpdate()));
|
||||
}
|
||||
|
||||
QmlProfilerEngine::~QmlProfilerEngine()
|
||||
{
|
||||
if (d->m_running)
|
||||
if (d->m_profilerState && d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning)
|
||||
stop();
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool QmlProfilerEngine::start()
|
||||
{
|
||||
QTC_ASSERT(d->m_profilerState, return false);
|
||||
|
||||
if (d->m_runner) {
|
||||
delete d->m_runner;
|
||||
d->m_runner = 0;
|
||||
}
|
||||
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppStarting);
|
||||
|
||||
if (QmlProjectManager::QmlProjectRunConfiguration *rc =
|
||||
qobject_cast<QmlProjectManager::QmlProjectRunConfiguration *>(runConfiguration())) {
|
||||
if (rc->observerPath().isEmpty()) {
|
||||
QmlProjectManager::QmlProjectPlugin::showQmlObserverToolWarning();
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
|
||||
AnalyzerManager::stopTool();
|
||||
return false;
|
||||
}
|
||||
@@ -190,13 +182,14 @@ bool QmlProfilerEngine::start()
|
||||
if (LocalQmlProfilerRunner *qmlRunner = qobject_cast<LocalQmlProfilerRunner *>(d->m_runner)) {
|
||||
if (!qmlRunner->hasExecutable()) {
|
||||
showNonmodalWarning(tr("No executable file to launch."));
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
|
||||
AnalyzerManager::stopTool();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (d->m_runner) {
|
||||
connect(d->m_runner, SIGNAL(stopped()), this, SLOT(stopped()));
|
||||
connect(d->m_runner, SIGNAL(stopped()), this, SLOT(processEnded()));
|
||||
connect(d->m_runner, SIGNAL(appendMessage(QString,Utils::OutputFormat)),
|
||||
this, SLOT(logApplicationMessage(QString,Utils::OutputFormat)));
|
||||
d->m_runner->start();
|
||||
@@ -205,81 +198,80 @@ bool QmlProfilerEngine::start()
|
||||
emit processRunning(startParameters().connParams.port);
|
||||
}
|
||||
|
||||
|
||||
d->m_running = true;
|
||||
d->m_delayedDelete = false;
|
||||
d->m_runningTimer.start();
|
||||
|
||||
if (d->m_fetchDataFromStart) {
|
||||
d->m_fetchingData = true;
|
||||
d->m_hasData = false;
|
||||
}
|
||||
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppRunning);
|
||||
emit starting(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void QmlProfilerEngine::stop()
|
||||
{
|
||||
if (d->m_fetchingData) {
|
||||
if (d->m_running)
|
||||
d->m_delayedDelete = true;
|
||||
// will result in dataReceived() call
|
||||
emit stopRecording();
|
||||
d->m_fetchDataFromStart = true;
|
||||
} else {
|
||||
finishProcess();
|
||||
d->m_fetchDataFromStart = false;
|
||||
QTC_ASSERT(d->m_profilerState, return);
|
||||
|
||||
switch (d->m_profilerState->currentState()) {
|
||||
case QmlProfilerStateManager::AppRunning : {
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppStopRequested);
|
||||
break;
|
||||
}
|
||||
case QmlProfilerStateManager::AppReadyToStop : {
|
||||
cancelProcess();
|
||||
break;
|
||||
}
|
||||
case QmlProfilerStateManager::AppKilled : {
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qDebug() << tr("Unexpected engine stop from state %1 in %2:%3").arg(d->m_profilerState->currentStateAsString(), QString(__FILE__), QString::number(__LINE__));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEngine::stopped()
|
||||
void QmlProfilerEngine::processEnded()
|
||||
{
|
||||
// if it was killed, preserve recording flag
|
||||
if (d->m_running)
|
||||
d->m_fetchDataFromStart = d->m_fetchingData;
|
||||
QTC_ASSERT(d->m_profilerState, return);
|
||||
|
||||
// user feedback
|
||||
if (d->m_running && d->m_fetchingData && !d->m_hasData) {
|
||||
showNonmodalWarning(tr("Application finished before loading profiled data.\n Please use the stop button instead."));
|
||||
emit applicationDied();
|
||||
}
|
||||
|
||||
d->m_running = false;
|
||||
d->m_runningTimer.stop();
|
||||
switch (d->m_profilerState->currentState()) {
|
||||
case QmlProfilerStateManager::AppRunning : {
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppKilled);
|
||||
AnalyzerManager::stopTool();
|
||||
|
||||
emit finished();
|
||||
emit recordingChanged(d->m_fetchDataFromStart);
|
||||
break;
|
||||
}
|
||||
case QmlProfilerStateManager::AppStopped :
|
||||
// fallthrough
|
||||
case QmlProfilerStateManager::AppKilled : {
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qDebug() << tr("Process died unexpectedly from state %1 in %2:%3").arg(d->m_profilerState->currentStateAsString(), QString(__FILE__), QString::number(__LINE__));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEngine::setFetchingData(bool b)
|
||||
void QmlProfilerEngine::cancelProcess()
|
||||
{
|
||||
d->m_fetchingData = b;
|
||||
if (d->m_running && b)
|
||||
d->m_hasData = false;
|
||||
if (!d->m_running)
|
||||
d->m_fetchDataFromStart = b;
|
||||
}
|
||||
QTC_ASSERT(d->m_profilerState, return);
|
||||
|
||||
void QmlProfilerEngine::dataReceived()
|
||||
{
|
||||
if (d->m_delayedDelete)
|
||||
finishProcess();
|
||||
d->m_delayedDelete = false;
|
||||
d->m_hasData = true;
|
||||
}
|
||||
switch (d->m_profilerState->currentState()) {
|
||||
case QmlProfilerStateManager::AppReadyToStop : {
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppStopped);
|
||||
break;
|
||||
}
|
||||
case QmlProfilerStateManager::AppRunning : {
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppKilled);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
qDebug() << tr("Unexpected process termination requested with state %1 in %2:%3").arg(d->m_profilerState->currentStateAsString(), QString(__FILE__), QString::number(__LINE__));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEngine::finishProcess()
|
||||
{
|
||||
// user stop?
|
||||
if (d->m_running) {
|
||||
d->m_running = false;
|
||||
d->m_runningTimer.stop();
|
||||
if (d->m_runner)
|
||||
d->m_runner->stop();
|
||||
emit finished();
|
||||
emit recordingChanged(d->m_fetchDataFromStart);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEngine::logApplicationMessage(const QString &msg, Utils::OutputFormat format)
|
||||
@@ -305,11 +297,10 @@ void QmlProfilerEngine::wrongSetupMessageBox(const QString &errorMessage)
|
||||
|
||||
infoBox->show();
|
||||
|
||||
d->m_running = false;
|
||||
d->m_runningTimer.stop();
|
||||
// KILL
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppKilled);
|
||||
AnalyzerManager::stopTool();
|
||||
emit finished();
|
||||
emit recordingChanged(d->m_fetchDataFromStart);
|
||||
}
|
||||
|
||||
void QmlProfilerEngine::wrongSetupMessageBoxFinished(int button)
|
||||
@@ -348,5 +339,44 @@ void QmlProfilerEngine::processIsRunning(quint16 port)
|
||||
emit processRunning(d->m_runner->debugPort());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Profiler State
|
||||
void QmlProfilerEngine::registerProfilerStateManager( QmlProfilerStateManager *profilerState )
|
||||
{
|
||||
// disconnect old
|
||||
if (d->m_profilerState) {
|
||||
disconnect(d->m_profilerState, SIGNAL(stateChanged()), this, SLOT(profilerStateChanged()));
|
||||
}
|
||||
|
||||
d->m_profilerState = profilerState;
|
||||
|
||||
// connect
|
||||
if (d->m_profilerState) {
|
||||
connect(d->m_profilerState, SIGNAL(stateChanged()), this, SLOT(profilerStateChanged()));
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEngine::profilerStateChanged()
|
||||
{
|
||||
switch (d->m_profilerState->currentState()) {
|
||||
case QmlProfilerStateManager::AppReadyToStop : {
|
||||
cancelProcess();
|
||||
break;
|
||||
}
|
||||
case QmlProfilerStateManager::Idle : {
|
||||
// for some reason the engine is not deleted when it goes to idle
|
||||
// a new one will be created on the next run, and this one will
|
||||
// be only deleted if the new one is running the same app
|
||||
|
||||
// we need to explictly disconnect it here without expecting a deletion
|
||||
// as it will not be run any more, otherwise we will get funny side effects
|
||||
registerProfilerStateManager(0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#define QMLPROFILERENGINE_H
|
||||
|
||||
#include <analyzerbase/ianalyzerengine.h>
|
||||
#include "qmlprofilerstatemanager.h"
|
||||
#include <utils/outputformat.h>
|
||||
|
||||
namespace QmlProfiler {
|
||||
@@ -49,29 +50,29 @@ public:
|
||||
ProjectExplorer::RunConfiguration *runConfiguration);
|
||||
~QmlProfilerEngine();
|
||||
|
||||
void registerProfilerStateManager( QmlProfilerStateManager *profilerState );
|
||||
|
||||
static void showNonmodalWarning(const QString &warningMsg);
|
||||
signals:
|
||||
void processRunning(quint16 port);
|
||||
void stopRecording();
|
||||
void timeUpdate();
|
||||
void recordingChanged(bool recording);
|
||||
void applicationDied();
|
||||
|
||||
public slots:
|
||||
bool start();
|
||||
void stop();
|
||||
|
||||
private slots:
|
||||
void stopped();
|
||||
void processEnded();
|
||||
|
||||
void setFetchingData(bool);
|
||||
void dataReceived();
|
||||
void finishProcess();
|
||||
void cancelProcess();
|
||||
void logApplicationMessage(const QString &msg, Utils::OutputFormat format);
|
||||
void wrongSetupMessageBox(const QString &errorMessage);
|
||||
void wrongSetupMessageBoxFinished(int);
|
||||
void processIsRunning(quint16 port = 0);
|
||||
|
||||
private slots:
|
||||
void profilerStateChanged();
|
||||
|
||||
private:
|
||||
class QmlProfilerEnginePrivate;
|
||||
QmlProfilerEnginePrivate *d;
|
||||
|
@@ -48,6 +48,11 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
#include "qmlprofilerviewmanager.h"
|
||||
#include "qmlprofilertool.h"
|
||||
#include <QMenu>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
using namespace QmlJsDebugClient;
|
||||
|
||||
@@ -90,31 +95,63 @@ public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QmlProfilerEventsWidget::QmlProfilerEventsWidget(QmlJsDebugClient::QmlProfilerEventList *model, QWidget *parent) : QWidget(parent)
|
||||
class QmlProfilerEventsWidget::QmlProfilerEventsWidgetPrivate
|
||||
{
|
||||
public:
|
||||
QmlProfilerEventsWidgetPrivate(QmlProfilerEventsWidget *qq):q(qq) {}
|
||||
~QmlProfilerEventsWidgetPrivate() {}
|
||||
|
||||
QmlProfilerEventsWidget *q;
|
||||
|
||||
Analyzer::IAnalyzerTool *m_profilerTool;
|
||||
QmlProfilerViewManager *m_viewContainer;
|
||||
|
||||
QmlProfilerEventsMainView *m_eventTree;
|
||||
QmlProfilerEventsParentsAndChildrenView *m_eventChildren;
|
||||
QmlProfilerEventsParentsAndChildrenView *m_eventParents;
|
||||
QmlProfilerDataModel *m_profilerDataModel;
|
||||
|
||||
bool m_globalStatsEnabled;
|
||||
};
|
||||
|
||||
QmlProfilerEventsWidget::QmlProfilerEventsWidget(QWidget *parent,
|
||||
Analyzer::IAnalyzerTool *profilerTool,
|
||||
QmlProfilerViewManager *container,
|
||||
QmlProfilerDataModel *profilerDataModel )
|
||||
: QWidget(parent), d(new QmlProfilerEventsWidgetPrivate(this))
|
||||
{
|
||||
setObjectName("QmlProfilerEventsView");
|
||||
|
||||
m_eventTree = new QmlProfilerEventsMainView(model, this);
|
||||
m_eventTree->setViewType(QmlProfilerEventsMainView::EventsView);
|
||||
connect(m_eventTree, SIGNAL(gotoSourceLocation(QString,int,int)), this, SIGNAL(gotoSourceLocation(QString,int,int)));
|
||||
connect(m_eventTree, SIGNAL(showEventInTimeline(int)), this, SIGNAL(showEventInTimeline(int)));
|
||||
d->m_profilerDataModel = profilerDataModel;
|
||||
connect(d->m_profilerDataModel, SIGNAL(stateChanged()),
|
||||
this, SLOT(profilerDataModelStateChanged()));
|
||||
|
||||
m_eventChildren = new QmlProfilerEventsParentsAndChildrenView(model, QmlProfilerEventsParentsAndChildrenView::ChildrenView, this);
|
||||
m_eventParents = new QmlProfilerEventsParentsAndChildrenView(model, QmlProfilerEventsParentsAndChildrenView::ParentsView, this);
|
||||
connect(m_eventTree, SIGNAL(eventSelected(int)), m_eventChildren, SLOT(displayEvent(int)));
|
||||
connect(m_eventTree, SIGNAL(eventSelected(int)), m_eventParents, SLOT(displayEvent(int)));
|
||||
connect(m_eventChildren, SIGNAL(eventClicked(int)), m_eventTree, SLOT(selectEvent(int)));
|
||||
connect(m_eventParents, SIGNAL(eventClicked(int)), m_eventTree, SLOT(selectEvent(int)));
|
||||
d->m_eventTree = new QmlProfilerEventsMainView(QmlProfilerEventsMainView::EventsView, this, d->m_profilerDataModel);
|
||||
connect(d->m_eventTree, SIGNAL(gotoSourceLocation(QString,int,int)), this, SIGNAL(gotoSourceLocation(QString,int,int)));
|
||||
connect(d->m_eventTree, SIGNAL(showEventInTimeline(int)), this, SIGNAL(showEventInTimeline(int)));
|
||||
|
||||
d->m_eventChildren = new QmlProfilerEventsParentsAndChildrenView(
|
||||
QmlProfilerEventsParentsAndChildrenView::ChildrenView,
|
||||
this,
|
||||
d->m_profilerDataModel);
|
||||
d->m_eventParents = new QmlProfilerEventsParentsAndChildrenView(
|
||||
QmlProfilerEventsParentsAndChildrenView::ParentsView,
|
||||
this,
|
||||
d->m_profilerDataModel);
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(int)), d->m_eventChildren, SLOT(displayEvent(int)));
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(int)), d->m_eventParents, SLOT(displayEvent(int)));
|
||||
connect(d->m_eventChildren, SIGNAL(eventClicked(int)), d->m_eventTree, SLOT(selectEvent(int)));
|
||||
connect(d->m_eventParents, SIGNAL(eventClicked(int)), d->m_eventTree, SLOT(selectEvent(int)));
|
||||
|
||||
// widget arrangement
|
||||
QVBoxLayout *groupLayout = new QVBoxLayout;
|
||||
groupLayout->setContentsMargins(0,0,0,0);
|
||||
groupLayout->setSpacing(0);
|
||||
Core::MiniSplitter *splitterVertical = new Core::MiniSplitter;
|
||||
splitterVertical->addWidget(m_eventTree);
|
||||
splitterVertical->addWidget(d->m_eventTree);
|
||||
Core::MiniSplitter *splitterHorizontal = new Core::MiniSplitter;
|
||||
splitterHorizontal->addWidget(m_eventParents);
|
||||
splitterHorizontal->addWidget(m_eventChildren);
|
||||
splitterHorizontal->addWidget(d->m_eventParents);
|
||||
splitterHorizontal->addWidget(d->m_eventChildren);
|
||||
splitterHorizontal->setOrientation(Qt::Horizontal);
|
||||
splitterVertical->addWidget(splitterHorizontal);
|
||||
splitterVertical->setOrientation(Qt::Vertical);
|
||||
@@ -123,23 +160,21 @@ QmlProfilerEventsWidget::QmlProfilerEventsWidget(QmlJsDebugClient::QmlProfilerEv
|
||||
groupLayout->addWidget(splitterVertical);
|
||||
setLayout(groupLayout);
|
||||
|
||||
m_eventStatistics = model;
|
||||
if (model) {
|
||||
connect(model, SIGNAL(stateChanged()), this, SLOT(eventListStateChanged()));
|
||||
}
|
||||
|
||||
m_globalStatsEnabled = true;
|
||||
d->m_profilerTool = profilerTool;
|
||||
d->m_viewContainer = container;
|
||||
d->m_globalStatsEnabled = true;
|
||||
}
|
||||
|
||||
QmlProfilerEventsWidget::~QmlProfilerEventsWidget()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::eventListStateChanged()
|
||||
void QmlProfilerEventsWidget::profilerDataModelStateChanged()
|
||||
{
|
||||
if (m_eventStatistics) {
|
||||
QmlProfilerEventList::State newState = m_eventStatistics->currentState();
|
||||
if (newState == QmlProfilerEventList::Empty) {
|
||||
if (d->m_profilerDataModel) {
|
||||
QmlProfilerDataModel::State newState = d->m_profilerDataModel->currentState();
|
||||
if (newState == QmlProfilerDataModel::Empty) {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
@@ -148,57 +183,119 @@ void QmlProfilerEventsWidget::eventListStateChanged()
|
||||
void QmlProfilerEventsWidget::switchToV8View()
|
||||
{
|
||||
setObjectName("QmlProfilerV8ProfileView");
|
||||
m_eventTree->setViewType(QmlProfilerEventsMainView::V8ProfileView);
|
||||
m_eventParents->setViewType(QmlProfilerEventsParentsAndChildrenView::V8ParentsView);
|
||||
m_eventChildren->setViewType(QmlProfilerEventsParentsAndChildrenView::V8ChildrenView);
|
||||
d->m_eventTree->setViewType(QmlProfilerEventsMainView::V8ProfileView);
|
||||
d->m_eventParents->setViewType(QmlProfilerEventsParentsAndChildrenView::V8ParentsView);
|
||||
d->m_eventChildren->setViewType(QmlProfilerEventsParentsAndChildrenView::V8ChildrenView);
|
||||
setToolTip(tr("Trace information from the v8 JavaScript engine. Available only in Qt5 based applications"));
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::clear()
|
||||
{
|
||||
m_eventTree->clear();
|
||||
m_eventChildren->clear();
|
||||
m_eventParents->clear();
|
||||
d->m_eventTree->clear();
|
||||
d->m_eventChildren->clear();
|
||||
d->m_eventParents->clear();
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd)
|
||||
{
|
||||
clear();
|
||||
m_eventTree->getStatisticsInRange(rangeStart, rangeEnd);
|
||||
m_globalStatsEnabled = m_eventTree->isRangeGlobal(rangeStart, rangeEnd);
|
||||
d->m_eventTree->getStatisticsInRange(rangeStart, rangeEnd);
|
||||
d->m_globalStatsEnabled = d->m_eventTree->isRangeGlobal(rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
QModelIndex QmlProfilerEventsWidget::selectedItem() const
|
||||
{
|
||||
return m_eventTree->selectedItem();
|
||||
return d->m_eventTree->selectedItem();
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::contextMenuEvent(QContextMenuEvent *ev)
|
||||
{
|
||||
emit contextMenuRequested(ev->globalPos());
|
||||
QTC_ASSERT(d->m_viewContainer, return;);
|
||||
|
||||
QMenu menu;
|
||||
QAction *copyRowAction = 0;
|
||||
QAction *copyTableAction = 0;
|
||||
QAction *showExtendedStatsAction = 0;
|
||||
QAction *getLocalStatsAction = 0;
|
||||
QAction *getGlobalStatsAction = 0;
|
||||
|
||||
QmlProfilerTool *profilerTool = qobject_cast<QmlProfilerTool *>(d->m_profilerTool);
|
||||
QPoint position = ev->globalPos();
|
||||
|
||||
if (profilerTool) {
|
||||
QList <QAction *> commonActions = profilerTool->profilerContextMenuActions();
|
||||
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"));
|
||||
|
||||
if (isQml()) {
|
||||
// only for qml events view, not for v8
|
||||
showExtendedStatsAction = menu.addAction(tr("Extended Event Statistics"));
|
||||
showExtendedStatsAction->setCheckable(true);
|
||||
showExtendedStatsAction->setChecked(showExtendedStatistics());
|
||||
}
|
||||
}
|
||||
|
||||
if (isQml()) {
|
||||
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);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
if (selectedAction == getGlobalStatsAction) {
|
||||
if (d->m_profilerDataModel) {
|
||||
getStatisticsInRange(d->m_profilerDataModel->traceStartTime(),
|
||||
d->m_profilerDataModel->traceEndTime());
|
||||
}
|
||||
}
|
||||
if (selectedAction == showExtendedStatsAction)
|
||||
setShowExtendedStatistics(!showExtendedStatistics());
|
||||
}
|
||||
}
|
||||
|
||||
bool QmlProfilerEventsWidget::mouseOnTable(const QPoint &position) const
|
||||
{
|
||||
QPoint tableTopLeft = m_eventTree->mapToGlobal(QPoint(0,0));
|
||||
QPoint tableBottomRight = m_eventTree->mapToGlobal(QPoint(m_eventTree->width(), m_eventTree->height()));
|
||||
QPoint tableTopLeft = d->m_eventTree->mapToGlobal(QPoint(0,0));
|
||||
QPoint tableBottomRight = d->m_eventTree->mapToGlobal(QPoint(d->m_eventTree->width(), d->m_eventTree->height()));
|
||||
return (position.x() >= tableTopLeft.x() && position.x() <= tableBottomRight.x() && position.y() >= tableTopLeft.y() && position.y() <= tableBottomRight.y());
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::copyTableToClipboard() const
|
||||
{
|
||||
m_eventTree->copyTableToClipboard();
|
||||
d->m_eventTree->copyTableToClipboard();
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::copyRowToClipboard() const
|
||||
{
|
||||
m_eventTree->copyRowToClipboard();
|
||||
d->m_eventTree->copyRowToClipboard();
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::updateSelectedEvent(int eventId) const
|
||||
{
|
||||
if (m_eventTree->selectedEventId() != eventId)
|
||||
m_eventTree->selectEvent(eventId);
|
||||
if (d->m_eventTree->selectedEventId() != eventId)
|
||||
d->m_eventTree->selectEvent(eventId);
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::selectBySourceLocation(const QString &filename, int line, int column)
|
||||
@@ -207,22 +304,31 @@ void QmlProfilerEventsWidget::selectBySourceLocation(const QString &filename, in
|
||||
// Our javascript trace data does not store column information
|
||||
// thus we ignore it here
|
||||
Q_UNUSED(column);
|
||||
m_eventTree->selectEventByLocation(filename, line);
|
||||
d->m_eventTree->selectEventByLocation(filename, line);
|
||||
}
|
||||
|
||||
bool QmlProfilerEventsWidget::hasGlobalStats() const
|
||||
{
|
||||
return m_globalStatsEnabled;
|
||||
return d->m_globalStatsEnabled;
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::setShowExtendedStatistics(bool show)
|
||||
{
|
||||
m_eventTree->setShowExtendedStatistics(show);
|
||||
d->m_eventTree->setShowExtendedStatistics(show);
|
||||
}
|
||||
|
||||
bool QmlProfilerEventsWidget::showExtendedStatistics() const
|
||||
{
|
||||
return m_eventTree->showExtendedStatistics();
|
||||
return d->m_eventTree->showExtendedStatistics();
|
||||
}
|
||||
|
||||
bool QmlProfilerEventsWidget::isQml() const
|
||||
{
|
||||
return d->m_eventTree->viewType() == QmlProfilerEventsMainView::EventsView;
|
||||
}
|
||||
bool QmlProfilerEventsWidget::isV8() const
|
||||
{
|
||||
return d->m_eventTree->viewType() == QmlProfilerEventsMainView::V8ProfileView;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -232,8 +338,8 @@ class QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate
|
||||
public:
|
||||
QmlProfilerEventsMainViewPrivate(QmlProfilerEventsMainView *qq) : q(qq) {}
|
||||
|
||||
void buildModelFromList(const QmlEventDescriptions &list, QStandardItem *parentItem, const QmlEventDescriptions &visitedFunctionsList = QmlEventDescriptions() );
|
||||
void buildV8ModelFromList( const QV8EventDescriptions &list );
|
||||
void buildModelFromList(const QList<QmlRangeEventData *> &list, QStandardItem *parentItem );
|
||||
void buildV8ModelFromList( const QList<QV8EventData *> &list );
|
||||
int getFieldCount();
|
||||
|
||||
QString textForItem(QStandardItem *item, bool recursive) const;
|
||||
@@ -242,7 +348,7 @@ public:
|
||||
QmlProfilerEventsMainView *q;
|
||||
|
||||
QmlProfilerEventsMainView::ViewTypes m_viewType;
|
||||
QmlProfilerEventList *m_eventStatistics;
|
||||
QmlProfilerDataModel *m_profilerDataModel;
|
||||
QStandardItemModel *m_model;
|
||||
QList<bool> m_fieldShown;
|
||||
QHash<int, int> m_columnIndex; // maps field enum to column index
|
||||
@@ -254,8 +360,10 @@ public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QmlProfilerEventsMainView::QmlProfilerEventsMainView(QmlProfilerEventList *model, QWidget *parent) :
|
||||
QTreeView(parent), d(new QmlProfilerEventsMainViewPrivate(this))
|
||||
QmlProfilerEventsMainView::QmlProfilerEventsMainView(ViewTypes viewType,
|
||||
QWidget *parent,
|
||||
QmlProfilerDataModel *dataModel)
|
||||
: QTreeView(parent), d(new QmlProfilerEventsMainViewPrivate(this))
|
||||
{
|
||||
setObjectName("QmlProfilerEventsTable");
|
||||
header()->setResizeMode(QHeaderView::Interactive);
|
||||
@@ -268,15 +376,17 @@ QmlProfilerEventsMainView::QmlProfilerEventsMainView(QmlProfilerEventList *model
|
||||
setModel(d->m_model);
|
||||
connect(this,SIGNAL(clicked(QModelIndex)), this,SLOT(jumpToItem(QModelIndex)));
|
||||
|
||||
d->m_eventStatistics = 0;
|
||||
setEventStatisticsModel(model);
|
||||
d->m_profilerDataModel = dataModel;
|
||||
connect(d->m_profilerDataModel,SIGNAL(stateChanged()),
|
||||
this,SLOT(profilerDataModelStateChanged()));
|
||||
connect(d->m_profilerDataModel,SIGNAL(detailsChanged(int,QString)),
|
||||
this,SLOT(changeDetailsForEvent(int,QString)));
|
||||
|
||||
d->m_firstNumericColumn = 0;
|
||||
d->m_preventSelectBounce = false;
|
||||
d->m_showExtendedStatistics = false;
|
||||
|
||||
// default view
|
||||
setViewType(EventsView);
|
||||
setViewType(viewType);
|
||||
}
|
||||
|
||||
QmlProfilerEventsMainView::~QmlProfilerEventsMainView()
|
||||
@@ -285,24 +395,11 @@ QmlProfilerEventsMainView::~QmlProfilerEventsMainView()
|
||||
delete d->m_model;
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::setEventStatisticsModel( QmlProfilerEventList *model )
|
||||
void QmlProfilerEventsMainView::profilerDataModelStateChanged()
|
||||
{
|
||||
if (d->m_eventStatistics) {
|
||||
disconnect(d->m_eventStatistics,SIGNAL(stateChanged()),this,SLOT(eventListStateChanged()));
|
||||
disconnect(d->m_eventStatistics,SIGNAL(detailsChanged(int,QString)),this,SLOT(changeDetailsForEvent(int,QString)));
|
||||
}
|
||||
d->m_eventStatistics = model;
|
||||
if (model) {
|
||||
connect(d->m_eventStatistics,SIGNAL(stateChanged()),this,SLOT(eventListStateChanged()));
|
||||
connect(d->m_eventStatistics,SIGNAL(detailsChanged(int,QString)),this,SLOT(changeDetailsForEvent(int,QString)));
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::eventListStateChanged()
|
||||
{
|
||||
if (d->m_eventStatistics) {
|
||||
QmlProfilerEventList::State newState = d->m_eventStatistics->currentState();
|
||||
if (newState == QmlProfilerEventList::Done)
|
||||
if (d->m_profilerDataModel) {
|
||||
QmlProfilerDataModel::State newState = d->m_profilerDataModel->currentState();
|
||||
if (newState == QmlProfilerDataModel::Done)
|
||||
buildModel();
|
||||
}
|
||||
}
|
||||
@@ -319,6 +416,11 @@ void QmlProfilerEventsMainView::setFieldViewable(Fields field, bool show)
|
||||
}
|
||||
}
|
||||
|
||||
QmlProfilerEventsMainView::ViewTypes QmlProfilerEventsMainView::viewType() const
|
||||
{
|
||||
return d->m_viewType;
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::setViewType(ViewTypes type)
|
||||
{
|
||||
d->m_viewType = type;
|
||||
@@ -465,12 +567,12 @@ int QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::getFieldCount()
|
||||
|
||||
void QmlProfilerEventsMainView::buildModel()
|
||||
{
|
||||
if (d->m_eventStatistics) {
|
||||
if (d->m_profilerDataModel) {
|
||||
clear();
|
||||
if (d->m_viewType == V8ProfileView)
|
||||
d->buildV8ModelFromList( d->m_eventStatistics->getV8Events() );
|
||||
d->buildV8ModelFromList( d->m_profilerDataModel->getV8Events() );
|
||||
else
|
||||
d->buildModelFromList( d->m_eventStatistics->getEventDescriptions(), d->m_model->invisibleRootItem() );
|
||||
d->buildModelFromList( d->m_profilerDataModel->getEventDescriptions(), d->m_model->invisibleRootItem() );
|
||||
|
||||
setShowExtendedStatistics(d->m_showExtendedStatistics);
|
||||
|
||||
@@ -488,18 +590,15 @@ void QmlProfilerEventsMainView::buildModel()
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildModelFromList( const QmlEventDescriptions &list, QStandardItem *parentItem, const QmlEventDescriptions &visitedFunctionsList )
|
||||
void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildModelFromList( const QList<QmlRangeEventData *> &list, QStandardItem *parentItem)
|
||||
{
|
||||
foreach (QmlEventData *binding, list) {
|
||||
if (visitedFunctionsList.contains(binding))
|
||||
continue;
|
||||
|
||||
foreach (QmlRangeEventData *binding, list) {
|
||||
if (binding->calls == 0)
|
||||
continue;
|
||||
|
||||
QList<QStandardItem *> newRow;
|
||||
if (m_fieldShown[Name]) {
|
||||
newRow << new EventsViewItem(binding->displayname);
|
||||
newRow << new EventsViewItem(binding->displayName);
|
||||
}
|
||||
|
||||
if (m_fieldShown[Type]) {
|
||||
@@ -572,7 +671,7 @@ void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildModelFrom
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildV8ModelFromList(const QV8EventDescriptions &list)
|
||||
void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildV8ModelFromList(const QList<QV8EventData *> &list)
|
||||
{
|
||||
for (int index = 0; index < list.count(); index++) {
|
||||
QV8EventData *v8event = list.at(index);
|
||||
@@ -649,13 +748,17 @@ QString QmlProfilerEventsMainView::nameForType(int typeNumber)
|
||||
|
||||
void QmlProfilerEventsMainView::getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd)
|
||||
{
|
||||
d->m_eventStatistics->compileStatistics(rangeStart, rangeEnd);
|
||||
if (d->m_profilerDataModel)
|
||||
d->m_profilerDataModel->compileStatistics(rangeStart, rangeEnd);
|
||||
buildModel();
|
||||
}
|
||||
|
||||
bool QmlProfilerEventsMainView::isRangeGlobal(qint64 rangeStart, qint64 rangeEnd) const
|
||||
{
|
||||
return d->m_eventStatistics->traceStartTime() == rangeStart && d->m_eventStatistics->traceEndTime() == rangeEnd;
|
||||
if (d->m_profilerDataModel)
|
||||
return d->m_profilerDataModel->traceStartTime() == rangeStart && d->m_profilerDataModel->traceEndTime() == rangeEnd;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
int QmlProfilerEventsMainView::selectedEventId() const
|
||||
@@ -691,7 +794,7 @@ void QmlProfilerEventsMainView::jumpToItem(const QModelIndex &index)
|
||||
// show in callers/callees subwindow
|
||||
emit eventSelected(infoItem->data(EventIdRole).toInt());
|
||||
|
||||
// show in timelineview
|
||||
// show in timelinerenderer
|
||||
if (d->m_viewType == EventsView) {
|
||||
emit showEventInTimeline(infoItem->data(EventIdRole).toInt());
|
||||
}
|
||||
@@ -819,9 +922,11 @@ void QmlProfilerEventsMainView::copyRowToClipboard() const
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QmlProfilerEventsParentsAndChildrenView::QmlProfilerEventsParentsAndChildrenView(QmlJsDebugClient::QmlProfilerEventList *model, SubViewType subtableType, QWidget *parent):QTreeView(parent)
|
||||
QmlProfilerEventsParentsAndChildrenView::QmlProfilerEventsParentsAndChildrenView(
|
||||
SubViewType subtableType, QWidget *parent, QmlProfilerDataModel *model)
|
||||
: QTreeView(parent)
|
||||
{
|
||||
m_eventList = model;
|
||||
m_profilerDataModel = model;
|
||||
setModel(new QStandardItemModel(this));
|
||||
setRootIsDecorated(false);
|
||||
setFrameStyle(QFrame::NoFrame);
|
||||
@@ -843,30 +948,33 @@ void QmlProfilerEventsParentsAndChildrenView::setViewType(SubViewType type)
|
||||
|
||||
void QmlProfilerEventsParentsAndChildrenView::displayEvent(int eventId)
|
||||
{
|
||||
if (!m_profilerDataModel)
|
||||
return;
|
||||
|
||||
bool isV8 = m_subtableType == V8ParentsView || m_subtableType == V8ChildrenView;
|
||||
bool isChildren = m_subtableType == ChildrenView || m_subtableType == V8ChildrenView;
|
||||
|
||||
if (isV8) {
|
||||
QmlJsDebugClient::QV8EventData *v8event = m_eventList->v8EventDescription(eventId);
|
||||
QV8EventData *v8event = m_profilerDataModel->v8EventDescription(eventId);
|
||||
if (v8event) {
|
||||
if (isChildren) {
|
||||
QList <QmlJsDebugClient::QV8EventSub *> childrenList = v8event->childrenHash.values();
|
||||
QList <QV8EventSub *> childrenList = v8event->childrenHash.values();
|
||||
rebuildTree((QObject *)&childrenList);
|
||||
}
|
||||
else {
|
||||
QList <QmlJsDebugClient::QV8EventSub *> parentList = v8event->parentHash.values();
|
||||
QList <QV8EventSub *> parentList = v8event->parentHash.values();
|
||||
rebuildTree((QObject *)&parentList);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
QmlJsDebugClient::QmlEventData *qmlEvent = m_eventList->eventDescription(eventId);
|
||||
QmlRangeEventData *qmlEvent = m_profilerDataModel->eventDescription(eventId);
|
||||
if (qmlEvent) {
|
||||
if (isChildren) {
|
||||
QList <QmlJsDebugClient::QmlEventSub *> childrenList = qmlEvent->childrenHash.values();
|
||||
QList <QmlRangeEventRelative *> childrenList = qmlEvent->childrenHash.values();
|
||||
rebuildTree((QObject *)&childrenList);
|
||||
}
|
||||
else {
|
||||
QList <QmlJsDebugClient::QmlEventSub *> parentList = qmlEvent->parentHash.values();
|
||||
QList <QmlRangeEventRelative *> parentList = qmlEvent->parentHash.values();
|
||||
rebuildTree((QObject *)&parentList);
|
||||
}
|
||||
}
|
||||
@@ -881,7 +989,7 @@ void QmlProfilerEventsParentsAndChildrenView::displayEvent(int eventId)
|
||||
sortByColumn(2);
|
||||
}
|
||||
|
||||
void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *eventList)
|
||||
void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *profilerDataModel)
|
||||
{
|
||||
Q_ASSERT(treeModel());
|
||||
treeModel()->clear();
|
||||
@@ -889,8 +997,8 @@ void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *eventList)
|
||||
QStandardItem *topLevelItem = treeModel()->invisibleRootItem();
|
||||
bool isV8 = m_subtableType == V8ParentsView || m_subtableType == V8ChildrenView;
|
||||
|
||||
QList <QmlEventSub *> *qmlList = static_cast< QList <QmlEventSub *> *>(eventList);
|
||||
QList <QV8EventSub*> *v8List = static_cast< QList <QV8EventSub *> *>(eventList);
|
||||
QList <QmlRangeEventRelative *> *qmlList = static_cast< QList <QmlRangeEventRelative *> *>(profilerDataModel);
|
||||
QList <QV8EventSub*> *v8List = static_cast< QList <QV8EventSub *> *>(profilerDataModel);
|
||||
|
||||
int listLength;
|
||||
if (!isV8)
|
||||
@@ -901,9 +1009,9 @@ void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *eventList)
|
||||
for (int index=0; index < listLength; index++) {
|
||||
QList<QStandardItem *> newRow;
|
||||
if (!isV8) {
|
||||
QmlEventSub *event = qmlList->at(index);
|
||||
QmlRangeEventRelative *event = qmlList->at(index);
|
||||
|
||||
newRow << new EventsViewItem(event->reference->displayname);
|
||||
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));
|
||||
|
@@ -34,9 +34,13 @@
|
||||
#define QMLPROFILEREVENTVIEW_H
|
||||
|
||||
#include <QTreeView>
|
||||
#include <qmljsdebugclient/qmlprofilereventtypes.h>
|
||||
#include <qmljsdebugclient/qmlprofilereventlist.h>
|
||||
#include <QStandardItemModel>
|
||||
#include <qmljsdebugclient/qmlprofilereventtypes.h>
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
|
||||
#include <analyzerbase/ianalyzertool.h>
|
||||
|
||||
#include "qmlprofilerviewmanager.h"
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
@@ -44,9 +48,6 @@ namespace Internal {
|
||||
class QmlProfilerEventsMainView;
|
||||
class QmlProfilerEventsParentsAndChildrenView;
|
||||
|
||||
typedef QHash<QString, QmlJsDebugClient::QmlEventData *> QmlEventHash;
|
||||
typedef QList<QmlJsDebugClient::QmlEventData *> QmlEventList;
|
||||
|
||||
enum ItemRole {
|
||||
EventHashStrRole = Qt::UserRole+1,
|
||||
FilenameRole = Qt::UserRole+2,
|
||||
@@ -59,7 +60,10 @@ class QmlProfilerEventsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QmlProfilerEventsWidget(QmlJsDebugClient::QmlProfilerEventList *model, QWidget *parent);
|
||||
explicit QmlProfilerEventsWidget(QWidget *parent,
|
||||
Analyzer::IAnalyzerTool *profilerTool,
|
||||
QmlProfilerViewManager *container,
|
||||
QmlProfilerDataModel *profilerDataModel );
|
||||
~QmlProfilerEventsWidget();
|
||||
|
||||
void switchToV8View();
|
||||
@@ -75,9 +79,11 @@ public:
|
||||
void setShowExtendedStatistics(bool show);
|
||||
bool showExtendedStatistics() const;
|
||||
|
||||
bool isQml() const;
|
||||
bool isV8() const;
|
||||
|
||||
signals:
|
||||
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
|
||||
void contextMenuRequested(const QPoint &position);
|
||||
void showEventInTimeline(int eventId);
|
||||
|
||||
public slots:
|
||||
@@ -85,18 +91,14 @@ public slots:
|
||||
void selectBySourceLocation(const QString &filename, int line, int column);
|
||||
|
||||
private slots:
|
||||
void eventListStateChanged();
|
||||
void profilerDataModelStateChanged();
|
||||
|
||||
protected:
|
||||
void contextMenuEvent(QContextMenuEvent *ev);
|
||||
|
||||
private:
|
||||
QmlProfilerEventsMainView *m_eventTree;
|
||||
QmlProfilerEventsParentsAndChildrenView *m_eventChildren;
|
||||
QmlProfilerEventsParentsAndChildrenView *m_eventParents;
|
||||
QmlJsDebugClient::QmlProfilerEventList *m_eventStatistics;
|
||||
|
||||
bool m_globalStatsEnabled;
|
||||
class QmlProfilerEventsWidgetPrivate;
|
||||
QmlProfilerEventsWidgetPrivate *d;
|
||||
};
|
||||
|
||||
class QmlProfilerEventsMainView : public QTreeView
|
||||
@@ -129,12 +131,14 @@ public:
|
||||
MaxViewTypes
|
||||
};
|
||||
|
||||
explicit QmlProfilerEventsMainView(QmlJsDebugClient::QmlProfilerEventList *model, QWidget *parent);
|
||||
explicit QmlProfilerEventsMainView(ViewTypes viewType,
|
||||
QWidget *parent,
|
||||
QmlProfilerDataModel *dataModel);
|
||||
~QmlProfilerEventsMainView();
|
||||
|
||||
void setEventStatisticsModel(QmlJsDebugClient::QmlProfilerEventList *model);
|
||||
void setFieldViewable(Fields field, bool show);
|
||||
void setViewType(ViewTypes type);
|
||||
ViewTypes viewType() const;
|
||||
void setShowAnonymousEvents( bool showThem );
|
||||
|
||||
QModelIndex selectedItem() const;
|
||||
@@ -157,7 +161,6 @@ signals:
|
||||
void showEventInTimeline(int eventId);
|
||||
|
||||
public slots:
|
||||
void eventListStateChanged();
|
||||
void clear();
|
||||
void jumpToItem(const QModelIndex &index);
|
||||
void selectEvent(int eventId);
|
||||
@@ -165,6 +168,9 @@ public slots:
|
||||
void buildModel();
|
||||
void changeDetailsForEvent(int eventId, const QString &newString);
|
||||
|
||||
private slots:
|
||||
void profilerDataModelStateChanged();
|
||||
|
||||
private:
|
||||
void setHeaderLabels();
|
||||
|
||||
@@ -186,7 +192,9 @@ public:
|
||||
MaxSubtableTypes
|
||||
};
|
||||
|
||||
explicit QmlProfilerEventsParentsAndChildrenView(QmlJsDebugClient::QmlProfilerEventList *model, SubViewType subtableType, QWidget *parent);
|
||||
explicit QmlProfilerEventsParentsAndChildrenView(SubViewType subtableType,
|
||||
QWidget *parent,
|
||||
QmlProfilerDataModel *model);
|
||||
~QmlProfilerEventsParentsAndChildrenView();
|
||||
|
||||
void setViewType(SubViewType type);
|
||||
@@ -200,10 +208,10 @@ public slots:
|
||||
void clear();
|
||||
|
||||
private:
|
||||
void rebuildTree(void *eventList);
|
||||
void rebuildTree(void *profilerDataModel);
|
||||
void updateHeader();
|
||||
QStandardItemModel *treeModel();
|
||||
QmlJsDebugClient::QmlProfilerEventList *m_eventList;
|
||||
QmlProfilerDataModel *m_profilerDataModel;
|
||||
|
||||
SubViewType m_subtableType;
|
||||
};
|
||||
|
163
src/plugins/qmlprofiler/qmlprofilerstatemanager.cpp
Normal file
163
src/plugins/qmlprofiler/qmlprofilerstatemanager.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** 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, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlprofilerstatemanager.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
// uncomment for printing the state changes to debug output
|
||||
//#define _DEBUG_PROFILERSTATE_
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
inline QString stringForState(int state) {
|
||||
switch (state) {
|
||||
case QmlProfilerStateManager::Idle: return QString("Idle");
|
||||
case QmlProfilerStateManager::AppStarting: return QString("AppStarting");
|
||||
case QmlProfilerStateManager::AppRunning: return QString("AppRunning");
|
||||
case QmlProfilerStateManager::AppStopRequested: return QString("AppStopRequested");
|
||||
case QmlProfilerStateManager::AppReadyToStop: return QString("AppReadyToStop");
|
||||
case QmlProfilerStateManager::AppStopped: return QString("AppStopped");
|
||||
case QmlProfilerStateManager::AppKilled: return QString("AppKilled");
|
||||
default: break;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
class QmlProfilerStateManager::QmlProfilerStateManagerPrivate
|
||||
{
|
||||
public:
|
||||
QmlProfilerStateManagerPrivate(QmlProfilerStateManager *qq) : q(qq) {}
|
||||
~QmlProfilerStateManagerPrivate() {}
|
||||
|
||||
QmlProfilerStateManager *q;
|
||||
|
||||
QmlProfilerStateManager::QmlProfilerState m_currentState;
|
||||
bool m_clientRecording;
|
||||
bool m_serverRecording;
|
||||
};
|
||||
QmlProfilerStateManager::QmlProfilerStateManager(QObject *parent) :
|
||||
QObject(parent),d(new QmlProfilerStateManagerPrivate(this))
|
||||
{
|
||||
d->m_currentState = Idle;
|
||||
d->m_clientRecording = true;
|
||||
d->m_serverRecording = false;
|
||||
}
|
||||
|
||||
QmlProfilerStateManager::~QmlProfilerStateManager()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QmlProfilerStateManager::QmlProfilerState QmlProfilerStateManager::currentState()
|
||||
{
|
||||
return d->m_currentState;
|
||||
}
|
||||
|
||||
bool QmlProfilerStateManager::clientRecording()
|
||||
{
|
||||
return d->m_clientRecording;
|
||||
}
|
||||
|
||||
bool QmlProfilerStateManager::serverRecording()
|
||||
{
|
||||
return d->m_serverRecording;
|
||||
}
|
||||
|
||||
QString QmlProfilerStateManager::currentStateAsString()
|
||||
{
|
||||
return stringForState(d->m_currentState);
|
||||
}
|
||||
|
||||
void QmlProfilerStateManager::setCurrentState(QmlProfilerState newState)
|
||||
{
|
||||
#ifdef _DEBUG_PROFILERSTATE_
|
||||
qDebug() << "Profiler state change request from" << stringForState(d->m_currentState) << "to" << stringForState(newState);
|
||||
#endif
|
||||
QTC_ASSERT(d->m_currentState != newState, /**/);
|
||||
switch (newState) {
|
||||
case Idle:
|
||||
QTC_ASSERT(d->m_currentState == AppStarting || d->m_currentState == AppStopped || d->m_currentState == AppKilled, /**/);
|
||||
break;
|
||||
case AppStarting:
|
||||
QTC_ASSERT(d->m_currentState == Idle, /**/);
|
||||
break;
|
||||
case AppRunning:
|
||||
QTC_ASSERT(d->m_currentState == AppStarting, /**/);
|
||||
break;
|
||||
case AppStopRequested:
|
||||
QTC_ASSERT(d->m_currentState == AppRunning, /**/);
|
||||
break;
|
||||
case AppReadyToStop:
|
||||
QTC_ASSERT(d->m_currentState == AppStopRequested, /**/);
|
||||
break;
|
||||
case AppStopped:
|
||||
QTC_ASSERT(d->m_currentState == AppReadyToStop, /**/);
|
||||
break;
|
||||
case AppKilled:
|
||||
QTC_ASSERT(d->m_currentState == AppRunning, /**/);
|
||||
break;
|
||||
default:
|
||||
qDebug() << tr("Switching to unknown state in %1:%2").arg(QString(__FILE__), QString::number(__LINE__));
|
||||
break;
|
||||
}
|
||||
|
||||
d->m_currentState = newState;
|
||||
emit stateChanged();
|
||||
}
|
||||
|
||||
void QmlProfilerStateManager::setClientRecording(bool recording)
|
||||
{
|
||||
#ifdef _DEBUG_PROFILERSTATE_
|
||||
qDebug() << "Setting client recording flag from" << d->m_serverRecording << "to" << recording;
|
||||
#endif
|
||||
if (d->m_clientRecording != recording) {
|
||||
d->m_clientRecording = recording;
|
||||
emit clientRecordingChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerStateManager::setServerRecording(bool recording)
|
||||
{
|
||||
#ifdef _DEBUG_PROFILERSTATE_
|
||||
qDebug() << "Setting server recording flag from" << d->m_serverRecording << "to" << recording;
|
||||
#endif
|
||||
if (d->m_serverRecording != recording) {
|
||||
d->m_serverRecording = recording;
|
||||
emit serverRecordingChanged();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -30,25 +30,53 @@
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef COMMANDLISTENER_H
|
||||
#define COMMANDLISTENER_H
|
||||
#ifndef QMLPROFILERSTATEMANAGER_H
|
||||
#define QMLPROFILERSTATEMANAGER_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QObject>
|
||||
|
||||
class CommandListener : public QThread
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerStateManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CommandListener(QObject *parent = 0);
|
||||
enum QmlProfilerState {
|
||||
Idle,
|
||||
AppStarting,
|
||||
AppRunning,
|
||||
AppStopRequested,
|
||||
AppReadyToStop,
|
||||
AppStopped,
|
||||
AppKilled
|
||||
};
|
||||
|
||||
void run();
|
||||
explicit QmlProfilerStateManager(QObject *parent = 0);
|
||||
~QmlProfilerStateManager();
|
||||
|
||||
QmlProfilerState currentState();
|
||||
bool clientRecording();
|
||||
bool serverRecording();
|
||||
|
||||
QString currentStateAsString();
|
||||
|
||||
void requestStop() { m_stopRequested = true; }
|
||||
signals:
|
||||
void command(const QString &command);
|
||||
void stateChanged();
|
||||
void clientRecordingChanged();
|
||||
void serverRecordingChanged();
|
||||
|
||||
public slots:
|
||||
void setCurrentState(QmlProfilerState newState);
|
||||
void setClientRecording(bool recording);
|
||||
void setServerRecording(bool recording);
|
||||
|
||||
private:
|
||||
bool m_stopRequested;
|
||||
class QmlProfilerStateManagerPrivate;
|
||||
QmlProfilerStateManagerPrivate *d;
|
||||
};
|
||||
|
||||
#endif // COMMANDLISTENER_H
|
||||
}
|
||||
}
|
||||
|
||||
#endif // QMLPROFILERSTATEMANAGER_H
|
@@ -31,24 +31,20 @@
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlprofilertool.h"
|
||||
#include "qmlprofilerstatemanager.h"
|
||||
#include "qmlprofilerengine.h"
|
||||
#include "qmlprofilerplugin.h"
|
||||
#include "qmlprofilerconstants.h"
|
||||
#include "qmlprofilerattachdialog.h"
|
||||
#include "qmlprofilereventview.h"
|
||||
|
||||
#include "tracewindow.h"
|
||||
#include "timelineview.h"
|
||||
|
||||
#include <qmljsdebugclient/qmlprofilereventlist.h>
|
||||
#include <qmljsdebugclient/qdeclarativedebugclient.h>
|
||||
#include "qmlprofilerviewmanager.h"
|
||||
#include "qmlprofilerclientmanager.h"
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
#include "qmlprofilerdetailsrewriter.h"
|
||||
#include "timelinerenderer.h"
|
||||
|
||||
#include <analyzerbase/analyzermanager.h>
|
||||
#include <analyzerbase/analyzerconstants.h>
|
||||
#include <analyzerbase/analyzerruncontrol.h>
|
||||
|
||||
#include "canvas/qdeclarativecanvas_p.h"
|
||||
#include "canvas/qdeclarativecanvastimer_p.h"
|
||||
#include "canvas/qdeclarativecontext2d_p.h"
|
||||
#include "canvas/qmlprofilercanvas.h"
|
||||
|
||||
#include <qmlprojectmanager/qmlprojectrunconfiguration.h>
|
||||
@@ -56,7 +52,6 @@
|
||||
#include <utils/fileinprojectfinder.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <projectexplorer/session.h>
|
||||
@@ -65,7 +60,6 @@
|
||||
#include <remotelinux/remotelinuxrunconfiguration.h>
|
||||
#include <remotelinux/linuxdeviceconfiguration.h>
|
||||
|
||||
#include <texteditor/itexteditor.h>
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/icore.h>
|
||||
@@ -82,23 +76,22 @@
|
||||
#include <qt4projectmanager/qt-s60/s60devicerunconfiguration.h>
|
||||
#include <qt4projectmanager/qt-s60/s60deployconfiguration.h>
|
||||
|
||||
#include <QFile>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QTabWidget>
|
||||
#include <QToolButton>
|
||||
#include <QMessageBox>
|
||||
#include <QDockWidget>
|
||||
#include <QFileDialog>
|
||||
#include <QMenu>
|
||||
#include <QTimer>
|
||||
#include <QTime>
|
||||
|
||||
using namespace Core;
|
||||
using namespace Core::Constants;
|
||||
using namespace Analyzer;
|
||||
using namespace Analyzer::Constants;
|
||||
using namespace QmlProfiler::Internal;
|
||||
using namespace QmlProfiler::Constants;
|
||||
using namespace QmlJsDebugClient;
|
||||
using namespace ProjectExplorer;
|
||||
using namespace QmlProjectManager;
|
||||
@@ -112,59 +105,67 @@ public:
|
||||
|
||||
QmlProfilerTool *q;
|
||||
|
||||
QDeclarativeDebugConnection *m_client;
|
||||
QTimer m_connectionTimer;
|
||||
int m_connectionAttempts;
|
||||
TraceWindow *m_traceWindow;
|
||||
QmlProfilerEventsWidget *m_eventsView;
|
||||
QmlProfilerEventsWidget *m_v8profilerView;
|
||||
QmlProfilerStateManager *m_profilerState;
|
||||
QmlProfilerClientManager *m_profilerConnections;
|
||||
QmlProfilerDataModel *m_profilerDataModel;
|
||||
QmlProfilerDetailsRewriter *m_detailsRewriter;
|
||||
|
||||
QmlProfilerViewManager *m_viewContainer;
|
||||
Utils::FileInProjectFinder m_projectFinder;
|
||||
RunConfiguration *m_runConfiguration;
|
||||
bool m_isAttached;
|
||||
QToolButton *m_recordButton;
|
||||
QToolButton *m_clearButton;
|
||||
bool m_recordingEnabled;
|
||||
bool m_appIsRunning;
|
||||
bool m_qmlActive;
|
||||
bool m_v8Active;
|
||||
QTime m_appTimer;
|
||||
qint64 m_appRunningTime;
|
||||
|
||||
enum ConnectMode {
|
||||
TcpConnection, OstConnection
|
||||
};
|
||||
// elapsed time display
|
||||
QTimer m_recordingTimer;
|
||||
QTime m_recordingElapsedTime;
|
||||
QLabel *m_timeLabel;
|
||||
|
||||
ConnectMode m_connectMode;
|
||||
QString m_tcpHost;
|
||||
quint16 m_tcpPort;
|
||||
QString m_ostDevice;
|
||||
QString m_sysroot;
|
||||
// save and load actions
|
||||
QAction *m_saveQmlTrace;
|
||||
QAction *m_loadQmlTrace;
|
||||
};
|
||||
|
||||
QmlProfilerTool::QmlProfilerTool(QObject *parent)
|
||||
: IAnalyzerTool(parent), d(new QmlProfilerToolPrivate(this))
|
||||
{
|
||||
setObjectName("QmlProfilerTool");
|
||||
d->m_client = 0;
|
||||
d->m_connectionAttempts = 0;
|
||||
d->m_traceWindow = 0;
|
||||
|
||||
d->m_profilerState = 0;
|
||||
d->m_viewContainer = 0;
|
||||
d->m_runConfiguration = 0;
|
||||
d->m_isAttached = false;
|
||||
d->m_recordingEnabled = true;
|
||||
d->m_appIsRunning = false;
|
||||
d->m_appTimer.start();
|
||||
d->m_appRunningTime = 0;
|
||||
|
||||
d->m_connectionTimer.setInterval(200);
|
||||
connect(&d->m_connectionTimer, SIGNAL(timeout()), SLOT(tryToConnect()));
|
||||
|
||||
qmlRegisterType<Canvas>("Monitor", 1, 0, "Canvas");
|
||||
qmlRegisterType<QmlProfilerCanvas>("Monitor", 1, 0, "Canvas2D");
|
||||
qmlRegisterType<Context2D>();
|
||||
qmlRegisterType<CanvasImage>();
|
||||
qmlRegisterType<CanvasGradient>();
|
||||
qmlRegisterType<TimelineView>("Monitor", 1, 0,"TimelineView");
|
||||
qmlRegisterType<TimelineRenderer>("Monitor", 1, 0,"TimelineRenderer");
|
||||
|
||||
d->m_profilerState = new QmlProfilerStateManager(this);
|
||||
connect(d->m_profilerState, SIGNAL(stateChanged()), this, SLOT(profilerStateChanged()));
|
||||
connect(d->m_profilerState, SIGNAL(clientRecordingChanged()), this, SLOT(clientRecordingChanged()));
|
||||
connect(d->m_profilerState, SIGNAL(serverRecordingChanged()), this, SLOT(serverRecordingChanged()));
|
||||
|
||||
d->m_profilerConnections = new QmlProfilerClientManager(this);
|
||||
d->m_profilerConnections->registerProfilerStateManager(d->m_profilerState);
|
||||
|
||||
d->m_profilerDataModel = new QmlProfilerDataModel(this);
|
||||
connect(d->m_profilerDataModel, SIGNAL(stateChanged()), this, SLOT(profilerDataModelStateChanged()));
|
||||
connect(d->m_profilerDataModel, SIGNAL(error(QString)), this, SLOT(showErrorDialog(QString)));
|
||||
connect(d->m_profilerConnections, SIGNAL(addRangedEvent(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)), d->m_profilerDataModel, SLOT(addRangedEvent(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)));
|
||||
connect(d->m_profilerConnections, SIGNAL(addV8Event(int,QString,QString,int,double,double)), d->m_profilerDataModel, SLOT(addV8Event(int,QString,QString,int,double,double)));
|
||||
connect(d->m_profilerConnections, SIGNAL(addFrameEvent(qint64,int,int)), d->m_profilerDataModel, SLOT(addFrameEvent(qint64,int,int)));
|
||||
connect(d->m_profilerConnections, SIGNAL(traceStarted(qint64)), d->m_profilerDataModel, SLOT(setTraceStartTime(qint64)));
|
||||
connect(d->m_profilerConnections, SIGNAL(traceFinished(qint64)), d->m_profilerDataModel, SLOT(setTraceEndTime(qint64)));
|
||||
connect(d->m_profilerConnections, SIGNAL(dataReadyForProcessing()), d->m_profilerDataModel, SLOT(complete()));
|
||||
|
||||
|
||||
d->m_detailsRewriter = new QmlProfilerDetailsRewriter(this);
|
||||
connect(d->m_profilerDataModel, SIGNAL(requestDetailsForLocation(int,QmlJsDebugClient::QmlEventLocation)),
|
||||
d->m_detailsRewriter, SLOT(requestDetailsForLocation(int,QmlJsDebugClient::QmlEventLocation)));
|
||||
connect(d->m_detailsRewriter, SIGNAL(rewriteDetailsString(int,QmlJsDebugClient::QmlEventLocation,QString)),
|
||||
d->m_profilerDataModel, SLOT(rewriteDetailsString(int,QmlJsDebugClient::QmlEventLocation,QString)));
|
||||
connect(d->m_detailsRewriter, SIGNAL(eventDetailsChanged()), d->m_profilerDataModel, SLOT(finishedRewritingDetails()));
|
||||
connect(d->m_profilerDataModel, SIGNAL(reloadDocumentsForDetails()), d->m_detailsRewriter, SLOT(reloadDocuments()));
|
||||
|
||||
Command *command = 0;
|
||||
const Context globalContext(C_GLOBAL);
|
||||
@@ -176,7 +177,7 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
|
||||
menu->addMenu(options, G_ANALYZER_OPTIONS);
|
||||
options->menu()->setEnabled(true);
|
||||
|
||||
QAction *act = new QAction(tr("Load QML Trace"), options);
|
||||
QAction *act = d->m_loadQmlTrace = new QAction(tr("Load QML Trace"), options);
|
||||
command = am->registerAction(act, "Analyzer.Menu.StartAnalyzer.QMLProfilerOptions.LoadQMLTrace", globalContext);
|
||||
connect(act, SIGNAL(triggered()), this, SLOT(showLoadDialog()));
|
||||
options->addAction(command);
|
||||
@@ -186,11 +187,13 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
|
||||
command = am->registerAction(act, "Analyzer.Menu.StartAnalyzer.QMLProfilerOptions.SaveQMLTrace", globalContext);
|
||||
connect(act, SIGNAL(triggered()), this, SLOT(showSaveDialog()));
|
||||
options->addAction(command);
|
||||
|
||||
d->m_recordingTimer.setInterval(100);
|
||||
connect(&d->m_recordingTimer, SIGNAL(timeout()), this, SLOT(updateTimeDisplay()));
|
||||
}
|
||||
|
||||
QmlProfilerTool::~QmlProfilerTool()
|
||||
{
|
||||
delete d->m_client;
|
||||
delete d;
|
||||
}
|
||||
|
||||
@@ -220,86 +223,14 @@ IAnalyzerTool::ToolMode QmlProfilerTool::toolMode() const
|
||||
return AnyMode;
|
||||
}
|
||||
|
||||
void QmlProfilerTool::showContextMenu(const QPoint &position)
|
||||
{
|
||||
QmlProfilerEventsWidget *eventView = qobject_cast<QmlProfilerEventsWidget *>(sender());
|
||||
TraceWindow *traceView = qobject_cast<TraceWindow *>(sender());
|
||||
|
||||
QMenu menu;
|
||||
QAction *loadAction = menu.addAction(tr("Load QML Trace"));
|
||||
QAction *saveAction = menu.addAction(tr("Save QML Trace"));
|
||||
QAction *copyRowAction = 0;
|
||||
QAction *copyTableAction = 0;
|
||||
QAction *showExtendedStatsAction = 0;
|
||||
QAction *viewAllAction = 0;
|
||||
QAction *getLocalStatsAction = 0;
|
||||
QAction *getGlobalStatsAction = 0;
|
||||
|
||||
if (eventView && eventView->mouseOnTable(position)) {
|
||||
menu.addSeparator();
|
||||
if (eventView->selectedItem().isValid())
|
||||
copyRowAction = menu.addAction(tr("Copy Row"));
|
||||
copyTableAction = menu.addAction(tr("Copy Table"));
|
||||
|
||||
if (eventView == d->m_eventsView) {
|
||||
// only for qml events view, not for v8
|
||||
showExtendedStatsAction = menu.addAction(tr("Extended Event Statistics"));
|
||||
showExtendedStatsAction->setCheckable(true);
|
||||
showExtendedStatsAction->setChecked(eventView->showExtendedStatistics());
|
||||
}
|
||||
}
|
||||
|
||||
if (sender() == d->m_traceWindow || sender() == d->m_eventsView) {
|
||||
menu.addSeparator();
|
||||
getLocalStatsAction = menu.addAction(tr("Limit Events Pane to Current Range"));
|
||||
if (!d->m_traceWindow->hasValidSelection())
|
||||
getLocalStatsAction->setEnabled(false);
|
||||
getGlobalStatsAction = menu.addAction(tr("Reset Events Pane"));
|
||||
if (d->m_eventsView->hasGlobalStats())
|
||||
getGlobalStatsAction->setEnabled(false);
|
||||
}
|
||||
|
||||
if (traceView) {
|
||||
if (traceView->getEventList()->count() > 0) {
|
||||
menu.addSeparator();
|
||||
viewAllAction = menu.addAction(tr("Reset Zoom"));
|
||||
}
|
||||
}
|
||||
|
||||
QAction *selectedAction = menu.exec(position);
|
||||
|
||||
if (selectedAction) {
|
||||
if (selectedAction == loadAction)
|
||||
showLoadDialog();
|
||||
if (selectedAction == saveAction)
|
||||
showSaveDialog();
|
||||
if (selectedAction == copyRowAction)
|
||||
eventView->copyRowToClipboard();
|
||||
if (selectedAction == copyTableAction)
|
||||
eventView->copyTableToClipboard();
|
||||
if (selectedAction == viewAllAction)
|
||||
traceView->viewAll();
|
||||
if (selectedAction == getLocalStatsAction) {
|
||||
d->m_eventsView->getStatisticsInRange(
|
||||
d->m_traceWindow->selectionStart(),
|
||||
d->m_traceWindow->selectionEnd());
|
||||
}
|
||||
if (selectedAction == getGlobalStatsAction) {
|
||||
d->m_eventsView->getStatisticsInRange(
|
||||
d->m_traceWindow->getEventList()->traceStartTime(),
|
||||
d->m_traceWindow->getEventList()->traceEndTime());
|
||||
}
|
||||
if (selectedAction == showExtendedStatsAction)
|
||||
eventView->setShowExtendedStatistics(!eventView->showExtendedStatistics());
|
||||
}
|
||||
}
|
||||
|
||||
IAnalyzerEngine *QmlProfilerTool::createEngine(const AnalyzerStartParameters &sp,
|
||||
RunConfiguration *runConfiguration)
|
||||
{
|
||||
QmlProfilerEngine *engine = new QmlProfilerEngine(this, sp, runConfiguration);
|
||||
|
||||
d->m_connectMode = QmlProfilerToolPrivate::TcpConnection;
|
||||
engine->registerProfilerStateManager(d->m_profilerState);
|
||||
|
||||
bool isTcpConnection = true;
|
||||
|
||||
if (runConfiguration) {
|
||||
// Check minimum Qt Version. We cannot really be sure what the Qt version
|
||||
@@ -324,16 +255,15 @@ IAnalyzerEngine *QmlProfilerTool::createEngine(const AnalyzerStartParameters &sp
|
||||
runConfiguration->target()->activeDeployConfiguration())) {
|
||||
if (deployConfig->communicationChannel()
|
||||
== Qt4ProjectManager::S60DeployConfiguration::CommunicationCodaSerialConnection) {
|
||||
d->m_connectMode = QmlProfilerToolPrivate::OstConnection;
|
||||
d->m_ostDevice = deployConfig->serialPortName();
|
||||
d->m_profilerConnections->setOstConnection(deployConfig->serialPortName());
|
||||
isTcpConnection = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Check that there's something sensible in sp.connParams
|
||||
if (d->m_connectMode == QmlProfilerToolPrivate::TcpConnection) {
|
||||
d->m_tcpHost = sp.connParams.host;
|
||||
d->m_tcpPort = sp.connParams.port;
|
||||
if (isTcpConnection) {
|
||||
d->m_profilerConnections->setTcpConnection(sp.connParams.host, sp.connParams.port);
|
||||
}
|
||||
|
||||
d->m_runConfiguration = runConfiguration;
|
||||
@@ -364,20 +294,9 @@ IAnalyzerEngine *QmlProfilerTool::createEngine(const AnalyzerStartParameters &sp
|
||||
d->m_projectFinder.setProjectFiles(sourceFiles);
|
||||
d->m_projectFinder.setSysroot(sp.sysroot);
|
||||
|
||||
connect(engine, SIGNAL(processRunning(quint16)), this, SLOT(connectClient(quint16)));
|
||||
connect(engine, SIGNAL(finished()), this, SLOT(disconnectClient()));
|
||||
connect(engine, SIGNAL(finished()), this, SLOT(updateTimers()));
|
||||
connect(engine, SIGNAL(stopRecording()), this, SLOT(stopRecording()));
|
||||
connect(engine, SIGNAL(recordingChanged(bool)), this, SLOT(setRecording(bool)));
|
||||
connect(engine, SIGNAL(timeUpdate()), this, SLOT(updateTimers()));
|
||||
connect(d->m_traceWindow, SIGNAL(viewUpdated()), engine, SLOT(dataReceived()));
|
||||
connect(this, SIGNAL(connectionFailed()), engine, SLOT(finishProcess()));
|
||||
connect(this, SIGNAL(fetchingData(bool)), engine, SLOT(setFetchingData(bool)));
|
||||
connect(engine, SIGNAL(starting(const Analyzer::IAnalyzerEngine*)), this, SLOT(setAppIsRunning()));
|
||||
connect(engine, SIGNAL(finished()), this, SLOT(setAppIsStopped()));
|
||||
connect(this, SIGNAL(cancelRun()), engine, SLOT(finishProcess()));
|
||||
connect(engine, SIGNAL(applicationDied()), d->m_traceWindow, SLOT(applicationDied()));
|
||||
emit fetchingData(d->m_recordButton->isChecked());
|
||||
connect(engine, SIGNAL(processRunning(quint16)), d->m_profilerConnections, SLOT(connectClient(quint16)));
|
||||
connect(engine, SIGNAL(finished()), d->m_profilerConnections, SLOT(disconnectClient()));
|
||||
connect(d->m_profilerConnections, SIGNAL(connectionFailed()), engine, SLOT(cancelProcess()));
|
||||
|
||||
return engine;
|
||||
}
|
||||
@@ -444,53 +363,15 @@ AnalyzerStartParameters QmlProfilerTool::createStartParameters(RunConfiguration
|
||||
|
||||
QWidget *QmlProfilerTool::createWidgets()
|
||||
{
|
||||
QTC_ASSERT(!d->m_traceWindow, return 0);
|
||||
QTC_ASSERT(!d->m_viewContainer, return 0);
|
||||
|
||||
//
|
||||
// DockWidgets
|
||||
//
|
||||
|
||||
Utils::FancyMainWindow *mw = AnalyzerManager::mainWindow();
|
||||
|
||||
d->m_traceWindow = new TraceWindow(mw);
|
||||
d->m_traceWindow->reset(d->m_client);
|
||||
|
||||
connect(d->m_traceWindow, SIGNAL(clearViewsFromTool()), this, SLOT(clearDisplay()));
|
||||
connect(d->m_traceWindow, SIGNAL(gotoSourceLocation(QString,int,int)),this, SLOT(gotoSourceLocation(QString,int,int)));
|
||||
connect(d->m_traceWindow, SIGNAL(contextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
|
||||
connect(d->m_traceWindow->getEventList(), SIGNAL(error(QString)), this, SLOT(showErrorDialog(QString)));
|
||||
connect(d->m_traceWindow->getEventList(), SIGNAL(stateChanged()), this, SLOT(eventListStateChanged()));
|
||||
connect(d->m_traceWindow, SIGNAL(profilerStateChanged(bool,bool)), this, SLOT(profilerStateChanged(bool,bool)));
|
||||
connect(d->m_traceWindow, SIGNAL(recordingChanged(bool)), this, SLOT(setRecording(bool)));
|
||||
|
||||
d->m_eventsView = new QmlProfilerEventsWidget(d->m_traceWindow->getEventList(), mw);
|
||||
connect(d->m_eventsView, SIGNAL(gotoSourceLocation(QString,int,int)), this, SLOT(gotoSourceLocation(QString,int,int)));
|
||||
connect(d->m_eventsView, SIGNAL(contextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
|
||||
connect(d->m_eventsView, SIGNAL(showEventInTimeline(int)), d->m_traceWindow, SLOT(selectNextEvent(int)));
|
||||
connect(d->m_traceWindow, SIGNAL(selectedEventIdChanged(int)), d->m_eventsView, SLOT(updateSelectedEvent(int)));
|
||||
|
||||
d->m_v8profilerView = new QmlProfilerEventsWidget(d->m_traceWindow->getEventList(), mw);
|
||||
d->m_v8profilerView->switchToV8View();
|
||||
connect(d->m_v8profilerView, SIGNAL(gotoSourceLocation(QString,int,int)), this, SLOT(gotoSourceLocation(QString,int,int)));
|
||||
connect(d->m_v8profilerView, SIGNAL(contextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
|
||||
|
||||
connect(d->m_v8profilerView, SIGNAL(gotoSourceLocation(QString,int,int)), d->m_eventsView, SLOT(selectBySourceLocation(QString,int,int)));
|
||||
connect(d->m_eventsView, SIGNAL(gotoSourceLocation(QString,int,int)), d->m_v8profilerView, SLOT(selectBySourceLocation(QString,int,int)));
|
||||
|
||||
QDockWidget *eventsDock = AnalyzerManager::createDockWidget
|
||||
(this, tr("Events"), d->m_eventsView, Qt::BottomDockWidgetArea);
|
||||
QDockWidget *timelineDock = AnalyzerManager::createDockWidget
|
||||
(this, tr("Timeline"), d->m_traceWindow, Qt::BottomDockWidgetArea);
|
||||
QDockWidget *v8profilerDock = AnalyzerManager::createDockWidget
|
||||
(this, tr("JavaScript"), d->m_v8profilerView, Qt::BottomDockWidgetArea);
|
||||
|
||||
eventsDock->show();
|
||||
timelineDock->show();
|
||||
v8profilerDock->show();
|
||||
|
||||
mw->splitDockWidget(mw->toolBarDockWidget(), eventsDock, Qt::Vertical);
|
||||
mw->tabifyDockWidget(eventsDock, timelineDock);
|
||||
mw->tabifyDockWidget(timelineDock, v8profilerDock);
|
||||
d->m_viewContainer = new QmlProfilerViewManager(this,
|
||||
this,
|
||||
d->m_profilerDataModel,
|
||||
d->m_profilerState);
|
||||
connect(d->m_viewContainer, SIGNAL(gotoSourceLocation(QString,int,int)),
|
||||
this, SLOT(gotoSourceLocation(QString,int,int)));
|
||||
|
||||
//
|
||||
// Toolbar
|
||||
@@ -507,118 +388,53 @@ QWidget *QmlProfilerTool::createWidgets()
|
||||
|
||||
connect(d->m_recordButton,SIGNAL(clicked(bool)), this, SLOT(recordingButtonChanged(bool)));
|
||||
d->m_recordButton->setChecked(true);
|
||||
setRecording(d->m_recordingEnabled);
|
||||
setRecording(d->m_profilerState->clientRecording());
|
||||
layout->addWidget(d->m_recordButton);
|
||||
|
||||
d->m_clearButton = new QToolButton(toolbarWidget);
|
||||
d->m_clearButton->setIcon(QIcon(QLatin1String(":/qmlprofiler/clean_pane_small.png")));
|
||||
d->m_clearButton->setToolTip(tr("Discard data"));
|
||||
connect(d->m_clearButton,SIGNAL(clicked()), this, SLOT(clearDisplay()));
|
||||
|
||||
connect(d->m_clearButton,SIGNAL(clicked()), this, SLOT(clearData()));
|
||||
|
||||
layout->addWidget(d->m_clearButton);
|
||||
|
||||
QLabel *timeLabel = new QLabel();
|
||||
QPalette palette = timeLabel->palette();
|
||||
d->m_timeLabel = new QLabel();
|
||||
QPalette palette = d->m_timeLabel->palette();
|
||||
palette.setColor(QPalette::WindowText, Qt::white);
|
||||
timeLabel->setPalette(palette);
|
||||
timeLabel->setIndent(10);
|
||||
connect(d->m_traceWindow, SIGNAL(viewUpdated()), this, SLOT(updateTimers()));
|
||||
connect(this, SIGNAL(setTimeLabel(QString)), timeLabel, SLOT(setText(QString)));
|
||||
updateTimers();
|
||||
layout->addWidget(timeLabel);
|
||||
d->m_timeLabel->setPalette(palette);
|
||||
d->m_timeLabel->setIndent(10);
|
||||
updateTimeDisplay();
|
||||
layout->addWidget(d->m_timeLabel);
|
||||
|
||||
toolbarWidget->setLayout(layout);
|
||||
|
||||
return toolbarWidget;
|
||||
}
|
||||
|
||||
void QmlProfilerTool::connectClient(quint16 port)
|
||||
{
|
||||
if (d->m_client)
|
||||
delete d->m_client;
|
||||
d->m_client = new QDeclarativeDebugConnection;
|
||||
d->m_traceWindow->reset(d->m_client);
|
||||
connect(d->m_client, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
|
||||
this, SLOT(connectionStateChanged()));
|
||||
d->m_connectionTimer.start();
|
||||
d->m_appTimer.start();
|
||||
d->m_tcpPort = port;
|
||||
}
|
||||
|
||||
void QmlProfilerTool::connectToClient()
|
||||
{
|
||||
if (!d->m_client || d->m_client->state() != QAbstractSocket::UnconnectedState)
|
||||
return;
|
||||
|
||||
if (d->m_connectMode == QmlProfilerToolPrivate::TcpConnection) {
|
||||
logStatus(QString("QML Profiler: Connecting to %1:%2...").arg(d->m_tcpHost, QString::number(d->m_tcpPort)));
|
||||
d->m_client->connectToHost(d->m_tcpHost, d->m_tcpPort);
|
||||
} else {
|
||||
logStatus(QString("QML Profiler: Connecting to %1...").arg(d->m_tcpHost));
|
||||
d->m_client->connectToOst(d->m_ostDevice);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTool::disconnectClient()
|
||||
{
|
||||
// this might be actually be called indirectly by QDDConnectionPrivate::readyRead(), therefore allow
|
||||
// method to complete before deleting object
|
||||
if (d->m_client) {
|
||||
d->m_client->deleteLater();
|
||||
d->m_client = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTool::startRecording()
|
||||
{
|
||||
if (d->m_client && d->m_client->isConnected()) {
|
||||
clearDisplay();
|
||||
d->m_traceWindow->setRecording(true);
|
||||
}
|
||||
emit fetchingData(true);
|
||||
}
|
||||
|
||||
void QmlProfilerTool::stopRecording()
|
||||
{
|
||||
d->m_traceWindow->setRecording(false);
|
||||
emit fetchingData(false);
|
||||
|
||||
// manage early stop
|
||||
if (d->m_client && !d->m_client->isConnected() && d->m_appIsRunning)
|
||||
emit cancelRun();
|
||||
}
|
||||
|
||||
void QmlProfilerTool::recordingButtonChanged(bool recording)
|
||||
{
|
||||
if (recording)
|
||||
startRecording();
|
||||
else
|
||||
stopRecording();
|
||||
|
||||
setRecording(recording);
|
||||
d->m_profilerState->setClientRecording(recording);
|
||||
}
|
||||
|
||||
void QmlProfilerTool::setRecording(bool recording)
|
||||
{
|
||||
// update record button
|
||||
d->m_recordingEnabled = recording;
|
||||
// update display
|
||||
d->m_recordButton->setToolTip( recording ? tr("Disable profiling") : tr("Enable profiling"));
|
||||
d->m_recordButton->setIcon(QIcon(recording ? QLatin1String(":/qmlprofiler/recordOn.png") :
|
||||
QLatin1String(":/qmlprofiler/recordOff.png")));
|
||||
|
||||
d->m_recordButton->setChecked(recording);
|
||||
updateTimers();
|
||||
}
|
||||
|
||||
void QmlProfilerTool::setAppIsRunning()
|
||||
{
|
||||
d->m_appIsRunning = true;
|
||||
updateTimers();
|
||||
}
|
||||
|
||||
void QmlProfilerTool::setAppIsStopped()
|
||||
{
|
||||
d->m_appIsRunning = false;
|
||||
updateTimers();
|
||||
// manage timer
|
||||
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
|
||||
if (recording) {
|
||||
d->m_recordingTimer.start();
|
||||
d->m_recordingElapsedTime.start();
|
||||
} else {
|
||||
d->m_recordingTimer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTool::gotoSourceLocation(const QString &fileUrl, int lineNumber, int columnNumber)
|
||||
@@ -643,33 +459,30 @@ void QmlProfilerTool::gotoSourceLocation(const QString &fileUrl, int lineNumber,
|
||||
}
|
||||
}
|
||||
|
||||
inline QString stringifyTime(double seconds)
|
||||
void QmlProfilerTool::updateTimeDisplay()
|
||||
{
|
||||
double seconds = 0;
|
||||
if (d->m_profilerState->serverRecording() &&
|
||||
d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
|
||||
seconds = d->m_recordingElapsedTime.elapsed() / 1000.0;
|
||||
} else if (d->m_profilerDataModel->currentState() != QmlProfilerDataModel::Empty ) {
|
||||
seconds = (d->m_profilerDataModel->traceEndTime() - d->m_profilerDataModel->traceStartTime()) / 1.0e9;
|
||||
}
|
||||
QString timeString = QString::number(seconds,'f',1);
|
||||
return QmlProfilerTool::tr("%1 s").arg(timeString, 6);
|
||||
QString profilerTimeStr = QmlProfilerTool::tr("%1 s").arg(timeString, 6);
|
||||
d->m_timeLabel->setText(tr("Elapsed: %1").arg(profilerTimeStr));
|
||||
}
|
||||
|
||||
void QmlProfilerTool::updateTimers()
|
||||
void QmlProfilerTool::clearData()
|
||||
{
|
||||
// prof time
|
||||
QString profilerTimeStr = stringifyTime(d->m_traceWindow->profiledTime());
|
||||
emit setTimeLabel(tr("Elapsed: %1").arg(profilerTimeStr));
|
||||
}
|
||||
|
||||
void QmlProfilerTool::profilerStateChanged(bool qmlActive, bool v8active)
|
||||
{
|
||||
d->m_v8Active = v8active;
|
||||
d->m_qmlActive = qmlActive;
|
||||
updateTimers();
|
||||
d->m_profilerDataModel->clear();
|
||||
}
|
||||
|
||||
void QmlProfilerTool::clearDisplay()
|
||||
{
|
||||
d->m_appRunningTime = 0;
|
||||
d->m_traceWindow->clearDisplay();
|
||||
d->m_eventsView->clear();
|
||||
d->m_v8profilerView->clear();
|
||||
updateTimers();
|
||||
d->m_profilerConnections->clearBufferedData();
|
||||
d->m_viewContainer->clear();
|
||||
updateTimeDisplay();
|
||||
}
|
||||
|
||||
static void startRemoteTool(IAnalyzerTool *tool, StartMode mode)
|
||||
@@ -718,84 +531,6 @@ static void startRemoteTool(IAnalyzerTool *tool, StartMode mode)
|
||||
ProjectExplorerPlugin::instance()->startRunControl(rc, tool->runMode());
|
||||
}
|
||||
|
||||
void QmlProfilerTool::tryToConnect()
|
||||
{
|
||||
++d->m_connectionAttempts;
|
||||
|
||||
if (d->m_client && d->m_client->isConnected()) {
|
||||
d->m_connectionTimer.stop();
|
||||
d->m_connectionAttempts = 0;
|
||||
} else if (d->m_connectionAttempts == 50) {
|
||||
d->m_connectionTimer.stop();
|
||||
d->m_connectionAttempts = 0;
|
||||
|
||||
QMessageBox *infoBox = new QMessageBox(Core::ICore::mainWindow());
|
||||
infoBox->setIcon(QMessageBox::Critical);
|
||||
infoBox->setWindowTitle(tr("Qt Creator"));
|
||||
infoBox->setText(tr("Could not connect to the in-process QML profiler.\n"
|
||||
"Do you want to retry?"));
|
||||
infoBox->setStandardButtons(QMessageBox::Retry | QMessageBox::Cancel | QMessageBox::Help);
|
||||
infoBox->setDefaultButton(QMessageBox::Retry);
|
||||
infoBox->setModal(true);
|
||||
|
||||
connect(infoBox, SIGNAL(finished(int)),
|
||||
this, SLOT(retryMessageBoxFinished(int)));
|
||||
|
||||
infoBox->show();
|
||||
} else {
|
||||
connectToClient();
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTool::connectionStateChanged()
|
||||
{
|
||||
if (!d->m_client)
|
||||
return;
|
||||
switch (d->m_client->state()) {
|
||||
case QAbstractSocket::UnconnectedState:
|
||||
{
|
||||
if (QmlProfilerPlugin::debugOutput)
|
||||
qWarning("QML Profiler: disconnected");
|
||||
break;
|
||||
}
|
||||
case QAbstractSocket::HostLookupState:
|
||||
break;
|
||||
case QAbstractSocket::ConnectingState: {
|
||||
if (QmlProfilerPlugin::debugOutput)
|
||||
qWarning("QML Profiler: Connecting to debug server ...");
|
||||
break;
|
||||
}
|
||||
case QAbstractSocket::ConnectedState:
|
||||
{
|
||||
if (QmlProfilerPlugin::debugOutput)
|
||||
qWarning("QML Profiler: connected and running");
|
||||
updateRecordingState();
|
||||
break;
|
||||
}
|
||||
case QAbstractSocket::ClosingState:
|
||||
if (QmlProfilerPlugin::debugOutput)
|
||||
qWarning("QML Profiler: closing ...");
|
||||
break;
|
||||
case QAbstractSocket::BoundState:
|
||||
case QAbstractSocket::ListeningState:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTool::updateRecordingState()
|
||||
{
|
||||
if (d->m_client->isConnected()) {
|
||||
d->m_traceWindow->setRecording(d->m_recordingEnabled);
|
||||
} else {
|
||||
d->m_traceWindow->setRecording(false);
|
||||
}
|
||||
|
||||
if (d->m_traceWindow->isRecording())
|
||||
clearDisplay();
|
||||
|
||||
updateTimers();
|
||||
}
|
||||
|
||||
void QmlProfilerTool::startTool(StartMode mode)
|
||||
{
|
||||
using namespace ProjectExplorer;
|
||||
@@ -821,14 +556,25 @@ void QmlProfilerTool::logStatus(const QString &msg)
|
||||
|
||||
void QmlProfilerTool::logError(const QString &msg)
|
||||
{
|
||||
// TODO: Rather show errors in the application ouput
|
||||
MessageManager *messageManager = MessageManager::instance();
|
||||
messageManager->printToOutputPane(msg, true);
|
||||
}
|
||||
|
||||
void QmlProfilerTool::showErrorDialog(const QString &error)
|
||||
{
|
||||
QMessageBox *errorDialog = new QMessageBox(Core::ICore::mainWindow());
|
||||
errorDialog->setIcon(QMessageBox::Warning);
|
||||
errorDialog->setWindowTitle(tr("QML Profiler"));
|
||||
errorDialog->setText(error);
|
||||
errorDialog->setStandardButtons(QMessageBox::Ok);
|
||||
errorDialog->setDefaultButton(QMessageBox::Ok);
|
||||
errorDialog->setModal(false);
|
||||
errorDialog->show();
|
||||
}
|
||||
|
||||
void QmlProfilerTool::showSaveOption()
|
||||
{
|
||||
d->m_saveQmlTrace->setEnabled(d->m_traceWindow->getEventList()->count());
|
||||
d->m_saveQmlTrace->setEnabled(!d->m_profilerDataModel->isEmpty());
|
||||
}
|
||||
|
||||
void QmlProfilerTool::showSaveDialog()
|
||||
@@ -837,7 +583,7 @@ void QmlProfilerTool::showSaveDialog()
|
||||
if (!filename.isEmpty()) {
|
||||
if (!filename.endsWith(QLatin1String(TraceFileExtension)))
|
||||
filename += QLatin1String(TraceFileExtension);
|
||||
d->m_traceWindow->getEventList()->save(filename);
|
||||
d->m_profilerDataModel->save(filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -853,53 +599,98 @@ void QmlProfilerTool::showLoadDialog()
|
||||
|
||||
if (!filename.isEmpty()) {
|
||||
// delayed load (prevent graphical artifacts due to long load time)
|
||||
d->m_traceWindow->getEventList()->setFilename(filename);
|
||||
QTimer::singleShot(100, d->m_traceWindow->getEventList(), SLOT(load()));
|
||||
d->m_profilerDataModel->setFilename(filename);
|
||||
QTimer::singleShot(100, d->m_profilerDataModel, SLOT(load()));
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTool::showErrorDialog(const QString &error)
|
||||
void QmlProfilerTool::profilerDataModelStateChanged()
|
||||
{
|
||||
QMessageBox *errorDialog = new QMessageBox(Core::ICore::mainWindow());
|
||||
errorDialog->setIcon(QMessageBox::Warning);
|
||||
errorDialog->setWindowTitle(tr("QML Profiler"));
|
||||
errorDialog->setText(error);
|
||||
errorDialog->setStandardButtons(QMessageBox::Ok);
|
||||
errorDialog->setDefaultButton(QMessageBox::Ok);
|
||||
errorDialog->setModal(false);
|
||||
errorDialog->show();
|
||||
}
|
||||
|
||||
void QmlProfilerTool::retryMessageBoxFinished(int result)
|
||||
{
|
||||
switch (result) {
|
||||
case QMessageBox::Retry: {
|
||||
d->m_connectionAttempts = 0;
|
||||
d->m_connectionTimer.start();
|
||||
switch (d->m_profilerDataModel->currentState()) {
|
||||
case QmlProfilerDataModel::Empty :
|
||||
clearDisplay();
|
||||
break;
|
||||
}
|
||||
case QMessageBox::Help: {
|
||||
HelpManager *helpManager = HelpManager::instance();
|
||||
helpManager->handleHelpRequest("qthelp://com.nokia.qtcreator/doc/creator-debugging-qml.html");
|
||||
// fall through
|
||||
}
|
||||
default: {
|
||||
if (d->m_client) {
|
||||
logStatus("QML Profiler: Failed to connect! " + d->m_client->errorString());
|
||||
} else {
|
||||
logStatus("QML Profiler: Failed to connect!");
|
||||
}
|
||||
|
||||
emit connectionFailed();
|
||||
case QmlProfilerDataModel::AcquiringData :
|
||||
case QmlProfilerDataModel::ProcessingData :
|
||||
// nothing to be done for these two
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTool::eventListStateChanged()
|
||||
{
|
||||
if (d->m_traceWindow->getEventList()->currentState() == QmlProfilerEventList::Done) {
|
||||
case QmlProfilerDataModel::Done :
|
||||
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppStopRequested)
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppReadyToStop);
|
||||
showSaveOption();
|
||||
updateTimers();
|
||||
updateTimeDisplay();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QList <QAction *> QmlProfilerTool::profilerContextMenuActions() const
|
||||
{
|
||||
QList <QAction *> commonActions;
|
||||
commonActions << d->m_loadQmlTrace << d->m_saveQmlTrace;
|
||||
return commonActions;
|
||||
}
|
||||
|
||||
void QmlProfilerTool::showNonmodalWarning(const QString &warningMsg)
|
||||
{
|
||||
QMessageBox *noExecWarning = new QMessageBox(Core::ICore::mainWindow());
|
||||
noExecWarning->setIcon(QMessageBox::Warning);
|
||||
noExecWarning->setWindowTitle(tr("QML Profiler"));
|
||||
noExecWarning->setText(warningMsg);
|
||||
noExecWarning->setStandardButtons(QMessageBox::Ok);
|
||||
noExecWarning->setDefaultButton(QMessageBox::Ok);
|
||||
noExecWarning->setModal(false);
|
||||
noExecWarning->show();
|
||||
}
|
||||
|
||||
QMessageBox *QmlProfilerTool::requestMessageBox()
|
||||
{
|
||||
return new QMessageBox(Core::ICore::mainWindow());
|
||||
}
|
||||
|
||||
void QmlProfilerTool::handleHelpRequest(const QString &link)
|
||||
{
|
||||
HelpManager *helpManager = HelpManager::instance();
|
||||
helpManager->handleHelpRequest(link);
|
||||
}
|
||||
|
||||
void QmlProfilerTool::profilerStateChanged()
|
||||
{
|
||||
switch (d->m_profilerState->currentState()) {
|
||||
case QmlProfilerStateManager::AppKilled : {
|
||||
if (d->m_profilerDataModel->currentState() == QmlProfilerDataModel::AcquiringData) {
|
||||
showNonmodalWarning(tr("Application finished before loading profiled data.\n Please use the stop button instead."));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QmlProfilerStateManager::Idle :
|
||||
// when the app finishes, set recording display to client status
|
||||
setRecording(d->m_profilerState->clientRecording());
|
||||
break;
|
||||
default:
|
||||
// no special action needed for other states
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTool::clientRecordingChanged()
|
||||
{
|
||||
// if application is running, display server record changes
|
||||
// if application is stopped, display client record changes
|
||||
if (d->m_profilerState->currentState() != QmlProfilerStateManager::AppRunning) {
|
||||
setRecording(d->m_profilerState->clientRecording());
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTool::serverRecordingChanged()
|
||||
{
|
||||
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
|
||||
setRecording(d->m_profilerState->serverRecording());
|
||||
// clear the old data each time we start a new profiling session
|
||||
if (d->m_profilerState->serverRecording()) {
|
||||
clearData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -36,13 +36,11 @@
|
||||
#include <analyzerbase/ianalyzertool.h>
|
||||
#include <analyzerbase/ianalyzerengine.h>
|
||||
|
||||
#include <QPoint>
|
||||
class QMessageBox;
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
#define TraceFileExtension ".qtd"
|
||||
|
||||
class QmlProfilerTool : public Analyzer::IAnalyzerTool
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -72,49 +70,37 @@ public:
|
||||
QWidget *createWidgets();
|
||||
void startTool(Analyzer::StartMode mode);
|
||||
|
||||
public slots:
|
||||
void connectClient(quint16 port);
|
||||
void disconnectClient();
|
||||
QList <QAction *> profilerContextMenuActions() const;
|
||||
|
||||
// display dialogs / log output
|
||||
static QMessageBox *requestMessageBox();
|
||||
static void handleHelpRequest(const QString &link);
|
||||
static void logStatus(const QString &msg);
|
||||
static void logError(const QString &msg);
|
||||
static void showNonmodalWarning(const QString &warningMsg);
|
||||
|
||||
public slots:
|
||||
void profilerStateChanged();
|
||||
void clientRecordingChanged();
|
||||
void serverRecordingChanged();
|
||||
|
||||
void startRecording();
|
||||
void stopRecording();
|
||||
void recordingButtonChanged(bool recording);
|
||||
void setRecording(bool recording);
|
||||
|
||||
void setAppIsRunning();
|
||||
void setAppIsStopped();
|
||||
|
||||
void gotoSourceLocation(const QString &fileUrl, int lineNumber, int columnNumber);
|
||||
void updateTimers();
|
||||
void profilerStateChanged(bool qmlActive, bool v8active);
|
||||
|
||||
void clearDisplay();
|
||||
|
||||
void showContextMenu(const QPoint &position);
|
||||
|
||||
signals:
|
||||
void setTimeLabel(const QString &);
|
||||
void setStatusLabel(const QString &);
|
||||
void fetchingData(bool);
|
||||
void connectionFailed();
|
||||
void cancelRun();
|
||||
|
||||
private slots:
|
||||
void tryToConnect();
|
||||
void connectionStateChanged();
|
||||
void clearData();
|
||||
void showErrorDialog(const QString &error);
|
||||
void profilerDataModelStateChanged();
|
||||
void updateTimeDisplay();
|
||||
|
||||
void showSaveOption();
|
||||
void showSaveDialog();
|
||||
void showLoadDialog();
|
||||
void showErrorDialog(const QString &error);
|
||||
void retryMessageBoxFinished(int result);
|
||||
void eventListStateChanged();
|
||||
|
||||
private:
|
||||
void connectToClient();
|
||||
void updateRecordingState();
|
||||
void ensureWidgets();
|
||||
void logStatus(const QString &msg);
|
||||
void logError(const QString &msg);
|
||||
void clearDisplay();
|
||||
|
||||
class QmlProfilerToolPrivate;
|
||||
QmlProfilerToolPrivate *d;
|
||||
|
601
src/plugins/qmlprofiler/qmlprofilertraceview.cpp
Normal file
601
src/plugins/qmlprofiler/qmlprofilertraceview.cpp
Normal file
@@ -0,0 +1,601 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** 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, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlprofilertraceview.h"
|
||||
#include "qmlprofilertool.h"
|
||||
#include "qmlprofilerstatemanager.h"
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
|
||||
// Needed for the load&save actions in the context menu
|
||||
#include <analyzerbase/ianalyzertool.h>
|
||||
|
||||
// Comunication with the other views (limit events to range)
|
||||
#include "qmlprofilerviewmanager.h"
|
||||
|
||||
#include <utils/styledbar.h>
|
||||
|
||||
#include <QDeclarativeContext>
|
||||
#include <QToolButton>
|
||||
#include <QEvent>
|
||||
#include <QVBoxLayout>
|
||||
#include <QGraphicsObject>
|
||||
#include <QScrollBar>
|
||||
#include <QSlider>
|
||||
#include <QMenu>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
using namespace QmlJsDebugClient;
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
const int sliderTicks = 10000;
|
||||
const qreal sliderExp = 3;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
bool MouseWheelResizer::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::Wheel) {
|
||||
QWheelEvent *ev = static_cast<QWheelEvent *>(event);
|
||||
if (ev->modifiers() & Qt::ControlModifier) {
|
||||
emit mouseWheelMoved(ev->pos().x(), ev->pos().y(), ev->delta());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
void ZoomControl::setRange(qint64 startTime, qint64 endTime)
|
||||
{
|
||||
if (m_startTime != startTime || m_endTime != endTime) {
|
||||
m_startTime = startTime;
|
||||
m_endTime = endTime;
|
||||
emit rangeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
ScrollableDeclarativeView::ScrollableDeclarativeView(QWidget *parent)
|
||||
: QDeclarativeView(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ScrollableDeclarativeView::~ScrollableDeclarativeView()
|
||||
{
|
||||
}
|
||||
|
||||
void ScrollableDeclarativeView::scrollContentsBy(int dx, int dy)
|
||||
{
|
||||
// special workaround to track the scrollbar
|
||||
if (rootObject()) {
|
||||
int scrollY = rootObject()->property("scrollY").toInt();
|
||||
rootObject()->setProperty("scrollY", QVariant(scrollY - dy));
|
||||
}
|
||||
QDeclarativeView::scrollContentsBy(dx,dy);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
class QmlProfilerTraceView::QmlProfilerTraceViewPrivate
|
||||
{
|
||||
public:
|
||||
QmlProfilerTraceViewPrivate(QmlProfilerTraceView *qq) : q(qq) {}
|
||||
QmlProfilerTraceView *q;
|
||||
|
||||
QmlProfilerStateManager *m_profilerState;
|
||||
Analyzer::IAnalyzerTool *m_profilerTool;
|
||||
QmlProfilerViewManager *m_viewContainer;
|
||||
|
||||
QSize m_sizeHint;
|
||||
|
||||
ScrollableDeclarativeView *m_mainView;
|
||||
QDeclarativeView *m_timebar;
|
||||
QDeclarativeView *m_overview;
|
||||
QmlProfilerDataModel *m_profilerDataModel;
|
||||
|
||||
ZoomControl *m_zoomControl;
|
||||
|
||||
QToolButton *m_buttonRange;
|
||||
QToolButton *m_buttonLock;
|
||||
QWidget *m_zoomToolbar;
|
||||
int m_currentZoomLevel;
|
||||
};
|
||||
|
||||
QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerTool *profilerTool, QmlProfilerViewManager *container, QmlProfilerDataModel *model, QmlProfilerStateManager *profilerState)
|
||||
: QWidget(parent), d(new QmlProfilerTraceViewPrivate(this))
|
||||
{
|
||||
setObjectName("QML Profiler");
|
||||
|
||||
d->m_zoomControl = new ZoomControl(this);
|
||||
connect(d->m_zoomControl, SIGNAL(rangeChanged()), this, SLOT(updateRange()));
|
||||
|
||||
QVBoxLayout *groupLayout = new QVBoxLayout;
|
||||
groupLayout->setContentsMargins(0, 0, 0, 0);
|
||||
groupLayout->setSpacing(0);
|
||||
|
||||
d->m_mainView = new ScrollableDeclarativeView(this);
|
||||
d->m_mainView->setResizeMode(QDeclarativeView::SizeViewToRootObject);
|
||||
d->m_mainView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
d->m_mainView->setBackgroundBrush(QBrush(Qt::white));
|
||||
d->m_mainView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||
d->m_mainView->setFocus();
|
||||
|
||||
MouseWheelResizer *resizer = new MouseWheelResizer(this);
|
||||
connect(resizer,SIGNAL(mouseWheelMoved(int,int,int)), this, SLOT(mouseWheelMoved(int,int,int)));
|
||||
d->m_mainView->viewport()->installEventFilter(resizer);
|
||||
|
||||
QHBoxLayout *toolsLayout = new QHBoxLayout;
|
||||
|
||||
d->m_timebar = new QDeclarativeView(this);
|
||||
d->m_timebar->setResizeMode(QDeclarativeView::SizeRootObjectToView);
|
||||
d->m_timebar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
d->m_timebar->setFixedHeight(24);
|
||||
|
||||
d->m_overview = new QDeclarativeView(this);
|
||||
d->m_overview->setResizeMode(QDeclarativeView::SizeRootObjectToView);
|
||||
d->m_overview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
d->m_overview->setMaximumHeight(50);
|
||||
|
||||
d->m_zoomToolbar = createZoomToolbar();
|
||||
d->m_zoomToolbar->move(0, d->m_timebar->height());
|
||||
d->m_zoomToolbar->setVisible(false);
|
||||
|
||||
toolsLayout->addWidget(createToolbar());
|
||||
toolsLayout->addWidget(d->m_timebar);
|
||||
emit enableToolbar(false);
|
||||
|
||||
groupLayout->addLayout(toolsLayout);
|
||||
groupLayout->addWidget(d->m_mainView);
|
||||
groupLayout->addWidget(d->m_overview);
|
||||
|
||||
setLayout(groupLayout);
|
||||
|
||||
d->m_profilerTool = profilerTool;
|
||||
d->m_viewContainer = container;
|
||||
d->m_profilerDataModel = model;
|
||||
connect(d->m_profilerDataModel, SIGNAL(stateChanged()),
|
||||
this, SLOT(profilerDataModelStateChanged()));
|
||||
d->m_mainView->rootContext()->setContextProperty("qmlProfilerDataModel",
|
||||
d->m_profilerDataModel);
|
||||
d->m_overview->rootContext()->setContextProperty("qmlProfilerDataModel",
|
||||
d->m_profilerDataModel);
|
||||
|
||||
d->m_profilerState = profilerState;
|
||||
connect(d->m_profilerState, SIGNAL(stateChanged()),
|
||||
this, SLOT(profilerStateChanged()));
|
||||
connect(d->m_profilerState, SIGNAL(clientRecordingChanged()),
|
||||
this, SLOT(clientRecordingChanged()));
|
||||
connect(d->m_profilerState, SIGNAL(serverRecordingChanged()),
|
||||
this, SLOT(serverRecordingChanged()));
|
||||
|
||||
// Minimum height: 5 rows of 20 pixels + scrollbar of 50 pixels + 20 pixels margin
|
||||
setMinimumHeight(170);
|
||||
d->m_currentZoomLevel = 0;
|
||||
}
|
||||
|
||||
QmlProfilerTraceView::~QmlProfilerTraceView()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// Initialize widgets
|
||||
void QmlProfilerTraceView::reset()
|
||||
{
|
||||
d->m_mainView->rootContext()->setContextProperty("zoomControl", d->m_zoomControl);
|
||||
d->m_timebar->rootContext()->setContextProperty("zoomControl", d->m_zoomControl);
|
||||
d->m_overview->rootContext()->setContextProperty("zoomControl", d->m_zoomControl);
|
||||
|
||||
d->m_timebar->setSource(QUrl("qrc:/qmlprofiler/TimeDisplay.qml"));
|
||||
d->m_overview->setSource(QUrl("qrc:/qmlprofiler/Overview.qml"));
|
||||
|
||||
d->m_mainView->setSource(QUrl("qrc:/qmlprofiler/MainView.qml"));
|
||||
d->m_mainView->rootObject()->setProperty("width", QVariant(width()));
|
||||
d->m_mainView->rootObject()->setProperty("candidateHeight", QVariant(height() - d->m_timebar->height() - d->m_overview->height()));
|
||||
|
||||
connect(d->m_mainView->rootObject(), SIGNAL(updateCursorPosition()), this, SLOT(updateCursorPosition()));
|
||||
connect(d->m_mainView->rootObject(), SIGNAL(updateRangeButton()), this, SLOT(updateRangeButton()));
|
||||
connect(d->m_mainView->rootObject(), SIGNAL(updateLockButton()), this, SLOT(updateLockButton()));
|
||||
connect(this, SIGNAL(jumpToPrev()), d->m_mainView->rootObject(), SLOT(prevEvent()));
|
||||
connect(this, SIGNAL(jumpToNext()), d->m_mainView->rootObject(), SLOT(nextEvent()));
|
||||
connect(d->m_mainView->rootObject(), SIGNAL(selectedEventChanged(int)), this, SIGNAL(selectedEventChanged(int)));
|
||||
connect(d->m_mainView->rootObject(), SIGNAL(changeToolTip(QString)), this, SLOT(updateToolTip(QString)));
|
||||
connect(d->m_mainView->rootObject(), SIGNAL(updateVerticalScroll(int)), this, SLOT(updateVerticalScroll(int)));
|
||||
}
|
||||
|
||||
QWidget *QmlProfilerTraceView::createToolbar()
|
||||
{
|
||||
Utils::StyledBar *bar = new Utils::StyledBar(this);
|
||||
bar->setSingleRow(true);
|
||||
bar->setFixedWidth(150);
|
||||
bar->setFixedHeight(24);
|
||||
|
||||
QHBoxLayout *toolBarLayout = new QHBoxLayout(bar);
|
||||
toolBarLayout->setMargin(0);
|
||||
toolBarLayout->setSpacing(0);
|
||||
|
||||
QToolButton *buttonPrev= new QToolButton;
|
||||
buttonPrev->setIcon(QIcon(":/qmlprofiler/ico_prev.png"));
|
||||
buttonPrev->setToolTip(tr("Jump to previous event"));
|
||||
connect(buttonPrev, SIGNAL(clicked()), this, SIGNAL(jumpToPrev()));
|
||||
connect(this, SIGNAL(enableToolbar(bool)), buttonPrev, SLOT(setEnabled(bool)));
|
||||
|
||||
QToolButton *buttonNext= new QToolButton;
|
||||
buttonNext->setIcon(QIcon(":/qmlprofiler/ico_next.png"));
|
||||
buttonNext->setToolTip(tr("Jump to next event"));
|
||||
connect(buttonNext, SIGNAL(clicked()), this, SIGNAL(jumpToNext()));
|
||||
connect(this, SIGNAL(enableToolbar(bool)), buttonNext, SLOT(setEnabled(bool)));
|
||||
|
||||
QToolButton *buttonZoomControls = new QToolButton;
|
||||
buttonZoomControls->setIcon(QIcon(":/qmlprofiler/ico_zoom.png"));
|
||||
buttonZoomControls->setToolTip(tr("Show zoom slider"));
|
||||
buttonZoomControls->setCheckable(true);
|
||||
buttonZoomControls->setChecked(false);
|
||||
connect(buttonZoomControls, SIGNAL(toggled(bool)), d->m_zoomToolbar, SLOT(setVisible(bool)));
|
||||
connect(this, SIGNAL(enableToolbar(bool)), buttonZoomControls, SLOT(setEnabled(bool)));
|
||||
|
||||
d->m_buttonRange = new QToolButton;
|
||||
d->m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselection.png"));
|
||||
d->m_buttonRange->setToolTip(tr("Select range"));
|
||||
d->m_buttonRange->setCheckable(true);
|
||||
d->m_buttonRange->setChecked(false);
|
||||
connect(d->m_buttonRange, SIGNAL(clicked(bool)), this, SLOT(toggleRangeMode(bool)));
|
||||
connect(this, SIGNAL(enableToolbar(bool)), d->m_buttonRange, SLOT(setEnabled(bool)));
|
||||
connect(this, SIGNAL(rangeModeChanged(bool)), d->m_buttonRange, SLOT(setChecked(bool)));
|
||||
|
||||
d->m_buttonLock = new QToolButton;
|
||||
d->m_buttonLock->setIcon(QIcon(":/qmlprofiler/ico_selectionmode.png"));
|
||||
d->m_buttonLock->setToolTip(tr("View event information on mouseover"));
|
||||
d->m_buttonLock->setCheckable(true);
|
||||
d->m_buttonLock->setChecked(false);
|
||||
connect(d->m_buttonLock, SIGNAL(clicked(bool)), this, SLOT(toggleLockMode(bool)));
|
||||
connect(this, SIGNAL(enableToolbar(bool)), d->m_buttonLock, SLOT(setEnabled(bool)));
|
||||
connect(this, SIGNAL(lockModeChanged(bool)), d->m_buttonLock, SLOT(setChecked(bool)));
|
||||
|
||||
toolBarLayout->addWidget(buttonPrev);
|
||||
toolBarLayout->addWidget(buttonNext);
|
||||
toolBarLayout->addWidget(new Utils::StyledSeparator());
|
||||
toolBarLayout->addWidget(buttonZoomControls);
|
||||
toolBarLayout->addWidget(new Utils::StyledSeparator());
|
||||
toolBarLayout->addWidget(d->m_buttonRange);
|
||||
toolBarLayout->addWidget(d->m_buttonLock);
|
||||
|
||||
return bar;
|
||||
}
|
||||
|
||||
|
||||
QWidget *QmlProfilerTraceView::createZoomToolbar()
|
||||
{
|
||||
Utils::StyledBar *bar = new Utils::StyledBar(this);
|
||||
bar->setSingleRow(true);
|
||||
bar->setFixedWidth(150);
|
||||
bar->setFixedHeight(24);
|
||||
|
||||
QHBoxLayout *toolBarLayout = new QHBoxLayout(bar);
|
||||
toolBarLayout->setMargin(0);
|
||||
toolBarLayout->setSpacing(0);
|
||||
|
||||
QSlider *zoomSlider = new QSlider(Qt::Horizontal);
|
||||
zoomSlider->setFocusPolicy(Qt::NoFocus);
|
||||
zoomSlider->setRange(1, sliderTicks);
|
||||
zoomSlider->setInvertedAppearance(true);
|
||||
zoomSlider->setPageStep(sliderTicks/100);
|
||||
connect(this, SIGNAL(enableToolbar(bool)), zoomSlider, SLOT(setEnabled(bool)));
|
||||
connect(zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(setZoomLevel(int)));
|
||||
connect(this, SIGNAL(zoomLevelChanged(int)), zoomSlider, SLOT(setValue(int)));
|
||||
zoomSlider->setStyleSheet("\
|
||||
QSlider:horizontal {\
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #444444, stop: 1 #5a5a5a);\
|
||||
border: 1px #313131;\
|
||||
height: 20px;\
|
||||
margin: 0px 0px 0px 0px;\
|
||||
}\
|
||||
QSlider::add-page:horizontal {\
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #5a5a5a, stop: 1 #444444);\
|
||||
border: 1px #313131;\
|
||||
}\
|
||||
QSlider::sub-page:horizontal {\
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #5a5a5a, stop: 1 #444444);\
|
||||
border: 1px #313131;\
|
||||
}\
|
||||
");
|
||||
|
||||
toolBarLayout->addWidget(zoomSlider);
|
||||
|
||||
return bar;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
bool QmlProfilerTraceView::hasValidSelection() const
|
||||
{
|
||||
if (d->m_mainView->rootObject()) {
|
||||
return d->m_mainView->rootObject()->property("selectionRangeReady").toBool();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 QmlProfilerTraceView::selectionStart() const
|
||||
{
|
||||
if (d->m_mainView->rootObject()) {
|
||||
return d->m_mainView->rootObject()->property("selectionRangeStart").toLongLong();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
qint64 QmlProfilerTraceView::selectionEnd() const
|
||||
{
|
||||
if (d->m_mainView->rootObject()) {
|
||||
return d->m_mainView->rootObject()->property("selectionRangeEnd").toLongLong();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::clearDisplay()
|
||||
{
|
||||
d->m_zoomControl->setRange(0,0);
|
||||
|
||||
updateVerticalScroll(0);
|
||||
d->m_mainView->rootObject()->setProperty("scrollY", QVariant(0));
|
||||
|
||||
QMetaObject::invokeMethod(d->m_mainView->rootObject(), "clearAll");
|
||||
QMetaObject::invokeMethod(d->m_overview->rootObject(), "clearDisplay");
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::selectNextEventWithId(int eventId)
|
||||
{
|
||||
if (d->m_mainView->rootObject())
|
||||
QMetaObject::invokeMethod(d->m_mainView->rootObject(), "selectNextWithId",
|
||||
Q_ARG(QVariant,QVariant(eventId)));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// Goto source location
|
||||
void QmlProfilerTraceView::updateCursorPosition()
|
||||
{
|
||||
emit gotoSourceLocation(d->m_mainView->rootObject()->property("fileName").toString(),
|
||||
d->m_mainView->rootObject()->property("lineNumber").toInt(),
|
||||
d->m_mainView->rootObject()->property("columnNumber").toInt());
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// Toolbar buttons
|
||||
void QmlProfilerTraceView::toggleRangeMode(bool active)
|
||||
{
|
||||
bool rangeMode = d->m_mainView->rootObject()->property("selectionRangeMode").toBool();
|
||||
if (active != rangeMode) {
|
||||
if (active)
|
||||
d->m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselected.png"));
|
||||
else
|
||||
d->m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselection.png"));
|
||||
d->m_mainView->rootObject()->setProperty("selectionRangeMode", QVariant(active));
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::updateRangeButton()
|
||||
{
|
||||
bool rangeMode = d->m_mainView->rootObject()->property("selectionRangeMode").toBool();
|
||||
if (rangeMode)
|
||||
d->m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselected.png"));
|
||||
else
|
||||
d->m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselection.png"));
|
||||
emit rangeModeChanged(rangeMode);
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::toggleLockMode(bool active)
|
||||
{
|
||||
bool lockMode = !d->m_mainView->rootObject()->property("selectionLocked").toBool();
|
||||
if (active != lockMode) {
|
||||
d->m_mainView->rootObject()->setProperty("selectionLocked", QVariant(!active));
|
||||
d->m_mainView->rootObject()->setProperty("selectedItem", QVariant(-1));
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::updateLockButton()
|
||||
{
|
||||
bool lockMode = !d->m_mainView->rootObject()->property("selectionLocked").toBool();
|
||||
emit lockModeChanged(lockMode);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// Zoom control
|
||||
void QmlProfilerTraceView::setZoomLevel(int zoomLevel)
|
||||
{
|
||||
if (d->m_currentZoomLevel != zoomLevel && d->m_mainView->rootObject()) {
|
||||
QVariant newFactor = pow(qreal(zoomLevel) / qreal(sliderTicks), sliderExp);
|
||||
d->m_currentZoomLevel = zoomLevel;
|
||||
QMetaObject::invokeMethod(d->m_mainView->rootObject(), "updateWindowLength", Q_ARG(QVariant, newFactor));
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::updateRange()
|
||||
{
|
||||
if (!d->m_profilerDataModel)
|
||||
return;
|
||||
qreal duration = d->m_zoomControl->endTime() - d->m_zoomControl->startTime();
|
||||
if (duration <= 0)
|
||||
return;
|
||||
if (d->m_profilerDataModel->traceDuration() <= 0)
|
||||
return;
|
||||
int newLevel = pow(duration / d->m_profilerDataModel->traceDuration(), 1/sliderExp) * sliderTicks;
|
||||
if (d->m_currentZoomLevel != newLevel) {
|
||||
d->m_currentZoomLevel = newLevel;
|
||||
emit zoomLevelChanged(newLevel);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::mouseWheelMoved(int mouseX, int mouseY, int wheelDelta)
|
||||
{
|
||||
Q_UNUSED(mouseY);
|
||||
if (d->m_mainView->rootObject()) {
|
||||
QMetaObject::invokeMethod(d->m_mainView->rootObject(), "wheelZoom",
|
||||
Q_ARG(QVariant, QVariant(mouseX)),
|
||||
Q_ARG(QVariant, QVariant(wheelDelta)));
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////
|
||||
void QmlProfilerTraceView::updateToolTip(const QString &text)
|
||||
{
|
||||
setToolTip(text);
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::updateVerticalScroll(int newPosition)
|
||||
{
|
||||
d->m_mainView->verticalScrollBar()->setValue(newPosition);
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
if (d->m_mainView->rootObject()) {
|
||||
d->m_mainView->rootObject()->setProperty("width", QVariant(event->size().width()));
|
||||
int newHeight = event->size().height() - d->m_timebar->height() - d->m_overview->height();
|
||||
d->m_mainView->rootObject()->setProperty("candidateHeight", QVariant(newHeight));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Context menu
|
||||
void QmlProfilerTraceView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
{
|
||||
QMenu menu;
|
||||
QAction *viewAllAction = 0;
|
||||
QAction *getLocalStatsAction = 0;
|
||||
QAction *getGlobalStatsAction = 0;
|
||||
|
||||
QmlProfilerTool *profilerTool = qobject_cast<QmlProfilerTool *>(d->m_profilerTool);
|
||||
QPoint position = ev->globalPos();
|
||||
|
||||
if (profilerTool) {
|
||||
QList <QAction *> commonActions = profilerTool->profilerContextMenuActions();
|
||||
foreach (QAction *act, commonActions) {
|
||||
menu.addAction(act);
|
||||
}
|
||||
}
|
||||
|
||||
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 (d->m_viewContainer->hasGlobalStats())
|
||||
getGlobalStatsAction->setEnabled(false);
|
||||
|
||||
|
||||
if (d->m_profilerDataModel->count() > 0) {
|
||||
menu.addSeparator();
|
||||
viewAllAction = menu.addAction(tr("Reset Zoom"));
|
||||
}
|
||||
|
||||
|
||||
QAction *selectedAction = menu.exec(position);
|
||||
|
||||
if (selectedAction) {
|
||||
if (selectedAction == viewAllAction) {
|
||||
d->m_zoomControl->setRange(
|
||||
d->m_profilerDataModel->traceStartTime(),
|
||||
d->m_profilerDataModel->traceEndTime());
|
||||
}
|
||||
if (selectedAction == getLocalStatsAction) {
|
||||
d->m_viewContainer->getStatisticsInRange(
|
||||
d->m_viewContainer->selectionStart(),
|
||||
d->m_viewContainer->selectionEnd());
|
||||
}
|
||||
if (selectedAction == getGlobalStatsAction) {
|
||||
d->m_viewContainer->getStatisticsInRange(
|
||||
d->m_profilerDataModel->traceStartTime(),
|
||||
d->m_profilerDataModel->traceEndTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Tell QML the state of the profiler
|
||||
void QmlProfilerTraceView::setRecording(bool recording)
|
||||
{
|
||||
if (d->m_mainView->rootObject())
|
||||
d->m_mainView->rootObject()->setProperty("recordingEnabled", QVariant(recording));
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::setAppKilled()
|
||||
{
|
||||
if (d->m_mainView->rootObject())
|
||||
d->m_mainView->rootObject()->setProperty("appKilled",QVariant(true));
|
||||
}
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Profiler State
|
||||
void QmlProfilerTraceView::profilerDataModelStateChanged()
|
||||
{
|
||||
switch (d->m_profilerDataModel->currentState()) {
|
||||
case QmlProfilerDataModel::Empty :
|
||||
emit enableToolbar(false);
|
||||
break;
|
||||
case QmlProfilerDataModel::AcquiringData :
|
||||
// nothing to be done
|
||||
break;
|
||||
case QmlProfilerDataModel::ProcessingData :
|
||||
// nothing to be done
|
||||
break;
|
||||
case QmlProfilerDataModel::Done :
|
||||
emit enableToolbar(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::profilerStateChanged()
|
||||
{
|
||||
switch (d->m_profilerState->currentState()) {
|
||||
case QmlProfilerStateManager::AppKilled : {
|
||||
if (d->m_profilerDataModel->currentState() == QmlProfilerDataModel::AcquiringData)
|
||||
setAppKilled();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// no special action needed for other states
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::clientRecordingChanged()
|
||||
{
|
||||
// nothing yet
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::serverRecordingChanged()
|
||||
{
|
||||
setRecording(d->m_profilerState->serverRecording());
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
@@ -30,24 +30,23 @@
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef TRACEWINDOW_H
|
||||
#define TRACEWINDOW_H
|
||||
#ifndef QMLPROFILERTRACEVIEW_H
|
||||
#define QMLPROFILERTRACEVIEW_H
|
||||
|
||||
#include <qmljsdebugclient/qmlprofilertraceclient.h>
|
||||
#include <qmljsdebugclient/qmlprofilereventlist.h>
|
||||
#include "qmlprofilerdetailsrewriter.h"
|
||||
#include <qmljsdebugclient/qv8profilerclient.h>
|
||||
|
||||
#include <QPointer>
|
||||
#include <QWidget>
|
||||
#include <QToolButton>
|
||||
|
||||
#include <QEvent>
|
||||
#include <QDeclarativeView>
|
||||
|
||||
namespace Analyzer {
|
||||
class IAnalyzerTool;
|
||||
}
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerStateManager;
|
||||
class QmlProfilerViewManager;
|
||||
class QmlProfilerDataModel;
|
||||
|
||||
// capture mouse wheel events
|
||||
class MouseWheelResizer : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -87,117 +86,73 @@ protected:
|
||||
void scrollContentsBy(int dx, int dy);
|
||||
};
|
||||
|
||||
class TraceWindow : public QWidget
|
||||
class QmlProfilerTraceView : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TraceWindow(QWidget *parent = 0);
|
||||
~TraceWindow();
|
||||
explicit QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerTool *profilerTool, QmlProfilerViewManager *container, QmlProfilerDataModel *model, QmlProfilerStateManager *profilerState);
|
||||
~QmlProfilerTraceView();
|
||||
|
||||
void reset(QmlJsDebugClient::QDeclarativeDebugConnection *conn);
|
||||
|
||||
QmlJsDebugClient::QmlProfilerEventList *getEventList() const;
|
||||
ZoomControl *rangeTimes() const;
|
||||
|
||||
void setRecording(bool recording);
|
||||
bool isRecording() const;
|
||||
void viewAll();
|
||||
void reset();
|
||||
|
||||
bool hasValidSelection() const;
|
||||
qint64 selectionStart() const;
|
||||
qint64 selectionEnd() const;
|
||||
double profiledTime() const;
|
||||
|
||||
public slots:
|
||||
void clearDisplay();
|
||||
void selectNextEvent(int eventId);
|
||||
void applicationDied();
|
||||
void selectNextEventWithId(int eventId);
|
||||
|
||||
private slots:
|
||||
void updateCursorPosition();
|
||||
void updateTimer();
|
||||
void updateToolbar();
|
||||
void toggleRangeMode(bool);
|
||||
void toggleLockMode(bool);
|
||||
void updateRangeButton();
|
||||
void toggleLockMode(bool);
|
||||
void updateLockButton();
|
||||
|
||||
void setZoomLevel(int zoomLevel);
|
||||
void updateRange();
|
||||
void mouseWheelMoved(int x, int y, int delta);
|
||||
void mouseWheelMoved(int mouseX, int mouseY, int wheelDelta);
|
||||
|
||||
void qmlComplete();
|
||||
void v8Complete();
|
||||
void updateProfilerState();
|
||||
void updateToolTip(const QString &text);
|
||||
void updateVerticalScroll(int newPosition);
|
||||
void eventListStateChanged();
|
||||
void manageTraceStart(qint64 traceStart);
|
||||
void firstDataReceived();
|
||||
void correctTimer();
|
||||
void profilerDataModelStateChanged();
|
||||
|
||||
protected:
|
||||
virtual void resizeEvent(QResizeEvent *event);
|
||||
|
||||
private slots:
|
||||
void profilerStateChanged();
|
||||
void clientRecordingChanged();
|
||||
void serverRecordingChanged();
|
||||
|
||||
signals:
|
||||
void viewUpdated();
|
||||
void profilerStateChanged(bool qmlActive, bool v8active);
|
||||
void gotoSourceLocation(const QString &fileUrl, int lineNumber, int columNumber);
|
||||
void range(int type, qint64 startTime, qint64 length, const QStringList &data, const QmlJsDebugClient::QmlEventLocation &location);
|
||||
void v8range(int depth,const QString &function,const QString &filename,
|
||||
int lineNumber, double totalTime, double selfTime);
|
||||
void traceFinished(qint64);
|
||||
void traceStarted(qint64);
|
||||
void frameEvent(qint64, int, int);
|
||||
void recordingChanged(bool);
|
||||
void selectedEventChanged(int eventId);
|
||||
|
||||
void internalClearDisplay();
|
||||
void clearViewsFromTool();
|
||||
void jumpToPrev();
|
||||
void jumpToNext();
|
||||
void rangeModeChanged(bool);
|
||||
void lockModeChanged(bool);
|
||||
void enableToolbar(bool);
|
||||
void zoomLevelChanged(int);
|
||||
void updateViewZoom(QVariant zoomLevel);
|
||||
void wheelZoom(QVariant wheelCenter, QVariant wheelDelta);
|
||||
void globalZoom();
|
||||
|
||||
void contextMenuRequested(const QPoint& position);
|
||||
void selectNextEventInDisplay(QVariant eventId);
|
||||
void selectedEventIdChanged(int eventId);
|
||||
|
||||
private:
|
||||
void contextMenuEvent(QContextMenuEvent *);
|
||||
QWidget *createToolbar();
|
||||
QWidget *createZoomToolbar();
|
||||
void connectClientSignals();
|
||||
void disconnectClientSignals();
|
||||
|
||||
protected:
|
||||
virtual void resizeEvent(QResizeEvent *event);
|
||||
void setRecording(bool recording);
|
||||
void setAppKilled();
|
||||
|
||||
private:
|
||||
QWeakPointer<QmlJsDebugClient::QmlProfilerTraceClient> m_plugin;
|
||||
QWeakPointer<QmlJsDebugClient::QV8ProfilerClient> m_v8plugin;
|
||||
QSize m_sizeHint;
|
||||
|
||||
ScrollableDeclarativeView *m_mainView;
|
||||
QDeclarativeView *m_timebar;
|
||||
QDeclarativeView *m_overview;
|
||||
QmlJsDebugClient::QmlProfilerEventList *m_eventList;
|
||||
QmlProfilerDetailsRewriter *m_rewriter;
|
||||
bool m_qmlDataReady;
|
||||
bool m_v8DataReady;
|
||||
double m_profiledTime;
|
||||
|
||||
QWeakPointer<ZoomControl> m_zoomControl;
|
||||
|
||||
QToolButton *m_buttonRange;
|
||||
QToolButton *m_buttonLock;
|
||||
QWidget *m_zoomToolbar;
|
||||
int m_currentZoomLevel;
|
||||
class QmlProfilerTraceViewPrivate;
|
||||
QmlProfilerTraceViewPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
#endif // TRACEWINDOW_H
|
||||
#endif // QMLPROFILERTRACEVIEW_H
|
||||
|
172
src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp
Normal file
172
src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** 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, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlprofilerviewmanager.h"
|
||||
|
||||
#include "qmlprofilertraceview.h"
|
||||
#include "qmlprofilereventview.h"
|
||||
#include "qmlprofilertool.h"
|
||||
#include "qmlprofilerstatemanager.h"
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/fancymainwindow.h>
|
||||
#include <analyzerbase/analyzermanager.h>
|
||||
|
||||
|
||||
#include <QDockWidget>
|
||||
|
||||
using namespace Analyzer;
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerViewManager::QmlProfilerViewManagerPrivate {
|
||||
public:
|
||||
QmlProfilerViewManagerPrivate(QmlProfilerViewManager *qq) { Q_UNUSED(qq); }
|
||||
|
||||
QmlProfilerTraceView *traceView;
|
||||
QmlProfilerEventsWidget *eventsView;
|
||||
QmlProfilerEventsWidget *v8profilerView;
|
||||
QmlProfilerStateManager *profilerState;
|
||||
QmlProfilerDataModel *profilerDataModel;
|
||||
QmlProfilerTool *profilerTool;
|
||||
};
|
||||
|
||||
QmlProfilerViewManager::QmlProfilerViewManager(QObject *parent,
|
||||
QmlProfilerTool *profilerTool,
|
||||
QmlProfilerDataModel *model,
|
||||
QmlProfilerStateManager *profilerState)
|
||||
: QObject(parent), d(new QmlProfilerViewManagerPrivate(this))
|
||||
{
|
||||
setObjectName("QML Profiler View Manager");
|
||||
d->traceView = 0;
|
||||
d->eventsView = 0;
|
||||
d->v8profilerView = 0;
|
||||
d->profilerState = profilerState;
|
||||
d->profilerDataModel = model;
|
||||
d->profilerTool = profilerTool;
|
||||
createViews();
|
||||
}
|
||||
|
||||
QmlProfilerViewManager::~QmlProfilerViewManager()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Views
|
||||
void QmlProfilerViewManager::createViews()
|
||||
{
|
||||
QTC_ASSERT(d->profilerDataModel, return);
|
||||
QTC_ASSERT(d->profilerState, return);
|
||||
|
||||
Utils::FancyMainWindow *mw = AnalyzerManager::mainWindow();
|
||||
|
||||
d->traceView = new QmlProfilerTraceView(mw,
|
||||
d->profilerTool,
|
||||
this,
|
||||
d->profilerDataModel,
|
||||
d->profilerState);
|
||||
connect(d->traceView, SIGNAL(gotoSourceLocation(QString,int,int)),
|
||||
this, SIGNAL(gotoSourceLocation(QString,int,int)));
|
||||
|
||||
d->traceView->reset();
|
||||
|
||||
d->eventsView = new QmlProfilerEventsWidget(mw, d->profilerTool, this, d->profilerDataModel);
|
||||
connect(d->eventsView, SIGNAL(gotoSourceLocation(QString,int,int)), this,
|
||||
SIGNAL(gotoSourceLocation(QString,int,int)));
|
||||
connect(d->eventsView, SIGNAL(showEventInTimeline(int)), d->traceView,
|
||||
SLOT(selectNextEventWithId(int)));
|
||||
connect(d->traceView, SIGNAL(selectedEventChanged(int)), d->eventsView,
|
||||
SLOT(updateSelectedEvent(int)));
|
||||
|
||||
d->v8profilerView = new QmlProfilerEventsWidget(mw, d->profilerTool,
|
||||
this, d->profilerDataModel);
|
||||
d->v8profilerView->switchToV8View();
|
||||
connect(d->v8profilerView, SIGNAL(gotoSourceLocation(QString,int,int)),
|
||||
this, SIGNAL(gotoSourceLocation(QString,int,int)));
|
||||
connect(d->v8profilerView, SIGNAL(gotoSourceLocation(QString,int,int)),
|
||||
d->eventsView, SLOT(selectBySourceLocation(QString,int,int)));
|
||||
connect(d->eventsView, SIGNAL(gotoSourceLocation(QString,int,int)),
|
||||
d->v8profilerView, SLOT(selectBySourceLocation(QString,int,int)));
|
||||
|
||||
QDockWidget *eventsDock = AnalyzerManager::createDockWidget
|
||||
(d->profilerTool, tr("Events"), d->eventsView, Qt::BottomDockWidgetArea);
|
||||
QDockWidget *timelineDock = AnalyzerManager::createDockWidget
|
||||
(d->profilerTool, tr("Timeline"), d->traceView, Qt::BottomDockWidgetArea);
|
||||
QDockWidget *v8profilerDock = AnalyzerManager::createDockWidget
|
||||
(d->profilerTool, tr("JavaScript"), d->v8profilerView, Qt::BottomDockWidgetArea);
|
||||
|
||||
eventsDock->show();
|
||||
timelineDock->show();
|
||||
v8profilerDock->show();
|
||||
|
||||
mw->splitDockWidget(mw->toolBarDockWidget(), eventsDock, Qt::Vertical);
|
||||
mw->tabifyDockWidget(eventsDock, timelineDock);
|
||||
mw->tabifyDockWidget(timelineDock, v8profilerDock);
|
||||
}
|
||||
|
||||
bool QmlProfilerViewManager::hasValidSelection() const
|
||||
{
|
||||
return d->traceView->hasValidSelection();
|
||||
}
|
||||
|
||||
qint64 QmlProfilerViewManager::selectionStart() const
|
||||
{
|
||||
return d->traceView->selectionStart();
|
||||
}
|
||||
|
||||
qint64 QmlProfilerViewManager::selectionEnd() const
|
||||
{
|
||||
return d->traceView->selectionEnd();
|
||||
}
|
||||
|
||||
bool QmlProfilerViewManager::hasGlobalStats() const
|
||||
{
|
||||
return d->eventsView->hasGlobalStats();
|
||||
}
|
||||
|
||||
void QmlProfilerViewManager::getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd)
|
||||
{
|
||||
d->eventsView->getStatisticsInRange(rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
void QmlProfilerViewManager::clear()
|
||||
{
|
||||
d->traceView->clearDisplay();
|
||||
d->eventsView->clear();
|
||||
d->v8profilerView->clear();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
@@ -30,26 +30,50 @@
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlprofilerapplication.h"
|
||||
#include "commandlistener.h"
|
||||
#ifndef QMLPROFILERVIEWMANAGER_H
|
||||
#define QMLPROFILERVIEWMANAGER_H
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
#include <QObject>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerTool;
|
||||
class QmlProfilerDataModel;
|
||||
class QmlProfilerStateManager;
|
||||
|
||||
class QmlProfilerViewManager : public QObject
|
||||
{
|
||||
QmlProfilerApplication app(argc, argv);
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QmlProfilerViewManager(QObject *parent,
|
||||
QmlProfilerTool *profilerTool,
|
||||
QmlProfilerDataModel *model,
|
||||
QmlProfilerStateManager *profilerState);
|
||||
~QmlProfilerViewManager();
|
||||
|
||||
if (!app.parseArguments()) {
|
||||
app.printUsage();
|
||||
return 1;
|
||||
}
|
||||
void createViews();
|
||||
|
||||
CommandListener listener;
|
||||
QObject::connect(&listener, SIGNAL(command(QString)), &app, SLOT(userCommand(QString)));
|
||||
listener.start();
|
||||
// used by the options "limit events to range"
|
||||
bool hasValidSelection() const;
|
||||
qint64 selectionStart() const;
|
||||
qint64 selectionEnd() const;
|
||||
bool hasGlobalStats() const;
|
||||
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
|
||||
|
||||
int exitValue = app.exec();
|
||||
// wait for listener to exit
|
||||
listener.wait();
|
||||
public slots:
|
||||
void clear();
|
||||
|
||||
signals:
|
||||
void gotoSourceLocation(QString,int,int);
|
||||
|
||||
private:
|
||||
class QmlProfilerViewManagerPrivate;
|
||||
QmlProfilerViewManagerPrivate *d;
|
||||
};
|
||||
|
||||
|
||||
return exitValue;
|
||||
}
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
#endif // QMLPROFILERVIEWMANAGER_H
|
445
src/plugins/qmlprofiler/qv8profilerdatamodel.cpp
Normal file
445
src/plugins/qmlprofiler/qv8profilerdatamodel.cpp
Normal file
@@ -0,0 +1,445 @@
|
||||
#include "qv8profilerdatamodel.h"
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
using namespace QmlJsDebugClient;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
Q_DECLARE_TYPEINFO(QmlProfiler::Internal::QV8EventData, Q_MOVABLE_TYPE);
|
||||
Q_DECLARE_TYPEINFO(QmlProfiler::Internal::QV8EventSub, Q_MOVABLE_TYPE);
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
QV8EventData &QV8EventData::operator=(const QV8EventData &ref)
|
||||
{
|
||||
if (this == &ref)
|
||||
return *this;
|
||||
|
||||
displayName = ref.displayName;
|
||||
eventHashStr = ref.eventHashStr;
|
||||
filename = ref.filename;
|
||||
functionName = ref.functionName;
|
||||
line = ref.line;
|
||||
totalTime = ref.totalTime;
|
||||
totalPercent = ref.totalPercent;
|
||||
selfTime = ref.selfTime;
|
||||
selfPercent = ref.selfPercent;
|
||||
eventId = ref.eventId;
|
||||
|
||||
qDeleteAll(parentHash.values());
|
||||
parentHash.clear();
|
||||
foreach (const QString &key, ref.parentHash.keys()) {
|
||||
parentHash.insert(key, new QV8EventSub(ref.parentHash.value(key)));
|
||||
}
|
||||
|
||||
qDeleteAll(childrenHash.values());
|
||||
childrenHash.clear();
|
||||
foreach (const QString &key, ref.childrenHash.keys()) {
|
||||
childrenHash.insert(key, new QV8EventSub(ref.childrenHash.value(key)));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
QV8EventData::QV8EventData()
|
||||
{
|
||||
line = -1;
|
||||
eventId = -1;
|
||||
totalTime = 0;
|
||||
selfTime = 0;
|
||||
totalPercent = 0;
|
||||
selfPercent = 0;
|
||||
}
|
||||
|
||||
QV8EventData::~QV8EventData()
|
||||
{
|
||||
qDeleteAll(parentHash.values());
|
||||
parentHash.clear();
|
||||
qDeleteAll(childrenHash.values());
|
||||
childrenHash.clear();
|
||||
}
|
||||
|
||||
class QV8ProfilerDataModel::QV8ProfilerDataModelPrivate
|
||||
{
|
||||
public:
|
||||
QV8ProfilerDataModelPrivate(QV8ProfilerDataModel *qq) {Q_UNUSED(qq);}
|
||||
|
||||
QmlProfilerDataModel *qmlProfilerDataModel;
|
||||
|
||||
void clearV8RootEvent();
|
||||
void collectV8Statistics();
|
||||
|
||||
QHash<QString, QV8EventData *> v8EventHash;
|
||||
QHash<int, QV8EventData *> v8parents;
|
||||
QV8EventData v8RootEvent;
|
||||
qint64 v8MeasuredTime;
|
||||
};
|
||||
|
||||
QV8ProfilerDataModel::QV8ProfilerDataModel(QObject *parent,
|
||||
QmlProfilerDataModel *profilerDataModel)
|
||||
: QObject(parent), d(new QV8ProfilerDataModelPrivate(this))
|
||||
{
|
||||
d->v8MeasuredTime = 0;
|
||||
d->clearV8RootEvent();
|
||||
d->qmlProfilerDataModel = profilerDataModel;
|
||||
}
|
||||
|
||||
QV8ProfilerDataModel::~QV8ProfilerDataModel()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QV8ProfilerDataModel::clear()
|
||||
{
|
||||
qDeleteAll(d->v8EventHash.values());
|
||||
d->v8EventHash.clear();
|
||||
d->v8parents.clear();
|
||||
d->clearV8RootEvent();
|
||||
d->v8MeasuredTime = 0;
|
||||
}
|
||||
|
||||
bool QV8ProfilerDataModel::isEmpty() const
|
||||
{
|
||||
return d->v8EventHash.isEmpty();
|
||||
}
|
||||
|
||||
QV8EventData *QV8ProfilerDataModel::v8EventDescription(int eventId) const
|
||||
{
|
||||
foreach (QV8EventData *event, d->v8EventHash.values()) {
|
||||
if (event->eventId == eventId)
|
||||
return event;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
qint64 QV8ProfilerDataModel::v8MeasuredTime() const
|
||||
{
|
||||
return d->v8MeasuredTime;
|
||||
}
|
||||
|
||||
QList<QV8EventData *> QV8ProfilerDataModel::getV8Events() const
|
||||
{
|
||||
return d->v8EventHash.values();
|
||||
}
|
||||
|
||||
void QV8ProfilerDataModel::addV8Event(int depth,
|
||||
const QString &function,
|
||||
const QString &filename,
|
||||
int lineNumber,
|
||||
double totalTime,
|
||||
double selfTime)
|
||||
{
|
||||
QString displayName = filename.mid(filename.lastIndexOf(QLatin1Char('/')) + 1) +
|
||||
QLatin1Char(':') + QString::number(lineNumber);
|
||||
QString hashStr = QmlProfilerDataModel::getHashStringForV8Event(displayName, function);
|
||||
|
||||
d->qmlProfilerDataModel->setState(QmlProfilerDataModel::AcquiringData);
|
||||
|
||||
// time is given in milliseconds, but internally we store it in microseconds
|
||||
totalTime *= 1e6;
|
||||
selfTime *= 1e6;
|
||||
|
||||
// accumulate information
|
||||
QV8EventData *eventData = d->v8EventHash[hashStr];
|
||||
if (!eventData) {
|
||||
eventData = new QV8EventData;
|
||||
eventData->displayName = displayName;
|
||||
eventData->eventHashStr = hashStr;
|
||||
eventData->filename = filename;
|
||||
eventData->functionName = function;
|
||||
eventData->line = lineNumber;
|
||||
eventData->totalTime = totalTime;
|
||||
eventData->selfTime = selfTime;
|
||||
d->v8EventHash[hashStr] = eventData;
|
||||
} else {
|
||||
eventData->totalTime += totalTime;
|
||||
eventData->selfTime += selfTime;
|
||||
}
|
||||
d->v8parents[depth] = eventData;
|
||||
|
||||
QV8EventData *parentEvent = 0;
|
||||
if (depth == 0) {
|
||||
parentEvent = &d->v8RootEvent;
|
||||
d->v8MeasuredTime += totalTime;
|
||||
}
|
||||
if (depth > 0 && d->v8parents.contains(depth-1)) {
|
||||
parentEvent = d->v8parents.value(depth-1);
|
||||
}
|
||||
|
||||
if (parentEvent != 0) {
|
||||
if (!eventData->parentHash.contains(parentEvent->eventHashStr)) {
|
||||
QV8EventSub *newParentSub = new QV8EventSub(parentEvent);
|
||||
newParentSub->totalTime = totalTime;
|
||||
|
||||
eventData->parentHash.insert(parentEvent->eventHashStr, newParentSub);
|
||||
} else {
|
||||
QV8EventSub *newParentSub = eventData->parentHash.value(parentEvent->eventHashStr);
|
||||
newParentSub->totalTime += totalTime;
|
||||
}
|
||||
|
||||
if (!parentEvent->childrenHash.contains(eventData->eventHashStr)) {
|
||||
QV8EventSub *newChildSub = new QV8EventSub(eventData);
|
||||
newChildSub->totalTime = totalTime;
|
||||
|
||||
parentEvent->childrenHash.insert(eventData->eventHashStr, newChildSub);
|
||||
} else {
|
||||
QV8EventSub *newChildSub = parentEvent->childrenHash.value(eventData->eventHashStr);
|
||||
newChildSub->totalTime += totalTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QV8ProfilerDataModel::collectV8Statistics()
|
||||
{
|
||||
d->collectV8Statistics();
|
||||
}
|
||||
|
||||
void QV8ProfilerDataModel::QV8ProfilerDataModelPrivate::collectV8Statistics()
|
||||
{
|
||||
if (!v8EventHash.isEmpty()) {
|
||||
double totalTimes = v8MeasuredTime;
|
||||
double selfTimes = 0;
|
||||
foreach (QV8EventData *v8event, v8EventHash.values()) {
|
||||
selfTimes += v8event->selfTime;
|
||||
}
|
||||
|
||||
// prevent divisions by 0
|
||||
if (totalTimes == 0)
|
||||
totalTimes = 1;
|
||||
if (selfTimes == 0)
|
||||
selfTimes = 1;
|
||||
|
||||
// insert root event in eventlist
|
||||
// the +1 ns is to get it on top of the sorted list
|
||||
v8RootEvent.totalTime = v8MeasuredTime + 1;
|
||||
v8RootEvent.selfTime = 0;
|
||||
|
||||
QString rootEventHash = QmlProfilerDataModel::getHashStringForV8Event(
|
||||
QmlProfilerDataModel::rootEventName(),
|
||||
QmlProfilerDataModel::rootEventDescription());
|
||||
QV8EventData *v8RootEventPointer = v8EventHash[rootEventHash];
|
||||
if (v8RootEventPointer) {
|
||||
v8RootEvent = *v8RootEventPointer;
|
||||
} else {
|
||||
v8EventHash[rootEventHash] = new QV8EventData;
|
||||
*v8EventHash[rootEventHash] = v8RootEvent;
|
||||
}
|
||||
|
||||
foreach (QV8EventData *v8event, v8EventHash.values()) {
|
||||
v8event->totalPercent = v8event->totalTime * 100.0 / totalTimes;
|
||||
v8event->selfPercent = v8event->selfTime * 100.0 / selfTimes;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
foreach (QV8EventData *v8event, v8EventHash.values()) {
|
||||
v8event->eventId = index++;
|
||||
}
|
||||
v8RootEvent.eventId = v8EventHash[rootEventHash]->eventId;
|
||||
}
|
||||
}
|
||||
|
||||
void QV8ProfilerDataModel::QV8ProfilerDataModelPrivate::clearV8RootEvent()
|
||||
{
|
||||
v8RootEvent.displayName = QmlProfilerDataModel::rootEventName();
|
||||
v8RootEvent.eventHashStr = QmlProfilerDataModel::rootEventName();
|
||||
v8RootEvent.functionName = QmlProfilerDataModel::rootEventDescription();
|
||||
v8RootEvent.line = -1;
|
||||
v8RootEvent.totalTime = 0;
|
||||
v8RootEvent.totalPercent = 0;
|
||||
v8RootEvent.selfTime = 0;
|
||||
v8RootEvent.selfPercent = 0;
|
||||
v8RootEvent.eventId = -1;
|
||||
|
||||
qDeleteAll(v8RootEvent.parentHash.values());
|
||||
qDeleteAll(v8RootEvent.childrenHash.values());
|
||||
v8RootEvent.parentHash.clear();
|
||||
v8RootEvent.childrenHash.clear();
|
||||
}
|
||||
|
||||
void QV8ProfilerDataModel::save(QXmlStreamWriter &stream)
|
||||
{
|
||||
stream.writeStartElement("v8profile"); // v8 profiler output
|
||||
stream.writeAttribute("totalTime", QString::number(d->v8MeasuredTime));
|
||||
foreach (QV8EventData *v8event, d->v8EventHash.values()) {
|
||||
stream.writeStartElement("event");
|
||||
stream.writeAttribute("index",
|
||||
QString::number(
|
||||
d->v8EventHash.keys().indexOf(
|
||||
v8event->eventHashStr)));
|
||||
stream.writeTextElement("displayname", v8event->displayName);
|
||||
stream.writeTextElement("functionname", v8event->functionName);
|
||||
if (!v8event->filename.isEmpty()) {
|
||||
stream.writeTextElement("filename", v8event->filename);
|
||||
stream.writeTextElement("line", QString::number(v8event->line));
|
||||
}
|
||||
stream.writeTextElement("totalTime", QString::number(v8event->totalTime));
|
||||
stream.writeTextElement("selfTime", QString::number(v8event->selfTime));
|
||||
if (!v8event->childrenHash.isEmpty()) {
|
||||
stream.writeStartElement("childrenEvents");
|
||||
QStringList childrenIndexes;
|
||||
QStringList childrenTimes;
|
||||
QStringList parentTimes;
|
||||
foreach (QV8EventSub *v8child, v8event->childrenHash.values()) {
|
||||
childrenIndexes << QString::number(v8child->reference->eventId);
|
||||
childrenTimes << QString::number(v8child->totalTime);
|
||||
parentTimes << QString::number(v8child->totalTime);
|
||||
}
|
||||
|
||||
stream.writeAttribute("list", childrenIndexes.join(QString(", ")));
|
||||
stream.writeAttribute("childrenTimes", childrenTimes.join(QString(", ")));
|
||||
stream.writeAttribute("parentTimes", parentTimes.join(QString(", ")));
|
||||
stream.writeEndElement();
|
||||
}
|
||||
stream.writeEndElement();
|
||||
}
|
||||
stream.writeEndElement(); // v8 profiler output
|
||||
}
|
||||
|
||||
void QV8ProfilerDataModel::load(QXmlStreamReader &stream)
|
||||
{
|
||||
QHash <int, QV8EventData *> v8eventBuffer;
|
||||
QHash <int, QString> childrenIndexes;
|
||||
QHash <int, QString> childrenTimes;
|
||||
QHash <int, QString> parentTimes;
|
||||
QV8EventData *v8event = 0;
|
||||
|
||||
// time computation
|
||||
d->v8MeasuredTime = 0;
|
||||
double cumulatedV8Time = 0;
|
||||
|
||||
// get the v8 time
|
||||
QXmlStreamAttributes attributes = stream.attributes();
|
||||
if (attributes.hasAttribute("totalTime"))
|
||||
d->v8MeasuredTime = attributes.value("totalTime").toString().toDouble();
|
||||
|
||||
while (!stream.atEnd() && !stream.hasError()) {
|
||||
QXmlStreamReader::TokenType token = stream.readNext();
|
||||
QString elementName = stream.name().toString();
|
||||
switch (token) {
|
||||
case QXmlStreamReader::StartDocument : continue;
|
||||
case QXmlStreamReader::StartElement : {
|
||||
if (elementName == "event") {
|
||||
QXmlStreamAttributes attributes = stream.attributes();
|
||||
if (attributes.hasAttribute("index")) {
|
||||
int ndx = attributes.value("index").toString().toInt();
|
||||
if (!v8eventBuffer.value(ndx))
|
||||
v8eventBuffer[ndx] = new QV8EventData;
|
||||
v8event = v8eventBuffer[ndx];
|
||||
} else {
|
||||
v8event = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!v8event)
|
||||
break;
|
||||
|
||||
if (elementName == "childrenEvents") {
|
||||
QXmlStreamAttributes attributes = stream.attributes();
|
||||
int eventIndex = v8eventBuffer.key(v8event);
|
||||
if (attributes.hasAttribute("list")) {
|
||||
// store for later parsing (we haven't read all the events yet)
|
||||
childrenIndexes[eventIndex] = attributes.value("list").toString();
|
||||
}
|
||||
if (attributes.hasAttribute("childrenTimes")) {
|
||||
childrenTimes[eventIndex] =
|
||||
attributes.value("childrenTimes").toString();
|
||||
}
|
||||
if (attributes.hasAttribute("parentTimes")) {
|
||||
parentTimes[eventIndex] = attributes.value("parentTimes").toString();
|
||||
}
|
||||
}
|
||||
|
||||
stream.readNext();
|
||||
if (stream.tokenType() != QXmlStreamReader::Characters)
|
||||
break;
|
||||
QString readData = stream.text().toString();
|
||||
|
||||
if (elementName == "displayname") {
|
||||
v8event->displayName = readData;
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == "functionname") {
|
||||
v8event->functionName = readData;
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == "filename") {
|
||||
v8event->filename = readData;
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == "line") {
|
||||
v8event->line = readData.toInt();
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == "totalTime") {
|
||||
v8event->totalTime = readData.toDouble();
|
||||
cumulatedV8Time += v8event->totalTime;
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == "selfTime") {
|
||||
v8event->selfTime = readData.toDouble();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QXmlStreamReader::EndElement : {
|
||||
if (elementName == "v8profile") {
|
||||
// done reading the v8 profile data
|
||||
break;
|
||||
}
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// backwards compatibility
|
||||
if (d->v8MeasuredTime == 0)
|
||||
d->v8MeasuredTime = cumulatedV8Time;
|
||||
|
||||
// find v8events' children and parents
|
||||
foreach (int parentIndex, childrenIndexes.keys()) {
|
||||
QStringList childrenStrings = childrenIndexes.value(parentIndex).split(",");
|
||||
QStringList childrenTimesStrings = childrenTimes.value(parentIndex).split(", ");
|
||||
QStringList parentTimesStrings = parentTimes.value(parentIndex).split(", ");
|
||||
for (int ndx = 0; ndx < childrenStrings.count(); ndx++) {
|
||||
int childIndex = childrenStrings[ndx].toInt();
|
||||
if (v8eventBuffer.value(childIndex)) {
|
||||
QV8EventSub *newChild = new QV8EventSub(v8eventBuffer[childIndex]);
|
||||
QV8EventSub *newParent = new QV8EventSub(v8eventBuffer[parentIndex]);
|
||||
if (childrenTimesStrings.count() > ndx) {
|
||||
newChild->totalTime = childrenTimesStrings[ndx].toDouble();
|
||||
}
|
||||
if (parentTimesStrings.count() > ndx) {
|
||||
newParent->totalTime = parentTimesStrings[ndx].toDouble();
|
||||
}
|
||||
v8eventBuffer[parentIndex]->childrenHash.insert(
|
||||
newChild->reference->displayName,
|
||||
newChild);
|
||||
v8eventBuffer[childIndex]->parentHash.insert(
|
||||
newParent->reference->displayName,
|
||||
newParent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// store v8 events
|
||||
foreach (QV8EventData *storedV8Event, v8eventBuffer.values()) {
|
||||
storedV8Event->eventHashStr =
|
||||
QmlProfilerDataModel::getHashStringForV8Event(
|
||||
storedV8Event->displayName, storedV8Event->functionName);
|
||||
d->v8EventHash[storedV8Event->eventHashStr] = storedV8Event;
|
||||
}
|
||||
|
||||
d->collectV8Statistics();
|
||||
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
79
src/plugins/qmlprofiler/qv8profilerdatamodel.h
Normal file
79
src/plugins/qmlprofiler/qv8profilerdatamodel.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#ifndef QV8PROFILERDATAMODEL_H
|
||||
#define QV8PROFILERDATAMODEL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
|
||||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamWriter>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerDataModel;
|
||||
struct QV8EventSub;
|
||||
|
||||
struct QV8EventData
|
||||
{
|
||||
QV8EventData();
|
||||
~QV8EventData();
|
||||
|
||||
QString displayName;
|
||||
QString eventHashStr;
|
||||
QString filename;
|
||||
QString functionName;
|
||||
int line;
|
||||
double totalTime; // given in milliseconds
|
||||
double totalPercent;
|
||||
double selfTime;
|
||||
double selfPercent;
|
||||
QHash <QString, QV8EventSub *> parentHash;
|
||||
QHash <QString, QV8EventSub *> childrenHash;
|
||||
int eventId;
|
||||
|
||||
QV8EventData &operator=(const QV8EventData &ref);
|
||||
};
|
||||
|
||||
struct QV8EventSub {
|
||||
QV8EventSub(QV8EventData *from) : reference(from), totalTime(0) {}
|
||||
QV8EventSub(QV8EventSub *from) : reference(from->reference), totalTime(from->totalTime) {}
|
||||
|
||||
QV8EventData *reference;
|
||||
qint64 totalTime;
|
||||
};
|
||||
|
||||
class QV8ProfilerDataModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QV8ProfilerDataModel(QObject *parent, QmlProfilerDataModel *profilerDataModel);
|
||||
~QV8ProfilerDataModel();
|
||||
|
||||
void clear();
|
||||
bool isEmpty() const;
|
||||
QList<QV8EventData *> getV8Events() const;
|
||||
QV8EventData *v8EventDescription(int eventId) const;
|
||||
|
||||
qint64 v8MeasuredTime() const;
|
||||
void collectV8Statistics();
|
||||
|
||||
void save(QXmlStreamWriter &stream);
|
||||
void load(QXmlStreamReader &stream);
|
||||
|
||||
public slots:
|
||||
void addV8Event(int depth,
|
||||
const QString &function,
|
||||
const QString &filename,
|
||||
int lineNumber,
|
||||
double totalTime,
|
||||
double selfTime);
|
||||
|
||||
private:
|
||||
class QV8ProfilerDataModelPrivate;
|
||||
QV8ProfilerDataModelPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
#endif // QV8PROFILERDATAMODEL_H
|
@@ -30,7 +30,7 @@
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "timelineview.h"
|
||||
#include "timelinerenderer.h"
|
||||
|
||||
#include <qdeclarativecontext.h>
|
||||
#include <qdeclarativeproperty.h>
|
||||
@@ -45,9 +45,9 @@ using namespace QmlProfiler::Internal;
|
||||
|
||||
const int DefaultRowHeight = 30;
|
||||
|
||||
TimelineView::TimelineView(QDeclarativeItem *parent) :
|
||||
TimelineRenderer::TimelineRenderer(QDeclarativeItem *parent) :
|
||||
QDeclarativeItem(parent), m_startTime(0), m_endTime(0), m_spacing(0),
|
||||
m_lastStartTime(0), m_lastEndTime(0), m_eventList(0)
|
||||
m_lastStartTime(0), m_lastEndTime(0), m_profilerDataModel(0)
|
||||
{
|
||||
clearData();
|
||||
setFlag(QGraphicsItem::ItemHasNoContents, false);
|
||||
@@ -57,12 +57,12 @@ TimelineView::TimelineView(QDeclarativeItem *parent) :
|
||||
m_rowsExpanded << false;
|
||||
}
|
||||
|
||||
void TimelineView::componentComplete()
|
||||
void TimelineRenderer::componentComplete()
|
||||
{
|
||||
const QMetaObject *metaObject = this->metaObject();
|
||||
int propertyCount = metaObject->propertyCount();
|
||||
int requestPaintMethod = metaObject->indexOfMethod("requestPaint()");
|
||||
for (int ii = TimelineView::staticMetaObject.propertyCount(); ii < propertyCount; ++ii) {
|
||||
for (int ii = TimelineRenderer::staticMetaObject.propertyCount(); ii < propertyCount; ++ii) {
|
||||
QMetaProperty p = metaObject->property(ii);
|
||||
if (p.hasNotifySignal())
|
||||
QMetaObject::connect(this, p.notifySignalIndex(), this, requestPaintMethod, 0, 0);
|
||||
@@ -70,12 +70,12 @@ void TimelineView::componentComplete()
|
||||
QDeclarativeItem::componentComplete();
|
||||
}
|
||||
|
||||
void TimelineView::requestPaint()
|
||||
void TimelineRenderer::requestPaint()
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void TimelineView::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
|
||||
void TimelineRenderer::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
|
||||
{
|
||||
qint64 windowDuration = m_endTime - m_startTime;
|
||||
if (windowDuration <= 0)
|
||||
@@ -86,7 +86,8 @@ void TimelineView::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget
|
||||
m_rowWidths.clear();
|
||||
// The "1+" is because the reference screenshot features an empty row per type, in order to leave space for the title
|
||||
for (int i=0; i<QmlJsDebugClient::MaximumQmlEventType; i++) {
|
||||
m_rowWidths << 1 + (m_rowsExpanded[i] ? m_eventList->uniqueEventsOfType(i) : m_eventList->maxNestingForType(i));
|
||||
m_rowWidths << 1 + (m_rowsExpanded[i] ? m_profilerDataModel->uniqueEventsOfType(i) :
|
||||
m_profilerDataModel->maxNestingForType(i));
|
||||
}
|
||||
|
||||
// event rows
|
||||
@@ -105,8 +106,8 @@ void TimelineView::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget
|
||||
for (int j=0; j<m_rowWidths[i]; j++)
|
||||
m_rowLastX << -m_startTime * m_spacing;
|
||||
|
||||
int firstIndex = m_eventList->findFirstIndex(m_startTime);
|
||||
int lastIndex = m_eventList->findLastIndex(m_endTime);
|
||||
int firstIndex = m_profilerDataModel->findFirstIndex(m_startTime);
|
||||
int lastIndex = m_profilerDataModel->findLastIndex(m_endTime);
|
||||
|
||||
drawItemsToPainter(p, firstIndex, lastIndex);
|
||||
drawSelectionBoxes(p, firstIndex, lastIndex);
|
||||
@@ -116,25 +117,27 @@ void TimelineView::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget
|
||||
m_lastEndTime = m_endTime;
|
||||
}
|
||||
|
||||
QColor TimelineView::colorForItem(int itemIndex)
|
||||
QColor TimelineRenderer::colorForItem(int itemIndex)
|
||||
{
|
||||
int ndx = m_eventList->getEventId(itemIndex);
|
||||
int ndx = m_profilerDataModel->getEventId(itemIndex);
|
||||
return QColor::fromHsl((ndx*25)%360, 76, 166);
|
||||
}
|
||||
|
||||
void TimelineView::drawItemsToPainter(QPainter *p, int fromIndex, int toIndex)
|
||||
void TimelineRenderer::drawItemsToPainter(QPainter *p, int fromIndex, int toIndex)
|
||||
{
|
||||
int x, y, width, height, rowNumber, eventType;
|
||||
for (int i = fromIndex; i <= toIndex; i++) {
|
||||
x = (m_eventList->getStartTime(i) - m_startTime) * m_spacing;
|
||||
x = (m_profilerDataModel->getStartTime(i) - m_startTime) * m_spacing;
|
||||
|
||||
eventType = m_eventList->getType(i);
|
||||
eventType = m_profilerDataModel->getType(i);
|
||||
if (m_rowsExpanded[eventType])
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight*(m_eventList->eventPosInType(i) + 1);
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
(m_profilerDataModel->eventPosInType(i) + 1);
|
||||
else
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight*m_eventList->getNestingLevel(i);
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
m_profilerDataModel->getNestingLevel(i);
|
||||
|
||||
width = m_eventList->getDuration(i)*m_spacing;
|
||||
width = m_profilerDataModel->getDuration(i)*m_spacing;
|
||||
if (width<1)
|
||||
width = 1;
|
||||
|
||||
@@ -144,17 +147,19 @@ void TimelineView::drawItemsToPainter(QPainter *p, int fromIndex, int toIndex)
|
||||
m_rowLastX[rowNumber] = x+width;
|
||||
|
||||
// special: animations
|
||||
if (eventType == 0 && m_eventList->getAnimationCount(i) >= 0) {
|
||||
double scale = m_eventList->getMaximumAnimationCount() - m_eventList->getMinimumAnimationCount();
|
||||
if (eventType == 0 && m_profilerDataModel->getAnimationCount(i) >= 0) {
|
||||
double scale = m_profilerDataModel->getMaximumAnimationCount() -
|
||||
m_profilerDataModel->getMinimumAnimationCount();
|
||||
double fraction;
|
||||
if (scale > 1)
|
||||
fraction = (double)(m_eventList->getAnimationCount(i) - m_eventList->getMinimumAnimationCount()) / scale;
|
||||
fraction = (double)(m_profilerDataModel->getAnimationCount(i) -
|
||||
m_profilerDataModel->getMinimumAnimationCount()) / scale;
|
||||
else
|
||||
fraction = 1.0;
|
||||
height = DefaultRowHeight * (fraction * 0.85 + 0.15);
|
||||
y += DefaultRowHeight - height;
|
||||
|
||||
double fpsFraction = m_eventList->getFramerate(i) / 60.0;
|
||||
double fpsFraction = m_profilerDataModel->getFramerate(i) / 60.0;
|
||||
if (fpsFraction > 1.0)
|
||||
fpsFraction = 1.0;
|
||||
p->setBrush(QColor::fromHsl((fpsFraction*96)+10, 76, 166));
|
||||
@@ -167,12 +172,12 @@ void TimelineView::drawItemsToPainter(QPainter *p, int fromIndex, int toIndex)
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineView::drawSelectionBoxes(QPainter *p, int fromIndex, int toIndex)
|
||||
void TimelineRenderer::drawSelectionBoxes(QPainter *p, int fromIndex, int toIndex)
|
||||
{
|
||||
if (m_selectedItem == -1)
|
||||
return;
|
||||
|
||||
int id = m_eventList->getEventId(m_selectedItem);
|
||||
int id = m_profilerDataModel->getEventId(m_selectedItem);
|
||||
|
||||
p->setBrush(Qt::transparent);
|
||||
QColor selectionColor = Qt::blue;
|
||||
@@ -188,17 +193,19 @@ void TimelineView::drawSelectionBoxes(QPainter *p, int fromIndex, int toIndex)
|
||||
|
||||
QRect selectedItemRect(0,0,0,0);
|
||||
for (int i = fromIndex; i <= toIndex; i++) {
|
||||
if (m_eventList->getEventId(i) != id)
|
||||
if (m_profilerDataModel->getEventId(i) != id)
|
||||
continue;
|
||||
|
||||
x = (m_eventList->getStartTime(i) - m_startTime) * m_spacing;
|
||||
eventType = m_eventList->getType(i);
|
||||
x = (m_profilerDataModel->getStartTime(i) - m_startTime) * m_spacing;
|
||||
eventType = m_profilerDataModel->getType(i);
|
||||
if (m_rowsExpanded[eventType])
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight*(m_eventList->eventPosInType(i) + 1);
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
(m_profilerDataModel->eventPosInType(i) + 1);
|
||||
else
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight*m_eventList->getNestingLevel(i);
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
m_profilerDataModel->getNestingLevel(i);
|
||||
|
||||
width = m_eventList->getDuration(i)*m_spacing;
|
||||
width = m_profilerDataModel->getDuration(i)*m_spacing;
|
||||
if (width<1)
|
||||
width = 1;
|
||||
|
||||
@@ -215,7 +222,7 @@ void TimelineView::drawSelectionBoxes(QPainter *p, int fromIndex, int toIndex)
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineView::drawBindingLoopMarkers(QPainter *p, int fromIndex, int toIndex)
|
||||
void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int fromIndex, int toIndex)
|
||||
{
|
||||
int destindex;
|
||||
int xfrom, xto, eventType;
|
||||
@@ -228,35 +235,38 @@ void TimelineView::drawBindingLoopMarkers(QPainter *p, int fromIndex, int toInde
|
||||
|
||||
p->save();
|
||||
for (int i = fromIndex; i <= toIndex; i++) {
|
||||
destindex = m_eventList->getBindingLoopDest(i);
|
||||
destindex = m_profilerDataModel->getBindingLoopDest(i);
|
||||
if (destindex >= 0) {
|
||||
// from
|
||||
xfrom = (m_eventList->getStartTime(i) + m_eventList->getDuration(i)/2 -
|
||||
xfrom = (m_profilerDataModel->getStartTime(i) +
|
||||
m_profilerDataModel->getDuration(i)/2 -
|
||||
m_startTime) * m_spacing;
|
||||
eventType = m_eventList->getType(i);
|
||||
eventType = m_profilerDataModel->getType(i);
|
||||
if (m_rowsExpanded[eventType])
|
||||
yfrom = m_rowStarts[eventType] + DefaultRowHeight*
|
||||
(m_eventList->eventPosInType(i) + 1);
|
||||
(m_profilerDataModel->eventPosInType(i) + 1);
|
||||
else
|
||||
yfrom = m_rowStarts[eventType] + DefaultRowHeight*m_eventList->getNestingLevel(i);
|
||||
yfrom = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
m_profilerDataModel->getNestingLevel(i);
|
||||
|
||||
yfrom += DefaultRowHeight / 2;
|
||||
|
||||
// to
|
||||
xto = (m_eventList->getStartTime(destindex) + m_eventList->getDuration(destindex)/2 -
|
||||
xto = (m_profilerDataModel->getStartTime(destindex) +
|
||||
m_profilerDataModel->getDuration(destindex)/2 -
|
||||
m_startTime) * m_spacing;
|
||||
eventType = m_eventList->getType(destindex);
|
||||
eventType = m_profilerDataModel->getType(destindex);
|
||||
if (m_rowsExpanded[eventType])
|
||||
yto = m_rowStarts[eventType] + DefaultRowHeight*
|
||||
(m_eventList->eventPosInType(destindex) + 1);
|
||||
yto = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
(m_profilerDataModel->eventPosInType(destindex) + 1);
|
||||
else
|
||||
yto = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
m_eventList->getNestingLevel(destindex);
|
||||
m_profilerDataModel->getNestingLevel(destindex);
|
||||
|
||||
yto += DefaultRowHeight / 2;
|
||||
|
||||
// radius
|
||||
int eventWidth = m_eventList->getDuration(i) * m_spacing;
|
||||
int eventWidth = m_profilerDataModel->getDuration(i) * m_spacing;
|
||||
radius = 5;
|
||||
if (radius * 2 > eventWidth)
|
||||
radius = eventWidth / 2;
|
||||
@@ -283,7 +293,7 @@ void TimelineView::drawBindingLoopMarkers(QPainter *p, int fromIndex, int toInde
|
||||
p->restore();
|
||||
}
|
||||
|
||||
void TimelineView::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
void TimelineRenderer::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
// special case: if there is a drag area below me, don't accept the
|
||||
// events unless I'm actually clicking inside an item
|
||||
@@ -294,19 +304,19 @@ void TimelineView::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
|
||||
}
|
||||
|
||||
void TimelineView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
void TimelineRenderer::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
manageClicked();
|
||||
}
|
||||
|
||||
void TimelineView::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
void TimelineRenderer::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
event->setAccepted(false);
|
||||
}
|
||||
|
||||
|
||||
void TimelineView::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
|
||||
void TimelineRenderer::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
manageHovered(event->pos().x(), event->pos().y());
|
||||
@@ -314,7 +324,7 @@ void TimelineView::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
|
||||
event->setAccepted(false);
|
||||
}
|
||||
|
||||
void TimelineView::manageClicked()
|
||||
void TimelineRenderer::manageClicked()
|
||||
{
|
||||
if (m_currentSelection.eventIndex != -1) {
|
||||
if (m_currentSelection.eventIndex == m_selectedItem)
|
||||
@@ -328,7 +338,7 @@ void TimelineView::manageClicked()
|
||||
setSelectedItem(m_currentSelection.eventIndex);
|
||||
}
|
||||
|
||||
void TimelineView::manageHovered(int x, int y)
|
||||
void TimelineRenderer::manageHovered(int x, int y)
|
||||
{
|
||||
if (m_endTime - m_startTime <=0 || m_lastEndTime - m_lastStartTime <= 0)
|
||||
return;
|
||||
@@ -337,13 +347,16 @@ void TimelineView::manageHovered(int x, int y)
|
||||
int row = y / DefaultRowHeight;
|
||||
|
||||
// already covered? nothing to do
|
||||
if (m_currentSelection.eventIndex != -1 && time >= m_currentSelection.startTime && time <= m_currentSelection.endTime && row == m_currentSelection.row) {
|
||||
if (m_currentSelection.eventIndex != -1 &&
|
||||
time >= m_currentSelection.startTime &&
|
||||
time <= m_currentSelection.endTime &&
|
||||
row == m_currentSelection.row) {
|
||||
return;
|
||||
}
|
||||
|
||||
// find if there's items in the time range
|
||||
int eventFrom = m_eventList->findFirstIndex(time);
|
||||
int eventTo = m_eventList->findLastIndex(time);
|
||||
int eventFrom = m_profilerDataModel->findFirstIndex(time);
|
||||
int eventTo = m_profilerDataModel->findLastIndex(time);
|
||||
if (eventTo < eventFrom) {
|
||||
m_currentSelection.eventIndex = -1;
|
||||
return;
|
||||
@@ -352,19 +365,21 @@ void TimelineView::manageHovered(int x, int y)
|
||||
// find if we are in the right column
|
||||
int itemRow, eventType;
|
||||
for (int i=eventTo; i>=eventFrom; --i) {
|
||||
if (ceil(m_eventList->getEndTime(i)*m_spacing) < floor(time*m_spacing))
|
||||
if (ceil(m_profilerDataModel->getEndTime(i)*m_spacing) < floor(time*m_spacing))
|
||||
continue;
|
||||
|
||||
eventType = m_eventList->getType(i);
|
||||
eventType = m_profilerDataModel->getType(i);
|
||||
if (m_rowsExpanded[eventType])
|
||||
itemRow = m_rowStarts[eventType]/DefaultRowHeight + m_eventList->eventPosInType(i) + 1;
|
||||
itemRow = m_rowStarts[eventType]/DefaultRowHeight +
|
||||
m_profilerDataModel->eventPosInType(i) + 1;
|
||||
else
|
||||
itemRow = m_rowStarts[eventType]/DefaultRowHeight + m_eventList->getNestingLevel(i);
|
||||
itemRow = m_rowStarts[eventType]/DefaultRowHeight +
|
||||
m_profilerDataModel->getNestingLevel(i);
|
||||
if (itemRow == row) {
|
||||
// match
|
||||
m_currentSelection.eventIndex = i;
|
||||
m_currentSelection.startTime = m_eventList->getStartTime(i);
|
||||
m_currentSelection.endTime = m_eventList->getEndTime(i);
|
||||
m_currentSelection.startTime = m_profilerDataModel->getStartTime(i);
|
||||
m_currentSelection.endTime = m_profilerDataModel->getEndTime(i);
|
||||
m_currentSelection.row = row;
|
||||
if (!m_selectionLocked)
|
||||
setSelectedItem(i);
|
||||
@@ -376,7 +391,7 @@ void TimelineView::manageHovered(int x, int y)
|
||||
return;
|
||||
}
|
||||
|
||||
void TimelineView::clearData()
|
||||
void TimelineRenderer::clearData()
|
||||
{
|
||||
m_startTime = 0;
|
||||
m_endTime = 0;
|
||||
@@ -390,122 +405,125 @@ void TimelineView::clearData()
|
||||
m_selectionLocked = true;
|
||||
}
|
||||
|
||||
qint64 TimelineView::getDuration(int index) const
|
||||
qint64 TimelineRenderer::getDuration(int index) const
|
||||
{
|
||||
Q_ASSERT(m_eventList);
|
||||
return m_eventList->getEndTime(index) - m_eventList->getStartTime(index);
|
||||
Q_ASSERT(m_profilerDataModel);
|
||||
return m_profilerDataModel->getEndTime(index) -
|
||||
m_profilerDataModel->getStartTime(index);
|
||||
}
|
||||
|
||||
QString TimelineView::getFilename(int index) const
|
||||
QString TimelineRenderer::getFilename(int index) const
|
||||
{
|
||||
Q_ASSERT(m_eventList);
|
||||
return m_eventList->getFilename(index);
|
||||
Q_ASSERT(m_profilerDataModel);
|
||||
return m_profilerDataModel->getFilename(index);
|
||||
}
|
||||
|
||||
int TimelineView::getLine(int index) const
|
||||
int TimelineRenderer::getLine(int index) const
|
||||
{
|
||||
Q_ASSERT(m_eventList);
|
||||
return m_eventList->getLine(index);
|
||||
Q_ASSERT(m_profilerDataModel);
|
||||
return m_profilerDataModel->getLine(index);
|
||||
}
|
||||
|
||||
QString TimelineView::getDetails(int index) const
|
||||
QString TimelineRenderer::getDetails(int index) const
|
||||
{
|
||||
Q_ASSERT(m_eventList);
|
||||
return m_eventList->getDetails(index);
|
||||
Q_ASSERT(m_profilerDataModel);
|
||||
return m_profilerDataModel->getDetails(index);
|
||||
}
|
||||
|
||||
int TimelineView::getYPosition(int index) const
|
||||
int TimelineRenderer::getYPosition(int index) const
|
||||
{
|
||||
Q_ASSERT(m_eventList);
|
||||
if (index >= m_eventList->count() || m_rowStarts.isEmpty())
|
||||
Q_ASSERT(m_profilerDataModel);
|
||||
if (index >= m_profilerDataModel->count() || m_rowStarts.isEmpty())
|
||||
return 0;
|
||||
int y, eventType = m_eventList->getType(index);
|
||||
int y, eventType = m_profilerDataModel->getType(index);
|
||||
if (m_rowsExpanded[eventType])
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight*(m_eventList->eventPosInType(index) + 1);
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
(m_profilerDataModel->eventPosInType(index) + 1);
|
||||
else
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight*m_eventList->getNestingLevel(index);
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
m_profilerDataModel->getNestingLevel(index);
|
||||
return y;
|
||||
}
|
||||
|
||||
void TimelineView::setRowExpanded(int rowIndex, bool expanded)
|
||||
void TimelineRenderer::setRowExpanded(int rowIndex, bool expanded)
|
||||
{
|
||||
m_rowsExpanded[rowIndex] = expanded;
|
||||
update();
|
||||
}
|
||||
|
||||
void TimelineView::selectNext()
|
||||
void TimelineRenderer::selectNext()
|
||||
{
|
||||
if (m_eventList->count() == 0)
|
||||
if (m_profilerDataModel->count() == 0)
|
||||
return;
|
||||
|
||||
// select next in view or after
|
||||
int newIndex = m_selectedItem+1;
|
||||
if (newIndex >= m_eventList->count())
|
||||
if (newIndex >= m_profilerDataModel->count())
|
||||
newIndex = 0;
|
||||
if (m_eventList->getEndTime(newIndex) < m_startTime)
|
||||
newIndex = m_eventList->findFirstIndexNoParents(m_startTime);
|
||||
if (m_profilerDataModel->getEndTime(newIndex) < m_startTime)
|
||||
newIndex = m_profilerDataModel->findFirstIndexNoParents(m_startTime);
|
||||
setSelectedItem(newIndex);
|
||||
}
|
||||
|
||||
void TimelineView::selectPrev()
|
||||
void TimelineRenderer::selectPrev()
|
||||
{
|
||||
if (m_eventList->count() == 0)
|
||||
if (m_profilerDataModel->count() == 0)
|
||||
return;
|
||||
|
||||
// select last in view or before
|
||||
int newIndex = m_selectedItem-1;
|
||||
if (newIndex < 0)
|
||||
newIndex = m_eventList->count()-1;
|
||||
if (m_eventList->getStartTime(newIndex) > m_endTime)
|
||||
newIndex = m_eventList->findLastIndex(m_endTime);
|
||||
newIndex = m_profilerDataModel->count()-1;
|
||||
if (m_profilerDataModel->getStartTime(newIndex) > m_endTime)
|
||||
newIndex = m_profilerDataModel->findLastIndex(m_endTime);
|
||||
setSelectedItem(newIndex);
|
||||
}
|
||||
|
||||
int TimelineView::nextItemFromId(int eventId) const
|
||||
int TimelineRenderer::nextItemFromId(int eventId) const
|
||||
{
|
||||
int ndx = -1;
|
||||
if (m_selectedItem == -1)
|
||||
ndx = m_eventList->findFirstIndexNoParents(m_startTime);
|
||||
ndx = m_profilerDataModel->findFirstIndexNoParents(m_startTime);
|
||||
else
|
||||
ndx = m_selectedItem + 1;
|
||||
if (ndx >= m_eventList->count())
|
||||
if (ndx >= m_profilerDataModel->count())
|
||||
ndx = 0;
|
||||
int startIndex = ndx;
|
||||
do {
|
||||
if (m_eventList->getEventId(ndx) == eventId)
|
||||
if (m_profilerDataModel->getEventId(ndx) == eventId)
|
||||
return ndx;
|
||||
ndx = (ndx + 1) % m_eventList->count();
|
||||
ndx = (ndx + 1) % m_profilerDataModel->count();
|
||||
} while (ndx != startIndex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int TimelineView::prevItemFromId(int eventId) const
|
||||
int TimelineRenderer::prevItemFromId(int eventId) const
|
||||
{
|
||||
int ndx = -1;
|
||||
if (m_selectedItem == -1)
|
||||
ndx = m_eventList->findFirstIndexNoParents(m_startTime);
|
||||
ndx = m_profilerDataModel->findFirstIndexNoParents(m_startTime);
|
||||
else
|
||||
ndx = m_selectedItem - 1;
|
||||
if (ndx < 0)
|
||||
ndx = m_eventList->count() - 1;
|
||||
ndx = m_profilerDataModel->count() - 1;
|
||||
int startIndex = ndx;
|
||||
do {
|
||||
if (m_eventList->getEventId(ndx) == eventId)
|
||||
if (m_profilerDataModel->getEventId(ndx) == eventId)
|
||||
return ndx;
|
||||
if (--ndx < 0)
|
||||
ndx = m_eventList->count()-1;
|
||||
ndx = m_profilerDataModel->count()-1;
|
||||
} while (ndx != startIndex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void TimelineView::selectNextFromId(int eventId)
|
||||
void TimelineRenderer::selectNextFromId(int eventId)
|
||||
{
|
||||
int eventIndex = nextItemFromId(eventId);
|
||||
if (eventIndex != -1)
|
||||
setSelectedItem(eventIndex);
|
||||
}
|
||||
|
||||
void TimelineView::selectPrevFromId(int eventId)
|
||||
void TimelineRenderer::selectPrevFromId(int eventId)
|
||||
{
|
||||
int eventIndex = prevItemFromId(eventId);
|
||||
if (eventIndex != -1)
|
@@ -30,29 +30,29 @@
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef TIMELINEVIEW_H
|
||||
#define TIMELINEVIEW_H
|
||||
#ifndef TIMELINERENDERER_H
|
||||
#define TIMELINERENDERER_H
|
||||
|
||||
#include <QDeclarativeItem>
|
||||
#include <QScriptValue>
|
||||
#include <qmljsdebugclient/qmlprofilereventlist.h>
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class TimelineView : public QDeclarativeItem
|
||||
class TimelineRenderer : public QDeclarativeItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(qint64 startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged)
|
||||
Q_PROPERTY(qint64 endTime READ endTime WRITE setEndTime NOTIFY endTimeChanged)
|
||||
Q_PROPERTY(QObject* eventList READ eventList WRITE setEventList NOTIFY eventListChanged)
|
||||
Q_PROPERTY(QObject* profilerDataModel READ profilerDataModel WRITE setProfilerDataModel NOTIFY profilerDataModelChanged)
|
||||
Q_PROPERTY(bool selectionLocked READ selectionLocked WRITE setSelectionLocked NOTIFY selectionLockedChanged)
|
||||
Q_PROPERTY(int selectedItem READ selectedItem WRITE setSelectedItem NOTIFY selectedItemChanged)
|
||||
Q_PROPERTY(int startDragArea READ startDragArea WRITE setStartDragArea NOTIFY startDragAreaChanged)
|
||||
Q_PROPERTY(int endDragArea READ endDragArea WRITE setEndDragArea NOTIFY endDragAreaChanged)
|
||||
|
||||
public:
|
||||
explicit TimelineView(QDeclarativeItem *parent = 0);
|
||||
explicit TimelineRenderer(QDeclarativeItem *parent = 0);
|
||||
|
||||
qint64 startTime() const
|
||||
{
|
||||
@@ -84,11 +84,11 @@ public:
|
||||
return m_endDragArea;
|
||||
}
|
||||
|
||||
QmlJsDebugClient::QmlProfilerEventList *eventList() const { return m_eventList; }
|
||||
void setEventList(QObject *eventList)
|
||||
QmlProfilerDataModel *profilerDataModel() const { return m_profilerDataModel; }
|
||||
void setProfilerDataModel(QObject *profilerDataModel)
|
||||
{
|
||||
m_eventList = qobject_cast<QmlJsDebugClient::QmlProfilerEventList *>(eventList);
|
||||
emit eventListChanged(m_eventList);
|
||||
m_profilerDataModel = qobject_cast<QmlProfilerDataModel *>(profilerDataModel);
|
||||
emit profilerDataModelChanged(m_profilerDataModel);
|
||||
}
|
||||
|
||||
Q_INVOKABLE qint64 getDuration(int index) const;
|
||||
@@ -109,7 +109,7 @@ public:
|
||||
signals:
|
||||
void startTimeChanged(qint64 arg);
|
||||
void endTimeChanged(qint64 arg);
|
||||
void eventListChanged(QmlJsDebugClient::QmlProfilerEventList *list);
|
||||
void profilerDataModelChanged(QmlProfilerDataModel *list);
|
||||
void selectionLockedChanged(bool locked);
|
||||
void selectedItemChanged(int itemIndex);
|
||||
void startDragAreaChanged(int startDragArea);
|
||||
@@ -195,7 +195,7 @@ private:
|
||||
qint64 m_lastStartTime;
|
||||
qint64 m_lastEndTime;
|
||||
|
||||
QmlJsDebugClient::QmlProfilerEventList *m_eventList;
|
||||
QmlProfilerDataModel *m_profilerDataModel;
|
||||
|
||||
QList<int> m_rowLastX;
|
||||
QList<int> m_rowStarts;
|
||||
@@ -218,6 +218,6 @@ private:
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
QML_DECLARE_TYPE(QmlProfiler::Internal::TimelineView)
|
||||
QML_DECLARE_TYPE(QmlProfiler::Internal::TimelineRenderer)
|
||||
|
||||
#endif // TIMELINEVIEW_H
|
||||
#endif // TIMELINERENDERER_H
|
@@ -1,649 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** 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, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "tracewindow.h"
|
||||
|
||||
#include "qmlprofilerplugin.h"
|
||||
|
||||
#include <qmljsdebugclient/qmlprofilereventlist.h>
|
||||
#include <qmljsdebugclient/qmlprofilertraceclient.h>
|
||||
#include <utils/styledbar.h>
|
||||
|
||||
#include <QDeclarativeView>
|
||||
#include <QDeclarativeContext>
|
||||
#include <QVBoxLayout>
|
||||
#include <QGraphicsObject>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QScrollBar>
|
||||
#include <QSlider>
|
||||
#include <QWidget>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
using namespace QmlJsDebugClient;
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
const int sliderTicks = 10000;
|
||||
const qreal sliderExp = 3;
|
||||
|
||||
void ZoomControl::setRange(qint64 startTime, qint64 endTime)
|
||||
{
|
||||
if (m_startTime != startTime || m_endTime != endTime) {
|
||||
m_startTime = startTime;
|
||||
m_endTime = endTime;
|
||||
emit rangeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
ScrollableDeclarativeView::ScrollableDeclarativeView(QWidget *parent)
|
||||
: QDeclarativeView(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ScrollableDeclarativeView::~ScrollableDeclarativeView()
|
||||
{
|
||||
}
|
||||
|
||||
void ScrollableDeclarativeView::scrollContentsBy(int dx, int dy)
|
||||
{
|
||||
// special workaround to track the scrollbar
|
||||
if (rootObject()) {
|
||||
int scrollY = rootObject()->property("scrollY").toInt();
|
||||
rootObject()->setProperty("scrollY", QVariant(scrollY - dy));
|
||||
}
|
||||
QDeclarativeView::scrollContentsBy(dx,dy);
|
||||
}
|
||||
|
||||
TraceWindow::TraceWindow(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setObjectName("QML Profiler");
|
||||
|
||||
m_zoomControl = new ZoomControl(this);
|
||||
connect(m_zoomControl.data(), SIGNAL(rangeChanged()), this, SLOT(updateRange()));
|
||||
|
||||
QVBoxLayout *groupLayout = new QVBoxLayout;
|
||||
groupLayout->setContentsMargins(0, 0, 0, 0);
|
||||
groupLayout->setSpacing(0);
|
||||
|
||||
m_mainView = new ScrollableDeclarativeView(this);
|
||||
m_mainView->setResizeMode(QDeclarativeView::SizeViewToRootObject);
|
||||
m_mainView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
m_mainView->setBackgroundBrush(QBrush(Qt::white));
|
||||
m_mainView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||
m_mainView->setFocus();
|
||||
|
||||
MouseWheelResizer *resizer = new MouseWheelResizer(this);
|
||||
connect(resizer,SIGNAL(mouseWheelMoved(int,int,int)), this, SLOT(mouseWheelMoved(int,int,int)));
|
||||
m_mainView->viewport()->installEventFilter(resizer);
|
||||
|
||||
QHBoxLayout *toolsLayout = new QHBoxLayout;
|
||||
|
||||
m_timebar = new QDeclarativeView(this);
|
||||
m_timebar->setResizeMode(QDeclarativeView::SizeRootObjectToView);
|
||||
m_timebar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
m_timebar->setFixedHeight(24);
|
||||
|
||||
m_overview = new QDeclarativeView(this);
|
||||
m_overview->setResizeMode(QDeclarativeView::SizeRootObjectToView);
|
||||
m_overview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
m_overview->setMaximumHeight(50);
|
||||
|
||||
m_zoomToolbar = createZoomToolbar();
|
||||
m_zoomToolbar->move(0, m_timebar->height());
|
||||
m_zoomToolbar->setVisible(false);
|
||||
|
||||
toolsLayout->addWidget(createToolbar());
|
||||
toolsLayout->addWidget(m_timebar);
|
||||
|
||||
groupLayout->addLayout(toolsLayout);
|
||||
groupLayout->addWidget(m_mainView);
|
||||
groupLayout->addWidget(m_overview);
|
||||
|
||||
setLayout(groupLayout);
|
||||
|
||||
m_eventList = new QmlProfilerEventList(this);
|
||||
connect(this,SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)), m_eventList, SLOT(addRangedEvent(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)));
|
||||
connect(this, SIGNAL(traceFinished(qint64)), m_eventList, SLOT(setTraceEndTime(qint64)));
|
||||
connect(this, SIGNAL(traceStarted(qint64)), m_eventList, SLOT(setTraceStartTime(qint64)));
|
||||
connect(this, SIGNAL(frameEvent(qint64,int,int)), m_eventList, SLOT(addFrameEvent(qint64,int,int)));
|
||||
connect(m_eventList, SIGNAL(stateChanged()), this, SLOT(eventListStateChanged()));
|
||||
m_mainView->rootContext()->setContextProperty("qmlEventList", m_eventList);
|
||||
m_overview->rootContext()->setContextProperty("qmlEventList", m_eventList);
|
||||
|
||||
m_rewriter = new QmlProfilerDetailsRewriter(this);
|
||||
connect(m_eventList, SIGNAL(requestDetailsForLocation(int,QmlJsDebugClient::QmlEventLocation)), m_rewriter, SLOT(requestDetailsForLocation(int,QmlJsDebugClient::QmlEventLocation)));
|
||||
connect(m_rewriter, SIGNAL(rewriteDetailsString(int,QmlJsDebugClient::QmlEventLocation,QString)), m_eventList, SLOT(rewriteDetailsString(int,QmlJsDebugClient::QmlEventLocation,QString)));
|
||||
connect(m_rewriter, SIGNAL(eventDetailsChanged()), m_eventList, SLOT(finishedRewritingDetails()));
|
||||
connect(m_eventList, SIGNAL(reloadDocumentsForDetails()), m_rewriter, SLOT(reloadDocuments()));
|
||||
|
||||
connect(this, SIGNAL(v8range(int,QString,QString,int,double,double)), m_eventList, SLOT(addV8Event(int,QString,QString,int,double,double)));
|
||||
|
||||
// Minimum height: 5 rows of 20 pixels + scrollbar of 50 pixels + 20 pixels margin
|
||||
setMinimumHeight(170);
|
||||
m_currentZoomLevel = 0;
|
||||
m_profiledTime = 0;
|
||||
}
|
||||
|
||||
TraceWindow::~TraceWindow()
|
||||
{
|
||||
disconnectClientSignals();
|
||||
delete m_plugin.data();
|
||||
delete m_v8plugin.data();
|
||||
}
|
||||
|
||||
QWidget *TraceWindow::createToolbar()
|
||||
{
|
||||
Utils::StyledBar *bar = new Utils::StyledBar(this);
|
||||
bar->setSingleRow(true);
|
||||
bar->setFixedWidth(150);
|
||||
bar->setFixedHeight(24);
|
||||
|
||||
QHBoxLayout *toolBarLayout = new QHBoxLayout(bar);
|
||||
toolBarLayout->setMargin(0);
|
||||
toolBarLayout->setSpacing(0);
|
||||
|
||||
QToolButton *buttonPrev= new QToolButton;
|
||||
buttonPrev->setIcon(QIcon(":/qmlprofiler/ico_prev.png"));
|
||||
buttonPrev->setToolTip(tr("Jump to previous event"));
|
||||
connect(buttonPrev, SIGNAL(clicked()), this, SIGNAL(jumpToPrev()));
|
||||
connect(this, SIGNAL(enableToolbar(bool)), buttonPrev, SLOT(setEnabled(bool)));
|
||||
|
||||
QToolButton *buttonNext= new QToolButton;
|
||||
buttonNext->setIcon(QIcon(":/qmlprofiler/ico_next.png"));
|
||||
buttonNext->setToolTip(tr("Jump to next event"));
|
||||
connect(buttonNext, SIGNAL(clicked()), this, SIGNAL(jumpToNext()));
|
||||
connect(this, SIGNAL(enableToolbar(bool)), buttonNext, SLOT(setEnabled(bool)));
|
||||
|
||||
QToolButton *buttonZoomControls = new QToolButton;
|
||||
buttonZoomControls->setIcon(QIcon(":/qmlprofiler/ico_zoom.png"));
|
||||
buttonZoomControls->setToolTip(tr("Show zoom slider"));
|
||||
buttonZoomControls->setCheckable(true);
|
||||
buttonZoomControls->setChecked(false);
|
||||
connect(buttonZoomControls, SIGNAL(toggled(bool)), m_zoomToolbar, SLOT(setVisible(bool)));
|
||||
connect(this, SIGNAL(enableToolbar(bool)), buttonZoomControls, SLOT(setEnabled(bool)));
|
||||
|
||||
m_buttonRange = new QToolButton;
|
||||
m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselection.png"));
|
||||
m_buttonRange->setToolTip(tr("Select range"));
|
||||
m_buttonRange->setCheckable(true);
|
||||
m_buttonRange->setChecked(false);
|
||||
connect(m_buttonRange, SIGNAL(clicked(bool)), this, SLOT(toggleRangeMode(bool)));
|
||||
connect(this, SIGNAL(enableToolbar(bool)), m_buttonRange, SLOT(setEnabled(bool)));
|
||||
connect(this, SIGNAL(rangeModeChanged(bool)), m_buttonRange, SLOT(setChecked(bool)));
|
||||
|
||||
m_buttonLock = new QToolButton;
|
||||
m_buttonLock->setIcon(QIcon(":/qmlprofiler/ico_selectionmode.png"));
|
||||
m_buttonLock->setToolTip(tr("View event information on mouseover"));
|
||||
m_buttonLock->setCheckable(true);
|
||||
m_buttonLock->setChecked(false);
|
||||
connect(m_buttonLock, SIGNAL(clicked(bool)), this, SLOT(toggleLockMode(bool)));
|
||||
connect(this, SIGNAL(enableToolbar(bool)), m_buttonLock, SLOT(setEnabled(bool)));
|
||||
connect(this, SIGNAL(lockModeChanged(bool)), m_buttonLock, SLOT(setChecked(bool)));
|
||||
|
||||
toolBarLayout->addWidget(buttonPrev);
|
||||
toolBarLayout->addWidget(buttonNext);
|
||||
toolBarLayout->addWidget(new Utils::StyledSeparator());
|
||||
toolBarLayout->addWidget(buttonZoomControls);
|
||||
toolBarLayout->addWidget(new Utils::StyledSeparator());
|
||||
toolBarLayout->addWidget(m_buttonRange);
|
||||
toolBarLayout->addWidget(m_buttonLock);
|
||||
|
||||
return bar;
|
||||
}
|
||||
|
||||
|
||||
QWidget *TraceWindow::createZoomToolbar()
|
||||
{
|
||||
Utils::StyledBar *bar = new Utils::StyledBar(this);
|
||||
bar->setSingleRow(true);
|
||||
bar->setFixedWidth(150);
|
||||
bar->setFixedHeight(24);
|
||||
|
||||
QHBoxLayout *toolBarLayout = new QHBoxLayout(bar);
|
||||
toolBarLayout->setMargin(0);
|
||||
toolBarLayout->setSpacing(0);
|
||||
|
||||
QSlider *zoomSlider = new QSlider(Qt::Horizontal);
|
||||
zoomSlider->setFocusPolicy(Qt::NoFocus);
|
||||
zoomSlider->setRange(1, sliderTicks);
|
||||
zoomSlider->setInvertedAppearance(true);
|
||||
zoomSlider->setPageStep(sliderTicks/100);
|
||||
connect(this, SIGNAL(enableToolbar(bool)), zoomSlider, SLOT(setEnabled(bool)));
|
||||
connect(zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(setZoomLevel(int)));
|
||||
connect(this, SIGNAL(zoomLevelChanged(int)), zoomSlider, SLOT(setValue(int)));
|
||||
zoomSlider->setStyleSheet("\
|
||||
QSlider:horizontal {\
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #444444, stop: 1 #5a5a5a);\
|
||||
border: 1px #313131;\
|
||||
height: 20px;\
|
||||
margin: 0px 0px 0px 0px;\
|
||||
}\
|
||||
QSlider::add-page:horizontal {\
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #5a5a5a, stop: 1 #444444);\
|
||||
border: 1px #313131;\
|
||||
}\
|
||||
QSlider::sub-page:horizontal {\
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #5a5a5a, stop: 1 #444444);\
|
||||
border: 1px #313131;\
|
||||
}\
|
||||
");
|
||||
|
||||
toolBarLayout->addWidget(zoomSlider);
|
||||
|
||||
return bar;
|
||||
}
|
||||
|
||||
void TraceWindow::reset(QDeclarativeDebugConnection *conn)
|
||||
{
|
||||
disconnectClientSignals();
|
||||
|
||||
delete m_plugin.data();
|
||||
m_plugin = new QmlProfilerTraceClient(conn);
|
||||
delete m_v8plugin.data();
|
||||
m_v8plugin = new QV8ProfilerClient(conn);
|
||||
|
||||
connectClientSignals();
|
||||
|
||||
m_mainView->rootContext()->setContextProperty("connection", m_plugin.data());
|
||||
m_mainView->rootContext()->setContextProperty("zoomControl", m_zoomControl.data());
|
||||
m_timebar->rootContext()->setContextProperty("zoomControl", m_zoomControl.data());
|
||||
m_overview->rootContext()->setContextProperty("zoomControl", m_zoomControl.data());
|
||||
|
||||
m_timebar->setSource(QUrl("qrc:/qmlprofiler/TimeDisplay.qml"));
|
||||
m_overview->setSource(QUrl("qrc:/qmlprofiler/Overview.qml"));
|
||||
|
||||
m_mainView->setSource(QUrl("qrc:/qmlprofiler/MainView.qml"));
|
||||
m_mainView->rootObject()->setProperty("width", QVariant(width()));
|
||||
m_mainView->rootObject()->setProperty("candidateHeight", QVariant(height() - m_timebar->height() - m_overview->height()));
|
||||
|
||||
updateToolbar();
|
||||
|
||||
connect(m_mainView->rootObject(), SIGNAL(updateCursorPosition()), this, SLOT(updateCursorPosition()));
|
||||
connect(m_mainView->rootObject(), SIGNAL(updateTimer()), this, SLOT(updateTimer()));
|
||||
connect(m_mainView->rootObject(), SIGNAL(updateRangeButton()), this, SLOT(updateRangeButton()));
|
||||
connect(m_mainView->rootObject(), SIGNAL(updateLockButton()), this, SLOT(updateLockButton()));
|
||||
connect(m_eventList, SIGNAL(countChanged()), this, SLOT(updateToolbar()));
|
||||
connect(this, SIGNAL(jumpToPrev()), m_mainView->rootObject(), SLOT(prevEvent()));
|
||||
connect(this, SIGNAL(jumpToNext()), m_mainView->rootObject(), SLOT(nextEvent()));
|
||||
connect(this, SIGNAL(updateViewZoom(QVariant)), m_mainView->rootObject(), SLOT(updateWindowLength(QVariant)));
|
||||
connect(this, SIGNAL(wheelZoom(QVariant,QVariant)), m_mainView->rootObject(), SLOT(wheelZoom(QVariant,QVariant)));
|
||||
connect(this, SIGNAL(globalZoom()), m_mainView->rootObject(), SLOT(globalZoom()));
|
||||
connect(this, SIGNAL(selectNextEventInDisplay(QVariant)), m_mainView->rootObject(), SLOT(selectNextWithId(QVariant)));
|
||||
connect(m_mainView->rootObject(), SIGNAL(selectedEventIdChanged(int)), this, SIGNAL(selectedEventIdChanged(int)));
|
||||
connect(m_mainView->rootObject(), SIGNAL(changeToolTip(QString)), this, SLOT(updateToolTip(QString)));
|
||||
connect(m_mainView->rootObject(), SIGNAL(updateVerticalScroll(int)), this, SLOT(updateVerticalScroll(int)));
|
||||
|
||||
connect(this, SIGNAL(internalClearDisplay()), m_mainView->rootObject(), SLOT(clearAll()));
|
||||
connect(this,SIGNAL(internalClearDisplay()), m_overview->rootObject(), SLOT(clearDisplay()));
|
||||
|
||||
m_v8DataReady = false;
|
||||
m_qmlDataReady = false;
|
||||
}
|
||||
|
||||
void TraceWindow::connectClientSignals()
|
||||
{
|
||||
if (m_plugin) {
|
||||
connect(m_plugin.data(), SIGNAL(complete()), this, SLOT(qmlComplete()));
|
||||
connect(m_plugin.data(), SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)),
|
||||
this, SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)));
|
||||
connect(m_plugin.data(), SIGNAL(traceFinished(qint64)), this, SIGNAL(traceFinished(qint64)));
|
||||
connect(m_plugin.data(), SIGNAL(traceStarted(qint64)), this, SLOT(manageTraceStart(qint64)));
|
||||
connect(m_plugin.data(), SIGNAL(frame(qint64,int,int)), this, SIGNAL(frameEvent(qint64,int,int)));
|
||||
connect(m_plugin.data(), SIGNAL(enabledChanged()), this, SLOT(updateProfilerState()));
|
||||
connect(m_plugin.data(), SIGNAL(enabledChanged()), m_plugin.data(), SLOT(sendRecordingStatus()));
|
||||
connect(m_plugin.data(), SIGNAL(recordingChanged(bool)), this, SIGNAL(recordingChanged(bool)));
|
||||
}
|
||||
if (m_v8plugin) {
|
||||
connect(m_v8plugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
|
||||
connect(m_v8plugin.data(), SIGNAL(v8range(int,QString,QString,int,double,double)), this, SIGNAL(v8range(int,QString,QString,int,double,double)));
|
||||
connect(m_v8plugin.data(), SIGNAL(enabledChanged()), this, SLOT(updateProfilerState()));
|
||||
connect(m_v8plugin.data(), SIGNAL(enabledChanged()), m_v8plugin.data(), SLOT(sendRecordingStatus()));
|
||||
}
|
||||
}
|
||||
|
||||
void TraceWindow::disconnectClientSignals()
|
||||
{
|
||||
if (m_plugin) {
|
||||
disconnect(m_plugin.data(), SIGNAL(complete()), this, SLOT(qmlComplete()));
|
||||
disconnect(m_plugin.data(), SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)),
|
||||
this, SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)));
|
||||
disconnect(m_plugin.data(), SIGNAL(traceFinished(qint64)), this, SIGNAL(traceFinished(qint64)));
|
||||
disconnect(m_plugin.data(), SIGNAL(traceStarted(qint64)), this, SLOT(manageTraceStart(qint64)));
|
||||
disconnect(m_plugin.data(), SIGNAL(enabledChanged()), this, SLOT(updateProfilerState()));
|
||||
disconnect(m_plugin.data(), SIGNAL(enabledChanged()), m_plugin.data(), SLOT(sendRecordingStatus()));
|
||||
disconnect(m_plugin.data(), SIGNAL(recordingChanged(bool)), this, SIGNAL(recordingChanged(bool)));
|
||||
}
|
||||
if (m_v8plugin) {
|
||||
disconnect(m_v8plugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
|
||||
disconnect(m_v8plugin.data(), SIGNAL(v8range(int,QString,QString,int,double,double)), this, SIGNAL(v8range(int,QString,QString,int,double,double)));
|
||||
disconnect(m_v8plugin.data(), SIGNAL(enabledChanged()), this, SLOT(updateProfilerState()));
|
||||
disconnect(m_v8plugin.data(), SIGNAL(enabledChanged()), m_v8plugin.data(), SLOT(sendRecordingStatus()));
|
||||
}
|
||||
}
|
||||
|
||||
QmlProfilerEventList *TraceWindow::getEventList() const
|
||||
{
|
||||
return m_eventList;
|
||||
}
|
||||
|
||||
ZoomControl *TraceWindow::rangeTimes() const
|
||||
{
|
||||
return m_zoomControl.data();
|
||||
}
|
||||
|
||||
void TraceWindow::contextMenuEvent(QContextMenuEvent *ev)
|
||||
{
|
||||
emit contextMenuRequested(ev->globalPos());
|
||||
}
|
||||
|
||||
void TraceWindow::updateCursorPosition()
|
||||
{
|
||||
emit gotoSourceLocation(m_mainView->rootObject()->property("fileName").toString(),
|
||||
m_mainView->rootObject()->property("lineNumber").toInt(),
|
||||
m_mainView->rootObject()->property("columnNumber").toInt());
|
||||
}
|
||||
|
||||
void TraceWindow::updateTimer()
|
||||
{
|
||||
m_profiledTime = m_mainView->rootObject()->property("elapsedTime").toDouble();
|
||||
}
|
||||
|
||||
void TraceWindow::correctTimer()
|
||||
{
|
||||
// once the data is post-processed, use the eventlist time instead of the qml timer
|
||||
m_profiledTime = (m_eventList->traceEndTime() - m_eventList->traceStartTime()) / 1.0e9;
|
||||
if (m_profiledTime < 0)
|
||||
m_profiledTime = 0;
|
||||
emit viewUpdated();
|
||||
}
|
||||
|
||||
double TraceWindow::profiledTime() const
|
||||
{
|
||||
return m_profiledTime;
|
||||
}
|
||||
|
||||
void TraceWindow::clearDisplay()
|
||||
{
|
||||
m_eventList->clear();
|
||||
|
||||
if (m_plugin)
|
||||
m_plugin.data()->clearData();
|
||||
if (m_v8plugin)
|
||||
m_v8plugin.data()->clearData();
|
||||
|
||||
m_zoomControl.data()->setRange(0,0);
|
||||
m_profiledTime = 0;
|
||||
|
||||
updateVerticalScroll(0);
|
||||
m_mainView->rootObject()->setProperty("scrollY", QVariant(0));
|
||||
|
||||
emit internalClearDisplay();
|
||||
}
|
||||
|
||||
void TraceWindow::updateToolbar()
|
||||
{
|
||||
emit enableToolbar(m_eventList && m_eventList->count()>0);
|
||||
}
|
||||
|
||||
void TraceWindow::toggleRangeMode(bool active)
|
||||
{
|
||||
bool rangeMode = m_mainView->rootObject()->property("selectionRangeMode").toBool();
|
||||
if (active != rangeMode) {
|
||||
if (active)
|
||||
m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselected.png"));
|
||||
else
|
||||
m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselection.png"));
|
||||
m_mainView->rootObject()->setProperty("selectionRangeMode", QVariant(active));
|
||||
}
|
||||
}
|
||||
|
||||
void TraceWindow::updateRangeButton()
|
||||
{
|
||||
bool rangeMode = m_mainView->rootObject()->property("selectionRangeMode").toBool();
|
||||
if (rangeMode)
|
||||
m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselected.png"));
|
||||
else
|
||||
m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselection.png"));
|
||||
emit rangeModeChanged(rangeMode);
|
||||
}
|
||||
|
||||
void TraceWindow::toggleLockMode(bool active)
|
||||
{
|
||||
bool lockMode = !m_mainView->rootObject()->property("selectionLocked").toBool();
|
||||
if (active != lockMode) {
|
||||
m_mainView->rootObject()->setProperty("selectionLocked", QVariant(!active));
|
||||
m_mainView->rootObject()->setProperty("selectedItem", QVariant(-1));
|
||||
}
|
||||
}
|
||||
|
||||
void TraceWindow::updateLockButton()
|
||||
{
|
||||
bool lockMode = !m_mainView->rootObject()->property("selectionLocked").toBool();
|
||||
emit lockModeChanged(lockMode);
|
||||
}
|
||||
|
||||
void TraceWindow::setRecording(bool recording)
|
||||
{
|
||||
if (recording) {
|
||||
m_v8DataReady = false;
|
||||
m_qmlDataReady = false;
|
||||
}
|
||||
if (m_plugin)
|
||||
m_plugin.data()->setRecording(recording);
|
||||
if (m_v8plugin)
|
||||
m_v8plugin.data()->setRecording(recording);
|
||||
}
|
||||
|
||||
bool TraceWindow::isRecording() const
|
||||
{
|
||||
return m_plugin.data()->isRecording();
|
||||
}
|
||||
|
||||
void TraceWindow::qmlComplete()
|
||||
{
|
||||
m_qmlDataReady = true;
|
||||
if (!m_v8plugin || m_v8plugin.data()->status() != QDeclarativeDebugClient::Enabled || m_v8DataReady) {
|
||||
m_eventList->complete();
|
||||
// once complete is sent, reset the flags
|
||||
m_qmlDataReady = false;
|
||||
m_v8DataReady = false;
|
||||
}
|
||||
}
|
||||
|
||||
void TraceWindow::v8Complete()
|
||||
{
|
||||
m_v8DataReady = true;
|
||||
if (!m_plugin || m_plugin.data()->status() != QDeclarativeDebugClient::Enabled || m_qmlDataReady) {
|
||||
m_eventList->complete();
|
||||
// once complete is sent, reset the flags
|
||||
m_v8DataReady = false;
|
||||
m_qmlDataReady = false;
|
||||
}
|
||||
}
|
||||
|
||||
void TraceWindow::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
if (m_mainView->rootObject()) {
|
||||
m_mainView->rootObject()->setProperty("width", QVariant(event->size().width()));
|
||||
int newHeight = event->size().height() - m_timebar->height() - m_overview->height();
|
||||
m_mainView->rootObject()->setProperty("candidateHeight", QVariant(newHeight));
|
||||
}
|
||||
}
|
||||
|
||||
bool MouseWheelResizer::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::Wheel) {
|
||||
QWheelEvent *ev = static_cast<QWheelEvent *>(event);
|
||||
if (ev->modifiers() & Qt::ControlModifier) {
|
||||
emit mouseWheelMoved(ev->pos().x(), ev->pos().y(), ev->delta());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void TraceWindow::mouseWheelMoved(int x, int y, int delta)
|
||||
{
|
||||
Q_UNUSED(y);
|
||||
if (m_mainView->rootObject()) {
|
||||
emit wheelZoom(QVariant(x), QVariant(delta));
|
||||
}
|
||||
}
|
||||
|
||||
void TraceWindow::viewAll()
|
||||
{
|
||||
emit globalZoom();
|
||||
}
|
||||
|
||||
bool TraceWindow::hasValidSelection() const
|
||||
{
|
||||
if (m_mainView->rootObject()) {
|
||||
return m_mainView->rootObject()->property("selectionRangeReady").toBool();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 TraceWindow::selectionStart() const
|
||||
{
|
||||
if (m_mainView->rootObject()) {
|
||||
return m_mainView->rootObject()->property("selectionRangeStart").toLongLong();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
qint64 TraceWindow::selectionEnd() const
|
||||
{
|
||||
if (m_mainView->rootObject()) {
|
||||
return m_mainView->rootObject()->property("selectionRangeEnd").toLongLong();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TraceWindow::setZoomLevel(int zoomLevel)
|
||||
{
|
||||
if (m_currentZoomLevel != zoomLevel && m_mainView->rootObject()) {
|
||||
qreal newFactor = pow(qreal(zoomLevel) / qreal(sliderTicks), sliderExp);
|
||||
m_currentZoomLevel = zoomLevel;
|
||||
emit updateViewZoom(QVariant(newFactor));
|
||||
}
|
||||
}
|
||||
|
||||
void TraceWindow::updateRange()
|
||||
{
|
||||
if (!m_eventList)
|
||||
return;
|
||||
qreal duration = m_zoomControl.data()->endTime() - m_zoomControl.data()->startTime();
|
||||
if (duration <= 0)
|
||||
return;
|
||||
if (m_eventList->traceDuration() <= 0)
|
||||
return;
|
||||
int newLevel = pow(duration / m_eventList->traceDuration(), 1/sliderExp) * sliderTicks;
|
||||
if (m_currentZoomLevel != newLevel) {
|
||||
m_currentZoomLevel = newLevel;
|
||||
emit zoomLevelChanged(newLevel);
|
||||
}
|
||||
}
|
||||
|
||||
void TraceWindow::selectNextEvent(int eventId)
|
||||
{
|
||||
emit selectNextEventInDisplay(QVariant(eventId));
|
||||
}
|
||||
|
||||
void TraceWindow::updateProfilerState()
|
||||
{
|
||||
bool qmlActive = false;
|
||||
bool v8Active = false;
|
||||
if (m_plugin)
|
||||
qmlActive = m_plugin.data()->isEnabled();
|
||||
if (m_v8plugin)
|
||||
v8Active = m_v8plugin.data()->isEnabled();
|
||||
|
||||
emit profilerStateChanged(qmlActive, v8Active);
|
||||
}
|
||||
|
||||
void TraceWindow::updateToolTip(const QString &text)
|
||||
{
|
||||
setToolTip(text);
|
||||
}
|
||||
|
||||
void TraceWindow::updateVerticalScroll(int newPosition)
|
||||
{
|
||||
m_mainView->verticalScrollBar()->setValue(newPosition);
|
||||
}
|
||||
|
||||
void TraceWindow::eventListStateChanged()
|
||||
{
|
||||
switch (m_eventList->currentState()) {
|
||||
case QmlProfilerEventList::Empty :
|
||||
clearDisplay();
|
||||
break;
|
||||
case QmlProfilerEventList::AcquiringData :
|
||||
firstDataReceived();
|
||||
break;
|
||||
case QmlProfilerEventList::ProcessingData :
|
||||
// nothing to be done
|
||||
break;
|
||||
case QmlProfilerEventList::Done :
|
||||
correctTimer();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TraceWindow::manageTraceStart(qint64 traceStart)
|
||||
{
|
||||
// new trace started
|
||||
emit clearViewsFromTool();
|
||||
|
||||
emit traceStarted(traceStart);
|
||||
}
|
||||
|
||||
void TraceWindow::firstDataReceived()
|
||||
{
|
||||
if (m_plugin && m_plugin.data()->isRecording()) {
|
||||
// serverside recording disabled
|
||||
m_plugin.data()->setRecordingFromServer(false);
|
||||
}
|
||||
}
|
||||
|
||||
void TraceWindow::applicationDied()
|
||||
{
|
||||
if (m_mainView->rootObject())
|
||||
m_mainView->rootObject()->setProperty("applicationDied",QVariant(true));
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
@@ -1,57 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** 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, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "commandlistener.h"
|
||||
#include "constants.h"
|
||||
#include <QTextStream>
|
||||
|
||||
CommandListener::CommandListener(QObject *parent)
|
||||
: QThread(parent)
|
||||
, m_stopRequested(false)
|
||||
{
|
||||
}
|
||||
|
||||
void CommandListener::run()
|
||||
{
|
||||
QString line;
|
||||
QTextStream in(stdin, QIODevice::ReadOnly);
|
||||
do {
|
||||
line = in.readLine();
|
||||
line = line.trimmed();
|
||||
if (!line.isEmpty()) {
|
||||
emit command(line);
|
||||
if (line == QLatin1String(Constants::CMD_QUIT)
|
||||
|| line == QLatin1String(Constants::CMD_QUIT2))
|
||||
return;
|
||||
}
|
||||
} while (!m_stopRequested && !line.isNull());
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** 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, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef CONSTANTS_H
|
||||
#define CONSTANTS_H
|
||||
|
||||
namespace Constants {
|
||||
|
||||
const char CMD_HELP[] ="help";
|
||||
const char CMD_HELP2[] = "h";
|
||||
const char CMD_HELP3[] = "?";
|
||||
|
||||
const char CMD_RECORD[] ="record";
|
||||
const char CMD_RECORD2[] ="r";
|
||||
|
||||
const char CMD_QUIT[] ="quit";
|
||||
const char CMD_QUIT2[] = "q";
|
||||
|
||||
} // Contants
|
||||
|
||||
#endif // CONSTANTS_H
|
@@ -1,113 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** 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, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLPROFILERAPPLICATION_H
|
||||
#define QMLPROFILERAPPLICATION_H
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
|
||||
#include <qdeclarativedebugclient.h>
|
||||
#include <qmlprofilertraceclient.h>
|
||||
#include <qmlprofilereventlist.h>
|
||||
#include <qv8profilerclient.h>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QProcess)
|
||||
|
||||
class QmlProfilerApplication : public QCoreApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QmlProfilerApplication(int &argc, char **argv);
|
||||
~QmlProfilerApplication();
|
||||
|
||||
bool parseArguments();
|
||||
void printUsage();
|
||||
int exec();
|
||||
|
||||
public slots:
|
||||
void userCommand(const QString &command);
|
||||
|
||||
private slots:
|
||||
void run();
|
||||
void tryToConnect();
|
||||
void connected();
|
||||
void connectionStateChanged(QAbstractSocket::SocketState state);
|
||||
void connectionError(QAbstractSocket::SocketError error);
|
||||
void processHasOutput();
|
||||
void processFinished();
|
||||
|
||||
void traceClientEnabled();
|
||||
void profilerClientEnabled();
|
||||
void traceFinished();
|
||||
void recordingChanged();
|
||||
|
||||
void print(const QString &line);
|
||||
void logError(const QString &error);
|
||||
void logStatus(const QString &status);
|
||||
|
||||
void qmlComplete();
|
||||
void v8Complete();
|
||||
|
||||
private:
|
||||
void printCommands();
|
||||
QString traceFileName() const;
|
||||
|
||||
enum ApplicationMode {
|
||||
LaunchMode,
|
||||
AttachMode
|
||||
} m_runMode;
|
||||
|
||||
// LaunchMode
|
||||
QString m_programPath;
|
||||
QStringList m_programArguments;
|
||||
QProcess *m_process;
|
||||
QString m_tracePrefix;
|
||||
|
||||
QString m_hostName;
|
||||
quint16 m_port;
|
||||
bool m_verbose;
|
||||
bool m_quitAfterSave;
|
||||
|
||||
QmlJsDebugClient::QDeclarativeDebugConnection m_connection;
|
||||
QmlJsDebugClient::QmlProfilerTraceClient m_qmlProfilerClient;
|
||||
QmlJsDebugClient::QV8ProfilerClient m_v8profilerClient;
|
||||
QmlJsDebugClient::QmlProfilerEventList m_eventList;
|
||||
QTimer m_connectTimer;
|
||||
uint m_connectionAttempts;
|
||||
|
||||
bool m_qmlDataReady;
|
||||
bool m_v8DataReady;
|
||||
};
|
||||
|
||||
#endif // QMLPROFILERAPPLICATION_H
|
@@ -1,28 +0,0 @@
|
||||
QT = core
|
||||
include(../../../qtcreator.pri)
|
||||
include(../../rpath.pri)
|
||||
|
||||
TEMPLATE = app
|
||||
TARGET = qmlprofiler
|
||||
DESTDIR = $$IDE_BIN_PATH
|
||||
|
||||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
|
||||
include(../../shared/symbianutils/symbianutils.pri)
|
||||
include(../../libs/qmljsdebugclient/qmljsdebugclient-lib.pri)
|
||||
|
||||
INCLUDEPATH += ../../libs/qmljsdebugclient
|
||||
|
||||
SOURCES += main.cpp \
|
||||
qmlprofilerapplication.cpp \
|
||||
commandlistener.cpp
|
||||
|
||||
HEADERS += \
|
||||
qmlprofilerapplication.h \
|
||||
commandlistener.h \
|
||||
constants.h
|
||||
|
||||
target.path=/bin
|
||||
INSTALLS+=target
|
||||
|
@@ -1,7 +1,6 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS = qtpromaker \
|
||||
qmlprofilertool \
|
||||
qmlpuppet
|
||||
|
||||
win32 {
|
||||
|
Reference in New Issue
Block a user