QmlProfiler: first commit

This commit is contained in:
Christiaan Janssen
2011-03-11 12:22:57 +01:00
parent 39daf23247
commit f774556de7
40 changed files with 4337 additions and 1 deletions

View File

@@ -0,0 +1,34 @@
import QtQuick 1.1
import Monitor 1.0
import "MainView.js" as Plotter
Item {
id: detail
property string label
property string content
property int maxLines: 4
signal linkActivated(string url)
height: childrenRect.height
width: childrenRect.width
Item {
id: guideline
x: 70
width: 5
}
Text {
id: lbl
text: label + ":"
font.pixelSize: 12
font.bold: true
anchors.right: guideline.left
}
Text {
text: content
font.pixelSize: 12
anchors.baseline: lbl.baseline
anchors.left: guideline.right
maximumLineCount: maxLines
onLinkActivated: detail.linkActivated(link)
}
}

View File

@@ -0,0 +1,26 @@
import QtQuick 1.1
import Monitor 1.0
import "MainView.js" as Plotter
Text {
id: elapsed
color: "white"
Timer {
property date startDate
property bool reset: true
running: connection.recording
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
elapsed.text = time.toFixed(1) + "s"
}
}
}

View File

@@ -0,0 +1,23 @@
import QtQuick 1.1
Item {
property alias text: txt.text
height: 50
width: 150 //### required, or ignored by positioner
Text {
id: txt;
x: 5
font.pixelSize: 12
color: "#232323"
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
height: 1
width: parent.width
color: "#cccccc"
anchors.bottom: parent.bottom
}
}

View File

@@ -0,0 +1,110 @@
.pragma library
var values = [ ]; //events
var ranges = [ ];
var frameFps = [ ];
var valuesdone = false;
var xmargin = 0;
var ymargin = 0;
var names = [ "Painting", "Compiling", "Creating", "Binding", "Handling Signal"]
//### need better way to manipulate color from QML. In the meantime, these need to be kept in sync.
var colors = [ "#99CCB3", "#99CCCC", "#99B3CC", "#9999CC", "#CC99B3", "#CC99CC", "#CCCC99", "#CCB399" ];
var origColors = [ "#99CCB3", "#99CCCC", "#99B3CC", "#9999CC", "#CC99B3", "#CC99CC", "#CCCC99", "#CCB399" ];
var xRayColors = [ "#6699CCB3", "#6699CCCC", "#6699B3CC", "#669999CC", "#66CC99B3", "#66CC99CC", "#66CCCC99", "#66CCB399" ];
function reset()
{
values = [];
ranges = [];
frameFps = [];
xmargin = 0;
ymargin = 0;
valuesdone = false;
}
function calcFps()
{
if (values.length)
frameFps = new Array(values.length - 1);
for (var i = 0; i < values.length - 1; ++i) {
var frameTime = (values[i + 1] - values[i]) / 1000000;
frameFps[i] = 1000 / frameTime;
}
}
//draw background of the graph
function drawGraph(canvas, ctxt, region)
{
var grad = ctxt.createLinearGradient(0, 0, 0, canvas.canvasSize.height);
grad.addColorStop(0, '#fff');
grad.addColorStop(1, '#ccc');
ctxt.fillStyle = grad;
ctxt.fillRect(0, 0, canvas.canvasSize.width + xmargin, canvas.canvasSize.height - ymargin);
}
//draw the actual data to be graphed
function drawData(canvas, ctxt, region)
{
if (values.length == 0 && ranges.length == 0)
return;
var width = canvas.canvasSize.width - xmargin;
var height = canvas.height - ymargin;
var sumValue = ranges[ranges.length - 1].start + ranges[ranges.length - 1].duration - ranges[0].start;
var spacing = width / sumValue;
//### only draw those in range
for (var ii = 0; ii < ranges.length; ++ii) {
var xx = (ranges[ii].start - ranges[0].start) * spacing + xmargin;
if (xx > region.x + region.width)
continue;
var size = ranges[ii].duration * spacing;
if (xx + size < region.x)
continue;
if (size < 0.5)
size = 0.5;
ctxt.fillStyle = "rgba(0,0,0,1)" //colors[ranges[ii].type];
ctxt.fillRect(xx, ranges[ii].type*10, size, 10);
}
//draw fps overlay
var heightScale = height / 60;
ctxt.beginPath();
ctxt.moveTo(0,0);
for (var i = 1; i < values.length; ++i) {
var xx = (values[i] - ranges[0].start) * spacing + xmargin;
ctxt.lineTo(xx, height - frameFps[i-1]*heightScale)
}
ctxt.lineTo(width, 0);
ctxt.closePath();
var grad = ctxt.createLinearGradient(0, 0, 0, canvas.canvasSize.height);
grad.addColorStop(0, "rgba(255,128,128,.5)");
grad.addColorStop(1, "rgba(255,0,0,.5)");
ctxt.fillStyle = grad;
ctxt.fill();
}
function plot(canvas, ctxt, region)
{
drawGraph(canvas, ctxt, region);
drawData(canvas, ctxt, region);
}
function xScale(canvas)
{
if (values.length === 0 && ranges.length === 0)
return;
var width = canvas.canvasSize.width - xmargin;
var sumValue = ranges[ranges.length - 1].start + ranges[ranges.length - 1].duration - ranges[0].start;
var spacing = sumValue / width;
return spacing;
}

View File

@@ -0,0 +1,262 @@
import QtQuick 1.1
import Monitor 1.0
import "MainView.js" as Plotter
Rectangle {
id: root
property variant colors: Plotter.colors //the colors used for the timeline data
property bool xRay: false //useful for seeing "nested" ranges (but redraw is buggy -- QGV problem?)
property Item currentItem //currently selected item in the view
property bool zooming:false
// move the cursor in the editor
signal updateCursorPosition
property string fileName: ""
property int lineNumber: -1
function gotoSourceLocation(file,line) {
root.fileName = file;
root.lineNumber = line;
root.updateCursorPosition();
}
//handle debug data coming from C++
Connections {
target: connection
onEvent: {
if (Plotter.valuesdone) {
Plotter.reset();
view.clearData();
rangeMover.x = 2
rangeMover.opacity = 0
}
if (!Plotter.valuesdone && event === 0) //### only handle paint event
Plotter.values.push(time);
}
onRange: {
if (Plotter.valuesdone) {
Plotter.reset();
view.clearData();
rangeMover.x = 2
rangeMover.opacity = 0
}
if (!Plotter.valuesdone)
Plotter.ranges.push( { type: type, start: startTime, duration: length, label: data, fileName: fileName, line: line } );
}
onComplete: {
Plotter.valuesdone = true;
Plotter.calcFps();
view.setRanges(Plotter.ranges);
view.updateTimeline();
canvas.requestPaint();
rangeMover.x = 1 //### hack to get view to display things immediately
rangeMover.opacity = 1
}
}
//timeline background
Item {
anchors.fill: flick
Column {
anchors.fill: parent
Repeater {
model: 5 //### values.length?
delegate: Rectangle {
width: parent.width
height: 50 //###
color: index % 2 ? "#fafafa" : "white"
}
}
}
}
//our main interaction view
Flickable {
id: flick
anchors.top: parent.top
anchors.right: parent.right
anchors.left: labels.right
anchors.bottom: canvas.top
contentWidth: view.totalWidth
contentHeight: view.height
TimelineView {
id: view
width: flick.width; height: flick.height
startX: flick.contentX
onStartXChanged: {
var newX = startTime / Plotter.xScale(canvas) - canvas.canvasWindow.x;
if (Math.abs(rangeMover.x - newX) > .01)
rangeMover.x = newX
if (Math.abs(startX - flick.contentX) > .01)
flick.contentX = startX
}
startTime: rangeMover.value
property real prevXStep: -1
property real possibleEndTime: startTime + (rangeMover.width*Plotter.xScale(canvas))
onPossibleEndTimeChanged: {
var set = ((zooming && prevXStep != canvas.canvasWindow.x) || !zooming);
prevXStep = canvas.canvasWindow.x;
if (set)
endTime = possibleEndTime
}
onEndTimeChanged: updateTimeline()
delegate: Rectangle {
id: obj
property color baseColor: colors[type]
property color myColor: baseColor
function conditionalHide() {
if (!mouseArea.containsMouse)
mouseArea.exited()
}
height: 50
gradient: Gradient {
GradientStop { position: 0.0; color: myColor }
GradientStop { position: 0.5; color: Qt.darker(myColor, 1.1) }
GradientStop { position: 1.0; color: myColor }
}
smooth: true
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onEntered: {
currentItem = obj
myColor = Qt.darker(baseColor, 1.2)
rangeDetails.duration = duration
rangeDetails.label = label
rangeDetails.file = fileName
rangeDetails.line = line
rangeDetails.type = Plotter.names[type]
var pos = mapToItem(rangeDetails.parent, mouseX, y+height)
var preferredX = Math.max(10, pos.x - rangeDetails.width/2)
if (preferredX + rangeDetails.width > rangeDetails.parent.width)
preferredX = rangeDetails.parent.width - rangeDetails.width
rangeDetails.x = preferredX
rangeDetails.y = pos.y + 10
rangeDetails.visible = true
}
onExited: {
myColor = baseColor
rangeDetails.visible = false
rangeDetails.duration = ""
rangeDetails.label = ""
rangeDetails.type = ""
rangeDetails.file = ""
rangeDetails.line = -1
}
onClicked: root.gotoSourceLocation(rangeDetails.file, rangeDetails.line);
}
}
}
}
//popup showing the details for the hovered range
RangeDetails {
id: rangeDetails
}
Rectangle {
id: labels
width: 150
color: "#dcdcdc"
anchors.top: root.top
anchors.bottom: canvas.top
Column {
//### change to use Repeater + Plotter.names?
Label { text: "Painting" }
Label { text: "Compiling" }
Label { text: "Creating" }
Label { text: "Binding" }
Label { text: "Signal Handler" }
}
//right border divider
Rectangle {
width: 1
height: parent.height
anchors.right: parent.right
color: "#cccccc"
}
}
//bottom border divider
Rectangle {
height: 1
width: parent.width
anchors.bottom: canvas.top
color: "#cccccc"
}
//"overview" graph at the bottom
TiledCanvas {
id: canvas
anchors.bottom: parent.bottom
width: parent.width; height: 50
property int canvasWidth: width
canvasSize {
width: canvasWidth
height: canvas.height
}
tileSize.width: width
tileSize.height: height
canvasWindow.width: width
canvasWindow.height: 50
onDrawRegion: {
if (Plotter.valuesdone)
Plotter.plot(canvas, ctxt, region);
else
Plotter.drawGraph(canvas, ctxt, region) //just draw the background
}
}
//moves the range mover to the position of a click
MouseArea {
anchors.fill: canvas
//### ideally we could press to position then immediately drag
onPressed: rangeMover.x = mouse.x - rangeMover.width/2
}
RangeMover {
id: rangeMover
opacity: 0
anchors.top: canvas.top
}
Rectangle {
width: 50
height: 30
anchors.right: root.right
anchors.top: root.top
radius: 4
color: "#606085"
Elapsed {
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
}
}
}

