QmlProfiler: Centralize trace/window/range times

Avoid keeping multiple, potentially diverging copies of the same time
information and make sure all the times are consistent with each other.

Stating the times as properties allows us to use bindings in more
places, too.

Change-Id: I9cdd4f561ac22ad795939594ba340b1fbc070e9a
Reviewed-by: Kai Koehne <kai.koehne@theqtcompany.com>
This commit is contained in:
Ulf Hermann
2014-10-14 16:44:45 +02:00
committed by Ulf Hermann
parent ec118e04a3
commit 70102410df
25 changed files with 457 additions and 428 deletions

View File

@@ -138,24 +138,6 @@ int AbstractTimelineModel::height() const
return d->rowOffsets.last() + (depth - d->rowOffsets.size()) * DefaultRowHeight;
}
qint64 AbstractTimelineModel::traceStartTime() const
{
Q_D(const AbstractTimelineModel);
return d->modelManager->traceTime()->startTime();
}
qint64 AbstractTimelineModel::traceEndTime() const
{
Q_D(const AbstractTimelineModel);
return d->modelManager->traceTime()->endTime();
}
qint64 AbstractTimelineModel::traceDuration() const
{
Q_D(const AbstractTimelineModel);
return d->modelManager->traceTime()->duration();
}
QVariantMap AbstractTimelineModel::location(int index) const
{
Q_UNUSED(index);

View File

@@ -64,9 +64,6 @@ public:
void setRowHeight(int rowNumber, int height);
int height() const;
qint64 traceStartTime() const;
qint64 traceEndTime() const;
qint64 traceDuration() const;
bool accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const;
bool expanded() const;
bool hidden() const;

View File

@@ -40,7 +40,7 @@ Rectangle {
property alias selectionLocked : view.selectionLocked
property bool lockItemSelection : false
property real mainviewTimePerPixel : 0
property real mainviewTimePerPixel: zoomControl.rangeDuration / root.width
signal updateCursorPosition
property string fileName: ""
@@ -60,14 +60,8 @@ Rectangle {
Connections {
target: zoomControl
onRangeChanged: {
var startTime = zoomControl.startTime();
var endTime = zoomControl.endTime();
mainviewTimePerPixel = Math.abs(endTime - startTime) / root.width;
backgroundMarks.updateMarks(startTime, endTime);
view.startTime = startTime;
view.endTime = endTime;
backgroundMarks.updateMarks(zoomControl.rangeStart, zoomControl.rangeEnd);
zoomSliderToolBar.updateZoomLevel();
view.updateWindow();
}
onWindowChanged: {
@@ -80,9 +74,8 @@ Rectangle {
target: qmlProfilerModelProxy
onDataAvailable: {
view.clearData();
zoomControl.setRange(qmlProfilerModelProxy.traceStartTime(),
qmlProfilerModelProxy.traceStartTime() +
qmlProfilerModelProxy.traceDuration()/10);
zoomControl.setRange(zoomControl.traceStart,
zoomControl.traceStart + zoomControl.traceDuration / 10);
view.requestPaint();
}
onStateChanged: backgroundMarks.requestPaint()
@@ -106,11 +99,9 @@ Rectangle {
flick.contentX = 0;
flick.contentWidth = 0;
view.clearData();
view.startTime = view.endTime = 0;
rangeDetails.hide();
selectionRangeMode = false;
buttonsBar.updateRangeButton(selectionRangeMode);
zoomControl.setRange(0,0);
zoomSlider.externalUpdate = true;
zoomSlider.value = zoomSlider.minimumValue;
overview.clear();
@@ -122,13 +113,9 @@ Rectangle {
}
function recenter( centerPoint ) {
var windowLength = view.endTime - view.startTime;
var newStart = Math.floor(centerPoint - windowLength/2);
if (newStart < 0)
newStart = 0;
if (newStart + windowLength > qmlProfilerModelProxy.traceEndTime())
newStart = qmlProfilerModelProxy.traceEndTime() - windowLength;
zoomControl.setRange(newStart, newStart + windowLength);
var newStart = Math.floor(centerPoint - zoomControl.rangeDuration / 2);
zoomControl.setRange(Math.max(newStart, zoomControl.traceStart),
Math.min(newStart + zoomControl.rangeDuration, zoomControl.traceEnd));
}
function recenterOnItem(modelIndex, itemIndex)
@@ -137,8 +124,8 @@ Rectangle {
return;
// if item is outside of the view, jump back to its position
if (qmlProfilerModelProxy.endTime(modelIndex, itemIndex) < view.startTime ||
qmlProfilerModelProxy.startTime(modelIndex, itemIndex) > view.endTime) {
if (qmlProfilerModelProxy.endTime(modelIndex, itemIndex) < zoomControl.rangeStart ||
qmlProfilerModelProxy.startTime(modelIndex, itemIndex) > zoomControl.rangeEnd) {
recenter((qmlProfilerModelProxy.startTime(modelIndex, itemIndex) +
qmlProfilerModelProxy.endTime(modelIndex, itemIndex)) / 2);
}
@@ -278,7 +265,7 @@ Rectangle {
Flickable {
id: flick
contentHeight: labels.height
contentWidth: 0
contentWidth: zoomControl.windowDuration * width / Math.max(1, zoomControl.rangeDuration)
flickableDirection: Flickable.HorizontalAndVerticalFlick
boundsBehavior: Flickable.StopAtBounds
clip:true
@@ -290,12 +277,6 @@ Rectangle {
onInteractiveChanged: interactive = stayInteractive
onStayInteractiveChanged: interactive = stayInteractive
onWidthChanged: {
var duration = Math.abs(zoomControl.endTime() - zoomControl.startTime());
if (duration > 0)
contentWidth = zoomControl.windowLength() * width / duration;
}
// ***** child items
TimeMarks {
id: backgroundMarks
@@ -315,6 +296,7 @@ Rectangle {
id: view
profilerModelProxy: qmlProfilerModelProxy
zoomer: zoomControl
x: flick.contentX
y: flick.contentY
@@ -323,7 +305,6 @@ Rectangle {
width: scroller.width
height: flick.height
onEndTimeChanged: requestPaint()
onYChanged: requestPaint()
onHeightChanged: requestPaint()
property bool recursionGuard: false
@@ -331,42 +312,41 @@ Rectangle {
property int intX: x
property int intWidth: width
onIntXChanged: {
// Don't updateZoomControl if we're just updating the flick range, _from_
// zoomControl. The other way round is OK. We _want_ the flick range to be updated
// on external changes to zoomControl.
if (recursionGuard)
return;
var newStartTime = intX * (endTime - startTime) / intWidth +
zoomControl.windowStart();
if (Math.abs(newStartTime - startTime) >= 1) {
var newEndTime = (intX + intWidth) * (endTime - startTime) / intWidth +
zoomControl.windowStart();
zoomControl.setRange(newStartTime, newEndTime);
}
}
function updateWindow() {
var duration = zoomControl.duration();
if (recursionGuard || duration <= 0)
return;
recursionGuard = true;
if (!flick.movingHorizontally) {
// This triggers an unwanted automatic change in contentX. We ignore that by
// checking recursionGuard in this function and in updateZoomControl.
flick.contentWidth = zoomControl.windowLength() * intWidth / duration;
var newStartX = (startTime - zoomControl.windowStart()) * intWidth /
duration;
if (isFinite(newStartX) && Math.abs(newStartX - intX) >= 1)
flick.contentX = newStartX;
var newStartTime = intX * zoomControl.rangeDuration / intWidth +
zoomControl.windowStart;
if (Math.abs(newStartTime - zoomControl.rangeStart) >= 1) {
var newEndTime = (intX + intWidth) * zoomControl.rangeDuration / intWidth +
zoomControl.windowStart;
zoomControl.setRange(newStartTime, newEndTime);
}
recursionGuard = false;
}
function updateWindow() {
if (recursionGuard || zoomControl.rangeDuration <= 0)
return;
recursionGuard = true;
// This triggers an unwanted automatic change in contentX. We ignore that by
// checking recursionGuard in this function and in updateZoomControl.
flick.contentWidth = zoomControl.windowDuration * intWidth /
zoomControl.rangeDuration;
var newStartX = (zoomControl.rangeStart - zoomControl.windowStart) * intWidth /
zoomControl.rangeDuration;
if (isFinite(newStartX) && Math.abs(newStartX - flick.contentX) >= 1)
flick.contentX = newStartX;
recursionGuard = false;
}
onSelectionChanged: {
if (selectedItem !== -1) {
// display details
@@ -490,8 +470,8 @@ Rectangle {
function updateZoomLevel() {
zoomSlider.externalUpdate = true;
zoomSlider.value = Math.pow((view.endTime - view.startTime) /
zoomControl.windowLength(),
zoomSlider.value = Math.pow(zoomControl.rangeDuration /
Math.max(1, zoomControl.windowDuration),
1 / zoomSlider.exponent) * zoomSlider.maximumValue;
}
@@ -508,7 +488,7 @@ Rectangle {
property int minWindowLength: 1e5 // 0.1 ms
onValueChanged: {
if (externalUpdate || zoomControl.windowEnd() <= zoomControl.windowStart()) {
if (externalUpdate || zoomControl.windowEnd <= zoomControl.windowStart) {
// Zoom range is independently updated. We shouldn't mess
// with it here as otherwise we might introduce rounding
// or arithmetic errors.
@@ -517,18 +497,19 @@ Rectangle {
}
var windowLength = Math.max(
Math.pow(value / maximumValue, exponent) * zoomControl.windowLength(),
Math.pow(value / maximumValue, exponent) * zoomControl.windowDuration,
minWindowLength);
var fixedPoint = (view.startTime + view.endTime) / 2;
var fixedPoint = (zoomControl.rangeStart + zoomControl.rangeEnd) / 2;
if (view.selectedItem !== -1) {
// center on selected item if it's inside the current screen
var newFixedPoint = qmlProfilerModelProxy.startTime(view.selectedModel, view.selectedItem);
if (newFixedPoint >= view.startTime && newFixedPoint < view.endTime)
if (newFixedPoint >= zoomControl.rangeStart &&
newFixedPoint < zoomControl.rangeEnd)
fixedPoint = newFixedPoint;
}
var startTime = Math.max(zoomControl.windowStart(), fixedPoint - windowLength / 2)
var startTime = Math.max(zoomControl.windowStart, fixedPoint - windowLength / 2)
zoomControl.setRange(startTime, startTime + windowLength);
}
}

View File

@@ -31,6 +31,7 @@
.pragma library
var qmlProfilerModelProxy = 0;
var zoomControl = 0;
//draw background of the graph
function drawGraph(canvas, ctxt)
@@ -42,19 +43,17 @@ function drawGraph(canvas, ctxt)
//draw the actual data to be graphed
function drawData(canvas, ctxt)
{
if ((!qmlProfilerModelProxy) || qmlProfilerModelProxy.isEmpty())
if (!zoomControl || !qmlProfilerModelProxy || qmlProfilerModelProxy.isEmpty())
return;
var spacing = canvas.width / qmlProfilerModelProxy.traceDuration();
for (var modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount(); ++modelIndex) {
for (var ii = canvas.offset; ii < qmlProfilerModelProxy.count(modelIndex);
ii += canvas.increment) {
var xx = (qmlProfilerModelProxy.startTime(modelIndex,ii) -
qmlProfilerModelProxy.traceStartTime()) * spacing;
var xx = (qmlProfilerModelProxy.startTime(modelIndex,ii) - zoomControl.traceStart) *
canvas.spacing;
var eventWidth = qmlProfilerModelProxy.duration(modelIndex,ii) * spacing;
var eventWidth = qmlProfilerModelProxy.duration(modelIndex,ii) * canvas.spacing;
if (eventWidth < 1)
eventWidth = 1;
@@ -75,14 +74,13 @@ function drawBindingLoops(canvas, ctxt) {
ctxt.strokeStyle = "orange";
ctxt.lineWidth = 2;
var radius = 1;
var spacing = canvas.width / qmlProfilerModelProxy.traceDuration();
for (var modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount(); ++modelIndex) {
for (var ii = canvas.offset - canvas.increment; ii < qmlProfilerModelProxy.count(modelIndex);
ii += canvas.increment) {
if (qmlProfilerModelProxy.bindingLoopDest(modelIndex,ii) >= 0) {
var xcenter = Math.round(qmlProfilerModelProxy.startTime(modelIndex,ii) +
qmlProfilerModelProxy.duration(modelIndex,ii) -
qmlProfilerModelProxy.traceStartTime()) * spacing;
zoomControl.traceStart) * canvas.spacing;
var ycenter = Math.round(canvas.bump + canvas.blockHeight * modelIndex +
canvas.blockHeight / 2);
ctxt.beginPath();
@@ -95,10 +93,10 @@ function drawBindingLoops(canvas, ctxt) {
function drawNotes(canvas, ctxt)
{
if ((!qmlProfilerModelProxy) || qmlProfilerModelProxy.noteCount() === 0)
if (!zoomControl || !qmlProfilerModelProxy || qmlProfilerModelProxy.noteCount() === 0)
return;
var spacing = canvas.width / qmlProfilerModelProxy.traceDuration();
var spacing = canvas.width / zoomControl.traceDuration;
// divide canvas height in 7 parts: margin, 3*line, space, dot, margin
var vertSpace = (canvas.height - canvas.bump) / 7;
@@ -109,13 +107,11 @@ function drawNotes(canvas, ctxt)
var timelineIndex = qmlProfilerModelProxy.noteTimelineIndex(i);
if (timelineIndex === -1)
continue;
var traceStart = qmlProfilerModelProxy.traceStartTime();
var traceEnd = qmlProfilerModelProxy.traceEndTime();
var start = Math.max(qmlProfilerModelProxy.startTime(timelineModel, timelineIndex),
traceStart);
zoomControl.traceStart);
var end = Math.min(qmlProfilerModelProxy.endTime(timelineModel, timelineIndex),
traceEnd);
var annoX = Math.round(((start + end) / 2 - traceStart) * spacing);
zoomControl.traceStart);
var annoX = Math.round(((start + end) / 2 - zoomControl.traceStart) * spacing);
ctxt.moveTo(annoX, canvas.bump + vertSpace)
ctxt.lineTo(annoX, canvas.bump + vertSpace * 4)
@@ -128,26 +124,21 @@ function drawNotes(canvas, ctxt)
function drawTimeBar(canvas, ctxt)
{
if (!qmlProfilerModelProxy)
if (!zoomControl)
return;
var width = canvas.width;
var height = 10;
var startTime = qmlProfilerModelProxy.traceStartTime();
var endTime = qmlProfilerModelProxy.traceEndTime();
var totalTime = qmlProfilerModelProxy.traceDuration();
var spacing = width / totalTime;
var initialBlockLength = 120;
var timePerBlock = Math.pow(2, Math.floor( Math.log( totalTime / width *
var timePerBlock = Math.pow(2, Math.floor( Math.log( zoomControl.traceDuration / width *
initialBlockLength ) / Math.LN2 ) );
var pixelsPerBlock = timePerBlock * spacing;
var pixelsPerBlock = timePerBlock * canvas.spacing;
var pixelsPerSection = pixelsPerBlock / 5;
var blockCount = width / pixelsPerBlock;
var realStartTime = Math.floor(startTime/timePerBlock) * timePerBlock;
var realStartPos = (startTime-realStartTime) * spacing;
var realStartTime = Math.floor(zoomControl.traceStart / timePerBlock) * timePerBlock;
var realStartPos = (zoomControl.traceStart - realStartTime) * canvas.spacing;
var timePerPixel = timePerBlock/pixelsPerBlock;

View File

@@ -42,12 +42,11 @@ Canvas {
property int offset: -1
readonly property int bump: 10;
readonly property int blockHeight: (height - bump) / qmlProfilerModelProxy.models.length;
readonly property double spacing: width / zoomControl.traceDuration
// ***** properties
height: 50
property bool dataReady: false
property double startTime : 0
property double endTime : 0
property bool recursionGuard: false
onWidthChanged: offset = -1
@@ -64,10 +63,11 @@ Canvas {
function updateRange() {
if (recursionGuard)
return;
var newStartTime = Math.round(rangeMover.rangeLeft * qmlProfilerModelProxy.traceDuration() / width) + qmlProfilerModelProxy.traceStartTime();
var newEndTime = Math.round(rangeMover.rangeRight * qmlProfilerModelProxy.traceDuration() / width) + qmlProfilerModelProxy.traceStartTime();
if (startTime !== newStartTime || endTime !== newEndTime)
zoomControl.setRange(newStartTime, Math.max(newEndTime, newStartTime + 500));
var newStartTime = Math.round(rangeMover.rangeLeft * zoomControl.traceDuration / width) +
zoomControl.traceStart;
var newEndTime = Math.max(Math.round(rangeMover.rangeRight * zoomControl.traceDuration /
width) + zoomControl.traceStart, newStartTime + 500);
zoomControl.setRange(newStartTime, newEndTime);
}
function clamp(val, min, max) {
@@ -78,21 +78,18 @@ Canvas {
Connections {
target: zoomControl
onRangeChanged: {
if (qmlProfilerModelProxy) {
recursionGuard = true;
startTime = clamp(zoomControl.startTime(), qmlProfilerModelProxy.traceStartTime(), qmlProfilerModelProxy.traceEndTime());
endTime = clamp(zoomControl.endTime(), startTime, qmlProfilerModelProxy.traceEndTime());
var newRangeX = (startTime - qmlProfilerModelProxy.traceStartTime()) * width / qmlProfilerModelProxy.traceDuration();
var newWidth = (endTime - startTime) * width / qmlProfilerModelProxy.traceDuration();
var widthChanged = Math.abs(newWidth - rangeMover.rangeWidth) > 1;
var leftChanged = Math.abs(newRangeX - rangeMover.rangeLeft) > 1;
if (leftChanged)
rangeMover.rangeLeft = newRangeX;
recursionGuard = true;
var newRangeX = (zoomControl.rangeStart - zoomControl.traceStart) * width /
zoomControl.traceDuration;
var newWidth = zoomControl.rangeDuration * width / zoomControl.traceDuration;
var widthChanged = Math.abs(newWidth - rangeMover.rangeWidth) > 1;
var leftChanged = Math.abs(newRangeX - rangeMover.rangeLeft) > 1;
if (leftChanged)
rangeMover.rangeLeft = newRangeX;
if (leftChanged || widthChanged)
rangeMover.rangeRight = newRangeX + newWidth;
recursionGuard = false;
}
if (leftChanged || widthChanged)
rangeMover.rangeRight = newRangeX + newWidth;
recursionGuard = false;
}
}
@@ -123,6 +120,7 @@ Canvas {
var context = (canvas.context === null) ? getContext("2d") : canvas.context;
Plotter.qmlProfilerModelProxy = qmlProfilerModelProxy;
Plotter.zoomControl = zoomControl;
if (offset < 0) {
context.reset();

View File

@@ -39,7 +39,7 @@ RangeMover {
property string endTimeString: detailedPrintTime(startTime+duration)
property string durationString: detailedPrintTime(duration)
property double startTime: rangeLeft * viewTimePerPixel + zoomControl.windowStart()
property double startTime: rangeLeft * viewTimePerPixel + zoomControl.windowStart
property double duration: Math.max(rangeWidth * viewTimePerPixel, 500)
property double viewTimePerPixel: 1
property double creationReference : 0
@@ -49,7 +49,7 @@ RangeMover {
target: zoomControl
onRangeChanged: {
var oldTimePerPixel = selectionRange.viewTimePerPixel;
selectionRange.viewTimePerPixel = Math.abs(zoomControl.endTime() - zoomControl.startTime()) / view.intWidth;
selectionRange.viewTimePerPixel = zoomControl.rangeDuration / view.intWidth;
if (creationState === 3 && oldTimePerPixel != selectionRange.viewTimePerPixel) {
var newWidth = rangeWidth * oldTimePerPixel / viewTimePerPixel;
rangeLeft = rangeLeft * oldTimePerPixel / viewTimePerPixel;

View File

@@ -36,16 +36,9 @@ Canvas {
objectName: "TimeDisplay"
contextType: "2d"
property real startTime : 0
property real endTime : 0
Connections {
target: zoomControl
onRangeChanged: {
startTime = zoomControl.startTime();
endTime = zoomControl.endTime();
requestPaint();
}
onRangeChanged: requestPaint();
}
onPaint: {
@@ -55,7 +48,7 @@ Canvas {
context.fillStyle = "white";
context.fillRect(0, 0, width, height);
var totalTime = Math.max(1, endTime - startTime);
var totalTime = Math.max(1, zoomControl.rangeDuration);
var spacing = width / totalTime;
var initialBlockLength = 120;
@@ -64,8 +57,8 @@ Canvas {
var pixelsPerSection = pixelsPerBlock / 5;
var blockCount = width / pixelsPerBlock;
var realStartTime = Math.floor(startTime/timePerBlock) * timePerBlock;
var startPos = (startTime - realStartTime) * spacing;
var realStartTime = Math.floor(zoomControl.rangeStart / timePerBlock) * timePerBlock;
var startPos = (zoomControl.rangeStart - realStartTime) * spacing;
var timePerPixel = timePerBlock/pixelsPerBlock;
@@ -98,7 +91,6 @@ Canvas {
function clear()
{
startTime = endTime = 0;
requestPaint();
}
@@ -106,16 +98,15 @@ Canvas {
{
var round = 1;
var barrier = 1;
var range = endTime - startTime;
var units = ["μs", "ms", "s"];
for (var i = 0; i < units.length; ++i) {
barrier *= 1000;
if (range < barrier)
if (zoomControl.rangeDuration < barrier)
round *= 1000;
else if (range < barrier * 10)
else if (zoomControl.rangeDuration < barrier * 10)
round *= 100;
else if (range < barrier * 100)
else if (zoomControl.rangeDuration < barrier * 100)
round *= 10;
if (t < barrier * 1000)
return Math.floor(t / (barrier / round)) / round + units[i];

View File

@@ -32,7 +32,8 @@ SOURCES += \
sortedtimelinemodel.cpp \
qmlprofilerbasemodel.cpp \
qmlprofilerdatamodel.cpp \
notesmodel.cpp
notesmodel.cpp \
timelinezoomcontrol.cpp
HEADERS += \
qmlprofilerconstants.h \
@@ -67,7 +68,8 @@ HEADERS += \
abstracttimelinemodel_p.h \
qmlprofilerdatamodel.h \
qmlprofilerbasemodel_p.h \
notesmodel.h
notesmodel.h \
timelinezoomcontrol.h
RESOURCES += \
qml/qmlprofiler.qrc

View File

@@ -52,6 +52,7 @@ QtcPlugin {
"sortedtimelinemodel.h", "sortedtimelinemodel.cpp",
"timelinemodelaggregator.cpp", "timelinemodelaggregator.h",
"timelinerenderer.cpp", "timelinerenderer.h",
"timelinezoomcontrol.cpp", "timelinezoomcontrol.h"
]
}

View File

@@ -219,9 +219,9 @@ void QmlProfilerClientManager::disconnectClientSignals()
SLOT(addQmlEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
qint64,qint64,qint64,qint64,qint64)));
disconnect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64)),
d->modelManager->traceTime(), SLOT(setEndTime(qint64)));
d->modelManager->traceTime(), SLOT(increaseEndTime(qint64)));
disconnect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64)),
d->modelManager->traceTime(), SLOT(setStartTime(qint64)));
d->modelManager->traceTime(), SLOT(decreaseStartTime(qint64)));
disconnect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
// fixme: this should be unified for both clients
@@ -339,8 +339,7 @@ void QmlProfilerClientManager::retryMessageBoxFinished(int result)
void QmlProfilerClientManager::qmlComplete(qint64 maximumTime)
{
if (maximumTime > d->modelManager->traceTime()->endTime())
d->modelManager->traceTime()->setEndTime(maximumTime);
d->modelManager->traceTime()->increaseEndTime(maximumTime);
d->qmlDataReady = true;
if (!d->v8clientplugin ||
d->v8clientplugin.data()->state() != QmlDebug::QmlDebugClient::Enabled ||

View File

@@ -121,10 +121,12 @@ const QVector<QmlProfilerDataModel::QmlEventNoteData> &QmlProfilerDataModel::get
return d->eventNotes;
}
void QmlProfilerDataModel::setData(const QVector<QmlProfilerDataModel::QmlEventTypeData> &types,
void QmlProfilerDataModel::setData(qint64 traceStart, qint64 traceEnd,
const QVector<QmlProfilerDataModel::QmlEventTypeData> &types,
const QVector<QmlProfilerDataModel::QmlEventData> &events)
{
Q_D(QmlProfilerDataModel);
d->modelManager->traceTime()->setTime(traceStart, traceEnd);
d->eventList = events;
d->eventTypes = types;
for (int id = 0; id < types.count(); ++id)
@@ -260,7 +262,7 @@ void QmlProfilerDataModel::addQmlEvent(QmlDebug::Message message, QmlDebug::Rang
d->eventList.append(eventData);
d->modelManager->modelProxyCountUpdated(d->modelId, startTime,
d->modelManager->estimatedProfilingTime() * 2);
d->modelManager->traceTime()->duration() * 2);
}
qint64 QmlProfilerDataModel::lastTimeMark() const

View File

@@ -72,7 +72,8 @@ public:
const QVector<QmlEventData> &getEvents() const;
const QVector<QmlEventTypeData> &getEventTypes() const;
const QVector<QmlEventNoteData> &getEventNotes() const;
void setData(const QVector<QmlEventTypeData> &types, const QVector<QmlEventData> &events);
void setData(qint64 traceStart, qint64 traceEnd, const QVector<QmlEventTypeData> &types,
const QVector<QmlEventData> &events);
void setNoteData(const QVector<QmlEventNoteData> &notes);
int count() const;

View File

@@ -128,36 +128,33 @@ qint64 QmlProfilerTraceTime::duration() const
void QmlProfilerTraceTime::clear()
{
setStartTime(-1);
setEndTime(-1);
setTime(-1, -1);
}
void QmlProfilerTraceTime::setStartTime(qint64 time)
void QmlProfilerTraceTime::setTime(qint64 startTime, qint64 endTime)
{
if (time != m_startTime) {
m_startTime = time;
emit startTimeChanged(time);
}
}
void QmlProfilerTraceTime::setEndTime(qint64 time)
{
if (time != m_endTime) {
m_endTime = time;
emit endTimeChanged(time);
Q_ASSERT(startTime <= endTime);
if (startTime != m_startTime || endTime != m_endTime) {
m_startTime = startTime;
m_endTime = endTime;
emit timeChanged(startTime, endTime);
}
}
void QmlProfilerTraceTime::decreaseStartTime(qint64 time)
{
if (m_startTime > time)
setStartTime(time);
if (m_startTime > time) {
m_startTime = time;
emit timeChanged(time, m_endTime);
}
}
void QmlProfilerTraceTime::increaseEndTime(qint64 time)
{
if (m_endTime < time)
setEndTime(time);
if (m_endTime < time) {
m_endTime = time;
emit timeChanged(m_startTime, time);
}
}
@@ -186,7 +183,6 @@ public:
int totalWeight;
double progress;
double previousProgress;
qint64 estimatedTime;
// file to load
QString fileName;
@@ -298,14 +294,9 @@ const char *QmlProfilerModelManager::featureName(QmlDebug::ProfileFeature featur
return ProfileFeatureNames[feature];
}
qint64 QmlProfilerModelManager::estimatedProfilingTime() const
{
return d->estimatedTime;
}
void QmlProfilerModelManager::newTimeEstimation(qint64 estimation)
{
d->estimatedTime = estimation;
d->traceTime->increaseEndTime(d->traceTime->startTime() + estimation);
}
void QmlProfilerModelManager::addQmlEvent(QmlDebug::Message message,
@@ -323,7 +314,7 @@ void QmlProfilerModelManager::addQmlEvent(QmlDebug::Message message,
{
// If trace start time was not explicitly set, use the first event
if (d->traceTime->startTime() == -1)
d->traceTime->setStartTime(startTime);
d->traceTime->setTime(startTime, startTime + d->traceTime->duration());
QTC_ASSERT(state() == QmlProfilerDataState::AcquiringData, /**/);
d->model->addQmlEvent(message, rangeType, detailType, startTime, length, data, location,
@@ -346,9 +337,8 @@ void QmlProfilerModelManager::complete()
emit dataAvailable();
break;
case QmlProfilerDataState::AcquiringData:
// If trace end time was not explicitly set, use the last event
if (d->traceTime->endTime() == 0)
d->traceTime->setEndTime(d->model->lastTimeMark());
// Make sure the trace fits into the time span.
d->traceTime->increaseEndTime(d->model->lastTimeMark());
setState(QmlProfilerDataState::ProcessingData);
d->model->complete();
d->v8Model->complete();
@@ -418,8 +408,6 @@ void QmlProfilerModelManager::load()
QmlProfilerFileReader reader;
connect(&reader, SIGNAL(error(QString)), this, SIGNAL(error(QString)));
connect(&reader, SIGNAL(traceStartTime(qint64)), traceTime(), SLOT(setStartTime(qint64)));
connect(&reader, SIGNAL(traceEndTime(qint64)), traceTime(), SLOT(setEndTime(qint64)));
reader.setV8DataModel(d->v8Model);
reader.setQmlDataModel(d->model);
reader.load(&file);

View File

@@ -76,7 +76,7 @@ private:
friend class QmlProfiler::QmlProfilerModelManager;
};
class QmlProfilerTraceTime : public QObject
class QMLPROFILER_EXPORT QmlProfilerTraceTime : public QObject
{
Q_OBJECT
public:
@@ -88,14 +88,12 @@ public:
qint64 duration() const;
signals:
void startTimeChanged(qint64);
void endTimeChanged(qint64);
void timeChanged(qint64,qint64);
public slots:
void clear();
void setStartTime(qint64 time);
void setEndTime(qint64 time);
void setTime(qint64 startTime, qint64 endTime);
void decreaseStartTime(qint64 time);
void increaseEndTime(qint64 time);
@@ -134,8 +132,6 @@ public:
quint64 availableFeatures();
static const char *featureName(QmlDebug::ProfileFeature feature);
qint64 estimatedProfilingTime() const;
signals:
void error(const QString &error);
void stateChanged();

View File

@@ -31,7 +31,6 @@
#include "qmlprofilerstatewidget.h"
#include <QPainter>
#include <QVBoxLayout>
#include <QLabel>
#include <QProgressBar>

View File

@@ -141,6 +141,8 @@ bool QmlProfilerFileReader::load(QIODevice *device)
QXmlStreamReader stream(device);
bool validVersion = true;
qint64 traceStart = -1;
qint64 traceEnd = -1;
while (validVersion && !stream.atEnd() && !stream.hasError()) {
QXmlStreamReader::TokenType token = stream.readNext();
@@ -155,9 +157,9 @@ bool QmlProfilerFileReader::load(QIODevice *device)
else
validVersion = false;
if (attributes.hasAttribute(_("traceStart")))
emit traceStartTime(attributes.value(_("traceStart")).toString().toLongLong());
traceStart = attributes.value(_("traceStart")).toString().toLongLong();
if (attributes.hasAttribute(_("traceEnd")))
emit traceEndTime(attributes.value(_("traceEnd")).toString().toLongLong());
traceEnd = attributes.value(_("traceEnd")).toString().toLongLong();
}
if (elementName == _("eventData")) {
@@ -191,7 +193,7 @@ bool QmlProfilerFileReader::load(QIODevice *device)
emit error(tr("Error while parsing trace data file: %1").arg(stream.errorString()));
return false;
} else {
m_qmlModel->setData(m_qmlEvents, m_ranges);
m_qmlModel->setData(traceStart, qMax(traceStart, traceEnd), m_qmlEvents, m_ranges);
m_qmlModel->setNoteData(m_notes);
return true;
}

View File

@@ -61,9 +61,6 @@ public:
bool load(QIODevice *device);
signals:
void traceStartTime(qint64 traceStartTime);
void traceEndTime(qint64 traceStartTime);
void error(const QString &error);
private:

View File

@@ -40,6 +40,7 @@
// Communication with the other views (limit events to range)
#include "qmlprofilerviewmanager.h"
#include "timelinezoomcontrol.h"
#include <utils/styledbar.h>
@@ -61,89 +62,6 @@ using namespace QmlDebug;
namespace QmlProfiler {
namespace Internal {
/////////////////////////////////////////////////////////
ZoomControl::ZoomControl(const QmlProfilerTraceTime *traceTime, QObject *parent) :
QObject(parent), m_startTime(traceTime->startTime()), m_endTime(traceTime->endTime()),
m_windowStart(traceTime->startTime()), m_windowEnd(traceTime->endTime()),
m_traceTime(traceTime), m_windowLocked(false)
{
connect(traceTime, SIGNAL(startTimeChanged(qint64)), this, SLOT(rebuildWindow()));
connect(traceTime, SIGNAL(endTimeChanged(qint64)), this, SLOT(rebuildWindow()));
connect(&m_timer, SIGNAL(timeout()), this, SLOT(moveWindow()));
}
void ZoomControl::setRange(qint64 startTime, qint64 endTime)
{
if (m_startTime != startTime || m_endTime != endTime) {
m_timer.stop();
m_startTime = startTime;
m_endTime = endTime;
rebuildWindow();
emit rangeChanged();
}
}
void ZoomControl::rebuildWindow()
{
qint64 minDuration = 1; // qMax needs equal data types, so literal 1 won't do
qint64 shownDuration = qMax(duration(), minDuration);
qint64 oldWindowStart = m_windowStart;
qint64 oldWindowEnd = m_windowEnd;
if (m_traceTime->duration() / shownDuration < MAX_ZOOM_FACTOR) {
m_windowStart = m_traceTime->startTime();
m_windowEnd = m_traceTime->endTime();
} else if (windowLength() / shownDuration > MAX_ZOOM_FACTOR ||
windowLength() / shownDuration * 2 < MAX_ZOOM_FACTOR) {
qint64 keep = shownDuration * MAX_ZOOM_FACTOR / 2 - shownDuration;
m_windowStart = m_startTime - keep;
if (m_windowStart < m_traceTime->startTime()) {
keep += m_traceTime->startTime() - m_windowStart;
m_windowStart = m_traceTime->startTime();
}
m_windowEnd = m_endTime + keep;
if (m_windowEnd > m_traceTime->endTime()) {
m_windowStart = qMax(m_traceTime->startTime(),
m_windowStart - m_windowEnd - m_traceTime->endTime());
m_windowEnd = m_traceTime->endTime();
}
} else {
m_timer.start(500);
}
if (oldWindowStart != m_windowStart || oldWindowEnd != m_windowEnd)
emit windowChanged();
}
void ZoomControl::moveWindow()
{
if (m_windowLocked)
return;
m_timer.stop();
qint64 offset = (m_endTime - m_windowEnd + m_startTime - m_windowStart) / 2;
if (offset == 0 || (offset < 0 && m_windowStart == m_traceTime->startTime()) ||
(offset > 0 && m_windowEnd == m_traceTime->endTime())) {
return;
} else if (offset > duration()) {
offset = (offset + duration()) / 2;
} else if (offset < -duration()) {
offset = (offset - duration()) / 2;
}
m_windowStart += offset;
if (m_windowStart < m_traceTime->startTime()) {
m_windowEnd += m_traceTime->startTime() - m_windowStart;
m_windowStart = m_traceTime->startTime();
}
m_windowEnd += offset;
if (m_windowEnd > m_traceTime->endTime()) {
m_windowStart -= m_windowEnd - m_traceTime->endTime();
m_windowEnd = m_traceTime->endTime();
}
emit windowChanged();
m_timer.start(100);
}
/////////////////////////////////////////////////////////
class QmlProfilerTraceView::QmlProfilerTraceViewPrivate
{
@@ -167,7 +85,7 @@ public:
TimelineModelAggregator *m_modelProxy;
ZoomControl *m_zoomControl;
TimelineZoomControl *m_zoomControl;
};
QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerTool *profilerTool, QmlProfilerViewManager *container, QmlProfilerModelManager *modelManager, QmlProfilerStateManager *profilerState)
@@ -175,8 +93,9 @@ QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerT
{
setObjectName(QLatin1String("QML Profiler"));
d->m_zoomControl = new ZoomControl(modelManager->traceTime(), this);
connect(d->m_zoomControl, SIGNAL(rangeChanged()), this, SLOT(updateRange()));
d->m_zoomControl = new TimelineZoomControl(this);
connect(modelManager->traceTime(), &QmlProfilerTraceTime::timeChanged,
d->m_zoomControl, &TimelineZoomControl::setTrace);
QVBoxLayout *groupLayout = new QVBoxLayout;
groupLayout->setContentsMargins(0, 0, 0, 0);
@@ -305,20 +224,6 @@ void QmlProfilerTraceView::updateCursorPosition()
emit typeSelected(rootObject->property("typeId").toInt());
}
////////////////////////////////////////////////////////
// Zoom control
void QmlProfilerTraceView::updateRange()
{
if (!d->m_modelManager)
return;
qreal duration = d->m_zoomControl->endTime() - d->m_zoomControl->startTime();
if (duration <= 0)
return;
if (d->m_modelManager->traceTime()->duration() <= 0)
return;
QMetaObject::invokeMethod(d->m_mainView->rootObject()->findChild<QObject*>(QLatin1String("zoomSliderToolBar")), "updateZoomLevel");
}
////////////////////////////////////////////////////////
void QmlProfilerTraceView::resizeEvent(QResizeEvent *event)
{
@@ -374,9 +279,8 @@ void QmlProfilerTraceView::showContextMenu(QPoint position)
if (selectedAction) {
if (selectedAction == viewAllAction) {
d->m_zoomControl->setRange(
d->m_modelManager->traceTime()->startTime(),
d->m_modelManager->traceTime()->endTime());
d->m_zoomControl->setRange(d->m_zoomControl->traceStart(),
d->m_zoomControl->traceEnd());
}
if (selectedAction == getLocalStatsAction) {
d->m_viewContainer->getStatisticsInRange(

View File

@@ -46,43 +46,6 @@ namespace Internal {
class QmlProfilerStateManager;
class QmlProfilerViewManager;
// centralized zoom control
class ZoomControl : public QObject {
Q_OBJECT
public:
static const qint64 MAX_ZOOM_FACTOR = 1 << 12;
ZoomControl(const QmlProfilerTraceTime *traceTime, QObject *parent = 0);
~ZoomControl(){}
Q_INVOKABLE void setRange(qint64 startTime, qint64 endTime);
Q_INVOKABLE qint64 startTime() const { return m_startTime; }
Q_INVOKABLE qint64 endTime() const { return m_endTime; }
Q_INVOKABLE qint64 duration() const { return m_endTime - m_startTime; }
Q_INVOKABLE qint64 windowStart() const { return m_windowStart; }
Q_INVOKABLE qint64 windowEnd() const { return m_windowEnd; }
Q_INVOKABLE qint64 windowLength() const { return m_windowEnd - m_windowStart; }
void setWindowLocked(bool lock) { m_windowLocked = lock; }
signals:
void rangeChanged();
void windowChanged();
private slots:
void rebuildWindow();
void moveWindow();
private:
qint64 m_startTime;
qint64 m_endTime;
qint64 m_windowStart;
qint64 m_windowEnd;
const QmlProfilerTraceTime *m_traceTime;
QTimer m_timer;
bool m_windowLocked;
};
class QmlProfilerTraceView : public QWidget
{
@@ -106,9 +69,6 @@ public slots:
private slots:
void updateCursorPosition();
void updateRange();
void profilerDataModelStateChanged();
protected:

View File

@@ -381,20 +381,5 @@ int TimelineModelAggregator::modelCount() const
return d->modelList.count();
}
qint64 TimelineModelAggregator::traceStartTime() const
{
return d->modelManager->traceTime()->startTime();
}
qint64 TimelineModelAggregator::traceEndTime() const
{
return d->modelManager->traceTime()->endTime();
}
qint64 TimelineModelAggregator::traceDuration() const
{
return d->modelManager->traceTime()->duration();
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -58,10 +58,6 @@ public:
void clear();
Q_INVOKABLE int modelCount() const;
Q_INVOKABLE qint64 traceStartTime() const;
Q_INVOKABLE qint64 traceEndTime() const;
Q_INVOKABLE qint64 traceDuration() const;
Q_INVOKABLE bool isEmpty() const;
Q_INVOKABLE int modelOffset(int modelIndex) const;

View File

@@ -44,9 +44,9 @@
using namespace QmlProfiler::Internal;
TimelineRenderer::TimelineRenderer(QQuickPaintedItem *parent) :
QQuickPaintedItem(parent), m_startTime(0), m_endTime(0), m_spacing(0), m_spacedDuration(0),
m_lastStartTime(0), m_lastEndTime(0), m_profilerModelProxy(0), m_selectedItem(-1),
m_selectedModel(-1), m_selectionLocked(true), m_startDragArea(-1), m_endDragArea(-1)
QQuickPaintedItem(parent), m_spacing(0), m_spacedDuration(0), m_profilerModelProxy(0),
m_zoomer(0), m_selectedItem(-1), m_selectedModel(-1), m_selectionLocked(true),
m_startDragArea(-1), m_endDragArea(-1)
{
resetCurrentSelection();
setAcceptedMouseButtons(Qt::LeftButton);
@@ -77,6 +77,20 @@ void TimelineRenderer::setProfilerModelProxy(QObject *profilerModelProxy)
emit profilerModelProxyChanged(m_profilerModelProxy);
}
void TimelineRenderer::setZoomer(QObject *zoomControl)
{
TimelineZoomControl *zoomer = qobject_cast<TimelineZoomControl *>(zoomControl);
if (zoomer != m_zoomer) {
if (m_zoomer != 0)
disconnect(m_zoomer, SIGNAL(rangeChanged(qint64,qint64)), this, SLOT(requestPaint()));
m_zoomer = zoomer;
if (m_zoomer != 0)
connect(m_zoomer, SIGNAL(rangeChanged(qint64,qint64)), this, SLOT(requestPaint()));
emit zoomerChanged(zoomer);
update();
}
}
void TimelineRenderer::componentComplete()
{
const QMetaObject *metaObject = this->metaObject();
@@ -111,7 +125,7 @@ void TimelineRenderer::swapSelections(int modelIndex1, int modelIndex2)
inline void TimelineRenderer::getItemXExtent(int modelIndex, int i, int &currentX, int &itemWidth)
{
qint64 start = m_profilerModelProxy->startTime(modelIndex, i) - m_startTime;
qint64 start = m_profilerModelProxy->startTime(modelIndex, i) - m_zoomer->rangeStart();
// avoid integer overflows by using floating point for width calculations. m_spacing is qreal,
// too, so for some intermediate calculations we have to use floats anyway.
@@ -148,21 +162,20 @@ void TimelineRenderer::resetCurrentSelection()
void TimelineRenderer::paint(QPainter *p)
{
qint64 windowDuration = m_endTime - m_startTime;
if (windowDuration <= 0)
if (m_zoomer->rangeDuration() <= 0)
return;
m_spacing = qreal(width()) / windowDuration;
m_spacedDuration = (m_endTime - m_startTime) * m_spacing + 2 * OutOfScreenMargin;
m_spacing = width() / m_zoomer->rangeDuration();
m_spacedDuration = width() + 2 * OutOfScreenMargin;
p->setPen(Qt::transparent);
for (int modelIndex = 0; modelIndex < m_profilerModelProxy->modelCount(); modelIndex++) {
if (m_profilerModelProxy->hidden(modelIndex))
continue;
int lastIndex = m_profilerModelProxy->lastIndex(modelIndex, m_endTime);
int lastIndex = m_profilerModelProxy->lastIndex(modelIndex, m_zoomer->rangeEnd());
if (lastIndex >= 0 && lastIndex < m_profilerModelProxy->count(modelIndex)) {
int firstIndex = m_profilerModelProxy->firstIndex(modelIndex, m_startTime);
int firstIndex = m_profilerModelProxy->firstIndex(modelIndex, m_zoomer->rangeStart());
if (firstIndex >= 0) {
drawItemsToPainter(p, modelIndex, firstIndex, lastIndex);
if (m_selectedModel == modelIndex)
@@ -172,9 +185,6 @@ void TimelineRenderer::paint(QPainter *p)
}
}
drawNotes(p);
m_lastStartTime = m_startTime;
m_lastEndTime = m_endTime;
}
void TimelineRenderer::drawItemsToPainter(QPainter *p, int modelIndex, int fromIndex, int toIndex)
@@ -472,12 +482,13 @@ void TimelineRenderer::manageClicked()
void TimelineRenderer::manageHovered(int mouseX, int mouseY)
{
if (m_endTime - m_startTime <=0 || m_lastEndTime - m_lastStartTime <= 0)
qint64 duration = m_zoomer->rangeDuration();
if (duration <= 0)
return;
// Make the "selected" area 3 pixels wide by adding/subtracting 1 to catch very narrow events.
qint64 startTime = (mouseX - 1) * (m_endTime - m_startTime) / width() + m_startTime;
qint64 endTime = (mouseX + 1) * (m_endTime - m_startTime) / width() + m_startTime;
qint64 startTime = (mouseX - 1) * duration / width() + m_zoomer->rangeStart();
qint64 endTime = (mouseX + 1) * duration / width() + m_zoomer->rangeStart();
int row = rowFromPosition(mouseY + y());
int modelIndex = modelFromPosition(mouseY + y());
@@ -532,13 +543,9 @@ void TimelineRenderer::manageHovered(int mouseX, int mouseY)
void TimelineRenderer::clearData()
{
m_lastStartTime = 0;
m_lastEndTime = 0;
m_spacing = 0;
m_spacedDuration = 0;
resetCurrentSelection();
setStartTime(0);
setEndTime(0);
setSelectedItem(-1);
setSelectedModel(-1);
setSelectionLocked(true);
@@ -565,7 +572,7 @@ void TimelineRenderer::selectNext()
if (m_profilerModelProxy->isEmpty())
return;
qint64 searchTime = m_startTime;
qint64 searchTime = m_zoomer->rangeStart();
if (m_selectedItem != -1)
searchTime = m_profilerModelProxy->startTime(m_selectedModel, m_selectedItem);
@@ -586,7 +593,7 @@ void TimelineRenderer::selectNext()
}
int candidateModelIndex = -1;
qint64 candidateStartTime = m_profilerModelProxy->traceEndTime();
qint64 candidateStartTime = m_zoomer->traceEnd();
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++) {
if (itemIndexes[i] == -1)
continue;
@@ -603,7 +610,7 @@ void TimelineRenderer::selectNext()
} else {
// find the first index of them all (todo: the modelproxy should do this)
itemIndex = -1;
candidateStartTime = m_profilerModelProxy->traceEndTime();
candidateStartTime = m_zoomer->traceEnd();
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++)
if (m_profilerModelProxy->count(i) > 0 &&
m_profilerModelProxy->startTime(i,0) < candidateStartTime) {
@@ -621,7 +628,7 @@ void TimelineRenderer::selectPrev()
if (m_profilerModelProxy->isEmpty())
return;
qint64 searchTime = m_endTime;
qint64 searchTime = m_zoomer->rangeEnd();
if (m_selectedItem != -1)
searchTime = m_profilerModelProxy->startTime(m_selectedModel, m_selectedItem);
@@ -637,7 +644,7 @@ void TimelineRenderer::selectPrev()
}
int candidateModelIndex = -1;
qint64 candidateStartTime = m_profilerModelProxy->traceStartTime();
qint64 candidateStartTime = m_zoomer->traceStart();
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++) {
if (itemIndexes[i] == -1
|| itemIndexes[i] >= m_profilerModelProxy->count(i))
@@ -655,7 +662,7 @@ void TimelineRenderer::selectPrev()
} else {
// find the last index of them all (todo: the modelproxy should do this)
candidateModelIndex = 0;
candidateStartTime = m_profilerModelProxy->traceStartTime();
candidateStartTime = m_zoomer->traceStart();
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++)
if (m_profilerModelProxy->count(i) > 0 &&
m_profilerModelProxy->startTime(i,m_profilerModelProxy->count(i)-1) > candidateStartTime) {
@@ -676,7 +683,7 @@ int TimelineRenderer::nextItemFromSelectionId(int modelIndex, int selectionId) c
int ndx = -1;
if (m_selectedItem == -1 || modelIndex != m_selectedModel)
ndx = m_profilerModelProxy->firstIndexNoParents(modelIndex, m_startTime);
ndx = m_profilerModelProxy->firstIndexNoParents(modelIndex, m_zoomer->rangeStart());
else
ndx = m_selectedItem + 1;
@@ -695,7 +702,7 @@ int TimelineRenderer::prevItemFromSelectionId(int modelIndex, int selectionId) c
{
int ndx = -1;
if (m_selectedItem == -1 || modelIndex != m_selectedModel)
ndx = m_profilerModelProxy->firstIndexNoParents(modelIndex, m_startTime);
ndx = m_profilerModelProxy->firstIndexNoParents(modelIndex, m_zoomer->rangeStart());
else
ndx = m_selectedItem - 1;
if (ndx < 0)

View File

@@ -34,6 +34,7 @@
#include <QQuickPaintedItem>
#include <QJSValue>
#include "qmlprofilertimelinemodelproxy.h"
#include "timelinezoomcontrol.h"
#include "timelinemodelaggregator.h"
namespace QmlProfiler {
@@ -42,9 +43,8 @@ namespace Internal {
class TimelineRenderer : public QQuickPaintedItem
{
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 *profilerModelProxy READ profilerModelProxy WRITE setProfilerModelProxy NOTIFY profilerModelProxyChanged)
Q_PROPERTY(QObject *zoomer READ zoomer WRITE setZoomer NOTIFY zoomerChanged)
Q_PROPERTY(bool selectionLocked READ selectionLocked WRITE setSelectionLocked NOTIFY selectionLockedChanged)
Q_PROPERTY(int selectedItem READ selectedItem NOTIFY selectedItemChanged)
Q_PROPERTY(int selectedModel READ selectedModel NOTIFY selectedModelChanged)
@@ -54,16 +54,6 @@ class TimelineRenderer : public QQuickPaintedItem
public:
explicit TimelineRenderer(QQuickPaintedItem *parent = 0);
qint64 startTime() const
{
return m_startTime;
}
qint64 endTime() const
{
return m_endTime;
}
bool selectionLocked() const
{
return m_selectionLocked;
@@ -92,6 +82,9 @@ public:
TimelineModelAggregator *profilerModelProxy() const { return m_profilerModelProxy; }
void setProfilerModelProxy(QObject *profilerModelProxy);
TimelineZoomControl *zoomer() const { return m_zoomer; }
void setZoomer(QObject *zoomer);
Q_INVOKABLE int getYPosition(int modelIndex, int index) const;
Q_INVOKABLE void selectNext();
@@ -103,9 +96,8 @@ public:
Q_INVOKABLE void selectPrevFromSelectionId(int modelIndex, int selectionId);
signals:
void startTimeChanged(qint64 arg);
void endTimeChanged(qint64 arg);
void profilerModelProxyChanged(TimelineModelAggregator *list);
void zoomerChanged(TimelineZoomControl *zoomer);
void selectionLockedChanged(bool locked);
void selectedItemChanged(int itemIndex);
void selectedModelChanged(int modelIndex);
@@ -119,22 +111,6 @@ public slots:
void requestPaint();
void swapSelections(int modelIndex1, int modelIndex2);
void setStartTime(qint64 arg)
{
if (m_startTime != arg) {
m_startTime = arg;
emit startTimeChanged(arg);
}
}
void setEndTime(qint64 arg)
{
if (m_endTime != arg) {
m_endTime = arg;
emit endTimeChanged(arg);
}
}
void setSelectionLocked(bool locked)
{
if (m_selectionLocked != locked) {
@@ -205,15 +181,11 @@ private:
inline void getItemXExtent(int modelIndex, int i, int &currentX, int &itemWidth);
void resetCurrentSelection();
qint64 m_startTime;
qint64 m_endTime;
qreal m_spacing;
qreal m_spacedDuration;
qint64 m_lastStartTime;
qint64 m_lastEndTime;
TimelineModelAggregator *m_profilerModelProxy;
TimelineZoomControl *m_zoomer;
struct {
qint64 startTime;

View File

@@ -0,0 +1,173 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "timelinezoomcontrol.h"
namespace QmlProfiler {
TimelineZoomControl::TimelineZoomControl(QObject *parent) : QObject(parent), m_traceStart(-1), m_traceEnd(-1),
m_windowStart(-1), m_windowEnd(-1), m_rangeStart(-1), m_rangeEnd(-1), m_windowLocked(false)
{
connect(&m_timer, SIGNAL(timeout()), this, SLOT(moveWindow()));
}
void TimelineZoomControl::clear()
{
m_timer.stop();
setWindowLocked(false);
setRange(-1, -1);
setTrace(-1, -1);
}
void TimelineZoomControl::setTraceStart(qint64 start)
{
if (start != m_traceStart) {
if (m_traceEnd < start)
m_traceEnd = start;
m_traceStart = start;
emit traceChanged(start, m_traceEnd);
rebuildWindow();
}
}
void TimelineZoomControl::setTraceEnd(qint64 end)
{
if (end != m_traceEnd) {
if (m_traceStart > end)
m_traceStart = end;
m_traceEnd = end;
emit traceChanged(m_traceStart, end);
rebuildWindow();
}
}
void TimelineZoomControl::setTrace(qint64 start, qint64 end)
{
Q_ASSERT(start <= end);
if (start != m_traceStart || end != m_traceEnd) {
m_traceStart = start;
m_traceEnd = end;
emit traceChanged(start, end);
rebuildWindow();
}
}
void TimelineZoomControl::setRange(qint64 start, qint64 end)
{
Q_ASSERT(start <= end);
if (m_rangeStart != start || m_rangeEnd != end) {
m_timer.stop();
m_rangeStart = start;
m_rangeEnd = end;
rebuildWindow();
emit rangeChanged(start, end);
}
}
void TimelineZoomControl::setWindowLocked(bool windowLocked)
{
if (windowLocked != m_windowLocked) {
m_windowLocked = windowLocked;
emit windowLockedChanged(windowLocked);
}
}
void TimelineZoomControl::rebuildWindow()
{
qint64 minDuration = 1; // qMax needs equal data types, so literal 1 won't do
qint64 shownDuration = qMax(rangeDuration(), minDuration);
qint64 oldWindowStart = m_windowStart;
qint64 oldWindowEnd = m_windowEnd;
if (traceDuration() / shownDuration < MAX_ZOOM_FACTOR) {
m_windowStart = m_traceStart;
m_windowEnd = m_traceEnd;
} else if (windowDuration() / shownDuration > MAX_ZOOM_FACTOR ||
windowDuration() / shownDuration * 2 < MAX_ZOOM_FACTOR) {
qint64 keep = shownDuration * MAX_ZOOM_FACTOR / 2 - shownDuration;
m_windowStart = m_rangeStart - keep;
if (m_windowStart < m_traceStart) {
keep += m_traceStart - m_windowStart;
m_windowStart = m_traceStart;
}
m_windowEnd = m_rangeEnd + keep;
if (m_windowEnd > m_traceEnd) {
m_windowStart = qMax(m_traceStart, m_windowStart - m_windowEnd - m_traceEnd);
m_windowEnd = m_traceEnd;
}
} else {
m_timer.start(500);
}
if (oldWindowStart != m_windowStart || oldWindowEnd != m_windowEnd) {
clampRangeToWindow();
emit windowChanged(m_windowStart, m_windowEnd);
}
}
void TimelineZoomControl::moveWindow()
{
if (m_windowLocked)
return;
m_timer.stop();
qint64 offset = (m_rangeEnd - m_windowEnd + m_rangeStart - m_windowStart) / 2;
if (offset == 0 || (offset < 0 && m_windowStart == m_traceStart) ||
(offset > 0 && m_windowEnd == m_traceEnd)) {
return;
} else if (offset > rangeDuration()) {
offset = (offset + rangeDuration()) / 2;
} else if (offset < -rangeDuration()) {
offset = (offset - rangeDuration()) / 2;
}
m_windowStart += offset;
if (m_windowStart < m_traceStart) {
m_windowEnd += m_traceStart - m_windowStart;
m_windowStart = m_traceStart;
}
m_windowEnd += offset;
if (m_windowEnd > m_traceEnd) {
m_windowStart -= m_windowEnd - m_traceEnd;
m_windowEnd = m_traceEnd;
}
clampRangeToWindow();
emit windowChanged(m_windowStart, m_windowEnd);
m_timer.start(100);
}
void TimelineZoomControl::clampRangeToWindow()
{
qint64 rangeStart = qMin(qMax(m_rangeStart, m_windowStart), m_windowEnd);
qint64 rangeEnd = qMin(qMax(rangeStart, m_rangeEnd), m_windowEnd);
if (rangeStart != m_rangeStart || rangeEnd != m_rangeEnd)
setRange(rangeStart, rangeEnd);
}
}

View File

@@ -0,0 +1,105 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef TIMELINEZOOMCONTROL_H
#define TIMELINEZOOMCONTROL_H
#include <QTimer>
namespace QmlProfiler {
class TimelineZoomControl : public QObject {
Q_OBJECT
Q_PROPERTY(qint64 traceStart READ traceStart WRITE setTraceStart NOTIFY traceChanged)
Q_PROPERTY(qint64 traceEnd READ traceEnd WRITE setTraceEnd NOTIFY traceChanged)
Q_PROPERTY(qint64 traceDuration READ traceDuration NOTIFY traceChanged)
Q_PROPERTY(qint64 windowStart READ windowStart NOTIFY windowChanged)
Q_PROPERTY(qint64 windowEnd READ windowEnd NOTIFY windowChanged)
Q_PROPERTY(qint64 windowDuration READ windowDuration NOTIFY windowChanged)
Q_PROPERTY(qint64 rangeStart READ rangeStart NOTIFY rangeChanged)
Q_PROPERTY(qint64 rangeEnd READ rangeEnd NOTIFY rangeChanged)
Q_PROPERTY(qint64 rangeDuration READ rangeDuration NOTIFY rangeChanged)
Q_PROPERTY(bool windowLocked READ windowLocked WRITE setWindowLocked NOTIFY windowLockedChanged)
public:
static const qint64 MAX_ZOOM_FACTOR = 1 << 12;
TimelineZoomControl(QObject *parent = 0);
qint64 traceStart() const { return m_traceStart; }
qint64 traceEnd() const { return m_traceEnd; }
qint64 traceDuration() const { return m_traceEnd - m_traceStart; }
qint64 windowStart() const { return m_windowStart; }
qint64 windowEnd() const { return m_windowEnd; }
qint64 windowDuration() const { return m_windowEnd - m_windowStart; }
qint64 rangeStart() const { return m_rangeStart; }
qint64 rangeEnd() const { return m_rangeEnd; }
qint64 rangeDuration() const { return m_rangeEnd - m_rangeStart; }
bool windowLocked() const { return m_windowLocked; }
virtual void clear();
signals:
void traceChanged(qint64 start, qint64 end);
void windowChanged(qint64 start, qint64 end);
void rangeChanged(qint64 start, qint64 end);
void windowLockedChanged(bool windowLocked);
public slots:
void setTraceStart(qint64 start);
void setTraceEnd(qint64 end);
void setTrace(qint64 start, qint64 end);
void setRange(qint64 start, qint64 end);
void setWindowLocked(bool windowLocked);
protected slots:
void moveWindow();
protected:
qint64 m_traceStart;
qint64 m_traceEnd;
qint64 m_windowStart;
qint64 m_windowEnd;
qint64 m_rangeStart;
qint64 m_rangeEnd;
QTimer m_timer;
bool m_windowLocked;
void rebuildWindow();
void clampRangeToWindow();
};
}
#endif // TIMELINEZOOMCONTROL_H