View File

@@ -0,0 +1,20 @@
<plugin name=\"QmlProfiler\" version=\"$$QTCREATOR_VERSION\" compatVersion=\"$$QTCREATOR_VERSION\">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2011 Nokia Corporation</copyright>
<license>
Commercial Usage
Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and Nokia.
GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. 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.
</license>
<description>Qml Profiler Plugin</description>
<url>http://qt.nokia.com</url>
<dependencyList>
<dependency name=\"Core\" version=\"$$QTCREATOR_VERSION\"/>
<dependency name=\"ProjectExplorer\" version=\"$$QTCREATOR_VERSION\"/>
<dependency name=\"AnalyzerBase\" version=\"$$QTCREATOR_VERSION\"/>
</dependencyList>
</plugin>

View File

@@ -0,0 +1,61 @@
import QtQuick 1.1
import Monitor 1.0
import "MainView.js" as Plotter
BorderImage {
id: rangeDetails
property string duration //###int?
property string label
property string type
property string file
property int line
source: "popup.png"
border {
left: 10; top: 10
right: 20; bottom: 20
}
width: col.width + 45
height: childrenRect.height + 30
z: 1
visible: false
//title
Text {
id: typeTitle
text: rangeDetails.type
font.bold: true
y: 10
anchors.horizontalCenter: parent.horizontalCenter
anchors.horizontalCenterOffset: -5
}
//details
Column {
id: col
anchors.top: typeTitle.bottom
Detail {
label: "Duration"
content: rangeDetails.duration + "μs"
}
Detail {
opacity: content.length !== 0 ? 1 : 0
label: "Details"
content: rangeDetails.label
}
Detail {
opacity: content.length !== 0 ? 1 : 0
label: "Location"
content: {
var file = rangeDetails.file
var pos = file.lastIndexOf("/")
if (pos != -1)
file = file.substr(pos+1)
return (file.length !== 0) ? (file + ":" + rangeDetails.line) : "";
}
onLinkActivated: Qt.openUrlExternally(url)
}
}
}

View File

@@ -0,0 +1,62 @@
import "MainView.js" as Plotter
import QtQuick 1.1
import Monitor 1.0
Item {
id: rangeMover
width: rect.width; height: 50
property real prevXStep: -1
property real possibleValue: (canvas.canvasWindow.x + x) * Plotter.xScale(canvas)
onPossibleValueChanged: {
var set = (!zooming || (zooming && prevXStep != canvas.canvasWindow.x))
prevXStep = canvas.canvasWindow.x;
if (set)
value = possibleValue
}
property real value
//onValueChanged: console.log("*************** " + value)
/*Image {
id: leftRange
source: "range.png"
anchors.horizontalCenter: parent.left
anchors.bottom: parent.bottom
}*/
Rectangle {
id: rect
color: "#cc80b2f6"
width: 20
//anchors.left: parent.left
//anchors.right: rightRange.horizontalCenter
height: parent.height
}
/*Image {
id: rightRange
source: "range.png"
x: 13
anchors.bottom: parent.bottom
MouseArea {
width: parent.width
height: 15
drag.target: rightRange
drag.axis: "XAxis"
drag.minimumX: -7 //###
drag.maximumX: canvas.width - rangeMover.width //###
}
}*/
MouseArea {
anchors.fill: parent
drag.target: rangeMover
drag.axis: "XAxis"
drag.minimumX: 0
drag.maximumX: canvas.width - rangeMover.width //###
}
}

View File

@@ -0,0 +1,53 @@
import QtQuick 1.1
Rectangle {
id: button
property alias text: textItem.text
property bool recording: false
signal clicked
width: 80; height: textItem.height + 8
border.width: 1
border.color: Qt.darker(button.color, 1.4)
radius: height/2
smooth: true
color: "#049e0e"
Text {
id: textItem
anchors.centerIn: parent
font.pixelSize: 14
color: "white"
text: "Recording"
}
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: {
recording = !recording;
button.clicked()
}
}
StateGroup {
id: recordState
states: State {
name: "recording"
when: recording
PropertyChanges { target: button; color: "#ff120c"; }
PropertyChanges { target: textItem; text: "Stop" }
}
}
StateGroup {
states: State {
name: "pressed"; when: mouseArea.pressed && mouseArea.containsMouse
PropertyChanges { target: button; color: Qt.darker(color, 1.1); explicit: true }
PropertyChanges { target: textItem; x: textItem.x + 1; y: textItem.y + 1; explicit: true }
}
}
}

View File

@@ -0,0 +1,27 @@
import QtQuick 1.1
import Monitor 1.0
import "MainView.js" as Plotter
Rectangle {
property string label
signal clicked
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -1
width: 30; height: 22
border.color: "#cc80b2f6"
color: "transparent"
Text {
anchors.centerIn: parent
text: label
color: "white"
font.pixelSize: 14
}
MouseArea {
anchors.fill: parent
onClicked: parent.clicked()
}
}

View File

@@ -0,0 +1,11 @@
INCLUDEPATH += $$PWD
HEADERS += $$PWD/qdeclarativecontext2d_p.h \
$$PWD/qdeclarativecanvas_p.h \
$$PWD/qdeclarativetiledcanvas_p.h \
$$PWD/qdeclarativecanvastimer_p.h
SOURCES += $$PWD/qdeclarativecontext2d.cpp \
$$PWD/qdeclarativecanvas.cpp \
$$PWD/qdeclarativetiledcanvas.cpp \
$$PWD/qdeclarativecanvastimer.cpp

View File

@@ -0,0 +1,257 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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, 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qdeclarativecanvas_p.h"
#include "qdeclarativecanvastimer_p.h"
#include "qdeclarativecontext2d_p.h"
#include <QtGui/qpainter.h>
QT_BEGIN_NAMESPACE
Canvas::Canvas(QDeclarativeItem *parent)
: QDeclarativeItem(parent),
m_context(new Context2D(this)),
m_canvasWidth(0),
m_canvasHeight(0),
m_fillMode(Canvas::Stretch),
m_color(Qt::white)
{
setFlag(QGraphicsItem::ItemHasNoContents, false);
setCacheMode(QGraphicsItem::DeviceCoordinateCache);
}
void Canvas::componentComplete()
{
if (m_canvasWidth == 0 && m_canvasHeight == 0)
m_context->setSize(width(), height());
else
m_context->setSize(m_canvasWidth, m_canvasHeight);
connect(m_context, SIGNAL(changed()), this, SLOT(requestPaint()));
emit init();
QDeclarativeItem::componentComplete();
}
void Canvas::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
m_context->setInPaint(true);
emit paint();
bool oldAA = painter->testRenderHint(QPainter::Antialiasing);
bool oldSmooth = painter->testRenderHint(QPainter::SmoothPixmapTransform);
if (smooth())
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, smooth());
if (m_context->pixmap().isNull()) {
painter->fillRect(0, 0, width(), height(), m_color);
} else if (width() != m_context->pixmap().width() || height() != m_context->pixmap().height()) {
if (m_fillMode>= Tile) {
if (m_fillMode== Tile) {
painter->drawTiledPixmap(QRectF(0,0,width(),height()), m_context->pixmap());
} else {
qreal widthScale = width() / qreal(m_context->pixmap().width());
qreal heightScale = height() / qreal(m_context->pixmap().height());
QTransform scale;
if (m_fillMode== TileVertically) {
scale.scale(widthScale, 1.0);
QTransform old = painter->transform();
painter->setWorldTransform(scale * old);
painter->drawTiledPixmap(QRectF(0,0,m_context->pixmap().width(),height()), m_context->pixmap());
painter->setWorldTransform(old);
} else {
scale.scale(1.0, heightScale);
QTransform old = painter->transform();
painter->setWorldTransform(scale * old);
painter->drawTiledPixmap(QRectF(0,0,width(),m_context->pixmap().height()), m_context->pixmap());
painter->setWorldTransform(old);
}
}
} else {
qreal widthScale = width() / qreal(m_context->pixmap().width());
qreal heightScale = height() / qreal(m_context->pixmap().height());
QTransform scale;
if (m_fillMode== PreserveAspectFit) {
if (widthScale <= heightScale) {
heightScale = widthScale;
scale.translate(0, (height() - heightScale * m_context->pixmap().height()) / 2);
} else if (heightScale < widthScale) {
widthScale = heightScale;
scale.translate((width() - widthScale * m_context->pixmap().width()) / 2, 0);
}
} else if (m_fillMode== PreserveAspectCrop) {
if (widthScale < heightScale) {
widthScale = heightScale;
scale.translate((width() - widthScale * m_context->pixmap().width()) / 2, 0);
} else if (heightScale < widthScale) {
heightScale = widthScale;
scale.translate(0, (height() - heightScale * m_context->pixmap().height()) / 2);
}
}
if (clip()) {
painter->save();
painter->setClipRect(boundingRect(), Qt::IntersectClip);
}
scale.scale(widthScale, heightScale);
QTransform old = painter->transform();
painter->setWorldTransform(scale * old);
painter->drawPixmap(0, 0, m_context->pixmap());
painter->setWorldTransform(old);
if (clip()) {
painter->restore();
}
}
} else {
painter->drawPixmap(0, 0, m_context->pixmap());
}
if (smooth()) {
painter->setRenderHint(QPainter::Antialiasing, oldAA);
painter->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth);
}
m_context->setInPaint(false);
}
Context2D *Canvas::getContext(const QString &contextId)
{
if (contextId == QLatin1String("2d"))
return m_context;
qDebug("Canvas:requesting unsupported context");
return 0;
}
void Canvas::requestPaint()
{
update();
}
void Canvas::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
if (m_canvasWidth == 0 && m_canvasHeight == 0
&& newGeometry.width() > 0 && newGeometry.height() > 0) {
m_context->setSize(width(), height());
}
QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
}
void Canvas::setCanvasWidth(int newWidth)
{
if (m_canvasWidth != newWidth) {
m_canvasWidth = newWidth;
m_context->setSize(m_canvasWidth, m_canvasHeight);
emit canvasWidthChanged();
}
}
void Canvas::setCanvasHeight(int newHeight)
{
if (m_canvasHeight != newHeight) {
m_canvasHeight = newHeight;
m_context->setSize(m_canvasWidth, m_canvasHeight);
emit canvasHeightChanged();
}
}
void Canvas::setFillMode(FillMode mode)
{
if (m_fillMode == mode)
return;
m_fillMode = mode;
update();
emit fillModeChanged();
}
QColor Canvas::color()
{
return m_color;
}
void Canvas::setColor(const QColor &color)
{
if (m_color !=color) {
m_color = color;
colorChanged();
}
}
Canvas::FillMode Canvas::fillMode() const
{
return m_fillMode;
}
bool Canvas::save(const QString &filename) const
{
return m_context->pixmap().save(filename);
}
CanvasImage *Canvas::toImage() const
{
return new CanvasImage(m_context->pixmap());
}
void Canvas::setTimeout(const QScriptValue &handler, long timeout)
{
if (handler.isFunction())
CanvasTimer::createTimer(this, handler, timeout, true);
}
void Canvas::setInterval(const QScriptValue &handler, long interval)
{
if (handler.isFunction())
CanvasTimer::createTimer(this, handler, interval, false);
}
void Canvas::clearTimeout(const QScriptValue &handler)
{
CanvasTimer::removeTimer(handler);
}
void Canvas::clearInterval(const QScriptValue &handler)
{
CanvasTimer::removeTimer(handler);
}
QT_END_NAMESPACE

View File

@@ -0,0 +1,124 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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, 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QDECLARATIVECANVAS_P_H
#define QDECLARATIVECANVAS_P_H
#include <QtDeclarative/qdeclarativeitem.h>
#include "qdeclarativecontext2d_p.h"
#include "qdeclarativecanvastimer_p.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class Canvas : public QDeclarativeItem
{
Q_OBJECT
Q_ENUMS(FillMode)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged);
Q_PROPERTY(int canvasWidth READ canvasWidth WRITE setCanvasWidth NOTIFY canvasWidthChanged);
Q_PROPERTY(int canvasHeight READ canvasHeight WRITE setCanvasHeight NOTIFY canvasHeightChanged);
Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged)
public:
Canvas(QDeclarativeItem *parent = 0);
enum FillMode { Stretch, PreserveAspectFit, PreserveAspectCrop, Tile, TileVertically, TileHorizontally };
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
void setCanvasWidth(int newWidth);
int canvasWidth() {return m_canvasWidth;}
void setCanvasHeight(int canvasHeight);
int canvasHeight() {return m_canvasHeight;}
void componentComplete();
public Q_SLOTS:
Context2D *getContext(const QString & = QString("2d"));
void requestPaint();
FillMode fillMode() const;
void setFillMode(FillMode);
QColor color();
void setColor(const QColor &);
// Save current canvas to disk
bool save(const QString& filename) const;
// Timers
void setInterval(const QScriptValue &handler, long timeout);
void setTimeout(const QScriptValue &handler, long timeout);
void clearInterval(const QScriptValue &handler);
void clearTimeout(const QScriptValue &handler);
Q_SIGNALS:
void fillModeChanged();
void canvasWidthChanged();
void canvasHeightChanged();
void colorChanged();
void init();
void paint();
private:
// Return canvas contents as a drawable image
CanvasImage *toImage() const;
Context2D *m_context;
int m_canvasWidth;
int m_canvasHeight;
FillMode m_fillMode;
QColor m_color;
friend class Context2D;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif //QDECLARATIVECANVAS_P_H

View File

@@ -0,0 +1,98 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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, 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtScript/qscriptengine.h>
#include <QtScript/qscriptvalue.h>
#include <QtCore/qtimer.h>
#include "qdeclarativecanvastimer_p.h"
QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(QList<CanvasTimer*> , activeTimers);
CanvasTimer::CanvasTimer(QObject *parent, const QScriptValue &data)
: QTimer(parent), m_value(data)
{
}
void CanvasTimer::handleTimeout()
{
Q_ASSERT(m_value.isFunction());
m_value.call();
if (isSingleShot()) {
removeTimer(this);
}
}
void CanvasTimer::createTimer(QObject *parent, const QScriptValue &val, long timeout, bool singleshot)
{
CanvasTimer *timer = new CanvasTimer(parent, val);
timer->setInterval(timeout);
timer->setSingleShot(singleshot);
connect(timer, SIGNAL(timeout()), timer, SLOT(handleTimeout()));
activeTimers()->append(timer);
timer->start();
}
void CanvasTimer::removeTimer(CanvasTimer *timer)
{
activeTimers()->removeAll(timer);
timer->deleteLater();
}
void CanvasTimer::removeTimer(const QScriptValue &val)
{
if (!val.isFunction())
return;
for (int i = 0 ; i < activeTimers()->count() ; ++i) {
CanvasTimer *timer = activeTimers()->at(i);
if (timer->equals(val)) {
removeTimer(timer);
return;
}
}
}
QT_END_NAMESPACE

View File

@@ -0,0 +1,80 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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, 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QDECLARATIVECANVASTIMER_P_H
#define QDECLARATIVECANVASTIMER_P_H
#include <QtScript/qscriptvalue.h>
#include <QtCore/qtimer.h>
#include <QtCore/qlist.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class CanvasTimer : public QTimer
{
Q_OBJECT
public:
CanvasTimer(QObject *parent, const QScriptValue &data);
public Q_SLOTS:
void handleTimeout();
bool equals(const QScriptValue &value){return m_value.equals(value);}
public:
static void createTimer(QObject *parent, const QScriptValue &val, long timeout, bool singleshot);
static void removeTimer(CanvasTimer *timer);
static void removeTimer(const QScriptValue &);
private:
QScriptValue m_value;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QDECLARATIVECANVASTIMER_P_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,342 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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, 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QDECLARATIVECONTEXT2D_P_H
#define QDECLARATIVECONTEXT2D_P_H
#include <QtGui/qpainter.h>
#include <QtGui/qpainterpath.h>
#include <QtGui/qpixmap.h>
#include <QtCore/qstring.h>
#include <QtCore/qstack.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qvariant.h>
#include <QtScript/qscriptvalue.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
QColor colorFromString(const QString &name);
class CanvasGradient : public QObject
{
Q_OBJECT
public:
CanvasGradient(const QGradient &gradient) : m_gradient(gradient) {}
public slots:
QGradient value() { return m_gradient; }
void addColorStop(float pos, const QString &color) { m_gradient.setColorAt(pos, colorFromString(color));}
public:
QGradient m_gradient;
};
Q_DECLARE_METATYPE(CanvasGradient*)
class CanvasImage: public QObject
{
Q_OBJECT
Q_PROPERTY(QString src READ src WRITE setSrc NOTIFY sourceChanged)
Q_PROPERTY(int width READ width)
Q_PROPERTY(int height READ height)
public:
CanvasImage() {}
CanvasImage(const QString &url) : m_image(url), m_src(url) {}
CanvasImage(const QPixmap &pixmap) {m_image = pixmap;}
public slots:
int width() { return m_image.width(); }
int height() { return m_image.height(); }
QPixmap &value() { return m_image; }
QString src() { return m_src; }
void setSrc(const QString &src) { m_src = src; m_image.load(src); emit sourceChanged();}
signals:
void sourceChanged();
private:
QPixmap m_image;
QString m_src;
};
Q_DECLARE_METATYPE(CanvasImage*)
class ImageData {
};
class Context2D : public QObject
{
Q_OBJECT
// compositing
Q_PROPERTY(qreal globalAlpha READ globalAlpha WRITE setGlobalAlpha)
Q_PROPERTY(QString globalCompositeOperation READ globalCompositeOperation WRITE setGlobalCompositeOperation)
Q_PROPERTY(QVariant strokeStyle READ strokeStyle WRITE setStrokeStyle)
Q_PROPERTY(QVariant fillStyle READ fillStyle WRITE setFillStyle)
// line caps/joins
Q_PROPERTY(qreal lineWidth READ lineWidth WRITE setLineWidth)
Q_PROPERTY(QString lineCap READ lineCap WRITE setLineCap)
Q_PROPERTY(QString lineJoin READ lineJoin WRITE setLineJoin)
Q_PROPERTY(qreal miterLimit READ miterLimit WRITE setMiterLimit)
// shadows
Q_PROPERTY(qreal shadowOffsetX READ shadowOffsetX WRITE setShadowOffsetX)
Q_PROPERTY(qreal shadowOffsetY READ shadowOffsetY WRITE setShadowOffsetY)
Q_PROPERTY(qreal shadowBlur READ shadowBlur WRITE setShadowBlur)
Q_PROPERTY(QString shadowColor READ shadowColor WRITE setShadowColor)
// fonts
Q_PROPERTY(QString font READ font WRITE setFont)
Q_PROPERTY(QString textBaseline READ textBaseline WRITE setTextBaseline)
Q_PROPERTY(QString textAlign READ textAlign WRITE setTextAlign)
enum TextBaseLine { Alphabetic=0, Top, Middle, Bottom, Hanging};
enum TextAlign { Start=0, End, Left, Right, Center};
public:
Context2D(QObject *parent = 0);
void setSize(int width, int height);
void setSize(const QSize &size);
QSize size() const;
QPoint painterTranslate() const;
void setPainterTranslate(const QPoint &);
void scheduleChange();
void timerEvent(QTimerEvent *e);
void clear();
void reset();
QPixmap pixmap() { return m_pixmap; }
// compositing
qreal globalAlpha() const; // (default 1.0)
QString globalCompositeOperation() const; // (default over)
QVariant strokeStyle() const; // (default black)
QVariant fillStyle() const; // (default black)
void setGlobalAlpha(qreal alpha);
void setGlobalCompositeOperation(const QString &op);
void setStrokeStyle(const QVariant &style);
void setFillStyle(const QVariant &style);
// line caps/joins
qreal lineWidth() const; // (default 1)
QString lineCap() const; // "butt", "round", "square" (default "butt")
QString lineJoin() const; // "round", "bevel", "miter" (default "miter")
qreal miterLimit() const; // (default 10)
void setLineWidth(qreal w);
void setLineCap(const QString &s);
void setLineJoin(const QString &s);
void setMiterLimit(qreal m);
void setFont(const QString &font);
QString font();
void setTextBaseline(const QString &font);
QString textBaseline();
void setTextAlign(const QString &font);
QString textAlign();
// shadows
qreal shadowOffsetX() const; // (default 0)
qreal shadowOffsetY() const; // (default 0)
qreal shadowBlur() const; // (default 0)
QString shadowColor() const; // (default black)
void setShadowOffsetX(qreal x);
void setShadowOffsetY(qreal y);
void setShadowBlur(qreal b);
void setShadowColor(const QString &str);
struct MouseArea {
QScriptValue callback;
QScriptValue data;
QRectF rect;
QMatrix matrix;
};
const QList<MouseArea> &mouseAreas() const;
public slots:
void save(); // push state on state stack
void restore(); // pop state stack and restore state
void fillText(const QString &text, qreal x, qreal y);
void strokeText(const QString &text, qreal x, qreal y);
void setInPaint(bool val){m_inPaint = val;}
void scale(qreal x, qreal y);
void rotate(qreal angle);
void translate(qreal x, qreal y);
void transform(qreal m11, qreal m12, qreal m21, qreal m22,
qreal dx, qreal dy);
void setTransform(qreal m11, qreal m12, qreal m21, qreal m22,
qreal dx, qreal dy);
CanvasGradient *createLinearGradient(qreal x0, qreal y0,
qreal x1, qreal y1);
CanvasGradient *createRadialGradient(qreal x0, qreal y0,
qreal r0, qreal x1,
qreal y1, qreal r1);
// rects
void clearRect(qreal x, qreal y, qreal w, qreal h);
void fillRect(qreal x, qreal y, qreal w, qreal h);
void strokeRect(qreal x, qreal y, qreal w, qreal h);
// mouse
void mouseArea(qreal x, qreal y, qreal w, qreal h, const QScriptValue &, const QScriptValue & = QScriptValue());
// path API
void beginPath();
void closePath();
void moveTo(qreal x, qreal y);
void lineTo(qreal x, qreal y);
void quadraticCurveTo(qreal cpx, qreal cpy, qreal x, qreal y);
void bezierCurveTo(qreal cp1x, qreal cp1y,
qreal cp2x, qreal cp2y, qreal x, qreal y);
void arcTo(qreal x1, qreal y1, qreal x2, qreal y2, qreal radius);
void rect(qreal x, qreal y, qreal w, qreal h);
void arc(qreal x, qreal y, qreal radius,
qreal startAngle, qreal endAngle,
bool anticlockwise);
void fill();
void stroke();
void clip();
bool isPointInPath(qreal x, qreal y) const;
CanvasImage *createImage(const QString &url);
// drawing images (no overloads due to QTBUG-11604)
void drawImage(const QVariant &var, qreal dx, qreal dy, qreal dw, qreal dh);
// pixel manipulation
ImageData getImageData(qreal sx, qreal sy, qreal sw, qreal sh);
void putImageData(ImageData image, qreal dx, qreal dy);
void endPainting();
signals:
void changed();
private:
void setupPainter();
void beginPainting();
void updateShadowBuffer();
int m_changeTimerId;
QPainterPath m_path;
enum DirtyFlag {
DirtyTransformationMatrix = 0x00001,
DirtyClippingRegion = 0x00002,
DirtyStrokeStyle = 0x00004,
DirtyFillStyle = 0x00008,
DirtyGlobalAlpha = 0x00010,
DirtyLineWidth = 0x00020,
DirtyLineCap = 0x00040,
DirtyLineJoin = 0x00080,
DirtyMiterLimit = 0x00100,
MDirtyPen = DirtyStrokeStyle
| DirtyLineWidth
| DirtyLineCap
| DirtyLineJoin
| DirtyMiterLimit,
DirtyShadowOffsetX = 0x00200,
DirtyShadowOffsetY = 0x00400,
DirtyShadowBlur = 0x00800,
DirtyShadowColor = 0x01000,
DirtyGlobalCompositeOperation = 0x2000,
DirtyFont = 0x04000,
DirtyTextAlign = 0x08000,
DirtyTextBaseline = 0x10000,
AllIsFullOfDirt = 0xfffff
};
struct State {
State() : flags(0) {}
QMatrix matrix;
QPainterPath clipPath;
QBrush strokeStyle;
QBrush fillStyle;
qreal globalAlpha;
qreal lineWidth;
Qt::PenCapStyle lineCap;
Qt::PenJoinStyle lineJoin;
qreal miterLimit;
qreal shadowOffsetX;
qreal shadowOffsetY;
qreal shadowBlur;
QColor shadowColor;
QPainter::CompositionMode globalCompositeOperation;
QFont font;
Context2D::TextAlign textAlign;
Context2D::TextBaseLine textBaseline;
int flags;
};
int baseLineOffset(Context2D::TextBaseLine value, const QFontMetrics &metrics);
int textAlignOffset(Context2D::TextAlign value, const QFontMetrics &metrics, const QString &string);
QMatrix worldMatrix() const;
QPoint m_painterTranslate;
State m_state;
QStack<State> m_stateStack;
QPixmap m_pixmap;
QList<MouseArea> m_mouseAreas;
QImage m_shadowbuffer;
QVector<QRgb> m_shadowColorIndexBuffer;
QColor m_shadowColorBuffer;
QPainter m_painter;
int m_width, m_height;
bool m_inPaint;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QDECLARATIVECONTEXT2D_P_H

View File

@@ -0,0 +1,163 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qdeclarativetiledcanvas_p.h"
#include "qdeclarativecontext2d_p.h"
#include <QtGui/qpixmap.h>
#include <QtGui/qpainter.h>
TiledCanvas::TiledCanvas()
: m_context2d(new Context2D(this)), m_canvasSize(-1, -1), m_tileSize(100, 100)
{
setFlag(QGraphicsItem::ItemHasNoContents, false);
setAcceptedMouseButtons(Qt::LeftButton);
}
QSizeF TiledCanvas::canvasSize() const
{
return m_canvasSize;
}
void TiledCanvas::setCanvasSize(const QSizeF &v)
{
if (m_canvasSize != v) {
m_canvasSize = v;
emit canvasSizeChanged();
update();
}
}
QSize TiledCanvas::tileSize() const
{
return m_tileSize;
}
void TiledCanvas::setTileSize(const QSize &v)
{
if (v != m_tileSize) {
m_tileSize = v;
emit tileSizeChanged();
update();
}
}
QRectF TiledCanvas::canvasWindow() const
{
return m_canvasWindow;
}
void TiledCanvas::setCanvasWindow(const QRectF &v)
{
if (m_canvasWindow != v) {
m_canvasWindow = v;
emit canvasWindowChanged();
update();
}
}
void TiledCanvas::requestPaint()
{
update();
}
void TiledCanvas::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
{
if (m_context2d->size() != m_tileSize)
m_context2d->setSize(m_tileSize);
const int tw = m_tileSize.width();
const int th = m_tileSize.height();
int h1 = m_canvasWindow.left() / tw;
int htiles = ((m_canvasWindow.right() - h1 * tw) + tw - 1) / tw;
int v1 = m_canvasWindow.top() / th;
int vtiles = ((m_canvasWindow.bottom() - v1 * th) + th - 1) / th;
for (int yy = 0; yy < vtiles; ++yy) {
for (int xx = 0; xx < htiles; ++xx) {
int ht = xx + h1;
int vt = yy + v1;
m_context2d->reset();
m_context2d->setPainterTranslate(QPoint(-ht * tw, -vt * th));
emit drawRegion(m_context2d, QRect(ht * tw, vt * th, tw, th));
p->drawPixmap(-m_canvasWindow.x() + ht * tw, -m_canvasWindow.y() + vt * th, m_context2d->pixmap());
}
}
}
void TiledCanvas::componentComplete()
{
const QMetaObject *metaObject = this->metaObject();
int propertyCount = metaObject->propertyCount();
int requestPaintMethod = metaObject->indexOfMethod("requestPaint()");
for (int ii = TiledCanvas::staticMetaObject.propertyCount(); ii < propertyCount; ++ii) {
QMetaProperty p = metaObject->property(ii);
if (p.hasNotifySignal())
QMetaObject::connect(this, p.notifySignalIndex(), this, requestPaintMethod, 0, 0);
}
QDeclarativeItem::componentComplete();
}
void TiledCanvas::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
qWarning("MPE");
}
QPixmap TiledCanvas::getTile(int xx, int yy)
{
QPixmap pix(m_tileSize);
pix.fill(Qt::green);
QString text = QString::number(xx) + " " + QString::number(yy);
QPainter p(&pix);
p.drawText(pix.rect(), Qt::AlignHCenter | Qt::AlignVCenter, text);
return pix;
}

View File

@@ -0,0 +1,102 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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, 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QDECLARATIVETILEDCANVAS_P_H
#define QDECLARATIVETILEDCANVAS_P_H
#include <QtDeclarative/qdeclarativeitem.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class Context2D;
class TiledCanvas : public QDeclarativeItem
{
Q_OBJECT
Q_PROPERTY(QSizeF canvasSize READ canvasSize WRITE setCanvasSize NOTIFY canvasSizeChanged)
Q_PROPERTY(QSize tileSize READ tileSize WRITE setTileSize NOTIFY tileSizeChanged)
Q_PROPERTY(QRectF canvasWindow READ canvasWindow WRITE setCanvasWindow NOTIFY canvasWindowChanged)
public:
TiledCanvas();
QSizeF canvasSize() const;
void setCanvasSize(const QSizeF &);
QSize tileSize() const;
void setTileSize(const QSize &);
QRectF canvasWindow() const;
void setCanvasWindow(const QRectF &);
Q_SIGNALS:
void canvasSizeChanged();
void tileSizeChanged();
void canvasWindowChanged();
void drawRegion(Context2D *ctxt, const QRect &region);
public Q_SLOTS:
void requestPaint();
protected:
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
virtual void componentComplete();
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
private:
QPixmap getTile(int, int);
Context2D *m_context2d;
QSizeF m_canvasSize;
QSize m_tileSize;
QRectF m_canvasWindow;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QDECLARATIVETILEDCANVAS_P_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

View File

@@ -0,0 +1,6 @@
#ifndef MAC_P_H
#define MAC_P_H
void disableIntertia();
#endif // MAC_P_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,45 @@
TEMPLATE = lib
TARGET = QmlProfiler
DEFINES += PROFILER_LIBRARY
include(../../qtcreatorplugin.pri)
include(../../plugins/coreplugin/coreplugin.pri)
include(../../plugins/analyzerbase/analyzerbase.pri)
QT += network script opengl declarative
include(canvas/canvas.pri)
#include($$QMLJSDEBUGGER_PATH/qmljsdebugger-lib.pri)
SOURCES += \
qmlprofilerplugin.cpp \
qmlprofilertool.cpp \
qmlprofilerengine.cpp \
tracewindow.cpp \
timelineview.cpp
HEADERS += \
qmlprofilerconstants.h \
qmlprofiler_global.h \
qmlprofilerplugin.h \
qmlprofilertool.h \
qmlprofilerengine.h \
tracewindow.h \
timelineview.h \
mac_p.h
RESOURCES += \
qmlprofiler.qrc
OTHER_FILES += \
Detail.qml \
Elapsed.qml \
Label.qml \
MainView.qml \
RangeDetails.qml \
RangeMover.qml \
RecordButton.qml \
ToolButton.qml \
MainView.js

View File

@@ -0,0 +1,16 @@
<RCC>
<qresource prefix="/qml">
<file>Detail.qml</file>
<file>Elapsed.qml</file>
<file>Label.qml</file>
<file>lock.png</file>
<file>MainView.js</file>
<file>MainView.qml</file>
<file>popup.png</file>
<file>range.png</file>
<file>RangeDetails.qml</file>
<file>RangeMover.qml</file>
<file>RecordButton.qml</file>
<file>ToolButton.qml</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,13 @@
#ifndef QMLPROFILERPLUGIN_GLOBAL_H
#define QMLPROFILERPLUGIN_GLOBAL_H
#include <QtCore/QtGlobal>
#if defined(QMLPROFILERPLUGIN_LIBRARY)
# define QMLPROFILERPLUGINSHARED_EXPORT Q_DECL_EXPORT
#else
# define QMLPROFILERPLUGINSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // QMLPROFILERPLUGIN_GLOBAL_H

View File

@@ -0,0 +1,14 @@
#ifndef QMLPROFILERPLUGINCONSTANTS_H
#define QMLPROFILERPLUGINCONSTANTS_H
namespace QmlProfiler {
namespace Constants {
const char * const ACTION_ID = "QmlProfilerPlugin.Action";
const char * const MENU_ID = "QmlProfilerPlugin.Menu";
} // namespace QmlProfiler
} // namespace Constants
#endif // QMLPROFILERPLUGINCONSTANTS_H

View File

@@ -0,0 +1,126 @@
#include "qmlprofilerengine.h"
#include "qmlprofilerplugin.h"
#include "qmlprofilertool.h"
#include <projectexplorer/applicationrunconfiguration.h>
#include <private/qdeclarativedebugclient_p.h>
#include "timelineview.h"
#include "tracewindow.h"
#include <QDebug>
#include "canvas/qdeclarativecanvas_p.h"
#include "canvas/qdeclarativecontext2d_p.h"
#include "canvas/qdeclarativetiledcanvas_p.h"
#include <utils/environment.h>
#include <QProcess>
#include "tracewindow.h"
using namespace Analyzer::Internal;
class QmlProfilerEngine::QmlProfilerEnginePrivate
{
public:
QmlProfilerEnginePrivate(QmlProfilerEngine *qq) : q(qq) {}
~QmlProfilerEnginePrivate() {}
bool launchperfmonitor();
QmlProfilerEngine *q;
QString m_workingDirectory;
QString m_executable;
QString m_commandLineArguments;
Utils::Environment m_environment;
QProcess *m_process;
bool m_running;
};
QmlProfilerEngine::QmlProfilerEngine(ProjectExplorer::RunConfiguration *runConfiguration)
: IAnalyzerEngine(runConfiguration), d(new QmlProfilerEnginePrivate(this))
{
ProjectExplorer::LocalApplicationRunConfiguration *localAppConfig =
qobject_cast<ProjectExplorer::LocalApplicationRunConfiguration *>(runConfiguration);
if (!localAppConfig)
return;
d->m_workingDirectory = localAppConfig->workingDirectory();
d->m_executable = localAppConfig->executable();
d->m_commandLineArguments = localAppConfig->commandLineArguments();
d->m_environment = localAppConfig->environment();
d->m_process = 0;
d->m_running = false;
}
QmlProfilerEngine::~QmlProfilerEngine()
{
if (d->m_running)
stop();
delete d;
}
void QmlProfilerEngine::start()
{
d->launchperfmonitor();
d->m_running = true;
emit processRunning();
}
void QmlProfilerEngine::stop()
{
d->m_running = false;
emit stopRecording();
}
void QmlProfilerEngine::viewUpdated()
{
d->m_process->terminate();
if (!d->m_process->waitForFinished(1000)) {
d->m_process->kill();
d->m_process->waitForFinished();
}
emit processTerminated();
delete d->m_process;
}
bool QmlProfilerEngine::QmlProfilerEnginePrivate::launchperfmonitor()
{
bool qtquick1 = false;
m_process = new QProcess();
QStringList arguments("-qmljsdebugger=port:" + QString::number(QmlProfilerTool::port) + ",block");
if (QmlProfilerPlugin::debugOutput)
qWarning("QmlProfiler: Launching %s", qPrintable(m_executable));
if (qtquick1) {
QProcessEnvironment env;
env.insert("QMLSCENE_IMPORT_NAME", "quick1");
m_process->setProcessEnvironment(env);
}
m_process->setProcessChannelMode(QProcess::ForwardedChannels);
m_process->setWorkingDirectory(m_workingDirectory);
m_process->start(m_executable, arguments);
if (!m_process->waitForStarted()) {
if (QmlProfilerPlugin::debugOutput)
qWarning("QmlProfiler: %s failed to start", qPrintable(m_executable));
return false;
}
sleep(1);
if (QmlProfilerPlugin::debugOutput)
qWarning("QmlProfiler: Connecting to %s:%d", qPrintable(QmlProfilerTool::host), QmlProfilerTool::port);
return true;
}

View File

@@ -0,0 +1,36 @@
#ifndef QMLPROFILERENGINE_H
#define QMLPROFILERENGINE_H
#include "ianalyzerengine.h"
namespace Analyzer {
namespace Internal {
class QmlProfilerEngine : public IAnalyzerEngine
{
Q_OBJECT
public:
explicit QmlProfilerEngine(ProjectExplorer::RunConfiguration *runConfiguration);
~QmlProfilerEngine();
void start();
void stop();
signals:
void processRunning();
void processTerminated();
void stopRecording();
public slots:
void viewUpdated();
private:
class QmlProfilerEnginePrivate;
QmlProfilerEnginePrivate *d;
};
}
}
#endif // QMLPROFILERENGINE_H

View File

@@ -0,0 +1,93 @@
#include "qmlprofilerplugin.h"
#include "qmlprofilerconstants.h"
#include <coreplugin/icore.h>
#include <coreplugin/icontext.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/coreconstants.h>
#include <analyzerbase/analyzermanager.h>
#include <QtGui/QAction>
#include <QtGui/QMessageBox>
#include <QtGui/QMainWindow>
#include <QtGui/QMenu>
#include <QtCore/QtPlugin>
#include "qmlprofilertool.h"
using namespace Analyzer;
using namespace Analyzer::Internal;
QmlProfilerPlugin *QmlProfilerPlugin::m_instance = 0;
bool QmlProfilerPlugin::debugOutput = false;
class QmlProfilerPlugin::QmlProfilerPluginPrivate
{
public:
QmlProfilerPluginPrivate(QmlProfilerPlugin *qq):
q(qq)
{}
void initialize(const QStringList &arguments, QString *errorString);
QmlProfilerPlugin *q;
};
void QmlProfilerPlugin::QmlProfilerPluginPrivate::initialize(const QStringList &arguments, QString *errorString)
{
Q_UNUSED(arguments)
Q_UNUSED(errorString)
// AnalyzerManager::instance()->addTool(new MemcheckTool(this));
}
QmlProfilerPlugin::QmlProfilerPlugin()
: d(new QmlProfilerPluginPrivate(this))
{
m_instance = this;
}
QmlProfilerPlugin::~QmlProfilerPlugin()
{
delete d;
m_instance = 0;
}
bool QmlProfilerPlugin::initialize(const QStringList &arguments, QString *errorString)
{
d->initialize(arguments, errorString);
AnalyzerManager::instance()->addTool(new QmlProfilerTool(this));
return true;
}
void QmlProfilerPlugin::extensionsInitialized()
{
// Retrieve objects from the plugin manager's object pool
// "In the extensionsInitialized method, a plugin can be sure that all
// plugins that depend on it are completely initialized."
}
ExtensionSystem::IPlugin::ShutdownFlag QmlProfilerPlugin::aboutToShutdown()
{
// Save settings
// Disconnect from signals that are not needed during shutdown
// Hide UI (if you add UI that is not in the main window directly)
return SynchronousShutdown;
}
QmlProfilerPlugin *QmlProfilerPlugin::instance()
{
return m_instance;
}
Q_EXPORT_PLUGIN(QmlProfilerPlugin)

View File

@@ -0,0 +1,38 @@
#ifndef QMLPROFILERPLUGIN_H
#define QMLPROFILERPLUGIN_H
#include "qmlprofiler_global.h"
#include <extensionsystem/iplugin.h>
namespace Analyzer {
namespace Internal {
class QmlProfilerPlugin : public ExtensionSystem::IPlugin
{
Q_OBJECT
public:
static QmlProfilerPlugin *instance();
QmlProfilerPlugin();
~QmlProfilerPlugin();
bool initialize(const QStringList &arguments, QString *errorString);
void extensionsInitialized();
ShutdownFlag aboutToShutdown();
static bool debugOutput;
private:
class QmlProfilerPluginPrivate;
QmlProfilerPluginPrivate *d;
static QmlProfilerPlugin *m_instance;
};
} // namespace Internal
} // namespace Analyzer
#endif // QMLPROFILERPLUGIN_H

View File

@@ -0,0 +1,205 @@
#include "qmlprofilertool.h"
#include "qmlprofilerengine.h"
#include "qmlprofilerplugin.h"
#include "tracewindow.h"
#include <private/qdeclarativedebugclient_p.h>
#include <analyzerbase/analyzermanager.h>
#include <analyzerbase/analyzerconstants.h>
#include "timelineview.h"
#include "canvas/qdeclarativecanvas_p.h"
#include "canvas/qdeclarativecontext2d_p.h"
#include "canvas/qdeclarativetiledcanvas_p.h"
#include <qmlprojectmanager/qmlprojectrunconfiguration.h>
#include <utils/fileinprojectfinder.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/project.h>
#include <texteditor/itexteditor.h>
#include <coreplugin/editormanager/editormanager.h>
#include <QtCore/QFile>
using namespace Analyzer;
using namespace Analyzer::Internal;
QString QmlProfilerTool::host = QLatin1String("localhost");
quint16 QmlProfilerTool::port = 33455;
// Adapter for output pane.
class QmlProfilerOutputPaneAdapter : public Analyzer::IAnalyzerOutputPaneAdapter
{
public:
explicit QmlProfilerOutputPaneAdapter(QmlProfilerTool *mct) :
IAnalyzerOutputPaneAdapter(mct), m_tool(mct) {}
virtual QWidget *toolBarWidget() { return m_tool->createToolBarWidget(); }
virtual QWidget *paneWidget() { return m_tool->createTimeLineWidget(); }
virtual void clearContents() { /*TODO*/ }
virtual void setFocus() { /*TODO*/ }
virtual bool hasFocus() const { return false; /*TODO*/ }
virtual bool canFocus() const { return false; /*TODO*/ }
virtual bool canNavigate() const { return false; /*TODO*/ }
virtual bool canNext() const { return false; /*TODO*/ }
virtual bool canPrevious() const { return false; /*TODO*/ }
virtual void goToNext() { /*TODO*/ }
virtual void goToPrev() { /*TODO*/ }
private:
QmlProfilerTool *m_tool;
};
class QmlProfilerTool::QmlProfilerToolPrivate
{
public:
QmlProfilerToolPrivate(QmlProfilerTool *qq) : q(qq) {}
~QmlProfilerToolPrivate() {}
QmlProfilerTool *q;
QDeclarativeDebugConnection *m_client;
TraceWindow *m_traceWindow;
QmlProfilerOutputPaneAdapter *m_outputPaneAdapter;
};
QmlProfilerTool::QmlProfilerTool(QObject *parent)
: IAnalyzerTool(parent), d(new QmlProfilerToolPrivate(this))
{
d->m_client = 0;
d->m_traceWindow = 0;
d->m_outputPaneAdapter = 0;
}
QmlProfilerTool::~QmlProfilerTool()
{
if (d->m_client->isConnected())
d->m_client->disconnectFromHost();
delete d->m_traceWindow;
delete d->m_outputPaneAdapter;
delete d;
}
QString QmlProfilerTool::id() const
{
return "QmlProfiler";
}
QString QmlProfilerTool::displayName() const
{
return tr("Qml Performance Monitor");
}
IAnalyzerTool::ToolMode QmlProfilerTool::mode() const
{
return DebugMode;
}
IAnalyzerEngine *QmlProfilerTool::createEngine(ProjectExplorer::RunConfiguration *runConfiguration)
{
QmlProfilerEngine *engine = new QmlProfilerEngine(runConfiguration);
connect(engine, SIGNAL(processRunning()), this, SLOT(connectClient()));
connect(engine, SIGNAL(processTerminated()), this, SLOT(disconnectClient()));
connect(engine, SIGNAL(stopRecording()), this, SLOT(stopRecording()));
connect(d->m_traceWindow, SIGNAL(viewUpdated()), engine, SLOT(viewUpdated()));
connect(d->m_traceWindow, SIGNAL(gotoSourceLocation(QString,int)), this, SLOT(gotoSourceLocation(QString,int)));
return engine;
}
void QmlProfilerTool::initialize(ExtensionSystem::IPlugin */*plugin*/)
{
qmlRegisterType<Canvas>("QtQuick",1,1, "Canvas");
qmlRegisterType<TiledCanvas>("QtQuick",1,1, "TiledCanvas");
qmlRegisterType<Context2D>();
qmlRegisterType<CanvasImage>();
qmlRegisterType<CanvasGradient>();
qmlRegisterType<TimelineView>("Monitor",1,0,"TimelineView");
d->m_client = new QDeclarativeDebugConnection;
d->m_traceWindow = new TraceWindow();
d->m_traceWindow->reset(d->m_client);
}
IAnalyzerOutputPaneAdapter *QmlProfilerTool::outputPaneAdapter()
{
if (!d->m_outputPaneAdapter)
d->m_outputPaneAdapter = new QmlProfilerOutputPaneAdapter(this);
return d->m_outputPaneAdapter;
}
QWidget *QmlProfilerTool::createToolBarWidget()
{
// custom toolbar (TODO)
return 0;
}
QWidget *QmlProfilerTool::createTimeLineWidget()
{
return d->m_traceWindow;
}
void QmlProfilerTool::connectClient()
{
QDeclarativeDebugConnection *newClient = new QDeclarativeDebugConnection;
d->m_traceWindow->reset(newClient);
delete d->m_client;
d->m_client = newClient;
d->m_client->connectToHost(host, port);
d->m_client->waitForConnected();
if (d->m_client->state() == QDeclarativeDebugConnection::ConnectedState) {
d->m_traceWindow->setRecording(true);
if (QmlProfilerPlugin::debugOutput)
qWarning("QmlProfiler: connected and running");
} else {
if (QmlProfilerPlugin::debugOutput)
qWarning("QmlProfiler: Failed to connect: %s", qPrintable(d->m_client->errorString()));
}
}
void QmlProfilerTool::disconnectClient()
{
d->m_client->disconnectFromHost();
}
void QmlProfilerTool::stopRecording()
{
d->m_traceWindow->setRecording(false);
}
void QmlProfilerTool::gotoSourceLocation(const QString &fileName, int lineNumber)
{
if (lineNumber < 0 || !QFile::exists(QUrl(fileName).toLocalFile()))
return;
Utils::FileInProjectFinder m_projectFinder;
ProjectExplorer::Project *m_debugProject;
m_debugProject = ProjectExplorer::ProjectExplorerPlugin::instance()->startupProject();
m_projectFinder.setProjectDirectory(m_debugProject->projectDirectory());
QString projectFileName = m_projectFinder.findFile(fileName);
Core::EditorManager *editorManager = Core::EditorManager::instance();
Core::IEditor *editor = editorManager->openEditor(projectFileName);
TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor);
if (textEditor) {
editorManager->addCurrentPositionToNavigationHistory();
textEditor->gotoLine(lineNumber);
textEditor->widget()->setFocus();
}
}

View File

@@ -0,0 +1,50 @@
#ifndef QMLPROFILERTOOL_H
#define QMLPROFILERTOOL_H
#include "ianalyzertool.h"
#include "ianalyzerengine.h"
namespace Analyzer {
namespace Internal {
class QmlProfilerTool : public IAnalyzerTool
{
Q_OBJECT
public:
explicit QmlProfilerTool(QObject *parent = 0);
~QmlProfilerTool();
QString id() const;
QString displayName() const;
ToolMode mode() const;
void initialize(ExtensionSystem::IPlugin *plugin);
IAnalyzerEngine *createEngine(ProjectExplorer::RunConfiguration *runConfiguration);
IAnalyzerOutputPaneAdapter *outputPaneAdapter();
QWidget *createToolBarWidget();
QWidget *createTimeLineWidget();
public slots:
void connectClient();
void disconnectClient();
void stopRecording();
void gotoSourceLocation(const QString &fileName, int lineNumber);
public:
// Todo: configurable parameters
static QString host;
static quint16 port;
private:
class QmlProfilerToolPrivate;
QmlProfilerToolPrivate *d;
};
}
}
#endif // QMLPROFILERTOOL_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

View File

@@ -0,0 +1,201 @@
#include "timelineview.h"
#include <qdeclarativecontext.h>
#include <qdeclarativeproperty.h>
#include <private/qperformancetimer_p.h>
TimelineView::TimelineView(QDeclarativeItem *parent) :
QDeclarativeItem(parent), m_delegate(0), m_startTime(0), m_endTime(0), m_startX(0),
prevMin(0), prevMax(0), m_totalWidth(0)
{
}
void TimelineView::componentComplete()
{
QDeclarativeItem::componentComplete();
}
void TimelineView::clearData()
{
m_rangeList.clear();
m_items.clear();
m_startTime = 0;
m_endTime = 0;
m_startX = 0;
prevMin = 0;
prevMax = 0;
m_prevLimits.clear();
m_totalWidth = 0;
}
void TimelineView::setRanges(const QScriptValue &value)
{
//TODO clear old values (always?)
m_ranges = value;
//### below code not yet used anywhere
int length = m_ranges.property("length").toInt32();
for (int i = 0; i < length; ++i) {
int type = m_ranges.property(i).property("type").toNumber();
Q_ASSERT(type >= 0);
while (m_rangeList.count() <= type)
m_rangeList.append(ValueList());
m_rangeList[type] << m_ranges.property(i);
}
for (int i = 0; i < m_rangeList.count(); ++i)
m_prevLimits << PrevLimits(0, 0);
}
void TimelineView::setStartX(qreal arg)
{
if (arg == m_startX)
return;
if (!m_ranges.isArray())
return;
qreal window = m_endTime - m_startTime;
if (window == 0) //###
return;
qreal spacing = width() / window;
qreal oldStart = m_startTime;
m_startTime = arg / spacing;
m_endTime += m_startTime - oldStart;
updateTimeline(false);
m_startX = arg;
emit startXChanged(m_startX);
}
void TimelineView::updateTimeline(bool updateStartX)
{
if (!m_delegate)
return;
if (!m_ranges.isArray())
return;
int length = m_ranges.property("length").toInt32();
qreal startValue = m_ranges.property(0).property("start").toNumber();
qreal endValue = m_ranges.property(length-1).property("start").toNumber() + m_ranges.property(length-1).property("duration").toNumber();
qreal totalRange = endValue - startValue;
qreal window = m_endTime - m_startTime;
if (window == 0) //###
return;
qreal spacing = width() / window;
qreal oldtw = m_totalWidth;
m_totalWidth = totalRange * spacing;
qreal offsets[length][2];
for (int i = 0; i < length; ++i) {
offsets[i][0] = (m_ranges.property(i).property("start").toNumber() - startValue);
offsets[i][1] = (m_ranges.property(i).property("start").toNumber() + m_ranges.property(i).property("duration").toNumber() - startValue);
}
// Find region samples
int minsample = 0;
int maxsample = 0;
for (int i = 0; i < length; ++i) {
if (offsets[i][1] >= m_startTime)
break;
minsample = i;
}
for (int i = minsample + 1; i < length; ++i) {
maxsample = i;
if (offsets[i][0] > m_endTime)
break;
}
//### overkill (if we can expose whether or not data is nested)
for (int i = maxsample + 1; i < length; ++i) {
if (offsets[i][0] < m_endTime)
maxsample = i;
}
//qDebug() << maxsample - minsample;
if (updateStartX) {
qreal oldStartX = m_startX;
m_startX = qRound(m_startTime * spacing);
if (m_startX != oldStartX) {
emit startXChanged(m_startX);
}
}
//### emitting this before startXChanged was causing issues
if (m_totalWidth != oldtw)
emit totalWidthChanged(m_totalWidth);
//clear items no longer in view
while (prevMin < minsample) {
delete m_items.take(prevMin);
++prevMin;
}
while (prevMax > maxsample) {
delete m_items.take(prevMax);
--prevMax;
}
// Show items
int z = 0;
for (int i = maxsample-1; i >= minsample; --i) {
QDeclarativeItem *item = 0;
item = m_items.value(i);
bool creating = false;
if (!item) {
QDeclarativeContext *ctxt = new QDeclarativeContext(qmlContext(this));
item = qobject_cast<QDeclarativeItem*>(m_delegate->beginCreate(ctxt));
m_items.insert(i, item);
creating = true;
int type = m_ranges.property(i).property("type").toNumber();
ctxt->setParent(item); //### QDeclarative_setParent_noEvent(ctxt, item); instead?
ctxt->setContextProperty("duration", qMax(qRound(m_ranges.property(i).property("duration").toNumber()/qreal(1000)),1));
ctxt->setContextProperty("fileName", m_ranges.property(i).property("fileName").toString());
ctxt->setContextProperty("line", m_ranges.property(i).property("line").toNumber());
QString label;
QVariantList list = m_ranges.property(i).property("label").toVariant().value<QVariantList>();
for (int i = 0; i < list.size(); ++i) {
if (i > 0)
label += "\n";
QString sub = list.at(i).toString();
//### only do rewrite for bindings...
if (type == 3) {
//### don't construct in loop
QRegExp rewrite("\\(function \\$(\\w+)\\(\\) \\{ return (.+) \\}\\)");
bool match = rewrite.exactMatch(sub);
if (match)
sub = rewrite.cap(1) + ": " + rewrite.cap(2);
}
label += sub;
}
ctxt->setContextProperty("label", label);
ctxt->setContextProperty("type", type);
item->setY(type*50);
item->setParentItem(this);
}
if (item) {
item->setX(offsets[i][0]*spacing);
item->setWidth(m_ranges.property(i).property("duration").toNumber() * spacing);
item->setZValue(++z);
}
if (creating)
m_delegate->completeCreate();
}
prevMin = minsample;
prevMax = maxsample;
}

View File

@@ -0,0 +1,109 @@
#ifndef TIMELINEVIEW_H
#define TIMELINEVIEW_H
#include <QDeclarativeItem>
#include <QScriptValue>
class TimelineView : public QDeclarativeItem
{
Q_OBJECT
Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
Q_PROPERTY(qint64 startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged)
Q_PROPERTY(qint64 endTime READ endTime WRITE setEndTime NOTIFY endTimeChanged)
Q_PROPERTY(qreal startX READ startX WRITE setStartX NOTIFY startXChanged)
Q_PROPERTY(qreal totalWidth READ totalWidth NOTIFY totalWidthChanged)
public:
explicit TimelineView(QDeclarativeItem *parent = 0);
QDeclarativeComponent * delegate() const
{
return m_delegate;
}
qint64 startTime() const
{
return m_startTime;
}
qint64 endTime() const
{
return m_endTime;
}
qreal startX() const
{
return m_startX;
}
qreal totalWidth() const
{
return m_totalWidth;
}
signals:
void delegateChanged(QDeclarativeComponent * arg);
void startTimeChanged(qint64 arg);
void endTimeChanged(qint64 arg);
void startXChanged(qreal arg);
void totalWidthChanged(qreal arg);
public slots:
void clearData();
void setRanges(const QScriptValue &value);
void updateTimeline(bool updateStartX = true);
void setDelegate(QDeclarativeComponent * arg)
{
if (m_delegate != arg) {
m_delegate = arg;
emit delegateChanged(arg);
}
}
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 setStartX(qreal arg);
protected:
void componentComplete();
private:
QDeclarativeComponent * m_delegate;
QScriptValue m_ranges;
typedef QList<QScriptValue> ValueList;
QList<ValueList> m_rangeList;
QHash<int,QDeclarativeItem*> m_items;
qint64 m_startTime;
qint64 m_endTime;
qreal m_startX;
int prevMin;
int prevMax;
struct PrevLimits {
PrevLimits(int _min, int _max) : min(_min), max(_max) {}
int min;
int max;
};
QList<PrevLimits> m_prevLimits;
qreal m_totalWidth;
};
QML_DECLARE_TYPE(TimelineView)
#endif // TIMELINEVIEW_H

View File

@@ -0,0 +1,309 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "tracewindow.h"
#include <QtCore/qdebug.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qmargins.h>
#include <QtGui/qapplication.h>
#include <QtGui/qpainter.h>
#include <QtGui/qboxlayout.h>
#include <QtGui/qevent.h>
#include <QtCore/qstack.h>
#include <QtOpenGL/QGLWidget>
#include <QGraphicsObject>
#include <QtDeclarative/qdeclarativeview.h>
#include <QtDeclarative/qdeclarativecontext.h>
#include <QtDeclarative/qdeclarative.h>
#include "qmlprofilerplugin.h"
//#include <jsdebuggeragent.h>
//#include <qdeclarativeviewobserver.h>
#define GAP_TIME 150
struct Location
{
Location() : line(-1) {}
Location(const QString &file, int lineNumber) : fileName(file), line(lineNumber) {}
QString fileName;
int line;
};
class TracePlugin : public QDeclarativeDebugClient
{
Q_OBJECT
Q_PROPERTY(bool recording READ recording WRITE setRecording NOTIFY recordingChanged)
public:
TracePlugin(QDeclarativeDebugConnection *client);
enum EventType {
FramePaint,
Mouse,
Key,
MaximumEventType
};
enum Message {
Event,
RangeStart,
RangeData,
RangeLocation,
RangeEnd,
Complete,
MaximumMessage
};
enum RangeType {
Painting,
Compiling,
Creating,
Binding,
HandlingSignal,
MaximumRangeType
};
bool recording() const
{
return m_recording;
}
public slots:
void setRecording(bool);
signals:
void complete();
void gap(qint64);
void event(int event, qint64 time);
void range(int type, qint64 startTime, qint64 length, const QStringList &data, const QString &fileName, int line);
void sample(int, int, int, bool);
void recordingChanged(bool arg);
void enabled();
protected:
virtual void statusChanged(Status);
virtual void messageReceived(const QByteArray &);
private:
qint64 m_inProgressRanges;
QStack<qint64> m_rangeStartTimes[MaximumRangeType];
QStack<QStringList> m_rangeDatas[MaximumRangeType];
QStack<Location> m_rangeLocations[MaximumRangeType];
int m_rangeCount[MaximumRangeType];
qint64 m_maximumTime;
bool m_recording;
};
TracePlugin::TracePlugin(QDeclarativeDebugConnection *client)
: QDeclarativeDebugClient(QLatin1String("CanvasFrameRate"), client), m_inProgressRanges(0), m_maximumTime(0), m_recording(false)
{
::memset(m_rangeCount, 0, MaximumRangeType * sizeof(int));
}
void TracePlugin::setRecording(bool v)
{
if (v == m_recording)
return;
QByteArray ba;
QDataStream stream(&ba, QIODevice::WriteOnly);
stream << v;
sendMessage(ba);
m_recording = v;
emit recordingChanged(v);
}
void TracePlugin::statusChanged(Status status)
{
if (status == Enabled) {
m_recording = !m_recording;
setRecording(!m_recording);
emit enabled();
}
}
void TracePlugin::messageReceived(const QByteArray &data)
{
QByteArray rwData = data;
QDataStream stream(&rwData, QIODevice::ReadOnly);
qint64 time;
int messageType;
stream >> time >> messageType;
// qDebug() << __FUNCTION__ << messageType;
if (messageType >= MaximumMessage)
return;
if (time > (m_maximumTime + GAP_TIME) && 0 == m_inProgressRanges)
emit gap(time);
if (messageType == Event) {
int event;
stream >> event;
if (event < MaximumEventType) {
emit this->event((EventType)event, time);
m_maximumTime = qMax(time, m_maximumTime);
}
} else if (messageType == Complete) {
emit complete();
} else {
int range;
stream >> range;
if (range >= MaximumRangeType)
return;
if (messageType == RangeStart) {
m_rangeStartTimes[range].push(time);
m_inProgressRanges |= (1 << range);
++m_rangeCount[range];
} else if (messageType == RangeData) {
QString data;
stream >> data;
int count = m_rangeCount[range];
if (count > 0) {
while (m_rangeDatas[range].count() < count)
m_rangeDatas[range].push(QStringList());
m_rangeDatas[range][count-1] << data;
}
} else if (messageType == RangeLocation) {
QString fileName;
int line;
stream >> fileName >> line;
if (m_rangeCount[range] > 0) {
m_rangeLocations[range].push(Location(fileName, line));
}
} else {
if (m_rangeCount[range] > 0) {
--m_rangeCount[range];
if (m_inProgressRanges & (1 << range))
m_inProgressRanges &= ~(1 << range);
m_maximumTime = qMax(time, m_maximumTime);
QStringList data = m_rangeDatas[range].count() ? m_rangeDatas[range].pop() : QStringList();
Location location = m_rangeLocations[range].count() ? m_rangeLocations[range].pop() : Location();
qint64 startTime = m_rangeStartTimes[range].pop();
emit this->range((RangeType)range, startTime, time - startTime, data, location.fileName, location.line);
if (m_rangeCount[range] == 0) {
int count = m_rangeDatas[range].count() +
m_rangeStartTimes[range].count() +
m_rangeLocations[range].count();
if (count != 0)
qWarning() << "incorrectly nested data";
}
}
}
}
}
TraceWindow::TraceWindow(QWidget *parent)
: QWidget(parent),
m_plugin(0), m_recordAtStart(false)
{
setObjectName(tr("Qml Perfomance Monitor"));
QVBoxLayout *groupLayout = new QVBoxLayout;
groupLayout->setContentsMargins(0, 0, 0, 0);
groupLayout->setSpacing(0);
m_view = new QDeclarativeView(this);
if (Analyzer::Internal::QmlProfilerPlugin::debugOutput) {
//new QmlJSDebugger::JSDebuggerAgent(m_view->engine());
//new QmlJSDebugger::QDeclarativeViewObserver(m_view, m_view);
}
m_view->setViewport(new QGLWidget());
m_view->setResizeMode(QDeclarativeView::SizeRootObjectToView);
m_view->setFocus();
groupLayout->addWidget(m_view);
setLayout(groupLayout);
// Maximum height: 5 rows of 50 pixels + scrollbar of 50 pixels
setMinimumHeight(300);
setMaximumHeight(300);
}
TraceWindow::~TraceWindow()
{
delete m_plugin;
}
void TraceWindow::reset(QDeclarativeDebugConnection *conn)
{
if (m_plugin)
disconnect(m_plugin,SIGNAL(complete()), this, SIGNAL(viewUpdated()));
delete m_plugin;
m_plugin = new TracePlugin(conn);
connect(m_plugin,SIGNAL(complete()), this, SIGNAL(viewUpdated()));
if (m_recordAtStart)
m_plugin->setRecording(true);
m_view->rootContext()->setContextProperty("connection", m_plugin);
m_view->setSource(QUrl("qrc:/qml/MainView.qml"));
connect(m_view->rootObject(), SIGNAL(updateCursorPosition()), this, SLOT(updateCursorPosition()));
}
void TraceWindow::updateCursorPosition()
{
emit gotoSourceLocation(m_view->rootObject()->property("fileName").toString(),
m_view->rootObject()->property("lineNumber").toInt());
}
void TraceWindow::setRecordAtStart(bool record)
{
m_recordAtStart = record;
}
void TraceWindow::setRecording(bool recording)
{
m_plugin->setRecording(recording);
}
#include "tracewindow.moc"

View File

@@ -0,0 +1,75 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef CANVASFRAMERATE_H
#define CANVASFRAMERATE_H
#include <private/qdeclarativedebugclient_p.h>
#include <QtCore/qpointer.h>
#include <QtGui/qwidget.h>
class QTabWidget;
class QSlider;
class QGroupBox;
class QLabel;
class QSpinBox;
class QPushButton;
class QDeclarativeView;
class TracePlugin;
class TraceWindow : public QWidget
{
Q_OBJECT
public:
TraceWindow(QWidget *parent = 0);
~TraceWindow();
void reset(QDeclarativeDebugConnection *conn);
void setRecordAtStart(bool record);
void setRecording(bool recording);
public slots:
void updateCursorPosition();
signals:
void viewUpdated();
void gotoSourceLocation(const QString &fileName, int lineNumber);
private:
TracePlugin *m_plugin;
QSize m_sizeHint;
bool m_recordAtStart;
QDeclarativeView *m_view;
};
#endif // CANVASFRAMERATE_H