QmlProfilerExtension: using QtCreator's qmlprofiler plugin

Change-Id: I3daca67692a1b9c390bbd396fdd2991ae3c50297
Reviewed-by: Kai Koehne <kai.koehne@digia.com>
This commit is contained in:
Christiaan Janssen
2013-08-12 11:44:35 +02:00
parent f889349adb
commit ab17b3ea6e
104 changed files with 8 additions and 18623 deletions

View File

@@ -1,17 +0,0 @@
<plugin name=\"QmlProfiler\" version=\"$$QTCREATOR_VERSION\" compatVersion=\"$$QTCREATOR_VERSION\">
<vendor>Digia Plc</vendor>
<copyright>(C) 2013 Digia Plc</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 Digia.
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>
<category>Qt Quick</category>
<description>Qml Profiler Plugin</description>
<url>http://www.qt-project.org</url>
$$dependencyList
</plugin>

View File

@@ -1,62 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef ABSTRACTQMLPROFILERRUNNER_H
#define ABSTRACTQMLPROFILERRUNNER_H
#include <QObject>
#include <utils/outputformat.h>
namespace QmlProfiler {
namespace Internal {
class AbstractQmlProfilerRunner : public QObject
{
Q_OBJECT
public:
explicit AbstractQmlProfilerRunner(QObject *parent = 0) : QObject(parent) { }
virtual quint16 debugPort() const = 0;
public slots:
virtual void start() = 0;
virtual void stop() = 0;
signals:
void started();
void stopped();
void appendMessage(const QString &message, Utils::OutputFormat format);
};
} // namespace Internal
} // namespace QmlProfiler
#endif // ABSTRACTQMLPROFILERRUNNER_H

View File

@@ -1,82 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "abstracttimelinemodel.h"
namespace QmlProfiler {
AbstractTimelineModel::AbstractTimelineModel(QObject *parent) : QObject(parent)
{}
AbstractTimelineModel::~AbstractTimelineModel()
{}
void AbstractTimelineModel::setModelManager(QmlProfiler::Internal::QmlProfilerModelManager *modelManager)
{
m_modelManager = modelManager;
connect(modelManager->simpleModel(),SIGNAL(changed()),this,SLOT(dataChanged()));
m_modelId = modelManager->registerModelProxy();
}
qint64 AbstractTimelineModel::traceStartTime() const
{
return m_modelManager->traceTime()->startTime();
}
qint64 AbstractTimelineModel::traceEndTime() const
{
return m_modelManager->traceTime()->endTime();
}
qint64 AbstractTimelineModel::traceDuration() const
{
return m_modelManager->traceTime()->duration();
}
int AbstractTimelineModel::getState() const
{
return (int)m_modelManager->state();
}
int AbstractTimelineModel::rowCount() const
{
int count = 0;
for (int i=0; i<categoryCount(); i++)
count += categoryDepth(i);
return count;
}
int AbstractTimelineModel::getBindingLoopDest(int index) const
{
Q_UNUSED(index);
return -1;
}
}

View File

@@ -1,116 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef ABSTRACTTIMELINEMODEL_H
#define ABSTRACTTIMELINEMODEL_H
#include "qmlprofiler_global.h"
#include "qmlprofilermodelmanager.h"
#include "qmlprofilersimplemodel.h"
#include <QObject>
#include <QVariant>
#include <QColor>
namespace QmlProfiler {
class QMLPROFILER_EXPORT AbstractTimelineModel : public QObject {
Q_OBJECT
public:
explicit AbstractTimelineModel(QObject *parent = 0);
~AbstractTimelineModel();
void setModelManager(QmlProfiler::Internal::QmlProfilerModelManager *modelManager);
virtual int categories() const = 0;
virtual QStringList categoryTitles() const = 0;
virtual QString name() const = 0;
virtual int count() const = 0;
virtual bool isEmpty() const = 0;
virtual bool eventAccepted(const Internal::QmlProfilerSimpleModel::QmlEventData &event) const = 0;
Q_INVOKABLE virtual qint64 lastTimeMark() const = 0;
Q_INVOKABLE qint64 traceStartTime() const;
Q_INVOKABLE qint64 traceEndTime() const;
Q_INVOKABLE qint64 traceDuration() const;
Q_INVOKABLE int getState() const;
Q_INVOKABLE virtual bool expanded(int category) const = 0;
Q_INVOKABLE virtual void setExpanded(int category, bool expanded) = 0;
Q_INVOKABLE virtual int categoryDepth(int categoryIndex) const = 0;
Q_INVOKABLE virtual int categoryCount() const = 0;
Q_INVOKABLE virtual int rowCount() const;
Q_INVOKABLE virtual const QString categoryLabel(int categoryIndex) const = 0;
virtual int findFirstIndex(qint64 startTime) const = 0;
virtual int findFirstIndexNoParents(qint64 startTime) const = 0;
virtual int findLastIndex(qint64 endTime) const = 0;
virtual int getEventType(int index) const = 0;
virtual int getEventCategory(int index) const = 0;
virtual int getEventRow(int index) const = 0;
Q_INVOKABLE virtual qint64 getDuration(int index) const = 0;
Q_INVOKABLE virtual qint64 getStartTime(int index) const = 0;
Q_INVOKABLE virtual qint64 getEndTime(int index) const = 0;
Q_INVOKABLE virtual int getEventId(int index) const = 0;
Q_INVOKABLE virtual int getBindingLoopDest(int index) const;
Q_INVOKABLE virtual QColor getColor(int index) const = 0;
Q_INVOKABLE virtual float getHeight(int index) const = 0;
Q_INVOKABLE virtual const QVariantList getLabelsForCategory(int category) const = 0;
Q_INVOKABLE virtual const QVariantList getEventDetails(int index) const = 0;
// returned map should contain "file", "line", "column" properties, or be empty
Q_INVOKABLE virtual const QVariantMap getEventLocation(int index) const = 0;
Q_INVOKABLE virtual int getEventIdForHash(const QString &eventHash) const = 0;
Q_INVOKABLE virtual int getEventIdForLocation(const QString &filename, int line, int column) const = 0;
signals:
void countChanged();
void dataAvailable();
void stateChanged();
void emptyChanged();
void expandedChanged();
//protected slots:
// virtual void dataChanged() = 0;
protected:
QmlProfiler::Internal::QmlProfilerModelManager *m_modelManager;
int m_modelId;
};
}
#endif // ABSTRACTTIMELINEMODEL_H

View File

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

View File

@@ -1,244 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qdeclarativecanvas_p.h"
#include "qdeclarativecanvastimer_p.h"
#include "qdeclarativecontext2d_p.h"
#include <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

@@ -1,108 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QDECLARATIVECANVAS_P_H
#define QDECLARATIVECANVAS_P_H
#include <qdeclarativeitem.h>
#include "qdeclarativecontext2d_p.h"
#include "qdeclarativecanvastimer_p.h"
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 & = QLatin1String("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
#endif //QDECLARATIVECANVAS_P_H

View File

@@ -1,85 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qdeclarativecanvastimer_p.h"
#include <qscriptengine.h>
#include <qscriptvalue.h>
#include <qtimer.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

@@ -1,64 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QDECLARATIVECANVASTIMER_P_H
#define QDECLARATIVECANVASTIMER_P_H
#include <qscriptvalue.h>
#include <qtimer.h>
#include <qlist.h>
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
#endif // QDECLARATIVECANVASTIMER_P_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,324 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QDECLARATIVECONTEXT2D_P_H
#define QDECLARATIVECONTEXT2D_P_H
#include <qpainter.h>
#include <qpainterpath.h>
#include <qpixmap.h>
#include <qstring.h>
#include <qstack.h>
#include <qmetatype.h>
#include <qcoreevent.h>
#include <qvariant.h>
#include <qscriptvalue.h>
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;
};
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;
};
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
Q_DECLARE_METATYPE(CanvasImage*)
Q_DECLARE_METATYPE(CanvasGradient*)
#endif // QDECLARATIVECONTEXT2D_P_H

View File

@@ -1,91 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilercanvas.h"
#include "qdeclarativecontext2d_p.h"
#include <qpixmap.h>
#include <qpainter.h>
namespace QmlProfiler {
namespace Internal {
QmlProfilerCanvas::QmlProfilerCanvas()
: m_context2d(new Context2D(this))
, m_dirty(true)
{
setFlag(QGraphicsItem::ItemHasNoContents, false);
setAcceptedMouseButtons(Qt::LeftButton);
setCacheMode(QGraphicsItem::DeviceCoordinateCache);
}
void QmlProfilerCanvas::requestPaint()
{
update();
}
void QmlProfilerCanvas::requestRedraw()
{
setDirty(true);
update();
}
void QmlProfilerCanvas::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
{
if (m_context2d->size().width() != width() || m_context2d->size().height() != height()) {
m_dirty = true;
m_context2d->setSize(width(), height());
}
if (m_dirty) {
m_context2d->reset();
emit drawRegion(m_context2d, QRect(0, 0, width(), height()));
setDirty(false);
}
p->drawPixmap(0, 0, m_context2d->pixmap());
}
void QmlProfilerCanvas::componentComplete()
{
const QMetaObject *metaObject = this->metaObject();
int propertyCount = metaObject->propertyCount();
int requestPaintMethod = metaObject->indexOfMethod("requestPaint()");
for (int ii = QmlProfilerCanvas::staticMetaObject.propertyCount(); ii < propertyCount; ++ii) {
QMetaProperty p = metaObject->property(ii);
if (p.hasNotifySignal())
QMetaObject::connect(this, p.notifySignalIndex(), this, requestPaintMethod, 0, 0);
}
QDeclarativeItem::componentComplete();
}
}
}

View File

@@ -1,82 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERCANVAS_H
#define QMLPROFILERCANVAS_H
#include <QDeclarativeItem>
QT_BEGIN_NAMESPACE
class Context2D;
QT_END_NAMESPACE
namespace QmlProfiler {
namespace Internal {
class QmlProfilerCanvas : public QDeclarativeItem
{
Q_OBJECT
Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged)
public:
QmlProfilerCanvas();
bool dirty() const { return m_dirty; }
void setDirty(bool dirty)
{
if (m_dirty != dirty) {
m_dirty = dirty;
emit dirtyChanged(dirty);
}
}
signals:
void dirtyChanged(bool dirty);
void drawRegion(Context2D *ctxt, const QRect &region);
public slots:
void requestPaint();
void requestRedraw();
protected:
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
virtual void componentComplete();
private:
Context2D *m_context2d;
bool m_dirty;
};
}
}
#endif // QMLPROFILERCANVAS_H

View File

@@ -1,152 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "localqmlprofilerrunner.h"
#include "qmlprofilerplugin.h"
#include "qmlprofilerengine.h"
#include <analyzerbase/analyzerstartparameters.h>
#include <projectexplorer/runconfiguration.h>
#include <qmlprojectmanager/qmlprojectrunconfiguration.h>
#include <projectexplorer/localapplicationrunconfiguration.h>
#include <projectexplorer/environmentaspect.h>
using namespace QmlProfiler;
using namespace QmlProfiler::Internal;
using namespace ProjectExplorer;
LocalQmlProfilerRunner *LocalQmlProfilerRunner::createLocalRunner(
RunConfiguration *runConfiguration,
const Analyzer::AnalyzerStartParameters &sp,
QString *errorMessage,
QmlProfilerRunControl *engine)
{
QmlProjectManager::QmlProjectRunConfiguration *rc1 =
qobject_cast<QmlProjectManager::QmlProjectRunConfiguration *>(runConfiguration);
LocalApplicationRunConfiguration *rc2 =
qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
QTC_ASSERT(rc1 || rc2, return 0);
ProjectExplorer::EnvironmentAspect *environment
= runConfiguration->extraAspect<ProjectExplorer::EnvironmentAspect>();
QTC_ASSERT(environment, return 0);
Configuration conf;
if (rc1) {
// This is a "plain" .qmlproject.
conf.executable = rc1->observerPath();
conf.executableArguments = rc1->viewerArguments();
conf.workingDirectory = rc1->workingDirectory();
conf.environment = environment->environment();
} else {
// FIXME: Check.
conf.executable = rc2->executable();
conf.executableArguments = rc2->commandLineArguments();
conf.workingDirectory = rc2->workingDirectory();
conf.environment = environment->environment();
}
conf.port = sp.analyzerPort;
if (conf.executable.isEmpty()) {
if (errorMessage)
*errorMessage = tr("No executable file to launch.");
return 0;
}
return new LocalQmlProfilerRunner(conf, engine);
}
LocalQmlProfilerRunner::LocalQmlProfilerRunner(const Configuration &configuration,
QmlProfilerRunControl *engine) :
AbstractQmlProfilerRunner(engine),
m_configuration(configuration),
m_engine(engine)
{
connect(&m_launcher, SIGNAL(appendMessage(QString,Utils::OutputFormat)),
this, SIGNAL(appendMessage(QString,Utils::OutputFormat)));
}
LocalQmlProfilerRunner::~LocalQmlProfilerRunner()
{
disconnect();
}
void LocalQmlProfilerRunner::start()
{
if (m_engine->mode() != Analyzer::StartLocal)
return;
QString arguments = QString::fromLatin1("-qmljsdebugger=port:%1,block").arg(m_configuration.port);
if (!m_configuration.executableArguments.isEmpty())
arguments += QLatin1Char(' ') + m_configuration.executableArguments;
if (QmlProfilerPlugin::debugOutput)
qWarning("QmlProfiler: Launching %s:%d", qPrintable(m_configuration.executable),
m_configuration.port);
m_launcher.setWorkingDirectory(m_configuration.workingDirectory);
m_launcher.setEnvironment(m_configuration.environment);
connect(&m_launcher, SIGNAL(processExited(int,QProcess::ExitStatus)),
this, SLOT(spontaneousStop(int,QProcess::ExitStatus)));
m_launcher.start(ProjectExplorer::ApplicationLauncher::Gui, m_configuration.executable,
arguments);
emit started();
}
void LocalQmlProfilerRunner::spontaneousStop(int exitCode, QProcess::ExitStatus status)
{
if (QmlProfilerPlugin::debugOutput) {
if (status == QProcess::CrashExit)
qWarning("QmlProfiler: Application crashed.");
else
qWarning("QmlProfiler: Application exited (exit code %d).", exitCode);
}
disconnect(&m_launcher, SIGNAL(processExited(int,QProcess::ExitStatus)),
this, SLOT(spontaneousStop(int,QProcess::ExitStatus)));
emit stopped();
}
void LocalQmlProfilerRunner::stop()
{
if (m_engine->mode() != Analyzer::StartLocal)
return;
if (QmlProfilerPlugin::debugOutput)
qWarning("QmlProfiler: Stopping application ...");
if (m_launcher.isRunning())
m_launcher.stop();
}
quint16 LocalQmlProfilerRunner::debugPort() const
{
return m_configuration.port;
}

View File

@@ -1,85 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef LOCALQMLPROFILERRUNNER_H
#define LOCALQMLPROFILERRUNNER_H
#include "abstractqmlprofilerrunner.h"
#include <utils/environment.h>
#include <projectexplorer/applicationlauncher.h>
namespace ProjectExplorer { class RunConfiguration; }
namespace Analyzer { class AnalyzerStartParameters; }
namespace QmlProfiler {
namespace Internal {
class QmlProfilerRunControl;
class LocalQmlProfilerRunner : public AbstractQmlProfilerRunner
{
Q_OBJECT
public:
struct Configuration {
QString executable;
QString executableArguments;
quint16 port;
QString workingDirectory;
Utils::Environment environment;
};
static LocalQmlProfilerRunner *createLocalRunner(ProjectExplorer::RunConfiguration *runConfiguration,
const Analyzer::AnalyzerStartParameters &sp,
QString *errorMessage,
QmlProfilerRunControl *engine);
~LocalQmlProfilerRunner();
// AbstractQmlProfilerRunner
virtual void start();
virtual void stop();
virtual quint16 debugPort() const;
private slots:
void spontaneousStop(int exitCode, QProcess::ExitStatus status);
private:
LocalQmlProfilerRunner(const Configuration &configuration, QmlProfilerRunControl *engine);
private:
Configuration m_configuration;
ProjectExplorer::ApplicationLauncher m_launcher;
QmlProfilerRunControl *m_engine;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // LOCALQMLPROFILERRUNNER_H

View File

@@ -1,59 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
import QtQuick 1.0
import Monitor 1.0
Item {
id: detail
property string label
property string content
height: childrenRect.height+2
width: childrenRect.width
Item {
id: guideline
x: 70
width: 5
}
Text {
y: 1
id: lbl
text: label
font.pixelSize: 12
font.bold: true
}
Text {
text: content
font.pixelSize: 12
anchors.baseline: lbl.baseline
anchors.left: guideline.right
textFormat: Text.PlainText
}
}

View File

@@ -1,168 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
import QtQuick 1.0
Item {
id: labelContainer
property string text: qmlProfilerModelProxy.categoryLabel(modelIndex, categoryIndex)
property bool expanded: false
property int categoryIndex: qmlProfilerModelProxy.correctedCategoryIndexForModel(modelIndex, index)
property int modelIndex: qmlProfilerModelProxy.modelIndexForCategory(index);
property variant descriptions: []
property variant extdescriptions: []
property variant eventIds: []
visible: qmlProfilerModelProxy.categoryDepth(modelIndex, categoryIndex) > 0;
height: root.singleRowHeight
width: 150
onExpandedChanged: {
qmlProfilerModelProxy.setExpanded(modelIndex, categoryIndex, expanded);
backgroundMarks.requestRedraw();
getDescriptions();
updateHeight();
}
Component.onCompleted: {
updateHeight();
}
function updateHeight() {
if (expanded != qmlProfilerModelProxy.expanded(modelIndex, categoryIndex))
expanded = qmlProfilerModelProxy.expanded(modelIndex, categoryIndex);
height = root.singleRowHeight * qmlProfilerModelProxy.categoryDepth(modelIndex, categoryIndex);
}
function getDescriptions() {
visible = qmlProfilerModelProxy.categoryDepth(modelIndex, categoryIndex) > 0;
if (!visible)
return;
var desc=[];
var ids=[];
var extdesc=[];
var labelList = qmlProfilerModelProxy.getLabelsForCategory(modelIndex, categoryIndex);
for (var i = 0; i < labelList.length; i++ ) {
desc[i] = labelList[i].description;
ids[i] = labelList[i].id;
extdesc[i] = labelList[i].displayName + ":" + labelList[i].description;
}
descriptions = desc;
eventIds = ids;
extdescriptions = extdesc;
updateHeight();
}
Connections {
target: qmlProfilerModelProxy
onExpandedChanged: {
updateHeight();
}
onStateChanged: {
getDescriptions();
}
}
Text {
id: txt
x: 5
font.pixelSize: 12
text: labelContainer.text
color: "#232323"
height: root.singleRowHeight
width: 140
verticalAlignment: Text.AlignVCenter
}
Rectangle {
height: 1
width: parent.width
color: "#999999"
anchors.bottom: parent.bottom
z: 2
}
Column {
y: root.singleRowHeight
visible: expanded
Repeater {
model: descriptions.length
Rectangle {
width: labelContainer.width
height: root.singleRowHeight
color: "#eaeaea"
border.width: 1
border.color:"#c8c8c8"
Text {
height: root.singleRowHeight
x: 5
width: 140
text: descriptions[index]
textFormat: Text.PlainText
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: changeToolTip(extdescriptions[index]);
onExited: changeToolTip("");
onClicked: {
if (mouse.modifiers & Qt.ShiftModifier)
view.selectPrevFromId(modelIndex,eventIds[index]);
else
view.selectNextFromId(modelIndex,eventIds[index]);
}
}
}
}
}
Image {
//visible: descriptions.length > 0
visible: true
source: expanded ? "arrow_down.png" : "arrow_right.png"
x: parent.width - 12
y: root.singleRowHeight / 2 - height / 2
MouseArea {
anchors.fill: parent
anchors.rightMargin: -10
anchors.leftMargin: -10
anchors.topMargin: -10
anchors.bottomMargin: -10
onClicked: {
expanded = !expanded;
}
}
}
}

View File

@@ -1,605 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
import QtQuick 1.0
import Monitor 1.0
Rectangle {
id: root
// ***** properties
property int candidateHeight: 0
property int scrollY: 0
height: Math.max( candidateHeight, labels.height + 2 )
property int singleRowHeight: 30
property bool dataAvailable: true
property int eventCount: 0
property real progress: 0
property alias selectionLocked : view.selectionLocked
signal updateLockButton
property alias selectedItem: view.selectedItem
signal selectedEventChanged(int eventId)
property bool lockItemSelection : false
/* property variant names: [ qsTr("Painting"),
qsTr("Compiling"),
qsTr("Creating"),
qsTr("Binding"),
qsTr("Handling Signal")]
property variant colors : [ "#99CCB3", "#99CCCC", "#99B3CC",
"#9999CC", "#CC99B3", "#CC99CC", "#CCCC99", "#CCB399" ]
*/
property variant mainviewTimePerPixel : 0
signal updateCursorPosition
property string fileName: ""
property int lineNumber: -1
property int columnNumber: 0
signal updateRangeButton
property bool selectionRangeMode: false
property bool selectionRangeReady: selectionRange.ready
property variant selectionRangeStart: selectionRange.startTime
property variant selectionRangeEnd: selectionRange.startTime + selectionRange.duration
signal changeToolTip(string text)
signal updateVerticalScroll(int newPosition)
property bool recordingEnabled: false
property bool appKilled : false
property date recordingStartDate
property real elapsedTime
// ***** connections with external objects
Connections {
target: zoomControl
onRangeChanged: {
var startTime = zoomControl.startTime();
var endTime = zoomControl.endTime();
var duration = Math.abs(endTime - startTime);
mainviewTimePerPixel = duration / root.width;
backgroundMarks.updateMarks(startTime, endTime);
view.updateFlickRange(startTime, endTime);
if (duration > 0) {
var candidateWidth = qmlProfilerModelProxy.traceDuration() *
flick.width / duration;
if (flick.contentWidth !== candidateWidth)
flick.contentWidth = candidateWidth;
}
}
}
Connections {
target: qmlProfilerModelProxy
onCountChanged: {
eventCount = qmlProfilerModelProxy.count();
if (eventCount === 0)
root.clearAll();
if (eventCount > 1) {
root.progress = Math.min(1.0,
(qmlProfilerModelProxy.lastTimeMark() -
qmlProfilerModelProxy.traceStartTime()) / root.elapsedTime * 1e-9 );
} else {
root.progress = 0;
}
}
onStateChanged: {
switch (qmlProfilerModelProxy.getState()) {
case 0: {
root.clearAll();
break;
}
case 1: {
root.dataAvailable = false;
break;
}
case 2: {
root.progress = 0.9; // jump to 90%
break;
}
}
}
onDataAvailable: {
view.clearData();
zoomControl.setRange(0,0);
progress = 1.0;
dataAvailable = true;
view.visible = true;
view.requestPaint();
zoomControl.setRange(qmlProfilerModelProxy.traceStartTime(),
qmlProfilerModelProxy.traceStartTime() +
qmlProfilerModelProxy.traceDuration()/10);
}
}
// ***** functions
function gotoSourceLocation(file,line,column) {
if (file !== undefined) {
root.fileName = file;
root.lineNumber = line;
root.columnNumber = column;
root.updateCursorPosition();
}
}
function clearData() {
view.clearData();
dataAvailable = false;
appKilled = false;
eventCount = 0;
hideRangeDetails();
selectionRangeMode = false;
updateRangeButton();
zoomControl.setRange(0,0);
}
function clearDisplay() {
clearData();
view.visible = false;
}
function clearAll() {
clearDisplay();
elapsedTime = 0;
}
function nextEvent() {
view.selectNext();
}
function prevEvent() {
view.selectPrev();
}
function updateWindowLength(absoluteFactor) {
var windowLength = view.endTime - view.startTime;
if (qmlProfilerModelProxy.traceEndTime() <= qmlProfilerModelProxy.traceStartTime() ||
windowLength <= 0)
return;
var currentFactor = windowLength / qmlProfilerModelProxy.traceDuration();
updateZoom(absoluteFactor / currentFactor);
}
function updateZoom(relativeFactor) {
var min_length = 1e5; // 0.1 ms
var windowLength = view.endTime - view.startTime;
if (windowLength < min_length)
windowLength = min_length;
var newWindowLength = windowLength * relativeFactor;
if (newWindowLength > qmlProfilerModelProxy.traceDuration()) {
newWindowLength = qmlProfilerModelProxy.traceDuration();
relativeFactor = newWindowLength / windowLength;
}
if (newWindowLength < min_length) {
newWindowLength = min_length;
relativeFactor = newWindowLength / windowLength;
}
var fixedPoint = (view.startTime + view.endTime) / 2;
if (view.selectedItem !== -1) {
// center on selected item if it's inside the current screen
var newFixedPoint = qmlProfilerModelProxy.getStartTime(view.selectedModel, view.selectedItem);
if (newFixedPoint >= view.startTime && newFixedPoint < view.endTime)
fixedPoint = newFixedPoint;
}
var startTime = fixedPoint - relativeFactor*(fixedPoint - view.startTime);
zoomControl.setRange(startTime, startTime + newWindowLength);
}
function updateZoomCentered(centerX, relativeFactor)
{
var min_length = 1e5; // 0.1 ms
var windowLength = view.endTime - view.startTime;
if (windowLength < min_length)
windowLength = min_length;
var newWindowLength = windowLength * relativeFactor;
if (newWindowLength > qmlProfilerModelProxy.traceDuration()) {
newWindowLength = qmlProfilerModelProxy.traceDuration();
relativeFactor = newWindowLength / windowLength;
}
if (newWindowLength < min_length) {
newWindowLength = min_length;
relativeFactor = newWindowLength / windowLength;
}
var fixedPoint = (centerX - flick.x) * windowLength / flick.width + view.startTime;
var startTime = fixedPoint - relativeFactor*(fixedPoint - view.startTime);
zoomControl.setRange(startTime, startTime + newWindowLength);
}
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);
}
function recenterOnItem( modelIndex, itemIndex )
{
if (itemIndex === -1)
return;
// if item is outside of the view, jump back to its position
if (qmlProfilerModelProxy.getEndTime(modelIndex, itemIndex) < view.startTime ||
qmlProfilerModelProxy.getStartTime(modelIndex, itemIndex) > view.endTime) {
recenter((qmlProfilerModelProxy.getStartTime(modelIndex, itemIndex) +
qmlProfilerModelProxy.getEndTime(modelIndex, itemIndex)) / 2);
}
}
function wheelZoom(wheelCenter, wheelDelta) {
if (qmlProfilerModelProxy.traceEndTime() > qmlProfilerModelProxy.traceStartTime() &&
wheelDelta !== 0) {
if (wheelDelta>0)
updateZoomCentered(wheelCenter, 1/1.2);
else
updateZoomCentered(wheelCenter, 1.2);
}
}
function hideRangeDetails() {
rangeDetails.visible = false;
rangeDetails.duration = "";
rangeDetails.label = "";
//rangeDetails.type = "";
rangeDetails.file = "";
rangeDetails.line = -1;
rangeDetails.column = 0;
rangeDetails.isBindingLoop = false;
}
function selectNextByHash(hash) {
var eventId = qmlProfilerModelProxy.getEventIdForHash(hash);
if (eventId !== -1) {
selectNextById(eventId);
}
}
function selectNextById(eventId)
{
// this is a slot responding to events from the other pane
// which tracks only events from the basic model
if (!lockItemSelection) {
lockItemSelection = true;
var modelIndex = qmlProfilerModelProxy.basicModelIndex();
var itemIndex = view.nextItemFromId( modelIndex, eventId );
// select an item, lock to it, and recenter if necessary
if (view.selectedItem != itemIndex || view.selectedModel != modelIndex) {
view.selectedModel = modelIndex;
view.selectedItem = itemIndex;
if (itemIndex !== -1) {
view.selectionLocked = true;
recenterOnItem(modelIndex, itemIndex);
}
}
lockItemSelection = false;
}
}
// ***** slots
onSelectionRangeModeChanged: {
selectionRangeControl.enabled = selectionRangeMode;
selectionRange.reset(selectionRangeMode);
}
onSelectionLockedChanged: {
updateLockButton();
}
onSelectedItemChanged: {
if (selectedItem != -1 && !lockItemSelection) {
lockItemSelection = true;
// update in other views
var eventLocation = qmlProfilerModelProxy.getEventLocation(view.selectedModel, view.selectedItem);
gotoSourceLocation(eventLocation.file, eventLocation.line, eventLocation.column);
lockItemSelection = false;
}
}
onRecordingEnabledChanged: {
if (recordingEnabled) {
recordingStartDate = new Date();
elapsedTime = 0;
} else {
elapsedTime = (new Date() - recordingStartDate)/1000.0;
}
}
// ***** child items
TimeMarks {
id: backgroundMarks
y: labels.y
height: flick.height
anchors.left: flick.left
anchors.right: flick.right
}
Flickable {
id: flick
anchors.top: parent.top
anchors.topMargin: labels.y
anchors.right: parent.right
anchors.left: labels.right
height: root.height
contentWidth: 0;
contentHeight: labels.height
flickableDirection: Flickable.HorizontalFlick
onContentXChanged: {
if (Math.round(view.startX) !== contentX)
view.startX = contentX;
}
clip:true
MouseArea {
id: selectionRangeDrag
enabled: selectionRange.ready
anchors.fill: selectionRange
drag.target: selectionRange
drag.axis: "XAxis"
drag.minimumX: 0
drag.maximumX: flick.contentWidth - selectionRange.width
onPressed: {
selectionRange.isDragging = true;
}
onReleased: {
selectionRange.isDragging = false;
}
onDoubleClicked: {
zoomControl.setRange(selectionRange.startTime,
selectionRange.startTime + selectionRange.duration);
root.selectionRangeMode = false;
root.updateRangeButton();
}
}
SelectionRange {
id: selectionRange
visible: root.selectionRangeMode
height: root.height
z: 2
}
TimelineRenderer {
id: view
profilerModelProxy: qmlProfilerModelProxy
x: flick.contentX
width: flick.width
height: root.height
property variant startX: 0
onStartXChanged: {
var newStartTime = Math.round(startX * (endTime - startTime) / flick.width) +
qmlProfilerModelProxy.traceStartTime();
if (Math.abs(newStartTime - startTime) > 1) {
var newEndTime = Math.round((startX+flick.width) *
(endTime - startTime) /
flick.width) +
qmlProfilerModelProxy.traceStartTime();
zoomControl.setRange(newStartTime, newEndTime);
}
if (Math.round(startX) !== flick.contentX)
flick.contentX = startX;
}
function updateFlickRange(start, end) {
if (start !== startTime || end !== endTime) {
startTime = start;
endTime = end;
var newStartX = (startTime - qmlProfilerModelProxy.traceStartTime()) *
flick.width / (endTime-startTime);
if (Math.abs(newStartX - startX) >= 1)
startX = newStartX;
}
}
onSelectedItemChanged: {
if (selectedItem !== -1) {
// display details
rangeDetails.showInfo(qmlProfilerModelProxy.getEventDetails(selectedModel, selectedItem));
rangeDetails.setLocation(qmlProfilerModelProxy.getEventLocation(selectedModel, selectedItem));
// center view (horizontally)
var windowLength = view.endTime - view.startTime;
var eventStartTime = qmlProfilerModelProxy.getStartTime(selectedModel, selectedItem);
var eventEndTime = eventStartTime +
qmlProfilerModelProxy.getDuration(selectedModel, selectedItem);
if (eventEndTime < view.startTime || eventStartTime > view.endTime) {
var center = (eventStartTime + eventEndTime)/2;
var from = Math.min(qmlProfilerModelProxy.traceEndTime()-windowLength,
Math.max(0, Math.floor(center - windowLength/2)));
zoomControl.setRange(from, from + windowLength);
}
// center view (vertically)
var itemY = view.getYPosition(selectedModel, selectedItem);
if (itemY < root.scrollY) {
root.updateVerticalScroll(itemY);
} else
if (itemY + root.singleRowHeight >
root.scrollY + root.candidateHeight) {
root.updateVerticalScroll(itemY + root.singleRowHeight -
root.candidateHeight);
}
} else {
root.hideRangeDetails();
}
}
onItemPressed: {
var location = qmlProfilerModelProxy.getEventLocation(modelIndex, pressedItem);
if (location.hasOwnProperty("file")) // not empty
root.gotoSourceLocation(location.file, location.line, location.column);
}
// hack to pass mouse events to the other mousearea if enabled
startDragArea: selectionRangeDrag.enabled ? selectionRangeDrag.x :
-flick.contentX
endDragArea: selectionRangeDrag.enabled ?
selectionRangeDrag.x + selectionRangeDrag.width :
-flick.contentX-1
}
MouseArea {
id: selectionRangeControl
enabled: false
width: flick.width
height: root.height
x: flick.contentX
hoverEnabled: enabled
z: 2
onReleased: {
selectionRange.releasedOnCreation();
}
onPressed: {
selectionRange.pressedOnCreation();
}
onMousePositionChanged: {
selectionRange.movedOnCreation();
}
}
}
SelectionRangeDetails {
id: selectionRangeDetails
visible: root.selectionRangeMode
startTime: selectionRange.startTimeString
duration: selectionRange.durationString
endTime: selectionRange.endTimeString
showDuration: selectionRange.width > 1
}
RangeDetails {
id: rangeDetails
}
Rectangle {
id: labels
width: 150
color: "#dcdcdc"
height: col.height
property int rowCount: qmlProfilerModelProxy.categories();
Column {
id: col
Repeater {
model: labels.rowCount
delegate: Label { }
}
}
}
Rectangle {
id: labelsTail
anchors.top: labels.bottom
anchors.bottom: root.bottom
width: labels.width
color: labels.color
}
// Gradient borders
Item {
anchors.left: labels.right
width: 6
anchors.top: root.top
anchors.bottom: root.bottom
Rectangle {
x: parent.width
transformOrigin: Item.TopLeft
rotation: 90
width: parent.height
height: parent.width
gradient: Gradient {
GradientStop { position: 0.0; color: "#00000000"; }
GradientStop { position: 1.0; color: "#86000000"; }
}
}
}
Item {
anchors.right: root.right
width: 6
anchors.top: root.top
anchors.bottom: root.bottom
Rectangle {
x: parent.width
transformOrigin: Item.TopLeft
rotation: 90
width: parent.height
height: parent.width
gradient: Gradient {
GradientStop { position: 0.0; color: "#86000000"; }
GradientStop { position: 1.0; color: "#00000000"; }
}
}
}
Rectangle {
y: root.scrollY + root.candidateHeight - height
height: 6
width: root.width
x: 0
gradient: Gradient {
GradientStop { position: 0.0; color: "#00000000"; }
GradientStop { position: 1.0; color: "#86000000"; }
}
}
}

View File

@@ -1,181 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
.pragma library
var qmlProfilerModelProxy = 0;
//draw background of the graph
function drawGraph(canvas, ctxt, region)
{
ctxt.fillStyle = "#eaeaea";
ctxt.fillRect(0, 0, canvas.width, canvas.height);
}
//draw the actual data to be graphed
function drawData(canvas, ctxt, region)
{
if ((!qmlProfilerModelProxy) || qmlProfilerModelProxy.count() == 0)
return;
var width = canvas.width;
var bump = 10;
var height = canvas.height - bump;
var typeCount = qmlProfilerModelProxy.visibleCategories();
var blockHeight = height / typeCount;
var spacing = width / qmlProfilerModelProxy.traceDuration();
var modelRowStart = 0;
for (var modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount(); modelIndex++) {
for (var ii = 0; ii < qmlProfilerModelProxy.count(modelIndex); ++ii) {
var xx = (qmlProfilerModelProxy.getStartTime(modelIndex,ii) -
qmlProfilerModelProxy.traceStartTime()) * spacing;
if (xx > region.x + region.width)
continue;
var eventWidth = qmlProfilerModelProxy.getDuration(modelIndex,ii) * spacing;
if (xx + eventWidth < region.x)
continue;
if (eventWidth < 1)
eventWidth = 1;
xx = Math.round(xx);
var rowNumber = modelRowStart + qmlProfilerModelProxy.getEventCategoryInModel(modelIndex, ii);
var itemHeight = qmlProfilerModelProxy.getHeight(modelIndex,ii) * blockHeight;
var yy = (rowNumber + 1) * blockHeight - itemHeight ;
var itemColor = qmlProfilerModelProxy.getColorRGB(modelIndex, ii);
ctxt.fillStyle = "rgb("+itemColor[0]+","+itemColor[1]+","+itemColor[2]+")";
ctxt.fillRect(xx, bump + yy, eventWidth, itemHeight);
}
modelRowStart += qmlProfilerModelProxy.categoryCount(modelIndex);
}
// binding loops
ctxt.strokeStyle = "orange";
ctxt.lineWidth = 2;
var radius = 1;
modelRowStart = 0;
for (modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount(); modelIndex++) {
for (ii = 0; ii < qmlProfilerModelProxy.count(modelIndex); ++ii) {
if (qmlProfilerModelProxy.getBindingLoopDest(modelIndex,ii) >= 0) {
var xcenter = Math.round(qmlProfilerModelProxy.getStartTime(modelIndex,ii) +
qmlProfilerModelProxy.getDuration(modelIndex,ii) -
qmlProfilerModelProxy.traceStartTime()) * spacing;
var ycenter = Math.round(bump + (modelRowStart +
qmlProfilerModelProxy.getEventCategoryInModel(modelIndex, ii)) *
blockHeight + blockHeight/2);
ctxt.arc(xcenter, ycenter, radius, 0, 2*Math.PI, true);
ctxt.stroke();
}
}
modelRowStart += qmlProfilerModelProxy.categoryCount(modelIndex);
}
}
function drawTimeBar(canvas, ctxt, region)
{
if (!qmlProfilerModelProxy)
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 *
initialBlockLength ) / Math.LN2 ) );
var pixelsPerBlock = timePerBlock * spacing;
var pixelsPerSection = pixelsPerBlock / 5;
var blockCount = width / pixelsPerBlock;
var realStartTime = Math.floor(startTime/timePerBlock) * timePerBlock;
var realStartPos = (startTime-realStartTime) * spacing;
var timePerPixel = timePerBlock/pixelsPerBlock;
ctxt.fillStyle = "#000000";
ctxt.font = "6px sans-serif";
ctxt.fillStyle = "#cccccc";
ctxt.fillRect(0, 0, width, height);
for (var ii = 0; ii < blockCount+1; ii++) {
var x = Math.floor(ii*pixelsPerBlock - realStartPos);
// block boundary
ctxt.strokeStyle = "#525252";
ctxt.beginPath();
ctxt.moveTo(x, height/2);
ctxt.lineTo(x, height);
ctxt.stroke();
// block time label
ctxt.fillStyle = "#000000";
var timeString = prettyPrintTime((ii+0.5)*timePerBlock + realStartTime);
ctxt.textAlign = "center";
ctxt.fillText(timeString, x + pixelsPerBlock/2, height/2 + 3);
}
ctxt.fillStyle = "#808080";
ctxt.fillRect(0, height-1, width, 1);
}
function prettyPrintTime( t )
{
if (t <= 0) return "0";
if (t<1000) return t+" ns";
t = t/1000;
if (t<1000) return t+" μs";
t = Math.floor(t/100)/10;
if (t<1000) return t+" ms";
t = Math.floor(t)/1000;
if (t<60) return t+" s";
var m = Math.floor(t/60);
t = Math.floor(t - m*60);
return m+"m"+t+"s";
}
function plot(canvas, ctxt, region)
{
drawGraph(canvas, ctxt, region);
drawData(canvas, ctxt, region);
drawTimeBar(canvas, ctxt, region);
}

View File

@@ -1,126 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
import QtQuick 1.0
import Monitor 1.0
import "Overview.js" as Plotter
Canvas2D {
id: canvas
// ***** properties
height: 50
property bool dataReady: false
property variant startTime : 0
property variant endTime : 0
// ***** functions
function clearDisplay()
{
dataReady = false;
requestRedraw();
}
function updateRange() {
var newStartTime = Math.round(rangeMover.x * qmlProfilerModelProxy.traceDuration() / width) + qmlProfilerModelProxy.traceStartTime();
var newEndTime = Math.round((rangeMover.x + rangeMover.width) * qmlProfilerModelProxy.traceDuration() / width) + qmlProfilerModelProxy.traceStartTime();
if (startTime !== newStartTime || endTime !== newEndTime) {
zoomControl.setRange(newStartTime, newEndTime);
}
}
// ***** connections to external objects
Connections {
target: zoomControl
onRangeChanged: {
if (qmlProfilerModelProxy) {
startTime = zoomControl.startTime();
endTime = zoomControl.endTime();
var newRangeX = (startTime - qmlProfilerModelProxy.traceStartTime()) * width / qmlProfilerModelProxy.traceDuration();
if (rangeMover.x !== newRangeX)
rangeMover.x = newRangeX;
var newWidth = (endTime-startTime) * width / qmlProfilerModelProxy.traceDuration();
if (rangeMover.width !== newWidth)
rangeMover.width = newWidth;
}
}
}
Connections {
target: qmlProfilerModelProxy
onDataAvailable: {
dataReady = true;
requestRedraw();
}
}
// ***** slots
onDrawRegion: {
Plotter.qmlProfilerModelProxy = qmlProfilerModelProxy;
if (dataReady) {
Plotter.plot(canvas, ctxt, region);
} else {
Plotter.drawGraph(canvas, ctxt, region) //just draw the background
}
}
// ***** child items
MouseArea {
anchors.fill: canvas
function jumpTo(posX) {
var newX = posX - rangeMover.width/2;
if (newX < 0)
newX = 0;
if (newX + rangeMover.width > canvas.width)
newX = canvas.width - rangeMover.width;
rangeMover.x = newX;
updateRange();
}
onPressed: {
jumpTo(mouse.x);
}
onMousePositionChanged: {
jumpTo(mouse.x);
}
}
RangeMover {
id: rangeMover
visible: dataReady
}
Rectangle {
height: 1
width: parent.width
color: "#858585"
}
}

View File

@@ -1,235 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
import QtQuick 1.0
import Monitor 1.0
Item {
id: rangeDetails
property string duration
property string label
property string dialogTitle
property string file
property int line
property int column
property bool isBindingLoop
property bool locked: view.selectionLocked
width: col.width + 45
height: col.height + 30
z: 1
visible: false
x: 200
y: 25
property int yoffset: root.scrollY
onYoffsetChanged: {
y = relativey + yoffset
fitInView();
}
property int relativey : y - yoffset
onYChanged: relativey = y - yoffset
// keep inside view
Connections {
target: root
onWidthChanged: fitInView();
onCandidateHeightChanged: fitInView();
}
//property variant eventInfo
ListModel {
id: eventInfo
}
function showInfo(eventData) {
eventInfo.clear();
rangeDetails.dialogTitle = eventData[0]["title"];
for (var i = 1; i < eventData.length; i++) {
for (var k in eventData[i]) {
eventInfo.append({"key": k, "value":eventData[i][k]});
}
}
rangeDetails.visible = true;
}
function setLocation(location) {
if (location.hasOwnProperty("file")) { // not empty
file = location.file;
line = location.line;
column = location.column;
} else {
// reset to default values
file = "";
line = 0;
column = -1;
}
}
function fitInView() {
// don't reposition if it does not fit
if (root.width < width || root.candidateHeight < height)
return;
if (x + width > root.width)
x = root.width - width;
if (x < 0)
x = 0;
if (y - yoffset + height > root.candidateHeight)
y = root.candidateHeight - height + yoffset;
if (y < yoffset)
y = yoffset;
}
// shadow
BorderImage {
property int px: 4
source: "dialog_shadow.png"
border {
left: px; top: px
right: px; bottom: px
}
width: parent.width + 2*px - 1
height: parent.height
x: -px + 1
y: px + 1
}
// title bar
Rectangle {
width: parent.width
height: 20
color: "#55a3b8"
radius: 5
border.width: 1
border.color: "#a0a0a0"
}
Item {
width: parent.width+1
height: 11
y: 10
clip: true
Rectangle {
width: parent.width-1
height: 15
y: -5
color: "#55a3b8"
border.width: 1
border.color: "#a0a0a0"
}
}
//title
Text {
id: typeTitle
text: " "+rangeDetails.dialogTitle
font.bold: true
height: 18
y: 2
verticalAlignment: Text.AlignVCenter
width: parent.width
color: "white"
}
// Details area
Rectangle {
color: "white"
width: parent.width
height: col.height + 10
y: 20
border.width: 1
border.color: "#a0a0a0"
//details
Column {
id: col
x: 10
y: 5
Repeater {
model: eventInfo
Detail {
label: key
content: value
}
}
}
}
MouseArea {
width: col.width + 45
height: col.height + 30
drag.target: parent
drag.minimumX: 0
drag.maximumX: root.width - parent.width
drag.minimumY: yoffset
drag.maximumY: root.candidateHeight - parent.height + yoffset
onClicked: {
root.gotoSourceLocation(file, line, column);
root.recenterOnItem(view.selectedModel, view.selectedItem);
}
}
Image {
id: lockIcon
source: locked?"lock_closed.png" : "lock_open.png"
anchors.top: closeIcon.top
anchors.right: closeIcon.left
anchors.rightMargin: 4
width: 8
height: 12
MouseArea {
anchors.fill: parent
onClicked: {
root.selectionLocked = !root.selectionLocked;
}
}
}
Text {
id: closeIcon
x: col.width + 30
y: 4
text:"X"
color: "white"
MouseArea {
anchors.fill: parent
onClicked: {
root.hideRangeDetails();
view.selectedItem = -1;
}
}
}
}

View File

@@ -1,203 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
import QtQuick 1.0
Rectangle {
id: rangeMover
property color rangeColor:"#444a64b8"
property color borderColor:"#cc4a64b8"
property color dragMarkerColor: "#4a64b8"
width: 20
height: 50
color: rangeColor
property bool dragStarted: false
onXChanged: {
if (dragStarted) canvas.updateRange()
}
MouseArea {
anchors.fill: parent
drag.target: rangeMover
drag.axis: "XAxis"
drag.minimumX: 0
drag.maximumX: canvas.width - rangeMover.width
onPressed: {
parent.dragStarted = true;
}
onReleased: {
parent.dragStarted = false;
}
}
Rectangle {
id: leftRange
// used for dragging the borders
property real initialX: 0
property real initialWidth: 0
x: 0
height: parent.height
width: 1
color: borderColor
Rectangle {
id: leftBorderHandle
height: parent.height
x: -width
width: 7
color: "#869cd1"
visible: false
Image {
source: "range_handle.png"
x: 2
width: 4
height: 9
fillMode: Image.Tile
y: rangeMover.height / 2 - 4
}
}
states: State {
name: "highlighted"
PropertyChanges {
target: leftBorderHandle
visible: true
}
}
onXChanged: {
if (x !== 0) {
rangeMover.width = initialWidth - x;
rangeMover.x = initialX + x;
x = 0;
canvas.updateRange();
}
}
MouseArea {
x: -10
width: 13
y: 0
height: parent.height
drag.target: leftRange
drag.axis: "XAxis"
drag.minimumX: -parent.initialX
drag.maximumX: parent.initialWidth - 2
hoverEnabled: true
onEntered: {
parent.state = "highlighted";
}
onExited: {
if (!pressed) parent.state = "";
}
onReleased: {
if (!containsMouse) parent.state = "";
}
onPressed: {
parent.initialX = rangeMover.x;
parent.initialWidth = rangeMover.width;
}
}
}
Rectangle {
id: rightRange
x: rangeMover.width
height: parent.height
width: 1
color: borderColor
Rectangle {
id: rightBorderHandle
height: parent.height
x: 1
width: 7
color: "#869cd1"
visible: false
Image {
source: "range_handle.png"
x: 2
width: 4
height: 9
fillMode: Image.Tile
y: rangeMover.height / 2 - 4
}
}
states: State {
name: "highlighted"
PropertyChanges {
target: rightBorderHandle
visible: true
}
}
onXChanged: {
if (x!=rangeMover.width) {
rangeMover.width = x;
canvas.updateRange();
}
}
MouseArea {
x: -3
width: 13
y: 0
height: parent.height
drag.target: rightRange
drag.axis: "XAxis"
drag.minimumX: 1
drag.maximumX: canvas.width - rangeMover.x
hoverEnabled: true
onEntered: {
parent.state = "highlighted";
}
onExited: {
if (!pressed) parent.state = "";
}
onReleased: {
if (!containsMouse) parent.state = "";
}
}
}
}

View File

@@ -1,297 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
import QtQuick 1.0
Rectangle {
id: selectionRange
width: 1
color: "transparent"
property bool ready: visible && creationState === 3
property color rangeColor:"#444a64b8"
property color pressedColor:"#664a64b8"
property color borderColor:"#aa4a64b8"
property color dragMarkerColor: "#4a64b8"
property color singleLineColor: "#4a64b8"
property string startTimeString: detailedPrintTime(startTime)
property string endTimeString: detailedPrintTime(startTime+duration)
property string durationString: detailedPrintTime(duration)
property variant startTime: x * selectionRange.viewTimePerPixel + qmlProfilerModelProxy.traceStartTime()
property variant duration: width * selectionRange.viewTimePerPixel
property variant viewTimePerPixel: 1
property variant creationState : 0
property variant x1
property variant x2
property variant x3: Math.min(x1, x2)
property variant x4: Math.max(x1, x2)
property bool isDragging: false
Connections {
target: zoomControl
onRangeChanged: {
var oldTimePerPixel = selectionRange.viewTimePerPixel;
selectionRange.viewTimePerPixel = Math.abs(zoomControl.endTime() - zoomControl.startTime()) / flick.width;
if (creationState === 3 && oldTimePerPixel != selectionRange.viewTimePerPixel) {
selectionRange.x = x * oldTimePerPixel / selectionRange.viewTimePerPixel;
selectionRange.width = width * oldTimePerPixel / selectionRange.viewTimePerPixel;
}
}
}
onCreationStateChanged: {
switch (creationState) {
case 0: color = "transparent"; break;
case 1: color = singleLineColor; break;
default: color = rangeColor; break;
}
}
onIsDraggingChanged: {
if (isDragging)
color = pressedColor;
else
color = rangeColor;
}
function reset(setVisible) {
width = 1;
creationState = 0;
visible = setVisible;
}
function setPos(pos) {
switch (creationState) {
case 1: {
width = 1;
x1 = pos;
x2 = pos;
x = pos;
break;
}
case 2: {
x2 = pos;
x = x3;
width = x4-x3;
break;
}
default: return;
}
}
function detailedPrintTime( t )
{
if (t <= 0) return "0";
if (t<1000) return t+" ns";
t = Math.floor(t/1000);
if (t<1000) return t+" μs";
if (t<1e6) return (t/1000) + " ms";
return (t/1e6) + " s";
}
// creation control
function releasedOnCreation() {
if (selectionRange.creationState === 2) {
flick.interactive = true;
selectionRange.creationState = 3;
selectionRangeControl.enabled = false;
}
}
function pressedOnCreation() {
if (selectionRange.creationState === 1) {
flick.interactive = false;
selectionRange.setPos(selectionRangeControl.mouseX + flick.contentX);
selectionRange.creationState = 2;
}
}
function movedOnCreation() {
if (selectionRange.creationState === 0) {
selectionRange.creationState = 1;
}
if (!root.eventCount)
return;
if (!selectionRangeControl.pressed && selectionRange.creationState==3)
return;
if (selectionRangeControl.pressed) {
selectionRange.setPos(selectionRangeControl.mouseX + flick.contentX);
} else {
selectionRange.setPos(selectionRangeControl.mouseX + flick.contentX);
}
}
Rectangle {
id: leftBorder
visible: selectionRange.creationState === 3
// used for dragging the borders
property real initialX: 0
property real initialWidth: 0
x: 0
height: parent.height
width: 1
color: borderColor
Rectangle {
id: leftBorderHandle
height: parent.height
x: -width
width: 9
color: "#869cd1"
visible: false
Image {
source: "range_handle.png"
x: 4
width: 4
height: 63
fillMode: Image.Tile
y: root.scrollY + root.candidateHeight / 2 - 32
}
}
states: State {
name: "highlighted"
PropertyChanges {
target: leftBorderHandle
visible: true
}
}
onXChanged: if (x != 0) {
selectionRange.width = initialWidth - x;
selectionRange.x = initialX + x;
x = 0;
}
MouseArea {
x: -12
width: 15
y: 0
height: parent.height
drag.target: leftBorder
drag.axis: "XAxis"
drag.minimumX: -parent.initialX
drag.maximumX: parent.initialWidth - 2
hoverEnabled: true
onEntered: parent.state = "highlighted"
onExited: {
if (!pressed) parent.state = "";
}
onReleased: {
if (!containsMouse) parent.state = "" ;
}
onPressed: {
parent.initialX = selectionRange.x;
parent.initialWidth = selectionRange.width;
}
}
}
Rectangle {
id: rightBorder
visible: selectionRange.creationState === 3
x: selectionRange.width
height: parent.height
width: 1
color: borderColor
Rectangle {
id: rightBorderHandle
height: parent.height
x: 1
width: 9
color: "#869cd1"
visible: false
Image {
source: "range_handle.png"
x: 2
width: 4
height: 63
fillMode: Image.Tile
y: root.scrollY + root.candidateHeight / 2 - 32
}
}
states: State {
name: "highlighted"
PropertyChanges {
target: rightBorderHandle
visible: true
}
}
onXChanged: {
if (x != selectionRange.width) {
selectionRange.width = x;
}
}
MouseArea {
x: -3
width: 15
y: 0
height: parent.height
drag.target: rightBorder
drag.axis: "XAxis"
drag.minimumX: 1
drag.maximumX: flick.contentWidth - selectionRange.x
hoverEnabled: true
onEntered: {
parent.state = "highlighted";
}
onExited: {
if (!pressed) parent.state = "";
}
onReleased: {
if (!containsMouse) parent.state = "";
}
}
}
}

View File

@@ -1,189 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
import QtQuick 1.0
import Monitor 1.0
Item {
id: selectionRangeDetails
property string startTime
property string endTime
property string duration
property bool showDuration
width: 170
height: col.height + 30
z: 1
visible: false
x: 200
y: 125
property int yoffset: root.scrollY
onYoffsetChanged: {
y = relativey + yoffset
fitInView();
}
property int relativey : y - yoffset
onYChanged: relativey = y - yoffset
// keep inside view
Connections {
target: root
onWidthChanged: fitInView();
onCandidateHeightChanged: fitInView();
}
function fitInView() {
// don't reposition if it does not fit
if (root.width < width || root.candidateHeight < height)
return;
if (x + width > root.width)
x = root.width - width;
if (x < 0)
x = 0;
if (y + height - yoffset > root.candidateHeight)
y = root.candidateHeight - height + yoffset;
if (y < yoffset)
y = yoffset;
}
// shadow
BorderImage {
property int px: 4
source: "dialog_shadow.png"
border {
left: px; top: px
right: px; bottom: px
}
width: parent.width + 2*px - 1
height: parent.height
x: -px + 1
y: px + 1
}
// title bar
Rectangle {
width: parent.width
height: 20
color: "#4a64b8"
radius: 5
border.width: 1
border.color: "#a0a0a0"
}
Item {
width: parent.width+1
height: 11
y: 10
clip: true
Rectangle {
width: parent.width-1
height: 15
y: -5
color: "#4a64b8"
border.width: 1
border.color: "#a0a0a0"
}
}
//title
Text {
id: typeTitle
text: " "+qsTr("Selection")
font.bold: true
height: 18
y: 2
verticalAlignment: Text.AlignVCenter
width: parent.width
color: "white"
}
// Details area
Rectangle {
color: "white"
width: parent.width
height: col.height + 10
y: 20
border.width: 1
border.color: "#a0a0a0"
Column {
id: col
x: 10
y: 5
Detail {
label: qsTr("Start")
content: selectionRangeDetails.startTime
}
Detail {
label: qsTr("End")
visible: selectionRangeDetails.showDuration
content: selectionRangeDetails.endTime
}
Detail {
label: qsTr("Duration")
visible: selectionRangeDetails.showDuration
content: selectionRangeDetails.duration
}
}
}
MouseArea {
width: col.width + 45
height: col.height + 30
drag.target: parent
drag.minimumX: 0
drag.maximumX: root.width - parent.width
drag.minimumY: yoffset
drag.maximumY: root.candidateHeight - parent.height + yoffset
onClicked: {
if ((selectionRange.x < flick.contentX) ^ (selectionRange.x+selectionRange.width > flick.contentX + flick.width)) {
root.recenter(selectionRange.startTime + selectionRange.duration/2);
}
}
}
Text {
id: closeIcon
x: selectionRangeDetails.width - 14
y: 4
text:"X"
color: "white"
MouseArea {
anchors.fill: parent
anchors.leftMargin: -8
onClicked: {
root.selectionRangeMode = false;
root.updateRangeButton();
}
}
}
}

View File

@@ -1,140 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
import QtQuick 1.0
import Monitor 1.0
Canvas2D {
id: timeDisplay
property variant startTime : 0
property variant endTime : 0
property variant timePerPixel: 0
Component.onCompleted: {
requestRedraw();
}
onWidthChanged: {
requestRedraw();
}
onHeightChanged: {
requestRedraw();
}
Connections {
target: zoomControl
onRangeChanged: {
startTime = zoomControl.startTime();
endTime = zoomControl.endTime();
requestRedraw();
}
}
onDrawRegion: {
ctxt.fillStyle = "white";
ctxt.fillRect(0, 0, width, height);
var totalTime = endTime - startTime;
var spacing = width / totalTime;
var initialBlockLength = 120;
var timePerBlock = Math.pow(2, Math.floor( Math.log( totalTime / width * initialBlockLength ) / Math.LN2 ) );
var pixelsPerBlock = timePerBlock * spacing;
var pixelsPerSection = pixelsPerBlock / 5;
var blockCount = width / pixelsPerBlock;
var realStartTime = Math.floor(startTime/timePerBlock) * timePerBlock;
var realStartPos = (startTime-realStartTime) * spacing;
timePerPixel = timePerBlock/pixelsPerBlock;
var initialColor = Math.floor(realStartTime/timePerBlock) % 2;
ctxt.fillStyle = "#000000";
ctxt.font = "8px sans-serif";
for (var ii = 0; ii < blockCount+1; ii++) {
var x = Math.floor(ii*pixelsPerBlock - realStartPos);
ctxt.fillStyle = (ii+initialColor)%2 ? "#E6E6E6":"white";
ctxt.fillRect(x, 0, pixelsPerBlock, height);
ctxt.strokeStyle = "#B0B0B0";
ctxt.beginPath();
ctxt.moveTo(x, 0);
ctxt.lineTo(x, height);
ctxt.stroke();
ctxt.fillStyle = "#000000";
ctxt.fillText(prettyPrintTime(ii*timePerBlock + realStartTime), x + 5, height/2 + 5);
}
ctxt.strokeStyle = "#525252";
ctxt.beginPath();
ctxt.moveTo(0, height-1);
ctxt.lineTo(width, height-1);
ctxt.stroke();
// gradient borders
var gradientDark = "rgba(0, 0, 0, 0.53125)";
var gradientClear = "rgba(0, 0, 0, 0)";
var grad = ctxt.createLinearGradient(0, 0, 0, 6);
grad.addColorStop(0,gradientDark);
grad.addColorStop(1,gradientClear);
ctxt.fillStyle = grad;
ctxt.fillRect(0, 0, width, 6);
grad = ctxt.createLinearGradient(0, 0, 6, 0);
grad.addColorStop(0,gradientDark);
grad.addColorStop(1,gradientClear);
ctxt.fillStyle = grad;
ctxt.fillRect(0, 0, 6, height);
grad = ctxt.createLinearGradient(width, 0, width-6, 0);
grad.addColorStop(0,gradientDark);
grad.addColorStop(1,gradientClear);
ctxt.fillStyle = grad;
ctxt.fillRect(width-6, 0, 6, height);
}
function prettyPrintTime( t )
{
if (t <= 0) return "0";
if (t<1000) return t+" ns";
t = t/1000;
if (t<1000) return t+" μs";
t = Math.floor(t/100)/10;
if (t<1000) return t+" ms";
t = Math.floor(t)/1000;
if (t<60) return t+" s";
var m = Math.floor(t/60);
t = Math.floor(t - m*60);
return m+"m"+t+"s";
}
}

View File

@@ -1,148 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
import QtQuick 1.0
import Monitor 1.0
Canvas2D {
id: timeDisplay
property variant startTime
property variant endTime
property variant timePerPixel
Component.onCompleted: {
requestRedraw();
}
onWidthChanged: {
requestRedraw();
}
onHeightChanged: {
requestRedraw();
}
Connections {
target: labels
onHeightChanged: { requestRedraw(); }
}
onDrawRegion: {
drawBackgroundBars( ctxt, region );
var totalTime = endTime - startTime;
var spacing = width / totalTime;
var initialBlockLength = 120;
var timePerBlock = Math.pow(2, Math.floor( Math.log( totalTime / width * initialBlockLength ) / Math.LN2 ) );
var pixelsPerBlock = timePerBlock * spacing;
var pixelsPerSection = pixelsPerBlock / 5;
var blockCount = width / pixelsPerBlock;
var realStartTime = Math.floor(startTime/timePerBlock) * timePerBlock;
var realStartPos = (startTime-realStartTime) * spacing;
timePerPixel = timePerBlock/pixelsPerBlock;
ctxt.fillStyle = "#000000";
ctxt.font = "8px sans-serif";
for (var ii = 0; ii < blockCount+1; ii++) {
var x = Math.floor(ii*pixelsPerBlock - realStartPos);
ctxt.strokeStyle = "#B0B0B0";
ctxt.beginPath();
ctxt.moveTo(x, 0);
ctxt.lineTo(x, height);
ctxt.stroke();
ctxt.strokeStyle = "#CCCCCC";
for (var jj=1; jj < 5; jj++) {
var xx = Math.floor(ii*pixelsPerBlock + jj*pixelsPerSection - realStartPos);
ctxt.beginPath();
ctxt.moveTo(xx, 0);
ctxt.lineTo(xx, height);
ctxt.stroke();
}
}
// gray off out-of-bounds areas
var rectWidth;
if (startTime < qmlProfilerModelProxy.traceStartTime()) {
ctxt.fillStyle = "rgba(127,127,127,0.2)";
rectWidth = (qmlProfilerModelProxy.traceStartTime() - startTime) * spacing;
ctxt.fillRect(0, 0, rectWidth, height);
}
if (endTime > qmlProfilerModelProxy.traceEndTime()) {
ctxt.fillStyle = "rgba(127,127,127,0.2)";
var rectX = (qmlProfilerModelProxy.traceEndTime() - startTime) * spacing;
rectWidth = (endTime - qmlProfilerModelProxy.traceEndTime()) * spacing;
ctxt.fillRect(rectX, 0, rectWidth, height);
}
}
function updateMarks(start, end) {
if (startTime !== start || endTime !== end) {
startTime = start;
endTime = end;
requestRedraw();
}
}
function drawBackgroundBars( ctxt, region ) {
// TODO: redraw when amount of data changes
var colorIndex = true;
// row background
for (var y=0; y < labels.height; y+= root.singleRowHeight) {
ctxt.fillStyle = colorIndex ? "#f0f0f0" : "white";
ctxt.strokeStyle = colorIndex ? "#f0f0f0" : "white";
ctxt.fillRect(0, y, width, root.singleRowHeight);
colorIndex = !colorIndex;
}
// separators
var cumulatedHeight = 0;
for (var modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount(); modelIndex++) {
for (var i=0; i<qmlProfilerModelProxy.categoryCount(modelIndex); i++) {
cumulatedHeight += root.singleRowHeight * qmlProfilerModelProxy.categoryDepth(modelIndex, i);
ctxt.strokeStyle = "#B0B0B0";
ctxt.beginPath();
ctxt.moveTo(0, cumulatedHeight);
ctxt.lineTo(width, cumulatedHeight);
ctxt.stroke();
}
}
// bottom
ctxt.fillStyle = "#f5f5f5";
ctxt.fillRect(0, labels.height, width, height - labels.height);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 745 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 584 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 B

View File

@@ -1,30 +0,0 @@
<RCC>
<qresource prefix="/qmlprofiler">
<file>Detail.qml</file>
<file>Label.qml</file>
<file>MainView.qml</file>
<file>RangeDetails.qml</file>
<file>RangeMover.qml</file>
<file>TimeDisplay.qml</file>
<file>clean_pane_small.png</file>
<file>recordOff.png</file>
<file>recordOn.png</file>
<file>lock_closed.png</file>
<file>lock_open.png</file>
<file>TimeMarks.qml</file>
<file>Overview.qml</file>
<file>Overview.js</file>
<file>SelectionRange.qml</file>
<file>SelectionRangeDetails.qml</file>
<file>arrow_down.png</file>
<file>arrow_right.png</file>
<file>dialog_shadow.png</file>
<file>range_handle.png</file>
<file>ico_selectionmode.png</file>
<file>ico_zoom.png</file>
<file>ico_prev.png</file>
<file>ico_next.png</file>
<file>ico_rangeselection.png</file>
<file>ico_rangeselected.png</file>
</qresource>
</RCC>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 496 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 614 B

View File

@@ -1,80 +0,0 @@
DEFINES += QMLPROFILER_LIBRARY
QT += network script declarative
include(../../qtcreatorplugin.pri)
include(canvas/canvas.pri)
SOURCES += \
qmlprofilerplugin.cpp \
qmlprofilertool.cpp \
qmlprofilerengine.cpp \
qmlprofilerattachdialog.cpp \
localqmlprofilerrunner.cpp \
qmlprofilereventview.cpp \
qv8profilereventview.cpp \
qmlprofilerdetailsrewriter.cpp \
qmlprofilertraceview.cpp \
timelinerenderer.cpp \
qmlprofilerstatemanager.cpp \
qv8profilerdatamodel.cpp \
qmlprofilerclientmanager.cpp \
qmlprofilerviewmanager.cpp \
qmlprofilerstatewidget.cpp \
qmlprofilerruncontrolfactory.cpp \
qmlprofilermodelmanager.cpp \
qmlprofilersimplemodel.cpp \
qmlprofilerprocessedmodel.cpp \
qmlprofilereventsmodelproxy.cpp \
qmlprofilertimelinemodelproxy.cpp \
qmlprofilertreeview.cpp \
qmlprofilertracefile.cpp \
abstracttimelinemodel.cpp \
timelinemodelaggregator.cpp \
qmlprofilerpainteventsmodelproxy.cpp
HEADERS += \
qmlprofilerconstants.h \
qmlprofiler_global.h \
qmlprofilerplugin.h \
qmlprofilertool.h \
qmlprofilerengine.h \
qmlprofilerattachdialog.h \
abstractqmlprofilerrunner.h \
localqmlprofilerrunner.h \
qmlprofilereventview.h \
qv8profilereventview.h \
qmlprofilerdetailsrewriter.h \
qmlprofilertraceview.h \
timelinerenderer.h \
qmlprofilerstatemanager.h \
qv8profilerdatamodel.h \
qmlprofilerclientmanager.h \
qmlprofilerviewmanager.h \
qmlprofilerstatewidget.h \
qmlprofilerruncontrolfactory.h \
qmlprofilermodelmanager.h \
qmlprofilersimplemodel.h \
qmlprofilerprocessedmodel.h \
qmlprofilereventsmodelproxy.h \
qmlprofilertimelinemodelproxy.h \
qmlprofilertreeview.h \
qmlprofilertracefile.h \
abstracttimelinemodel.h \
timelinemodelaggregator.h \
qmlprofilerpainteventsmodelproxy.h
RESOURCES += \
qml/qmlprofiler.qrc
OTHER_FILES += \
qml/Detail.qml \
qml/Label.qml \
qml/MainView.qml \
qml/RangeDetails.qml \
qml/RangeMover.qml \
qml/TimeDisplay.qml \
qml/TimeMarks.qml \
qml/SelectionRange.qml \
qml/SelectionRangeDetails.qml \
qml/Overview.qml

View File

@@ -1,102 +0,0 @@
import qbs.base 1.0
import "../QtcPlugin.qbs" as QtcPlugin
QtcPlugin {
name: "QmlProfiler"
Depends { name: "Qt"; submodules: ["widgets", "network", "script", "declarative"] }
Depends { name: "Core" }
Depends { name: "AnalyzerBase" }
Depends { name: "Debugger" }
Depends { name: "QmlProjectManager" }
Depends { name: "Qt4ProjectManager" }
Depends { name: "RemoteLinux" }
Depends { name: "ProjectExplorer" }
Depends { name: "QtSupport" }
Depends { name: "TextEditor" }
Depends { name: "QmlDebug" }
Depends { name: "QmlJS" }
Depends { name: "QmlJSTools" }
Depends { name: "CPlusPlus" }
cpp.includePaths: base.concat("canvas")
files: [
"abstracttimelinemodel.h",
"abstracttimelinemodel.cpp",
"abstractqmlprofilerrunner.h",
"localqmlprofilerrunner.cpp",
"localqmlprofilerrunner.h",
"qmlprofiler_global.h",
"qmlprofilerattachdialog.cpp",
"qmlprofilerattachdialog.h",
"qmlprofilerclientmanager.cpp",
"qmlprofilerclientmanager.h",
"qmlprofilerconstants.h",
"qmlprofilerdetailsrewriter.cpp",
"qmlprofilerdetailsrewriter.h",
"qmlprofilerengine.cpp",
"qmlprofilerengine.h",
"qmlprofilereventsmodelproxy.cpp",
"qmlprofilereventsmodelproxy.h",
"qmlprofilereventview.cpp",
"qmlprofilereventview.h",
"qmlprofilermodelmanager.cpp",
"qmlprofilermodelmanager.h",
"qmlprofilerplugin.cpp",
"qmlprofilerplugin.h",
"qmlprofilerruncontrolfactory.cpp",
"qmlprofilerruncontrolfactory.h",
"qmlprofilerprocessedmodel.cpp",
"qmlprofilerprocessedmodel.h",
"qmlprofilersimplemodel.cpp",
"qmlprofilersimplemodel.h",
"qmlprofilerstatemanager.cpp",
"qmlprofilerstatemanager.h",
"qmlprofilerstatewidget.cpp",
"qmlprofilerstatewidget.h",
"qmlprofilertimelinemodelproxy.cpp",
"qmlprofilertimelinemodelproxy.h",
"qmlprofilertool.cpp",
"qmlprofilertool.h",
"qmlprofilertreeview.cpp",
"qmlprofilertreeview.h",
"qmlprofilertracefile.cpp",
"qmlprofilertracefile.h",
"qmlprofilertraceview.cpp",
"qmlprofilertraceview.h",
"qmlprofilerviewmanager.cpp",
"qmlprofilerviewmanager.h",
"qv8profilereventview.h",
"qv8profilereventview.cpp",
"qv8profilerdatamodel.cpp",
"qv8profilerdatamodel.h",
"timelinemodelaggregator.cpp",
"timelinemodelaggregator.h",
"timelinerenderer.cpp",
"timelinerenderer.h",
"qmlprofilerpainteventsmodelproxy.h",
"qmlprofilerpainteventsmodelproxy.cpp",
"canvas/qdeclarativecanvas.cpp",
"canvas/qdeclarativecanvas_p.h",
"canvas/qdeclarativecanvastimer.cpp",
"canvas/qdeclarativecanvastimer_p.h",
"canvas/qdeclarativecontext2d.cpp",
"canvas/qdeclarativecontext2d_p.h",
"canvas/qmlprofilercanvas.cpp",
"canvas/qmlprofilercanvas.h",
"qml/Detail.qml",
"qml/Label.qml",
"qml/MainView.qml",
"qml/Overview.js",
"qml/Overview.qml",
"qml/RangeDetails.qml",
"qml/RangeMover.qml",
"qml/SelectionRange.qml",
"qml/SelectionRangeDetails.qml",
"qml/TimeDisplay.qml",
"qml/TimeMarks.qml",
"qml/qmlprofiler.qrc",
]
}

View File

@@ -1,13 +0,0 @@
QTC_PLUGIN_NAME = QmlProfiler
QTC_LIB_DEPENDS += \
qmldebug \
extensionsystem
QTC_PLUGIN_DEPENDS += \
analyzerbase \
coreplugin \
debugger \
projectexplorer \
qmlprojectmanager \
qmljstools \
qtsupport \
texteditor

View File

@@ -1,42 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILER_GLOBAL_H
#define QMLPROFILER_GLOBAL_H
#include <QtGlobal>
#if defined(QMLPROFILER_LIBRARY)
# define QMLPROFILER_EXPORT Q_DECL_EXPORT
#else
# define QMLPROFILER_EXPORT Q_DECL_IMPORT
#endif
#endif // QMLPROFILER_GLOBAL_H

View File

@@ -1,109 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilerattachdialog.h"
#include <projectexplorer/kitchooser.h>
#include <coreplugin/id.h>
#include <QSpinBox>
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QPushButton>
using namespace ProjectExplorer;
namespace QmlProfiler {
namespace Internal {
class QmlProfilerAttachDialogPrivate
{
public:
QSpinBox *portSpinBox;
KitChooser *kitChooser;
};
QmlProfilerAttachDialog::QmlProfilerAttachDialog(QWidget *parent) :
QDialog(parent),
d(new QmlProfilerAttachDialogPrivate)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setWindowTitle(tr("Start QML Profiler"));
d->kitChooser = new KitChooser(this);
d->kitChooser->populate();
d->portSpinBox = new QSpinBox(this);
d->portSpinBox->setMaximum(65535);
d->portSpinBox->setValue(3768);
QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
QFormLayout *formLayout = new QFormLayout();
formLayout->addRow(tr("Kit:"), d->kitChooser);
formLayout->addRow(tr("&Port:"), d->portSpinBox);
QVBoxLayout *verticalLayout = new QVBoxLayout(this);
verticalLayout->addLayout(formLayout);
verticalLayout->addWidget(buttonBox);
connect(buttonBox, SIGNAL(accepted()), SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), SLOT(reject()));
}
QmlProfilerAttachDialog::~QmlProfilerAttachDialog()
{
delete d;
}
int QmlProfilerAttachDialog::port() const
{
return d->portSpinBox->value();
}
void QmlProfilerAttachDialog::setPort(const int port)
{
d->portSpinBox->setValue(port);
}
ProjectExplorer::Kit *QmlProfilerAttachDialog::kit() const
{
return d->kitChooser->currentKit();
}
void QmlProfilerAttachDialog::setKitId(const Core::Id &id)
{
d->kitChooser->setCurrentKitId(id);
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,63 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERATTACHDIALOG_H
#define QMLPROFILERATTACHDIALOG_H
#include <QDialog>
namespace Core { class Id; }
namespace ProjectExplorer { class Kit; }
namespace QmlProfiler {
namespace Internal {
class QmlProfilerAttachDialogPrivate;
class QmlProfilerAttachDialog : public QDialog
{
Q_OBJECT
public:
explicit QmlProfilerAttachDialog(QWidget *parent = 0);
~QmlProfilerAttachDialog();
int port() const;
void setPort(const int port);
ProjectExplorer::Kit *kit() const;
void setKitId(const Core::Id &id);
private:
QmlProfilerAttachDialogPrivate *d;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILERATTACHDIALOG_H

View File

@@ -1,129 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QmlProfiler::Internal::QmlProfilerAttachDialog</class>
<widget class="QDialog" name="QmlProfiler::Internal::QmlProfilerAttachDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>203</width>
<height>136</height>
</rect>
</property>
<property name="windowTitle">
<string>QML Profiler</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="addressLabel">
<property name="text">
<string>&amp;Host:</string>
</property>
<property name="buddy">
<cstring>addressLineEdit</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="addressLineEdit">
<property name="text">
<string>localhost</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="portLabel">
<property name="text">
<string>&amp;Port:</string>
</property>
<property name="buddy">
<cstring>portSpinBox</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="portSpinBox">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>3768</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Sys&amp;root:</string>
</property>
<property name="buddy">
<cstring>sysrootChooser</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Utils::PathChooser" name="sysrootChooser" native="true"/>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Utils::PathChooser</class>
<extends>QWidget</extends>
<header location="global">utils/pathchooser.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QmlProfiler::Internal::QmlProfilerAttachDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QmlProfiler::Internal::QmlProfilerAttachDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -1,451 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilerclientmanager.h"
#include "qmlprofilertool.h"
#include "qmlprofilerplugin.h"
#include <qmldebug/qmldebugclient.h>
#include <qmldebug/qmlprofilertraceclient.h>
#include <qmldebug/qv8profilerclient.h>
#include <utils/qtcassert.h>
#include <QPointer>
#include <QTimer>
#include <QMessageBox>
#include "qmlprofilermodelmanager.h"
using namespace QmlDebug;
using namespace Core;
namespace QmlProfiler {
namespace Internal {
class QmlProfilerClientManager::QmlProfilerClientManagerPrivate {
public:
QmlProfilerClientManagerPrivate(QmlProfilerClientManager *qq) { Q_UNUSED(qq); }
QmlProfilerStateManager* profilerState;
QmlDebugConnection *connection;
QPointer<QmlProfilerTraceClient> qmlclientplugin;
QPointer<QV8ProfilerClient> v8clientplugin;
QTimer connectionTimer;
int connectionAttempts;
enum ConnectMode {
TcpConnection, OstConnection
};
ConnectMode connectMode;
QString tcpHost;
quint64 tcpPort;
QString ostDevice;
QString sysroot;
bool v8DataReady;
bool qmlDataReady;
QmlProfilerModelManager *modelManager;
};
QmlProfilerClientManager::QmlProfilerClientManager(QObject *parent) :
QObject(parent), d(new QmlProfilerClientManagerPrivate(this))
{
setObjectName(QLatin1String("QML Profiler Connections"));
d->profilerState = 0;
d->connection = 0;
d->connectionAttempts = 0;
d->v8DataReady = false;
d->qmlDataReady = false;
d->modelManager = 0;
d->connectionTimer.setInterval(200);
connect(&d->connectionTimer, SIGNAL(timeout()), SLOT(tryToConnect()));
}
QmlProfilerClientManager::~QmlProfilerClientManager()
{
disconnectClientSignals();
delete d->connection;
delete d->qmlclientplugin.data();
delete d->v8clientplugin.data();
delete d;
}
void QmlProfilerClientManager::setModelManager(QmlProfilerModelManager *m)
{
if (d->modelManager) {
disconnect(this,SIGNAL(dataReadyForProcessing()), d->modelManager, SLOT(complete()));
}
d->modelManager = m;
if (d->modelManager) {
connect(this,SIGNAL(dataReadyForProcessing()), d->modelManager, SLOT(complete()));
}
}
////////////////////////////////////////////////////////////////
// Interface
void QmlProfilerClientManager::setTcpConnection(QString host, quint64 port)
{
d->connectMode = QmlProfilerClientManagerPrivate::TcpConnection;
d->tcpHost = host;
d->tcpPort = port;
}
void QmlProfilerClientManager::setOstConnection(QString ostDevice)
{
d->connectMode = QmlProfilerClientManagerPrivate::OstConnection;
d->ostDevice = ostDevice;
}
void QmlProfilerClientManager::clearBufferedData()
{
if (d->qmlclientplugin)
d->qmlclientplugin.data()->clearData();
if (d->v8clientplugin)
d->v8clientplugin.data()->clearData();
}
void QmlProfilerClientManager::discardPendingData()
{
if (d->connection)
d->connection->flush();
clearBufferedData();
}
////////////////////////////////////////////////////////////////
// Internal
void QmlProfilerClientManager::connectClient(quint16 port)
{
if (d->connection)
delete d->connection;
d->connection = new QmlDebugConnection;
enableServices();
connect(d->connection, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this, SLOT(connectionStateChanged()));
d->connectionTimer.start();
d->tcpPort = port;
}
void QmlProfilerClientManager::enableServices()
{
QTC_ASSERT(d->profilerState, return);
disconnectClientSignals();
d->profilerState->setServerRecording(false); // false by default (will be set to true when connected)
delete d->qmlclientplugin.data();
d->qmlclientplugin = new QmlProfilerTraceClient(d->connection);
delete d->v8clientplugin.data();
d->v8clientplugin = new QV8ProfilerClient(d->connection);
connectClientSignals();
}
void QmlProfilerClientManager::connectClientSignals()
{
QTC_ASSERT(d->profilerState, return);
if (d->qmlclientplugin) {
connect(d->qmlclientplugin.data(), SIGNAL(complete()),
this, SLOT(qmlComplete()));
connect(d->qmlclientplugin.data(),
SIGNAL(rangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
qint64,qint64,qint64,qint64,qint64)),
d->modelManager,
SLOT(addQmlEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
qint64,qint64,qint64,qint64,qint64)));
connect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64)),
d->modelManager->traceTime(), SLOT(setEndTime(qint64)));
connect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64)),
d->modelManager->traceTime(), SLOT(setStartTime(qint64)));
connect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
// fixme: this should be unified for both clients
connect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
d->profilerState, SLOT(setServerRecording(bool)));
}
if (d->v8clientplugin) {
connect(d->v8clientplugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
connect(d->v8clientplugin.data(),
SIGNAL(v8range(int,QString,QString,int,double,double)),
d->modelManager,
SLOT(addV8Event(int,QString,QString,int,double,double)));
connect(d->v8clientplugin.data(), SIGNAL(enabledChanged()),
d->v8clientplugin.data(), SLOT(sendRecordingStatus()));
}
}
void QmlProfilerClientManager::disconnectClientSignals()
{
if (d->qmlclientplugin) {
disconnect(d->qmlclientplugin.data(), SIGNAL(complete()),
this, SLOT(qmlComplete()));
disconnect(d->qmlclientplugin.data(),
SIGNAL(rangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
qint64,qint64,qint64,qint64,qint64)),
d->modelManager,
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)));
disconnect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64)),
d->modelManager->traceTime(), SLOT(setStartTime(qint64)));
disconnect(d->qmlclientplugin.data(), SIGNAL(frame(qint64,int,int)),
d->modelManager, SLOT(addFrameEvent(qint64,int,int)));
disconnect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
// fixme: this should be unified for both clients
disconnect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
d->profilerState, SLOT(setServerRecording(bool)));
}
if (d->v8clientplugin) {
disconnect(d->v8clientplugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
disconnect(d->v8clientplugin.data(),
SIGNAL(v8range(int,QString,QString,int,double,double)),
d->modelManager,
SLOT(addV8Event(int,QString,QString,int,double,double)));
disconnect(d->v8clientplugin.data(), SIGNAL(enabledChanged()),
d->v8clientplugin.data(), SLOT(sendRecordingStatus()));
}
}
void QmlProfilerClientManager::connectToClient()
{
if (!d->connection || d->connection->state() != QAbstractSocket::UnconnectedState)
return;
QmlProfilerTool::logStatus(QString::fromLatin1("QML Profiler: Connecting to %1:%2 ...")
.arg(d->tcpHost, QString::number(d->tcpPort)));
d->connection->connectToHost(d->tcpHost, d->tcpPort);
}
bool QmlProfilerClientManager::isConnected() const
{
return d->connection && d->connection->isConnected();
}
void QmlProfilerClientManager::disconnectClient()
{
// this might be actually be called indirectly by QDDConnectionPrivate::readyRead(), therefore allow
// method to complete before deleting object
if (d->connection) {
d->connection->deleteLater();
d->connection = 0;
}
}
void QmlProfilerClientManager::tryToConnect()
{
++d->connectionAttempts;
if (d->connection && d->connection->isConnected()) {
d->connectionTimer.stop();
d->connectionAttempts = 0;
} else if (d->connectionAttempts == 50) {
d->connectionTimer.stop();
d->connectionAttempts = 0;
QMessageBox *infoBox = QmlProfilerTool::requestMessageBox();
infoBox->setIcon(QMessageBox::Critical);
infoBox->setWindowTitle(tr("Qt Creator"));
infoBox->setText(tr("Could not connect to the in-process QML profiler.\n"
"Do you want to retry?"));
infoBox->setStandardButtons(QMessageBox::Retry |
QMessageBox::Cancel |
QMessageBox::Help);
infoBox->setDefaultButton(QMessageBox::Retry);
infoBox->setModal(true);
connect(infoBox, SIGNAL(finished(int)),
this, SLOT(retryMessageBoxFinished(int)));
infoBox->show();
} else {
connectToClient();
}
}
void QmlProfilerClientManager::connectionStateChanged()
{
if (!d->connection)
return;
switch (d->connection->state()) {
case QAbstractSocket::UnconnectedState:
{
if (QmlProfilerPlugin::debugOutput)
qWarning("QML Profiler: disconnected");
disconnectClient();
emit connectionClosed();
break;
}
case QAbstractSocket::HostLookupState:
break;
case QAbstractSocket::ConnectingState: {
if (QmlProfilerPlugin::debugOutput)
qWarning("QML Profiler: Connecting to debug server ...");
break;
}
case QAbstractSocket::ConnectedState:
{
if (QmlProfilerPlugin::debugOutput)
qWarning("QML Profiler: connected and running");
// notify the client recording status
clientRecordingChanged();
break;
}
case QAbstractSocket::ClosingState:
if (QmlProfilerPlugin::debugOutput)
qWarning("QML Profiler: closing ...");
break;
case QAbstractSocket::BoundState:
case QAbstractSocket::ListeningState:
break;
}
}
void QmlProfilerClientManager::retryMessageBoxFinished(int result)
{
switch (result) {
case QMessageBox::Retry: {
d->connectionAttempts = 0;
d->connectionTimer.start();
break;
}
case QMessageBox::Help: {
QmlProfilerTool::handleHelpRequest(QLatin1String("qthelp://org.qt-project.qtcreator/doc/creator-debugging-qml.html"));
// fall through
}
default: {
if (d->connection)
QmlProfilerTool::logStatus(QLatin1String("QML Profiler: Failed to connect! ") + d->connection->errorString());
else
QmlProfilerTool::logStatus(QLatin1String("QML Profiler: Failed to connect!"));
emit connectionFailed();
break;
}
}
}
void QmlProfilerClientManager::qmlComplete()
{
d->qmlDataReady = true;
if (!d->v8clientplugin || d->v8clientplugin.data()->status() != QmlDebug::Enabled || d->v8DataReady) {
emit dataReadyForProcessing();
// once complete is sent, reset the flags
d->qmlDataReady = false;
d->v8DataReady = false;
}
}
void QmlProfilerClientManager::v8Complete()
{
d->v8DataReady = true;
if (!d->qmlclientplugin || d->qmlclientplugin.data()->status() != QmlDebug::Enabled || d->qmlDataReady) {
emit dataReadyForProcessing();
// once complete is sent, reset the flags
d->v8DataReady = false;
d->qmlDataReady = false;
}
}
void QmlProfilerClientManager::stopClientsRecording()
{
if (d->qmlclientplugin)
d->qmlclientplugin.data()->setRecording(false);
if (d->v8clientplugin)
d->v8clientplugin.data()->setRecording(false);
}
////////////////////////////////////////////////////////////////
// Profiler State
void QmlProfilerClientManager::registerProfilerStateManager( QmlProfilerStateManager *profilerState )
{
if (d->profilerState) {
disconnect(d->profilerState, SIGNAL(stateChanged()),
this, SLOT(profilerStateChanged()));
disconnect(d->profilerState, SIGNAL(clientRecordingChanged()),
this, SLOT(clientRecordingChanged()));
disconnect(d->profilerState, SIGNAL(serverRecordingChanged()),
this, SLOT(serverRecordingChanged()));
}
d->profilerState = profilerState;
// connect
if (d->profilerState) {
connect(d->profilerState, SIGNAL(stateChanged()),
this, SLOT(profilerStateChanged()));
connect(d->profilerState, SIGNAL(clientRecordingChanged()),
this, SLOT(clientRecordingChanged()));
connect(d->profilerState, SIGNAL(serverRecordingChanged()),
this, SLOT(serverRecordingChanged()));
}
}
void QmlProfilerClientManager::profilerStateChanged()
{
QTC_ASSERT(d->profilerState, return);
switch (d->profilerState->currentState()) {
case QmlProfilerStateManager::AppStopRequested :
if (d->profilerState->serverRecording())
stopClientsRecording();
else
d->profilerState->setCurrentState(QmlProfilerStateManager::AppReadyToStop);
break;
default:
break;
}
}
void QmlProfilerClientManager::clientRecordingChanged()
{
QTC_ASSERT(d->profilerState, return);
if (d->profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
if (d->qmlclientplugin)
d->qmlclientplugin.data()->setRecording(d->profilerState->clientRecording());
if (d->v8clientplugin)
d->v8clientplugin.data()->setRecording(d->profilerState->clientRecording());
}
}
void QmlProfilerClientManager::serverRecordingChanged()
{
if (d->profilerState->serverRecording()) {
d->v8DataReady = false;
d->qmlDataReady = false;
}
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,98 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERCLIENTMANAGER_H
#define QMLPROFILERCLIENTMANAGER_H
#include <QObject>
#include <QStringList>
#include "qmlprofilerstatemanager.h"
#include <qmldebug/qmlprofilereventlocation.h>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerModelManager;
class QmlProfilerClientManager : public QObject
{
Q_OBJECT
public:
explicit QmlProfilerClientManager(QObject *parent = 0);
~QmlProfilerClientManager();
void registerProfilerStateManager(QmlProfilerStateManager *profilerState);
void setTcpConnection(QString host, quint64 port);
void setOstConnection(QString ostDevice);
void clearBufferedData();
void discardPendingData();
bool isConnected() const;
void setModelManager(QmlProfilerModelManager *m);
signals:
void connectionFailed();
void connectionClosed();
void dataReadyForProcessing();
public slots:
void connectClient(quint16 port);
void disconnectClient();
private slots:
void tryToConnect();
void connectionStateChanged();
void retryMessageBoxFinished(int result);
void qmlComplete();
void v8Complete();
void profilerStateChanged();
void clientRecordingChanged();
void serverRecordingChanged();
private:
class QmlProfilerClientManagerPrivate;
QmlProfilerClientManagerPrivate *d;
void connectToClient();
void enableServices();
void connectClientSignals();
void disconnectClientSignals();
void stopClientsRecording();
};
}
}
#endif // QMLPROFILERCLIENTMANAGER_H

View File

@@ -1,42 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERCONSTANTS_H
#define QMLPROFILERCONSTANTS_H
namespace QmlProfiler {
namespace Constants {
const char ATTACH[] = "Menu.Analyzer.Attach";
const char TraceFileExtension[] = ".qtd";
} // namespace Constants
} // namespace QmlProfiler
#endif // QMLPROFILERCONSTANTS_H

View File

@@ -1,211 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilerdetailsrewriter.h"
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <qmljstools/qmljsmodelmanager.h>
#include <utils/qtcassert.h>
namespace QmlProfiler {
namespace Internal {
struct PendingEvent {
QmlDebug::QmlEventLocation location;
QString localFile;
int requestId;
};
class PropertyVisitor: protected QmlJS::AST::Visitor
{
QmlJS::AST::Node * _lastValidNode;
unsigned _line;
unsigned _col;
public:
QmlJS::AST::Node * operator()(QmlJS::AST::Node *node, unsigned line, unsigned col)
{
_line = line;
_col = col;
_lastValidNode = 0;
accept(node);
return _lastValidNode;
}
protected:
using QmlJS::AST::Visitor::visit;
void accept(QmlJS::AST::Node *node)
{
if (node)
node->accept(this);
}
bool containsLocation(QmlJS::AST::SourceLocation start, QmlJS::AST::SourceLocation end)
{
return (_line > start.startLine || (_line == start.startLine && _col >= start.startColumn)) &&
(_line < end.startLine || (_line == end.startLine && _col <= end.startColumn));
}
virtual bool preVisit(QmlJS::AST::Node *node)
{
if (QmlJS::AST::cast<QmlJS::AST::UiQualifiedId *>(node))
return false;
return containsLocation(node->firstSourceLocation(), node->lastSourceLocation());
}
virtual bool visit(QmlJS::AST::UiScriptBinding *ast)
{
_lastValidNode = ast;
return true;
}
virtual bool visit(QmlJS::AST::UiPublicMember *ast)
{
_lastValidNode = ast;
return true;
}
};
/////////////////////////////////////////////////////////////////////////////////
class QmlProfilerDetailsRewriter::QmlProfilerDetailsRewriterPrivate
{
public:
QmlProfilerDetailsRewriterPrivate(QmlProfilerDetailsRewriter *qq,
Utils::FileInProjectFinder *fileFinder)
: m_projectFinder(fileFinder), q(qq) {}
~QmlProfilerDetailsRewriterPrivate() {}
QList <PendingEvent> m_pendingEvents;
QStringList m_pendingDocs;
Utils::FileInProjectFinder *m_projectFinder;
QmlProfilerDetailsRewriter *q;
};
QmlProfilerDetailsRewriter::QmlProfilerDetailsRewriter(
QObject *parent, Utils::FileInProjectFinder *fileFinder)
: QObject(parent), d(new QmlProfilerDetailsRewriterPrivate(this, fileFinder))
{ }
QmlProfilerDetailsRewriter::~QmlProfilerDetailsRewriter()
{
delete d;
}
void QmlProfilerDetailsRewriter::requestDetailsForLocation(int requestId,
const QmlDebug::QmlEventLocation &location)
{
const QString localFile = d->m_projectFinder->findFile(location.filename);
QFileInfo fileInfo(localFile);
if (!fileInfo.exists() || !fileInfo.isReadable())
return;
if (!QmlJS::Document::isQmlLikeLanguage(QmlJSTools::languageOfFile(localFile)))
return;
PendingEvent ev = {location, localFile, requestId};
d->m_pendingEvents << ev;
if (!d->m_pendingDocs.contains(localFile)) {
if (d->m_pendingDocs.isEmpty())
connect(QmlJS::ModelManagerInterface::instance(),
SIGNAL(documentUpdated(QmlJS::Document::Ptr)),
this,
SLOT(documentReady(QmlJS::Document::Ptr)));
d->m_pendingDocs << localFile;
}
}
void QmlProfilerDetailsRewriter::reloadDocuments()
{
if (!d->m_pendingDocs.isEmpty())
QmlJS::ModelManagerInterface::instance()->updateSourceFiles(d->m_pendingDocs, false);
else
emit eventDetailsChanged();
}
void QmlProfilerDetailsRewriter::rewriteDetailsForLocation(QTextStream &textDoc,
QmlJS::Document::Ptr doc, int requestId, const QmlDebug::QmlEventLocation &location)
{
PropertyVisitor propertyVisitor;
QmlJS::AST::Node *node = propertyVisitor(doc->ast(), location.line, location.column);
if (!node)
return;
qint64 startPos = node->firstSourceLocation().begin();
qint64 len = node->lastSourceLocation().end() - startPos;
textDoc.seek(startPos);
QString details = textDoc.read(len).replace(QLatin1Char('\n'), QLatin1Char(' ')).simplified();
emit rewriteDetailsString(requestId, details);
}
void QmlProfilerDetailsRewriter::clearRequests()
{
d->m_pendingDocs.clear();
}
void QmlProfilerDetailsRewriter::documentReady(QmlJS::Document::Ptr doc)
{
// this could be triggered by an unrelated reload in Creator
if (!d->m_pendingDocs.contains(doc->fileName()))
return;
// if the file could not be opened this slot is still triggered but source will be an empty string
QString source = doc->source();
if (!source.isEmpty()) {
QTextStream st(&source, QIODevice::ReadOnly);
for (int i = d->m_pendingEvents.count()-1; i>=0; i--) {
PendingEvent ev = d->m_pendingEvents[i];
if (ev.localFile == doc->fileName()) {
d->m_pendingEvents.removeAt(i);
rewriteDetailsForLocation(st, doc, ev.requestId, ev.location);
}
}
}
d->m_pendingDocs.removeOne(doc->fileName());
if (d->m_pendingDocs.isEmpty()) {
disconnect(QmlJS::ModelManagerInterface::instance(),
SIGNAL(documentUpdated(QmlJS::Document::Ptr)),
this,
SLOT(documentReady(QmlJS::Document::Ptr)));
emit eventDetailsChanged();
}
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,70 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERDETAILSREWRITER_H
#define QMLPROFILERDETAILSREWRITER_H
#include <QObject>
#include <qmldebug/qmlprofilereventlocation.h>
#include <qmljs/qmljsdocument.h>
#include <utils/fileinprojectfinder.h>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerDetailsRewriter : public QObject
{
Q_OBJECT
public:
explicit QmlProfilerDetailsRewriter(QObject *parent, Utils::FileInProjectFinder *fileFinder);
~QmlProfilerDetailsRewriter();
void clearRequests();
private:
void rewriteDetailsForLocation(QTextStream &textDoc, QmlJS::Document::Ptr doc, int requestId,
const QmlDebug::QmlEventLocation &location);
public slots:
void requestDetailsForLocation(int requestId, const QmlDebug::QmlEventLocation &location);
void reloadDocuments();
void documentReady(QmlJS::Document::Ptr doc);
signals:
void rewriteDetailsString(int requestId, const QString &details);
void eventDetailsChanged();
private:
class QmlProfilerDetailsRewriterPrivate;
QmlProfilerDetailsRewriterPrivate *d;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILERDETAILSREWRITER_H

View File

@@ -1,319 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilerengine.h"
#include "localqmlprofilerrunner.h"
#include <analyzerbase/analyzermanager.h>
#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
#include <coreplugin/helpmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/target.h>
#include <qmlprojectmanager/qmlprojectrunconfiguration.h>
#include <qmlprojectmanager/qmlprojectplugin.h>
#include <projectexplorer/environmentaspect.h>
#include <projectexplorer/localapplicationruncontrol.h>
#include <projectexplorer/localapplicationrunconfiguration.h>
#include <qmldebug/qmloutputparser.h>
#include <QMainWindow>
#include <QMessageBox>
#include <QTimer>
#include <QTcpServer>
using namespace Analyzer;
using namespace ProjectExplorer;
namespace QmlProfiler {
namespace Internal {
//
// QmlProfilerEnginePrivate
//
class QmlProfilerRunControl::QmlProfilerEnginePrivate
{
public:
QmlProfilerEnginePrivate() : m_running(false) {}
QmlProfilerStateManager *m_profilerState;
QTimer m_noDebugOutputTimer;
QmlDebug::QmlOutputParser m_outputParser;
bool m_running;
};
//
// QmlProfilerEngine
//
QmlProfilerRunControl::QmlProfilerRunControl(const Analyzer::AnalyzerStartParameters &sp,
ProjectExplorer::RunConfiguration *runConfiguration)
: AnalyzerRunControl(sp, runConfiguration)
, d(new QmlProfilerEnginePrivate)
{
d->m_profilerState = 0;
// Only wait 4 seconds for the 'Waiting for connection' on application output, then just try to connect
// (application output might be redirected / blocked)
d->m_noDebugOutputTimer.setSingleShot(true);
d->m_noDebugOutputTimer.setInterval(4000);
connect(&d->m_noDebugOutputTimer, SIGNAL(timeout()), this, SLOT(processIsRunning()));
d->m_outputParser.setNoOutputText(ApplicationLauncher::msgWinCannotRetrieveDebuggingOutput());
connect(&d->m_outputParser, SIGNAL(waitingForConnectionOnPort(quint16)),
this, SLOT(processIsRunning(quint16)));
connect(&d->m_outputParser, SIGNAL(noOutputMessage()),
this, SLOT(processIsRunning()));
connect(&d->m_outputParser, SIGNAL(errorMessage(QString)),
this, SLOT(wrongSetupMessageBox(QString)));
}
QmlProfilerRunControl::~QmlProfilerRunControl()
{
if (d->m_profilerState && d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning)
stopEngine();
delete d;
}
bool QmlProfilerRunControl::startEngine()
{
QTC_ASSERT(d->m_profilerState, return false);
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppStarting);
if (QmlProjectManager::QmlProjectRunConfiguration *rc =
qobject_cast<QmlProjectManager::QmlProjectRunConfiguration *>(runConfiguration())) {
if (rc->observerPath().isEmpty()) {
QmlProjectManager::QmlProjectPlugin::showQmlObserverToolWarning();
d->m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
AnalyzerManager::stopTool();
return false;
}
}
if (startParameters().startMode == StartLocal) {
d->m_noDebugOutputTimer.start();
} else {
emit processRunning(startParameters().analyzerPort);
}
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppRunning);
engineStarted();
return true;
}
void QmlProfilerRunControl::stopEngine()
{
QTC_ASSERT(d->m_profilerState, return);
switch (d->m_profilerState->currentState()) {
case QmlProfilerStateManager::AppRunning : {
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppStopRequested);
break;
}
case QmlProfilerStateManager::AppReadyToStop : {
cancelProcess();
break;
}
case QmlProfilerStateManager::AppDying :
// valid, but no further action is needed
break;
default: {
const QString message = QString::fromLatin1("Unexpected engine stop from state %1 in %2:%3")
.arg(d->m_profilerState->currentStateAsString(), QString::fromLatin1(__FILE__), QString::number(__LINE__));
qWarning("%s", qPrintable(message));
}
break;
}
}
void QmlProfilerRunControl::notifyRemoteFinished(bool success)
{
QTC_ASSERT(d->m_profilerState, return);
switch (d->m_profilerState->currentState()) {
case QmlProfilerStateManager::AppRunning : {
if (success)
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppDying);
else
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppKilled);
AnalyzerManager::stopTool();
runControlFinished();
break;
}
case QmlProfilerStateManager::AppStopped :
case QmlProfilerStateManager::AppKilled :
d->m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
break;
default: {
const QString message = QString::fromLatin1("Process died unexpectedly from state %1 in %2:%3")
.arg(d->m_profilerState->currentStateAsString(), QString::fromLatin1(__FILE__), QString::number(__LINE__));
qWarning("%s", qPrintable(message));
}
break;
}
}
void QmlProfilerRunControl::cancelProcess()
{
QTC_ASSERT(d->m_profilerState, return);
switch (d->m_profilerState->currentState()) {
case QmlProfilerStateManager::AppReadyToStop : {
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppStopped);
break;
}
case QmlProfilerStateManager::AppRunning : {
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppDying);
break;
}
default: {
const QString message = QString::fromLatin1("Unexpected process termination requested with state %1 in %2:%3")
.arg(d->m_profilerState->currentStateAsString(), QString::fromLatin1(__FILE__), QString::number(__LINE__));
qWarning("%s", qPrintable(message));
return;
}
}
runControlFinished();
}
void QmlProfilerRunControl::logApplicationMessage(const QString &msg, Utils::OutputFormat format)
{
appendMessage(msg, format);
d->m_outputParser.processOutput(msg);
}
void QmlProfilerRunControl::wrongSetupMessageBox(const QString &errorMessage)
{
QMessageBox *infoBox = new QMessageBox(Core::ICore::mainWindow());
infoBox->setIcon(QMessageBox::Critical);
infoBox->setWindowTitle(tr("Qt Creator"));
//: %1 is detailed error message
infoBox->setText(tr("Could not connect to the in-process QML debugger:\n%1")
.arg(errorMessage));
infoBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Help);
infoBox->setDefaultButton(QMessageBox::Ok);
infoBox->setModal(true);
connect(infoBox, SIGNAL(finished(int)),
this, SLOT(wrongSetupMessageBoxFinished(int)));
infoBox->show();
// KILL
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppDying);
AnalyzerManager::stopTool();
runControlFinished();
}
void QmlProfilerRunControl::wrongSetupMessageBoxFinished(int button)
{
if (button == QMessageBox::Help) {
Core::HelpManager *helpManager = Core::HelpManager::instance();
helpManager->handleHelpRequest(QLatin1String("qthelp://org.qt-project.qtcreator/doc/creator-debugging-qml.html"
"#setting-up-qml-debugging"));
}
}
void QmlProfilerRunControl::showNonmodalWarning(const QString &warningMsg)
{
QMessageBox *noExecWarning = new QMessageBox(Core::ICore::mainWindow());
noExecWarning->setIcon(QMessageBox::Warning);
noExecWarning->setWindowTitle(tr("QML Profiler"));
noExecWarning->setText(warningMsg);
noExecWarning->setStandardButtons(QMessageBox::Ok);
noExecWarning->setDefaultButton(QMessageBox::Ok);
noExecWarning->setModal(false);
noExecWarning->show();
}
void QmlProfilerRunControl::notifyRemoteSetupDone(quint16 port)
{
d->m_noDebugOutputTimer.stop();
emit processRunning(port);
}
void QmlProfilerRunControl::processIsRunning(quint16 port)
{
d->m_noDebugOutputTimer.stop();
if (port > 0 && startParameters().analyzerPort != 0)
emit processRunning(port);
}
void QmlProfilerRunControl::engineStarted()
{
d->m_running = true;
emit starting(this);
}
void QmlProfilerRunControl::runControlFinished()
{
d->m_running = false;
emit finished();
}
////////////////////////////////////////////////////////////////
// Profiler State
void QmlProfilerRunControl::registerProfilerStateManager( QmlProfilerStateManager *profilerState )
{
// disconnect old
if (d->m_profilerState)
disconnect(d->m_profilerState, SIGNAL(stateChanged()), this, SLOT(profilerStateChanged()));
d->m_profilerState = profilerState;
// connect
if (d->m_profilerState)
connect(d->m_profilerState, SIGNAL(stateChanged()), this, SLOT(profilerStateChanged()));
}
void QmlProfilerRunControl::profilerStateChanged()
{
switch (d->m_profilerState->currentState()) {
case QmlProfilerStateManager::AppReadyToStop : {
if (d->m_running)
cancelProcess();
break;
}
case QmlProfilerStateManager::Idle : {
d->m_noDebugOutputTimer.stop();
break;
}
default:
break;
}
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,86 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERENGINE_H
#define QMLPROFILERENGINE_H
#include "qmlprofilerstatemanager.h"
#include <analyzerbase/analyzerruncontrol.h>
#include <utils/outputformat.h>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerRunControl : public Analyzer::AnalyzerRunControl
{
Q_OBJECT
public:
QmlProfilerRunControl(const Analyzer::AnalyzerStartParameters &sp,
ProjectExplorer::RunConfiguration *runConfiguration);
~QmlProfilerRunControl();
void registerProfilerStateManager( QmlProfilerStateManager *profilerState );
static void showNonmodalWarning(const QString &warningMsg);
void notifyRemoteSetupDone(quint16 port);
signals:
void processRunning(quint16 port);
void timeUpdate();
public slots:
bool startEngine();
void stopEngine();
private slots:
void notifyRemoteFinished(bool success = true);
void cancelProcess();
void logApplicationMessage(const QString &msg, Utils::OutputFormat format);
void wrongSetupMessageBox(const QString &errorMessage);
void wrongSetupMessageBoxFinished(int);
void processIsRunning(quint16 port = 0);
void engineStarted();
void runControlFinished();
private slots:
void profilerStateChanged();
private:
class QmlProfilerEnginePrivate;
QmlProfilerEnginePrivate *d;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILERENGINE_H

View File

@@ -1,479 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilereventsmodelproxy.h"
#include "qmlprofilermodelmanager.h"
#include "qmlprofilersimplemodel.h"
#include <utils/qtcassert.h>
#include <QVector>
#include <QHash>
#include <QUrl>
#include <QString>
#include <QStack>
#include <QElapsedTimer>
#include <QDebug>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerEventsModelProxy::QmlProfilerEventsModelProxyPrivate
{
public:
QmlProfilerEventsModelProxyPrivate(QmlProfilerEventsModelProxy *qq) : q(qq) {}
~QmlProfilerEventsModelProxyPrivate() {}
QHash<QString, QmlProfilerEventsModelProxy::QmlEventStats> data;
QmlProfilerModelManager *modelManager;
QmlProfilerEventsModelProxy *q;
int modelId;
QVector<int> acceptedTypes;
QSet<QString> eventsInBindingLoop;
};
QmlProfilerEventsModelProxy::QmlProfilerEventsModelProxy(QmlProfilerModelManager *modelManager, QObject *parent)
: QObject(parent), d(new QmlProfilerEventsModelProxyPrivate(this))
{
d->modelManager = modelManager;
connect(modelManager->simpleModel(), SIGNAL(changed()), this, SLOT(dataChanged()));
d->modelId = modelManager->registerModelProxy();
d->acceptedTypes << QmlDebug::Compiling << QmlDebug::Creating << QmlDebug::Binding << QmlDebug::HandlingSignal;
}
QmlProfilerEventsModelProxy::~QmlProfilerEventsModelProxy()
{
delete d;
}
const QList<QmlProfilerEventsModelProxy::QmlEventStats> QmlProfilerEventsModelProxy::getData() const
{
return d->data.values();
}
void QmlProfilerEventsModelProxy::clear()
{
d->modelManager->modelProxyCountUpdated(d->modelId, 0, 1);
d->data.clear();
d->eventsInBindingLoop.clear();
}
void QmlProfilerEventsModelProxy::limitToRange(qint64 rangeStart, qint64 rangeEnd)
{
loadData(rangeStart, rangeEnd);
}
void QmlProfilerEventsModelProxy::dataChanged()
{
if (d->modelManager->state() == QmlProfilerDataState::ProcessingData)
loadData();
if (d->modelManager->state() == QmlProfilerDataState::Empty)
clear();
}
QSet<QString> QmlProfilerEventsModelProxy::eventsInBindingLoop() const
{
return d->eventsInBindingLoop;
}
void QmlProfilerEventsModelProxy::loadData(qint64 rangeStart, qint64 rangeEnd)
{
clear();
qint64 qmlTime = 0;
qint64 lastEndTime = 0;
QHash <QString, QVector<qint64> > durations;
const bool checkRanges = (rangeStart != -1) && (rangeEnd != -1);
const QVector<QmlProfilerSimpleModel::QmlEventData> eventList
= d->modelManager->simpleModel()->getEvents();
// used by binding loop detection
typedef QPair<QString, const QmlProfilerSimpleModel::QmlEventData*> CallStackEntry;
QStack<CallStackEntry> callStack;
callStack.push(CallStackEntry(QString(), 0)); // artificial root
for (int i = 0; i < eventList.size(); ++i) {
const QmlProfilerSimpleModel::QmlEventData *event = &eventList[i];
if (!d->acceptedTypes.contains(event->eventType))
continue;
if (checkRanges) {
if ((event->startTime + event->duration < rangeStart)
|| (event->startTime > rangeEnd))
continue;
}
// put event in hash
QString hash = QmlProfilerSimpleModel::getHashString(*event);
if (!d->data.contains(hash)) {
QmlEventStats stats = {
event->displayName,
hash,
event->data.join(QLatin1String(" ")),
event->location,
event->eventType,
event->bindingType,
event->duration,
1, //calls
event->duration, //minTime
event->duration, // maxTime
0, //timePerCall
0, //percentOfTime
0, //medianTime
false //isBindingLoop
};
d->data.insert(hash, stats);
// for median computing
durations.insert(hash, QVector<qint64>());
durations[hash].append(event->duration);
} else {
// update stats
QmlEventStats *stats = &d->data[hash];
stats->duration += event->duration;
if (event->duration < stats->minTime)
stats->minTime = event->duration;
if (event->duration > stats->maxTime)
stats->maxTime = event->duration;
stats->calls++;
// for median computing
durations[hash].append(event->duration);
}
// qml time computation
if (event->startTime > lastEndTime) { // assume parent event if starts before last end
qmlTime += event->duration;
lastEndTime = event->startTime + event->duration;
}
//
// binding loop detection
//
const QmlProfilerSimpleModel::QmlEventData *potentialParent = callStack.top().second;
while (potentialParent
&& !(potentialParent->startTime + potentialParent->duration > event->startTime)) {
callStack.pop();
potentialParent = callStack.top().second;
}
// check whether event is already in stack
bool inLoop = false;
for (int ii = 1; ii < callStack.size(); ++ii) {
if (callStack.at(ii).first == hash)
inLoop = true;
if (inLoop)
d->eventsInBindingLoop.insert(hash);
}
CallStackEntry newEntry(hash, event);
callStack.push(newEntry);
d->modelManager->modelProxyCountUpdated(d->modelId, i, eventList.count()*2);
}
// post-process: calc mean time, median time, percentoftime
foreach (const QString &hash, d->data.keys()) {
QmlEventStats* stats = &d->data[hash];
if (stats->calls > 0)
stats->timePerCall = stats->duration / (double)stats->calls;
QVector<qint64> eventDurations = durations.value(hash);
if (!eventDurations.isEmpty()) {
qSort(eventDurations);
stats->medianTime = eventDurations.at(eventDurations.count()/2);
}
stats->percentOfTime = stats->duration * 100.0 / qmlTime;
}
// set binding loop flag
foreach (const QString &eventHash, d->eventsInBindingLoop)
d->data[eventHash].isBindingLoop = true;
QString rootEventName = tr("<program>");
QmlDebug::QmlEventLocation rootEventLocation(rootEventName, 1, 1);
// insert root event
QmlEventStats rootEvent = {
rootEventName, //event.displayName,
rootEventName, // hash
tr("Main Program"), //event.details,
rootEventLocation, // location
(int)QmlDebug::Binding, // event type
0, // binding type
qmlTime + 1,
1, //calls
qmlTime + 1, //minTime
qmlTime + 1, // maxTime
qmlTime + 1, //timePerCall
100.0, //percentOfTime
qmlTime + 1, //medianTime;
false
};
d->data.insert(rootEventName, rootEvent);
d->modelManager->modelProxyCountUpdated(d->modelId, 1, 1);
emit dataAvailable();
}
int QmlProfilerEventsModelProxy::count() const
{
return d->data.count();
}
//////////////////////////////////////////////////////////////////////////////////
QmlProfilerEventRelativesModelProxy::QmlProfilerEventRelativesModelProxy(QmlProfilerModelManager *modelManager,
QmlProfilerEventsModelProxy *eventsModel,
QObject *parent)
: QObject(parent)
{
QTC_CHECK(modelManager);
m_modelManager = modelManager;
connect(modelManager->simpleModel(), SIGNAL(changed()), this, SLOT(dataChanged()));
QTC_CHECK(eventsModel);
m_eventsModel = eventsModel;
m_acceptedTypes << QmlDebug::Compiling << QmlDebug::Creating << QmlDebug::Binding << QmlDebug::HandlingSignal;
}
QmlProfilerEventRelativesModelProxy::~QmlProfilerEventRelativesModelProxy()
{
}
const QmlProfilerEventRelativesModelProxy::QmlEventRelativesMap QmlProfilerEventRelativesModelProxy::getData(const QString &hash) const
{
if (m_data.contains(hash))
return m_data[hash];
return QmlEventRelativesMap();
}
int QmlProfilerEventRelativesModelProxy::count() const
{
return m_data.count();
}
void QmlProfilerEventRelativesModelProxy::clear()
{
m_data.clear();
}
void QmlProfilerEventRelativesModelProxy::dataChanged()
{
loadData();
emit dataAvailable();
}
//////////////////////////////////////////////////////////////////////////////////
QmlProfilerEventParentsModelProxy::QmlProfilerEventParentsModelProxy(QmlProfilerModelManager *modelManager,
QmlProfilerEventsModelProxy *eventsModel,
QObject *parent)
: QmlProfilerEventRelativesModelProxy(modelManager, eventsModel, parent)
{}
QmlProfilerEventParentsModelProxy::~QmlProfilerEventParentsModelProxy()
{}
void QmlProfilerEventParentsModelProxy::loadData()
{
clear();
QmlProfilerSimpleModel *simpleModel = m_modelManager->simpleModel();
if (simpleModel->isEmpty())
return;
QHash<QString, QmlProfilerSimpleModel::QmlEventData> cachedEvents;
QString rootEventName = tr("<program>");
QmlProfilerSimpleModel::QmlEventData rootEvent = {
rootEventName,
QmlDebug::Binding,
0,
0,
0,
QStringList() << tr("Main Program"),
QmlDebug::QmlEventLocation(rootEventName, 0, 0),
0,0,0,0,0 // numericData fields
};
cachedEvents.insert(rootEventName, rootEvent);
// for level computation
QHash<int, qint64> endtimesPerLevel;
int level = QmlDebug::Constants::QML_MIN_LEVEL;
endtimesPerLevel[0] = 0;
const QSet<QString> eventsInBindingLoop = m_eventsModel->eventsInBindingLoop();
// compute parent-child relationship and call count
QHash<int, QString> lastParent;
//for (int index = fromIndex; index <= toIndex; index++) {
const QVector<QmlProfilerSimpleModel::QmlEventData> eventList = simpleModel->getEvents();
foreach (const QmlProfilerSimpleModel::QmlEventData &event, eventList) {
// whitelist
if (!m_acceptedTypes.contains(event.eventType))
continue;
// level computation
if (endtimesPerLevel[level] > event.startTime) {
level++;
} else {
while (level > QmlDebug::Constants::QML_MIN_LEVEL && endtimesPerLevel[level-1] <= event.startTime)
level--;
}
endtimesPerLevel[level] = event.startTime + event.duration;
QString parentHash = rootEventName;
QString eventHash = QmlProfilerSimpleModel::getHashString(event);
// save in cache
if (!cachedEvents.contains(eventHash))
cachedEvents.insert(eventHash, event);
if (level > QmlDebug::Constants::QML_MIN_LEVEL && lastParent.contains(level-1))
parentHash = lastParent[level-1];
QmlProfilerSimpleModel::QmlEventData *parentEvent = &(cachedEvents[parentHash]);
// generate placeholder if needed
if (!m_data.contains(eventHash))
m_data.insert(eventHash, QmlEventRelativesMap());
if (m_data[eventHash].contains(parentHash)) {
QmlEventRelativesData *parent = &(m_data[eventHash][parentHash]);
parent->calls++;
parent->duration += event.duration;
} else {
m_data[eventHash].insert(parentHash, QmlEventRelativesData());
QmlEventRelativesData *parent = &(m_data[eventHash][parentHash]);
parent->displayName = parentEvent->displayName;
parent->eventType = parentEvent->eventType;
parent->duration = event.duration;
parent->calls = 1;
parent->details = parentEvent->data.join(QLatin1String(""));
parent->isBindingLoop = eventsInBindingLoop.contains(parentHash);
}
// now lastparent is a string with the hash
lastParent[level] = eventHash;
}
}
//////////////////////////////////////////////////////////////////////////////////
QmlProfilerEventChildrenModelProxy::QmlProfilerEventChildrenModelProxy(QmlProfilerModelManager *modelManager,
QmlProfilerEventsModelProxy *eventsModel,
QObject *parent)
: QmlProfilerEventRelativesModelProxy(modelManager, eventsModel, parent)
{}
QmlProfilerEventChildrenModelProxy::~QmlProfilerEventChildrenModelProxy()
{}
void QmlProfilerEventChildrenModelProxy::loadData()
{
clear();
QmlProfilerSimpleModel *simpleModel = m_modelManager->simpleModel();
if (simpleModel->isEmpty())
return;
QString rootEventName = tr("<program>");
// for level computation
QHash<int, qint64> endtimesPerLevel;
int level = QmlDebug::Constants::QML_MIN_LEVEL;
endtimesPerLevel[0] = 0;
const QSet<QString> eventsInBindingLoop = m_eventsModel->eventsInBindingLoop();
// compute parent-child relationship and call count
QHash<int, QString> lastParent;
const QVector<QmlProfilerSimpleModel::QmlEventData> eventList = simpleModel->getEvents();
foreach (const QmlProfilerSimpleModel::QmlEventData &event, eventList) {
// whitelist
if (!m_acceptedTypes.contains(event.eventType))
continue;
// level computation
if (endtimesPerLevel[level] > event.startTime) {
level++;
} else {
while (level > QmlDebug::Constants::QML_MIN_LEVEL && endtimesPerLevel[level-1] <= event.startTime)
level--;
}
endtimesPerLevel[level] = event.startTime + event.duration;
QString parentHash = rootEventName;
QString eventHash = QmlProfilerSimpleModel::getHashString(event);
if (level > QmlDebug::Constants::QML_MIN_LEVEL && lastParent.contains(level-1))
parentHash = lastParent[level-1];
// generate placeholder if needed
if (!m_data.contains(parentHash))
m_data.insert(parentHash, QmlEventRelativesMap());
if (m_data[parentHash].contains(eventHash)) {
QmlEventRelativesData *child = &(m_data[parentHash][eventHash]);
child->calls++;
child->duration += event.duration;
} else {
m_data[parentHash].insert(eventHash, QmlEventRelativesData());
QmlEventRelativesData *child = &(m_data[parentHash][eventHash]);
child->displayName = event.displayName;
child->eventType = event.eventType;
child->duration = event.duration;
child->calls = 1;
child->details = event.data.join(QLatin1String(""));
child->isBindingLoop = eventsInBindingLoop.contains(parentHash);
}
// now lastparent is a string with the hash
lastParent[level] = eventHash;
}
}
}
}

View File

@@ -1,172 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILEREVENTSMODELPROXY_H
#define QMLPROFILEREVENTSMODELPROXY_H
#include "qmlprofilersimplemodel.h"
#include <QObject>
#include <qmldebug/qmlprofilereventtypes.h>
#include <qmldebug/qmlprofilereventlocation.h>
#include <QHash>
#include <QVector>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerModelManager;
class QmlProfilerEventsModelProxy : public QObject
{
Q_OBJECT
public:
struct QmlEventStats {
QString displayName;
QString eventHashStr;
QString details;
QmlDebug::QmlEventLocation location;
int eventType;
int bindingType;
qint64 duration;
qint64 calls;
qint64 minTime;
qint64 maxTime;
qint64 timePerCall;
double percentOfTime;
qint64 medianTime;
bool isBindingLoop;
};
QmlProfilerEventsModelProxy(QmlProfilerModelManager *modelManager, QObject *parent = 0);
~QmlProfilerEventsModelProxy();
const QList<QmlEventStats> getData() const;
int count() const;
void clear();
void limitToRange(qint64 rangeStart, qint64 rangeEnd);
signals:
void dataAvailable();
private:
void loadData(qint64 rangeStart = -1, qint64 rangeEnd = -1);
QSet<QString> eventsInBindingLoop() const;
private slots:
void dataChanged();
private:
class QmlProfilerEventsModelProxyPrivate;
QmlProfilerEventsModelProxyPrivate *d;
friend class QmlProfilerEventParentsModelProxy;
friend class QmlProfilerEventChildrenModelProxy;
};
class QmlProfilerEventRelativesModelProxy : public QObject
{
Q_OBJECT
public:
struct QmlEventRelativesData {
QString displayName;
int eventType;
qint64 duration;
qint64 calls;
QString details;
bool isBindingLoop;
};
typedef QHash <QString, QmlEventRelativesData> QmlEventRelativesMap;
QmlProfilerEventRelativesModelProxy(QmlProfilerModelManager *modelManager,
QmlProfilerEventsModelProxy *eventsModel,
QObject *parent = 0);
~QmlProfilerEventRelativesModelProxy();
int count() const;
void clear();
const QmlEventRelativesMap getData(const QString &hash) const;
protected:
virtual void loadData() = 0;
signals:
void dataAvailable();
protected slots:
void dataChanged();
protected:
QHash <QString, QmlEventRelativesMap> m_data;
QmlProfilerModelManager *m_modelManager;
QmlProfilerEventsModelProxy *m_eventsModel;
QVector <int> m_acceptedTypes;
};
class QmlProfilerEventParentsModelProxy : public QmlProfilerEventRelativesModelProxy
{
Q_OBJECT
public:
QmlProfilerEventParentsModelProxy(QmlProfilerModelManager *modelManager,
QmlProfilerEventsModelProxy *eventsModel,
QObject *parent = 0);
~QmlProfilerEventParentsModelProxy();
protected:
virtual void loadData();
signals:
void dataAvailable();
};
class QmlProfilerEventChildrenModelProxy : public QmlProfilerEventRelativesModelProxy
{
Q_OBJECT
public:
QmlProfilerEventChildrenModelProxy(QmlProfilerModelManager *modelManager,
QmlProfilerEventsModelProxy *eventsModel,
QObject *parent = 0);
~QmlProfilerEventChildrenModelProxy();
protected:
virtual void loadData();
signals:
void dataAvailable();
};
}
}
#endif

View File

@@ -1,906 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilereventview.h"
#include <QUrl>
#include <QHash>
#include <QStandardItem>
#include <QHeaderView>
#include <QApplication>
#include <QClipboard>
#include <QContextMenuEvent>
#include <QDebug>
#include <coreplugin/minisplitter.h>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include "qmlprofilerviewmanager.h"
#include "qmlprofilertool.h"
#include <QMenu>
#include <utils/qtcassert.h>
using namespace QmlDebug;
namespace QmlProfiler {
namespace Internal {
struct Colors {
Colors () {
this->bindingLoopBackground = QColor("orange").lighter();
}
QColor bindingLoopBackground;
};
Q_GLOBAL_STATIC(Colors, colors)
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
class EventsViewItem : public QStandardItem
{
public:
EventsViewItem(const QString &text) : QStandardItem(text) {}
virtual bool operator<(const QStandardItem &other) const
{
if (data().type() == QVariant::String) {
// first column
if (column() == 0) {
return data(FilenameRole).toString() == other.data(FilenameRole).toString() ?
data(LineRole).toInt() < other.data(LineRole).toInt() :
data(FilenameRole).toString() < other.data(FilenameRole).toString();
} else {
return data().toString().toLower() < other.data().toString().toLower();
}
}
return data().toDouble() < other.data().toDouble();
}
};
////////////////////////////////////////////////////////////////////////////////////
class QmlProfilerEventsWidget::QmlProfilerEventsWidgetPrivate
{
public:
QmlProfilerEventsWidgetPrivate(QmlProfilerEventsWidget *qq):q(qq) {}
~QmlProfilerEventsWidgetPrivate() {}
QmlProfilerEventsWidget *q;
Analyzer::IAnalyzerTool *m_profilerTool;
QmlProfilerViewManager *m_viewContainer;
QmlProfilerEventsMainView *m_eventTree;
QmlProfilerEventRelativesView *m_eventChildren;
QmlProfilerEventRelativesView *m_eventParents;
QmlProfilerEventsModelProxy *modelProxy;
bool globalStats;
};
QmlProfilerEventsWidget::QmlProfilerEventsWidget(QWidget *parent,
Analyzer::IAnalyzerTool *profilerTool,
QmlProfilerViewManager *container,
QmlProfilerModelManager *profilerModelManager )
: QWidget(parent), d(new QmlProfilerEventsWidgetPrivate(this))
{
setObjectName(QLatin1String("QmlProfilerEventsView"));
d->modelProxy = new QmlProfilerEventsModelProxy(profilerModelManager, this);
connect(profilerModelManager, SIGNAL(stateChanged()),
this, SLOT(profilerDataModelStateChanged()));
d->m_eventTree = new QmlProfilerEventsMainView(this, d->modelProxy);
connect(d->m_eventTree, SIGNAL(gotoSourceLocation(QString,int,int)), this, SIGNAL(gotoSourceLocation(QString,int,int)));
connect(d->m_eventTree, SIGNAL(eventSelected(QString)), this, SIGNAL(eventSelectedByHash(QString)));
d->m_eventChildren = new QmlProfilerEventRelativesView(
profilerModelManager,
new QmlProfilerEventChildrenModelProxy(profilerModelManager, d->modelProxy, this),
this);
d->m_eventParents = new QmlProfilerEventRelativesView(
profilerModelManager,
new QmlProfilerEventParentsModelProxy(profilerModelManager, d->modelProxy, this),
this);
connect(d->m_eventTree, SIGNAL(eventSelected(QString)), d->m_eventChildren, SLOT(displayEvent(QString)));
connect(d->m_eventTree, SIGNAL(eventSelected(QString)), d->m_eventParents, SLOT(displayEvent(QString)));
connect(d->m_eventChildren, SIGNAL(eventClicked(QString)), d->m_eventTree, SLOT(selectEvent(QString)));
connect(d->m_eventParents, SIGNAL(eventClicked(QString)), d->m_eventTree, SLOT(selectEvent(QString)));
// widget arrangement
QVBoxLayout *groupLayout = new QVBoxLayout;
groupLayout->setContentsMargins(0,0,0,0);
groupLayout->setSpacing(0);
Core::MiniSplitter *splitterVertical = new Core::MiniSplitter;
splitterVertical->addWidget(d->m_eventTree);
Core::MiniSplitter *splitterHorizontal = new Core::MiniSplitter;
splitterHorizontal->addWidget(d->m_eventParents);
splitterHorizontal->addWidget(d->m_eventChildren);
splitterHorizontal->setOrientation(Qt::Horizontal);
splitterVertical->addWidget(splitterHorizontal);
splitterVertical->setOrientation(Qt::Vertical);
splitterVertical->setStretchFactor(0,5);
splitterVertical->setStretchFactor(1,2);
groupLayout->addWidget(splitterVertical);
setLayout(groupLayout);
d->m_profilerTool = profilerTool;
d->m_viewContainer = container;
d->globalStats = true;
}
QmlProfilerEventsWidget::~QmlProfilerEventsWidget()
{
delete d->modelProxy;
delete d;
}
void QmlProfilerEventsWidget::profilerDataModelStateChanged()
{
}
void QmlProfilerEventsWidget::clear()
{
d->m_eventTree->clear();
d->m_eventChildren->clear();
d->m_eventParents->clear();
}
void QmlProfilerEventsWidget::getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd)
{
d->modelProxy->limitToRange(rangeStart, rangeEnd);
d->globalStats = (rangeStart == -1) && (rangeEnd == -1);
}
QModelIndex QmlProfilerEventsWidget::selectedItem() const
{
return d->m_eventTree->selectedItem();
}
void QmlProfilerEventsWidget::contextMenuEvent(QContextMenuEvent *ev)
{
QTC_ASSERT(d->m_viewContainer, return;);
QMenu menu;
QAction *copyRowAction = 0;
QAction *copyTableAction = 0;
QAction *showExtendedStatsAction = 0;
QAction *getLocalStatsAction = 0;
QAction *getGlobalStatsAction = 0;
QmlProfilerTool *profilerTool = qobject_cast<QmlProfilerTool *>(d->m_profilerTool);
QPoint position = ev->globalPos();
if (profilerTool) {
QList <QAction *> commonActions = profilerTool->profilerContextMenuActions();
foreach (QAction *act, commonActions) {
menu.addAction(act);
}
}
if (mouseOnTable(position)) {
menu.addSeparator();
if (selectedItem().isValid())
copyRowAction = menu.addAction(tr("Copy Row"));
copyTableAction = menu.addAction(tr("Copy Table"));
showExtendedStatsAction = menu.addAction(tr("Extended Event Statistics"));
showExtendedStatsAction->setCheckable(true);
showExtendedStatsAction->setChecked(showExtendedStatistics());
}
menu.addSeparator();
getLocalStatsAction = menu.addAction(tr("Limit Events Pane to Current Range"));
if (!d->m_viewContainer->hasValidSelection())
getLocalStatsAction->setEnabled(false);
getGlobalStatsAction = menu.addAction(tr("Reset Events Pane"));
if (hasGlobalStats())
getGlobalStatsAction->setEnabled(false);
QAction *selectedAction = menu.exec(position);
if (selectedAction) {
if (selectedAction == copyRowAction)
copyRowToClipboard();
if (selectedAction == copyTableAction)
copyTableToClipboard();
if (selectedAction == getLocalStatsAction) {
getStatisticsInRange(d->m_viewContainer->selectionStart(),
d->m_viewContainer->selectionEnd());
}
if (selectedAction == getGlobalStatsAction)
getStatisticsInRange(-1, -1);
if (selectedAction == showExtendedStatsAction)
setShowExtendedStatistics(!showExtendedStatistics());
}
}
void QmlProfilerEventsWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
emit resized();
}
bool QmlProfilerEventsWidget::mouseOnTable(const QPoint &position) const
{
QPoint tableTopLeft = d->m_eventTree->mapToGlobal(QPoint(0,0));
QPoint tableBottomRight = d->m_eventTree->mapToGlobal(QPoint(d->m_eventTree->width(), d->m_eventTree->height()));
return (position.x() >= tableTopLeft.x() && position.x() <= tableBottomRight.x() && position.y() >= tableTopLeft.y() && position.y() <= tableBottomRight.y());
}
void QmlProfilerEventsWidget::copyTableToClipboard() const
{
d->m_eventTree->copyTableToClipboard();
}
void QmlProfilerEventsWidget::copyRowToClipboard() const
{
d->m_eventTree->copyRowToClipboard();
}
void QmlProfilerEventsWidget::updateSelectedEvent(const QString &eventHash) const
{
if (d->m_eventTree->selectedEventHash() != eventHash)
d->m_eventTree->selectEvent(eventHash);
}
void QmlProfilerEventsWidget::selectBySourceLocation(const QString &filename, int line, int column)
{
d->m_eventTree->selectEventByLocation(filename, line, column);
}
bool QmlProfilerEventsWidget::hasGlobalStats() const
{
return d->globalStats;
}
void QmlProfilerEventsWidget::setShowExtendedStatistics(bool show)
{
d->m_eventTree->setShowExtendedStatistics(show);
}
bool QmlProfilerEventsWidget::showExtendedStatistics() const
{
return d->m_eventTree->showExtendedStatistics();
}
////////////////////////////////////////////////////////////////////////////////////
class QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate
{
public:
QmlProfilerEventsMainViewPrivate(QmlProfilerEventsMainView *qq) : q(qq) {}
int getFieldCount();
QString textForItem(QStandardItem *item, bool recursive = false) const;
QmlProfilerEventsMainView *q;
QmlProfilerEventsModelProxy *modelProxy;
QStandardItemModel *m_model;
QList<bool> m_fieldShown;
QHash<int, int> m_columnIndex; // maps field enum to column index
bool m_showExtendedStatistics;
int m_firstNumericColumn;
bool m_preventSelectBounce;
};
////////////////////////////////////////////////////////////////////////////////////
QmlProfilerEventsMainView::QmlProfilerEventsMainView(QWidget *parent,
QmlProfilerEventsModelProxy *modelProxy)
: QmlProfilerTreeView(parent), d(new QmlProfilerEventsMainViewPrivate(this))
{
setObjectName(QLatin1String("QmlProfilerEventsTable"));
setSortingEnabled(false);
d->m_model = new QStandardItemModel(this);
setModel(d->m_model);
connect(this,SIGNAL(clicked(QModelIndex)), this,SLOT(jumpToItem(QModelIndex)));
d->modelProxy = modelProxy;
connect(d->modelProxy,SIGNAL(dataAvailable()), this, SLOT(buildModel()));
// connect(d->modelProxy,SIGNAL(stateChanged()),
// this,SLOT(profilerDataModelStateChanged()));
d->m_firstNumericColumn = 0;
d->m_preventSelectBounce = false;
d->m_showExtendedStatistics = false;
setFieldViewable(Name, true);
setFieldViewable(Type, true);
setFieldViewable(TimeInPercent, true);
setFieldViewable(TotalTime, true);
setFieldViewable(SelfTimeInPercent, false);
setFieldViewable(SelfTime, false);
setFieldViewable(CallCount, true);
setFieldViewable(TimePerCall, true);
setFieldViewable(MaxTime, true);
setFieldViewable(MinTime, true);
setFieldViewable(MedianTime, true);
setFieldViewable(Details, true);
buildModel();
}
QmlProfilerEventsMainView::~QmlProfilerEventsMainView()
{
clear();
//delete d->modelProxy;
delete d->m_model;
delete d;
}
void QmlProfilerEventsMainView::profilerDataModelStateChanged()
{
}
void QmlProfilerEventsMainView::setFieldViewable(Fields field, bool show)
{
if (field < MaxFields) {
int length = d->m_fieldShown.count();
if (field >= length) {
for (int i=length; i<MaxFields; i++)
d->m_fieldShown << false;
}
d->m_fieldShown[field] = show;
}
}
void QmlProfilerEventsMainView::setHeaderLabels()
{
int fieldIndex = 0;
d->m_firstNumericColumn = 0;
d->m_columnIndex.clear();
if (d->m_fieldShown[Name]) {
d->m_columnIndex[Name] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Location)));
d->m_firstNumericColumn++;
}
if (d->m_fieldShown[Type]) {
d->m_columnIndex[Type] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Type)));
d->m_firstNumericColumn++;
}
if (d->m_fieldShown[TimeInPercent]) {
d->m_columnIndex[TimeInPercent] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TimeInPercent)));
}
if (d->m_fieldShown[TotalTime]) {
d->m_columnIndex[TotalTime] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TotalTime)));
}
if (d->m_fieldShown[SelfTimeInPercent]) {
d->m_columnIndex[Type] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(SelfTimeInPercent)));
}
if (d->m_fieldShown[SelfTime]) {
d->m_columnIndex[SelfTime] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(SelfTime)));
}
if (d->m_fieldShown[CallCount]) {
d->m_columnIndex[CallCount] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(CallCount)));
}
if (d->m_fieldShown[TimePerCall]) {
d->m_columnIndex[TimePerCall] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TimePerCall)));
}
if (d->m_fieldShown[MedianTime]) {
d->m_columnIndex[MedianTime] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MedianTime)));
}
if (d->m_fieldShown[MaxTime]) {
d->m_columnIndex[MaxTime] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MaxTime)));
}
if (d->m_fieldShown[MinTime]) {
d->m_columnIndex[MinTime] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MinTime)));
}
if (d->m_fieldShown[Details]) {
d->m_columnIndex[Details] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Details)));
}
}
void QmlProfilerEventsMainView::setShowExtendedStatistics(bool show)
{
// Not checking if already set because we don't want the first call to skip
d->m_showExtendedStatistics = show;
if (show) {
if (d->m_fieldShown[MedianTime])
showColumn(d->m_columnIndex[MedianTime]);
if (d->m_fieldShown[MaxTime])
showColumn(d->m_columnIndex[MaxTime]);
if (d->m_fieldShown[MinTime])
showColumn(d->m_columnIndex[MinTime]);
} else{
if (d->m_fieldShown[MedianTime])
hideColumn(d->m_columnIndex[MedianTime]);
if (d->m_fieldShown[MaxTime])
hideColumn(d->m_columnIndex[MaxTime]);
if (d->m_fieldShown[MinTime])
hideColumn(d->m_columnIndex[MinTime]);
}
}
bool QmlProfilerEventsMainView::showExtendedStatistics() const
{
return d->m_showExtendedStatistics;
}
void QmlProfilerEventsMainView::clear()
{
d->m_model->clear();
d->m_model->setColumnCount(d->getFieldCount());
setHeaderLabels();
setSortingEnabled(false);
}
int QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::getFieldCount()
{
int count = 0;
for (int i=0; i < m_fieldShown.count(); ++i)
if (m_fieldShown[i])
count++;
return count;
}
void QmlProfilerEventsMainView::buildModel()
{
clear();
parseModelProxy();
setShowExtendedStatistics(d->m_showExtendedStatistics);
setRootIsDecorated(false);
setSortingEnabled(true);
sortByColumn(d->m_firstNumericColumn,Qt::DescendingOrder);
expandAll();
if (d->m_fieldShown[Name])
resizeColumnToContents(0);
if (d->m_fieldShown[Type])
resizeColumnToContents(d->m_fieldShown[Name]?1:0);
collapseAll();
}
void QmlProfilerEventsMainView::parseModelProxy()
{
const QList <QmlProfilerEventsModelProxy::QmlEventStats> eventList = d->modelProxy->getData();
foreach (const QmlProfilerEventsModelProxy::QmlEventStats &event, eventList) {
QStandardItem *parentItem = d->m_model->invisibleRootItem();
QList<QStandardItem *> newRow;
if (d->m_fieldShown[Name])
newRow << new EventsViewItem(event.displayName);
if (d->m_fieldShown[Type]) {
QString typeString = QmlProfilerEventsMainView::nameForType(event.eventType);
QString toolTipText;
if (event.eventType == Binding) {
if (event.bindingType == (int)OptimizedBinding) {
typeString = typeString + tr(" (Opt)");
toolTipText = tr("Binding is evaluated by the optimized engine.");
} else if (event.bindingType == (int)V8Binding) {
toolTipText = tr("Binding not optimized (e.g. has side effects or assignments,\n"
"references to elements in other files, loops, etc.)");
}
}
newRow << new EventsViewItem(typeString);
newRow.last()->setData(QVariant(typeString));
if (!toolTipText.isEmpty())
newRow.last()->setToolTip(toolTipText);
}
if (d->m_fieldShown[TimeInPercent]) {
newRow << new EventsViewItem(QString::number(event.percentOfTime,'f',2)+QLatin1String(" %"));
newRow.last()->setData(QVariant(event.percentOfTime));
}
if (d->m_fieldShown[TotalTime]) {
newRow << new EventsViewItem(displayTime(event.duration));
newRow.last()->setData(QVariant(event.duration));
}
if (d->m_fieldShown[CallCount]) {
newRow << new EventsViewItem(QString::number(event.calls));
newRow.last()->setData(QVariant(event.calls));
}
if (d->m_fieldShown[TimePerCall]) {
newRow << new EventsViewItem(displayTime(event.timePerCall));
newRow.last()->setData(QVariant(event.timePerCall));
}
if (d->m_fieldShown[MedianTime]) {
newRow << new EventsViewItem(displayTime(event.medianTime));
newRow.last()->setData(QVariant(event.medianTime));
}
if (d->m_fieldShown[MaxTime]) {
newRow << new EventsViewItem(displayTime(event.maxTime));
newRow.last()->setData(QVariant(event.maxTime));
}
if (d->m_fieldShown[MinTime]) {
newRow << new EventsViewItem(displayTime(event.minTime));
newRow.last()->setData(QVariant(event.minTime));
}
if (d->m_fieldShown[Details]) {
newRow << new EventsViewItem(event.details);
newRow.last()->setData(QVariant(event.details));
}
if (!newRow.isEmpty()) {
// no edit
foreach (QStandardItem *item, newRow)
item->setEditable(false);
// metadata
newRow.at(0)->setData(QVariant(event.eventHashStr),EventHashStrRole);
newRow.at(0)->setData(QVariant(event.location.filename),FilenameRole);
newRow.at(0)->setData(QVariant(event.location.line),LineRole);
newRow.at(0)->setData(QVariant(event.location.column),ColumnRole);
if (event.isBindingLoop) {
foreach (QStandardItem *item, newRow) {
item->setBackground(colors()->bindingLoopBackground);
item->setToolTip(tr("Binding loop detected."));
}
}
// append
parentItem->appendRow(newRow);
}
}
}
QString QmlProfilerEventsMainView::displayTime(double time)
{
if (time < 1e6)
return QString::number(time/1e3,'f',3) + trUtf8(" \xc2\xb5s");
if (time < 1e9)
return QString::number(time/1e6,'f',3) + tr(" ms");
return QString::number(time/1e9,'f',3) + tr(" s");
}
QString QmlProfilerEventsMainView::nameForType(int typeNumber)
{
switch (typeNumber) {
case 0: return QmlProfilerEventsMainView::tr("Paint");
case 1: return QmlProfilerEventsMainView::tr("Compile");
case 2: return QmlProfilerEventsMainView::tr("Create");
case 3: return QmlProfilerEventsMainView::tr("Binding");
case 4: return QmlProfilerEventsMainView::tr("Signal");
}
return QString();
}
void QmlProfilerEventsMainView::getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd)
{
d->modelProxy->limitToRange(rangeStart, rangeEnd);
}
QString QmlProfilerEventsMainView::selectedEventHash() const
{
QModelIndex index = selectedItem();
if (!index.isValid())
return QString();
QStandardItem *item = d->m_model->item(index.row(), 0);
return item->data(EventHashStrRole).toString();
}
void QmlProfilerEventsMainView::jumpToItem(const QModelIndex &index)
{
if (d->m_preventSelectBounce)
return;
d->m_preventSelectBounce = true;
QStandardItem *clickedItem = d->m_model->itemFromIndex(index);
QStandardItem *infoItem;
if (clickedItem->parent())
infoItem = clickedItem->parent()->child(clickedItem->row(), 0);
else
infoItem = d->m_model->item(index.row(), 0);
// show in editor
int line = infoItem->data(LineRole).toInt();
int column = infoItem->data(ColumnRole).toInt();
QString fileName = infoItem->data(FilenameRole).toString();
if (line!=-1 && !fileName.isEmpty())
emit gotoSourceLocation(fileName, line, column);
// show in callers/callees subwindow
emit eventSelected(infoItem->data(EventHashStrRole).toString());
d->m_preventSelectBounce = false;
}
void QmlProfilerEventsMainView::selectEvent(const QString &eventHash)
{
for (int i=0; i<d->m_model->rowCount(); i++) {
QStandardItem *infoItem = d->m_model->item(i, 0);
if (infoItem->data(EventHashStrRole).toString() == eventHash) {
setCurrentIndex(d->m_model->indexFromItem(infoItem));
jumpToItem(currentIndex());
return;
}
}
}
void QmlProfilerEventsMainView::selectEventByLocation(const QString &filename, int line, int column)
{
if (d->m_preventSelectBounce)
return;
for (int i=0; i<d->m_model->rowCount(); i++) {
QStandardItem *infoItem = d->m_model->item(i, 0);
if (currentIndex() != d->m_model->indexFromItem(infoItem) &&
infoItem->data(FilenameRole).toString() == filename &&
infoItem->data(LineRole).toInt() == line &&
(column == -1 ||
infoItem->data(ColumnRole).toInt() == column)) {
setCurrentIndex(d->m_model->indexFromItem(infoItem));
jumpToItem(currentIndex());
return;
}
}
}
QModelIndex QmlProfilerEventsMainView::selectedItem() const
{
QModelIndexList sel = selectedIndexes();
if (sel.isEmpty())
return QModelIndex();
else
return sel.first();
}
QString QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::textForItem(QStandardItem *item, bool recursive) const
{
QString str;
if (recursive) {
// indentation
QStandardItem *itemParent = item->parent();
while (itemParent) {
str += QLatin1String(" ");
itemParent = itemParent->parent();
}
}
// item's data
int colCount = m_model->columnCount();
for (int j = 0; j < colCount; ++j) {
QStandardItem *colItem = item->parent() ? item->parent()->child(item->row(),j) : m_model->item(item->row(),j);
str += colItem->data(Qt::DisplayRole).toString();
if (j < colCount-1) str += QLatin1Char('\t');
}
str += QLatin1Char('\n');
// recursively print children
if (recursive && item->child(0))
for (int j = 0; j != item->rowCount(); j++)
str += textForItem(item->child(j));
return str;
}
void QmlProfilerEventsMainView::copyTableToClipboard() const
{
QString str;
// headers
int columnCount = d->m_model->columnCount();
for (int i = 0; i < columnCount; ++i) {
str += d->m_model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
if (i < columnCount - 1)
str += QLatin1Char('\t');
else
str += QLatin1Char('\n');
}
// data
int rowCount = d->m_model->rowCount();
for (int i = 0; i != rowCount; ++i) {
str += d->textForItem(d->m_model->item(i));
}
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(str, QClipboard::Selection);
clipboard->setText(str, QClipboard::Clipboard);
}
void QmlProfilerEventsMainView::copyRowToClipboard() const
{
QString str;
str = d->textForItem(d->m_model->itemFromIndex(selectedItem()), false);
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(str, QClipboard::Selection);
clipboard->setText(str, QClipboard::Clipboard);
}
////////////////////////////////////////////////////////////////////////////////////
class QmlProfilerEventRelativesView::QmlProfilerEventParentsViewPrivate
{
public:
QmlProfilerEventParentsViewPrivate(QmlProfilerEventRelativesView *qq):q(qq) {}
~QmlProfilerEventParentsViewPrivate() {}
QmlProfilerEventRelativesModelProxy *modelProxy;
QmlProfilerEventRelativesView *q;
};
QmlProfilerEventRelativesView::QmlProfilerEventRelativesView(QmlProfilerModelManager *modelManager, QmlProfilerEventRelativesModelProxy *modelProxy, QWidget *parent)
: QmlProfilerTreeView(parent), d(new QmlProfilerEventParentsViewPrivate(this))
{
Q_UNUSED(modelManager);
setSortingEnabled(false);
d->modelProxy = modelProxy;
setModel(new QStandardItemModel(this));
setRootIsDecorated(false);
updateHeader();
connect(this,SIGNAL(clicked(QModelIndex)), this,SLOT(jumpToItem(QModelIndex)));
}
QmlProfilerEventRelativesView::~QmlProfilerEventRelativesView()
{
delete d;
}
void QmlProfilerEventRelativesView::displayEvent(const QString &eventHash)
{
rebuildTree(d->modelProxy->getData(eventHash));
updateHeader();
resizeColumnToContents(0);
setSortingEnabled(true);
sortByColumn(2);
}
void QmlProfilerEventRelativesView::rebuildTree(QmlProfilerEventRelativesModelProxy::QmlEventRelativesMap eventMap)
{
Q_ASSERT(treeModel());
treeModel()->clear();
QStandardItem *topLevelItem = treeModel()->invisibleRootItem();
//foreach (const QmlProfilerEventParentsModelProxy::QmlEventParentData &event, eventMap.values()) {
foreach (const QString &key, eventMap.keys()) {
const QmlProfilerEventRelativesModelProxy::QmlEventRelativesData &event = eventMap[key];
QList<QStandardItem *> newRow;
// ToDo: here we were going to search for the data in the other modelproxy
// maybe we should store the data in this proxy and get it here
// no indirections at this level of abstraction!
newRow << new EventsViewItem(event.displayName);
newRow << new EventsViewItem(QmlProfilerEventsMainView::nameForType(event.eventType));
newRow << new EventsViewItem(QmlProfilerEventsMainView::displayTime(event.duration));
newRow << new EventsViewItem(QString::number(event.calls));
newRow << new EventsViewItem(event.details);
// newRow << new EventsViewItem(event->reference->displayName);
// newRow << new EventsViewItem(QmlProfilerEventsMainView::nameForType(event->reference->eventType));
// newRow << new EventsViewItem(QmlProfilerEventsMainView::displayTime(event->duration));
// newRow << new EventsViewItem(QString::number(event->calls));
// newRow << new EventsViewItem(event->reference->details);
newRow.at(0)->setData(QVariant(key), EventHashStrRole);
newRow.at(2)->setData(QVariant(event.duration));
newRow.at(3)->setData(QVariant(event.calls));
if (event.isBindingLoop) {
foreach (QStandardItem *item, newRow) {
item->setBackground(colors()->bindingLoopBackground);
item->setToolTip(tr("Part of binding loop."));
}
}
foreach (QStandardItem *item, newRow)
item->setEditable(false);
topLevelItem->appendRow(newRow);
}
}
void QmlProfilerEventRelativesView::clear()
{
if (treeModel()) {
treeModel()->clear();
updateHeader();
}
}
void QmlProfilerEventRelativesView::updateHeader()
{
bool calleesView = qobject_cast<QmlProfilerEventChildrenModelProxy *>(d->modelProxy) != 0;
if (treeModel()) {
treeModel()->setColumnCount(5);
int columnIndex = 0;
if (calleesView)
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(Callee)));
else
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(Caller)));
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(Type)));
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(TotalTime)));
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(CallCount)));
if (calleesView)
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(CalleeDescription)));
else
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(CallerDescription)));
}
}
QStandardItemModel *QmlProfilerEventRelativesView::treeModel()
{
return qobject_cast<QStandardItemModel *>(model());
}
void QmlProfilerEventRelativesView::jumpToItem(const QModelIndex &index)
{
if (treeModel()) {
QStandardItem *infoItem = treeModel()->item(index.row(), 0);
emit eventClicked(infoItem->data(EventHashStrRole).toString());
}
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,183 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILEREVENTVIEW_H
#define QMLPROFILEREVENTVIEW_H
#include <QTreeView>
#include <QStandardItemModel>
#include <qmldebug/qmlprofilereventtypes.h>
#include "qmlprofilermodelmanager.h"
#include "qmlprofilereventsmodelproxy.h"
#include "qmlprofilertreeview.h"
#include <analyzerbase/ianalyzertool.h>
#include "qmlprofilerviewmanager.h"
namespace QmlProfiler {
namespace Internal {
class QmlProfilerEventsMainView;
class QmlProfilerEventChildrenView;
class QmlProfilerEventRelativesView;
enum ItemRole {
EventHashStrRole = Qt::UserRole+1,
FilenameRole = Qt::UserRole+2,
LineRole = Qt::UserRole+3,
ColumnRole = Qt::UserRole+4,
EventIdRole = Qt::UserRole+5
};
class QmlProfilerEventsWidget : public QWidget
{
Q_OBJECT
public:
explicit QmlProfilerEventsWidget(QWidget *parent,
Analyzer::IAnalyzerTool *profilerTool,
QmlProfilerViewManager *container,
QmlProfilerModelManager *profilerModelManager );
~QmlProfilerEventsWidget();
void clear();
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
QModelIndex selectedItem() const;
bool mouseOnTable(const QPoint &position) const;
void copyTableToClipboard() const;
void copyRowToClipboard() const;
bool hasGlobalStats() const;
void setShowExtendedStatistics(bool show);
bool showExtendedStatistics() const;
signals:
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
void eventSelectedByHash(const QString &eventHash);
void resized();
public slots:
void updateSelectedEvent(const QString &eventHash) const;
void selectBySourceLocation(const QString &filename, int line, int column);
private slots:
void profilerDataModelStateChanged();
protected:
void contextMenuEvent(QContextMenuEvent *ev);
virtual void resizeEvent(QResizeEvent *event);
private:
class QmlProfilerEventsWidgetPrivate;
QmlProfilerEventsWidgetPrivate *d;
};
class QmlProfilerEventsMainView : public QmlProfilerTreeView
{
Q_OBJECT
public:
explicit QmlProfilerEventsMainView(QWidget *parent,
QmlProfilerEventsModelProxy *modelProxy);
~QmlProfilerEventsMainView();
void setFieldViewable(Fields field, bool show);
void setShowAnonymousEvents( bool showThem );
QModelIndex selectedItem() const;
void copyTableToClipboard() const;
void copyRowToClipboard() const;
static QString displayTime(double time);
static QString nameForType(int typeNumber);
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
// int selectedEventId() const;
QString selectedEventHash() const;
void setShowExtendedStatistics(bool);
bool showExtendedStatistics() const;
signals:
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
void eventSelected(const QString &eventHash);
public slots:
void clear();
void jumpToItem(const QModelIndex &index);
void selectEvent(const QString &eventHash);
void selectEventByLocation(const QString &filename, int line, int column);
void buildModel();
private slots:
void profilerDataModelStateChanged();
private:
void setHeaderLabels();
void parseModelProxy();
private:
class QmlProfilerEventsMainViewPrivate;
QmlProfilerEventsMainViewPrivate *d;
};
class QmlProfilerEventRelativesView : public QmlProfilerTreeView
{
Q_OBJECT
public:
explicit QmlProfilerEventRelativesView(QmlProfilerModelManager *modelManager,
QmlProfilerEventRelativesModelProxy *modelProxy,
QWidget *parent );
~QmlProfilerEventRelativesView();
signals:
void eventClicked(const QString &eventHash);
public slots:
void displayEvent(const QString &eventHash);
void jumpToItem(const QModelIndex &);
void clear();
private:
void rebuildTree(QmlProfilerEventParentsModelProxy::QmlEventRelativesMap eventMap);
void updateHeader();
QStandardItemModel *treeModel();
// QmlProfilerModelManager *m_profilerModelManager;
class QmlProfilerEventParentsViewPrivate;
QmlProfilerEventParentsViewPrivate *d;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILEREVENTVIEW_H

View File

@@ -1,355 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilermodelmanager.h"
#include "qmlprofilersimplemodel.h"
#include "qmlprofilerprocessedmodel.h"
#include "qv8profilerdatamodel.h"
#include "qmlprofilertracefile.h"
#include <utils/qtcassert.h>
#include <QDebug>
#include <QFile>
namespace QmlProfiler {
namespace Internal {
/////////////////////////////////////////////////////////////////////
QmlProfilerDataState::QmlProfilerDataState(QmlProfilerModelManager *modelManager, QObject *parent)
: QObject(parent), m_state(Empty), m_modelManager(modelManager)
{
connect(this, SIGNAL(error(QString)), m_modelManager, SIGNAL(error(QString)));
connect(this, SIGNAL(stateChanged()), m_modelManager, SIGNAL(stateChanged()));
}
void QmlProfilerDataState::setState(QmlProfilerDataState::State state)
{
// It's not an error, we are continuously calling "AcquiringData" for example
if (m_state == state)
return;
switch (state) {
case Empty:
// if it's not empty, complain but go on
QTC_ASSERT(m_modelManager->isEmpty(), /**/);
break;
case AcquiringData:
// we're not supposed to receive new data while processing older data
QTC_ASSERT(m_state != ProcessingData, return);
break;
case ProcessingData:
QTC_ASSERT(m_state == AcquiringData, return);
break;
case Done:
QTC_ASSERT(m_state == ProcessingData || m_state == Empty, return);
break;
default:
emit error(tr("Trying to set unknown state in events list"));
break;
}
m_state = state;
emit stateChanged();
return;
}
/////////////////////////////////////////////////////////////////////
QmlProfilerTraceTime::QmlProfilerTraceTime(QObject *parent) : QObject(parent)
{
clear();
}
QmlProfilerTraceTime::~QmlProfilerTraceTime()
{
}
qint64 QmlProfilerTraceTime::startTime() const
{
return m_startTime;
}
qint64 QmlProfilerTraceTime::endTime() const
{
return m_endTime;
}
qint64 QmlProfilerTraceTime::duration() const
{
return endTime() - startTime();
}
void QmlProfilerTraceTime::clear()
{
m_startTime = -1;
m_endTime = 0;
}
void QmlProfilerTraceTime::setStartTime(qint64 time)
{
m_startTime = time;
}
void QmlProfilerTraceTime::setEndTime(qint64 time)
{
m_endTime = time;
}
/////////////////////////////////////////////////////////////////////
class QmlProfilerModelManager::QmlProfilerModelManagerPrivate
{
public:
QmlProfilerModelManagerPrivate(QmlProfilerModelManager *qq) : q(qq) {}
~QmlProfilerModelManagerPrivate() {}
QmlProfilerModelManager *q;
QmlProfilerSimpleModel *model;
QV8ProfilerDataModel *v8Model;
QmlProfilerDataState *dataState;
QmlProfilerTraceTime *traceTime;
QVector <double> partialCounts;
double progress;
qint64 estimatedTime;
// file to load
QString fileName;
};
QmlProfilerModelManager::QmlProfilerModelManager(Utils::FileInProjectFinder *finder, QObject *parent) :
QObject(parent), d(new QmlProfilerModelManagerPrivate(this))
{
d->model = new QmlProfilerProcessedModel(finder, this);
d->v8Model = new QV8ProfilerDataModel(this);
// d->model = new QmlProfilerSimpleModel(this);
d->dataState = new QmlProfilerDataState(this, this);
d->traceTime = new QmlProfilerTraceTime(this);
}
QmlProfilerModelManager::~QmlProfilerModelManager()
{
delete d;
}
QmlProfilerTraceTime *QmlProfilerModelManager::traceTime() const
{
return d->traceTime;
}
QmlProfilerSimpleModel *QmlProfilerModelManager::simpleModel() const
{
return d->model;
}
QV8ProfilerDataModel *QmlProfilerModelManager::v8Model() const
{
return d->v8Model;
}
bool QmlProfilerModelManager::isEmpty() const
{
return d->model->isEmpty() && d->v8Model->isEmpty();
}
int QmlProfilerModelManager::count() const
{
return d->model->count();
}
double QmlProfilerModelManager::progress() const
{
return d->progress;
}
int QmlProfilerModelManager::registerModelProxy()
{
d->partialCounts << 0;
return d->partialCounts.count()-1;
}
void QmlProfilerModelManager::modelProxyCountUpdated(int proxyId, qint64 count, qint64 max)
{
d->progress -= d->partialCounts[proxyId] / d->partialCounts.count();
if (max <= 0)
d->partialCounts[proxyId] = 1;
else
d->partialCounts[proxyId] = (double)count / (double) max;
d->progress += d->partialCounts[proxyId] / d->partialCounts.count();
emit progressChanged();
if (d->progress > 0.99)
emit dataAvailable();
}
qint64 QmlProfilerModelManager::estimatedProfilingTime() const
{
return d->estimatedTime;
}
void QmlProfilerModelManager::newTimeEstimation(qint64 estimation)
{
d->estimatedTime = estimation;
}
void QmlProfilerModelManager::addQmlEvent(int type, int bindingType, qint64 startTime, qint64 length, const QStringList &data, const QmlDebug::QmlEventLocation &location,
qint64 ndata1, qint64 ndata2, qint64 ndata3, qint64 ndata4, qint64 ndata5)
{
// If trace start time was not explicitly set, use the first event
if (d->traceTime->startTime() == -1)
d->traceTime->setStartTime(startTime);
QTC_ASSERT(state() == QmlProfilerDataState::AcquiringData, /**/);
d->model->addQmlEvent(type, bindingType, startTime, length, data, location, ndata1, ndata2, ndata3, ndata4, ndata5);
emit countChanged();
}
void QmlProfilerModelManager::addV8Event(int depth, const QString &function, const QString &filename,
int lineNumber, double totalTime, double selfTime)
{
d->v8Model->addV8Event(depth, function, filename, lineNumber,totalTime, selfTime);
}
void QmlProfilerModelManager::complete()
{
if (state() == 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());
setState(QmlProfilerDataState::ProcessingData);
d->model->complete();
d->v8Model->complete();
setState(QmlProfilerDataState::Done);
} else
if (state() == QmlProfilerDataState::Empty) {
setState(QmlProfilerDataState::Done);
} else
if (state() == QmlProfilerDataState::Done) {
// repeated Done states are ignored
} else {
emit error(tr("Unexpected complete signal in data model"));
}
}
void QmlProfilerModelManager::save(const QString &filename)
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly)) {
emit error(tr("Could not open %1 for writing.").arg(filename));
return;
}
QmlProfilerFileWriter writer;
writer.setTraceTime(traceTime()->startTime(), traceTime()->endTime(), traceTime()->duration());
writer.setV8DataModel(d->v8Model);
writer.setQmlEvents(d->model->getEvents());
writer.save(&file);
}
void QmlProfilerModelManager::load(const QString &filename)
{
d->fileName = filename;
load();
}
void QmlProfilerModelManager::setFilename(const QString &filename)
{
d->fileName = filename;
}
void QmlProfilerModelManager::load()
{
QString filename = d->fileName;
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
emit error(tr("Could not open %1 for reading.").arg(filename));
return;
}
// erase current
clear();
setState(QmlProfilerDataState::AcquiringData);
QmlProfilerFileReader reader;
connect(&reader, SIGNAL(error(QString)), this, SIGNAL(error(QString)));
connect(&reader, SIGNAL(rangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
qint64, qint64, qint64, qint64, qint64)),
this, SLOT(addQmlEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
qint64, qint64, qint64, qint64, qint64)));
connect(&reader, SIGNAL(traceStartTime(qint64)), traceTime(), SLOT(setStartTime(qint64)));
connect(&reader, SIGNAL(traceEndTime(qint64)), traceTime(), SLOT(setEndTime(qint64)));
reader.setV8DataModel(d->v8Model);
reader.load(&file);
complete();
}
void QmlProfilerModelManager::setState(QmlProfilerDataState::State state)
{
d->dataState->setState(state);
}
QmlProfilerDataState::State QmlProfilerModelManager::state() const
{
return d->dataState->state();
}
void QmlProfilerModelManager::clear()
{
for (int i = 0; i < d->partialCounts.count(); i++)
d->partialCounts[i] = 0;
d->progress = 0;
d->model->clear();
d->v8Model->clear();
d->traceTime->clear();
emit countChanged();
setState(QmlProfilerDataState::Empty);
}
void QmlProfilerModelManager::prepareForWriting()
{
setState(QmlProfilerDataState::AcquiringData);
}
}
}

View File

@@ -1,155 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERMODELMANAGER_H
#define QMLPROFILERMODELMANAGER_H
#include <QObject>
#include "qmlprofiler_global.h"
#include "qmldebug/qmlprofilereventlocation.h"
#include <utils/fileinprojectfinder.h>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerSimpleModel;
class QV8ProfilerDataModel;
class QmlProfilerModelManager;
class QmlProfilerDataState : public QObject
{
Q_OBJECT
public:
enum State {
Empty,
AcquiringData,
ProcessingData,
Done
};
explicit QmlProfilerDataState(QmlProfilerModelManager *modelManager, QObject *parent = 0);
~QmlProfilerDataState() {}
State state() const { return m_state; }
signals:
void stateChanged();
void error(const QString &error);
private:
void setState(State state);
State m_state;
QmlProfilerModelManager *m_modelManager;
friend class QmlProfilerModelManager;
};
class QmlProfilerTraceTime : public QObject
{
Q_OBJECT
public:
explicit QmlProfilerTraceTime(QObject *parent);
~QmlProfilerTraceTime();
qint64 startTime() const;
qint64 endTime() const;
qint64 duration() const;
public slots:
void clear();
void setStartTime(qint64 time);
void setEndTime(qint64 time);
private:
qint64 m_startTime;
qint64 m_endTime;
};
// Interface between the Data Model and the Engine/Tool
class QMLPROFILER_EXPORT QmlProfilerModelManager : public QObject
{
Q_OBJECT
public:
explicit QmlProfilerModelManager(Utils::FileInProjectFinder *finder, QObject *parent = 0);
~QmlProfilerModelManager();
QmlProfilerDataState::State state() const;
QmlProfilerTraceTime *traceTime() const;
QmlProfilerSimpleModel *simpleModel() const;
QV8ProfilerDataModel *v8Model() const;
bool isEmpty() const;
int count() const;
double progress() const;
int registerModelProxy();
void modelProxyCountUpdated(int proxyId, qint64 count, qint64 max);
qint64 estimatedProfilingTime() const;
signals:
void countChanged();
void error(const QString &error);
void stateChanged();
void progressChanged();
void dataAvailable();
void requestDetailsForLocation(int eventType, const QmlDebug::QmlEventLocation &location);
public slots:
void clear();
void prepareForWriting();
void addQmlEvent(int type, int bindingType, qint64 startTime, qint64 length,
const QStringList &data, const QmlDebug::QmlEventLocation &location,
qint64 ndata1, qint64 ndata2, qint64 ndata3, qint64 ndata4, qint64 ndata5);
void addV8Event(int depth, const QString &function,const QString &filename, int lineNumber,
double totalTime, double selfTime);
void complete();
void save(const QString &filename);
void load(const QString &filename);
void setFilename(const QString &filename);
void load();
void newTimeEstimation(qint64 estimation);
private:
void setState(QmlProfilerDataState::State state);
private:
class QmlProfilerModelManagerPrivate;
QmlProfilerModelManagerPrivate *d;
};
}
}
#endif

View File

@@ -1,458 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilerpainteventsmodelproxy.h"
#include "qmlprofilermodelmanager.h"
#include "qmlprofilersimplemodel.h"
#include <QCoreApplication>
#include <QVector>
#include <QHash>
#include <QUrl>
#include <QString>
#include <QStack>
#include <QDebug>
namespace QmlProfiler {
namespace Internal {
struct CategorySpan {
bool expanded;
int expandedRows;
int contractedRows;
};
class PaintEventsModelProxy::PaintEventsModelProxyPrivate
{
public:
PaintEventsModelProxyPrivate(PaintEventsModelProxy *qq) : q(qq) {}
~PaintEventsModelProxyPrivate() {}
QString displayTime(double time);
void computeAnimationCountLimit();
QVector <PaintEventsModelProxy::QmlPaintEventData> eventList;
int minAnimationCount;
int maxAnimationCount;
bool expanded;
PaintEventsModelProxy *q;
};
PaintEventsModelProxy::PaintEventsModelProxy(QObject *parent)
: AbstractTimelineModel(parent), d(new PaintEventsModelProxyPrivate(this))
{
}
PaintEventsModelProxy::~PaintEventsModelProxy()
{
delete d;
}
int PaintEventsModelProxy::categories() const
{
return categoryCount();
}
QStringList PaintEventsModelProxy::categoryTitles() const
{
QStringList retString;
for (int i=0; i<categories(); i++)
retString << categoryLabel(i);
return retString;
}
QString PaintEventsModelProxy::name() const
{
return QLatin1String("PaintEventsModelProxy");
}
const QVector<PaintEventsModelProxy::QmlPaintEventData> PaintEventsModelProxy::getData() const
{
return d->eventList;
}
const QVector<PaintEventsModelProxy::QmlPaintEventData> PaintEventsModelProxy::getData(qint64 fromTime, qint64 toTime) const
{
int fromIndex = findFirstIndex(fromTime);
int toIndex = findLastIndex(toTime);
if (fromIndex != -1 && toIndex > fromIndex)
return d->eventList.mid(fromIndex, toIndex - fromIndex + 1);
else
return QVector<PaintEventsModelProxy::QmlPaintEventData>();
}
void PaintEventsModelProxy::clear()
{
d->eventList.clear();
d->minAnimationCount = 1;
d->maxAnimationCount = 1;
d->expanded = false;
m_modelManager->modelProxyCountUpdated(m_modelId, 0, 1);
}
void PaintEventsModelProxy::dataChanged()
{
if (m_modelManager->state() == QmlProfilerDataState::ProcessingData)
loadData();
if (m_modelManager->state() == QmlProfilerDataState::Empty)
clear();
emit stateChanged();
emit dataAvailable();
emit emptyChanged();
emit expandedChanged();
}
bool compareStartTimes(const PaintEventsModelProxy::QmlPaintEventData &t1, const PaintEventsModelProxy::QmlPaintEventData &t2)
{
return t1.startTime < t2.startTime;
}
bool PaintEventsModelProxy::eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const
{
return (event.eventType == QmlDebug::Painting && event.bindingType == QmlDebug::AnimationFrame);
}
void PaintEventsModelProxy::loadData()
{
clear();
QmlProfilerSimpleModel *simpleModel = m_modelManager->simpleModel();
if (simpleModel->isEmpty())
return;
// collect events
const QVector<QmlProfilerSimpleModel::QmlEventData> referenceList = simpleModel->getEvents();
foreach (const QmlProfilerSimpleModel::QmlEventData &event, referenceList) {
if (!eventAccepted(event))
continue;
qint64 estimatedDuration = 0;
// initial estimation of the event duration: 1/framerate
if (event.numericData1 > 0)
estimatedDuration = 1e9/event.numericData1;
// the profiler registers the animation events at the end of them
qint64 realStartTime = event.startTime - estimatedDuration;
// the duration of the events is estimated from the framerate
// we need to correct it before appending a new event
if (d->eventList.count() > 0) {
QmlPaintEventData *lastEvent = &d->eventList[d->eventList.count()-1];
if (lastEvent->startTime + lastEvent->duration >= realStartTime) {
// 1 nanosecond less to prevent overlap
lastEvent->duration = realStartTime - lastEvent->startTime - 1;
lastEvent->framerate = 1e9/lastEvent->duration;
}
}
QmlPaintEventData newEvent = {
realStartTime,
estimatedDuration,
(int)event.numericData1,
(int)event.numericData2
};
d->eventList.append(newEvent);
m_modelManager->modelProxyCountUpdated(m_modelId, d->eventList.count(), referenceList.count());
}
d->computeAnimationCountLimit();
qSort(d->eventList.begin(), d->eventList.end(), compareStartTimes);
m_modelManager->modelProxyCountUpdated(m_modelId, 1, 1);
emit countChanged();
}
/////////////////// QML interface
bool PaintEventsModelProxy::isEmpty() const
{
return count() == 0;
}
int PaintEventsModelProxy::count() const
{
return d->eventList.count();
}
qint64 PaintEventsModelProxy::lastTimeMark() const
{
return d->eventList.last().startTime + d->eventList.last().duration;
}
bool PaintEventsModelProxy::expanded(int ) const
{
return d->expanded;
}
void PaintEventsModelProxy::setExpanded(int category, bool expanded)
{
Q_UNUSED(category);
d->expanded = expanded;
emit expandedChanged();
}
int PaintEventsModelProxy::categoryDepth(int categoryIndex) const
{
Q_UNUSED(categoryIndex);
if (isEmpty())
return 0;
else
return 2;
}
int PaintEventsModelProxy::categoryCount() const
{
return 1;
}
const QString PaintEventsModelProxy::categoryLabel(int categoryIndex) const
{
Q_UNUSED(categoryIndex);
return tr("Painting");
}
int PaintEventsModelProxy::findFirstIndex(qint64 startTime) const
{
return findFirstIndexNoParents(startTime);
}
int PaintEventsModelProxy::findFirstIndexNoParents(qint64 startTime) const
{
if (d->eventList.isEmpty())
return -1;
if (d->eventList.count() == 1 || d->eventList.first().startTime+d->eventList.first().duration >= startTime)
return 0;
else
if (d->eventList.last().startTime+d->eventList.last().duration <= startTime)
return -1;
int fromIndex = 0;
int toIndex = d->eventList.count()-1;
while (toIndex - fromIndex > 1) {
int midIndex = (fromIndex + toIndex)/2;
if (d->eventList[midIndex].startTime + d->eventList[midIndex].duration < startTime)
fromIndex = midIndex;
else
toIndex = midIndex;
}
return toIndex;
}
int PaintEventsModelProxy::findLastIndex(qint64 endTime) const
{
if (d->eventList.isEmpty())
return -1;
if (d->eventList.first().startTime >= endTime)
return -1;
if (d->eventList.count() == 1)
return 0;
if (d->eventList.last().startTime <= endTime)
return d->eventList.count()-1;
int fromIndex = 0;
int toIndex = d->eventList.count()-1;
while (toIndex - fromIndex > 1) {
int midIndex = (fromIndex + toIndex)/2;
if (d->eventList[midIndex].startTime < endTime)
fromIndex = midIndex;
else
toIndex = midIndex;
}
return fromIndex;
}
int PaintEventsModelProxy::getEventType(int index) const
{
Q_UNUSED(index);
return (int)QmlDebug::Painting;
}
int PaintEventsModelProxy::getEventCategory(int index) const
{
Q_UNUSED(index);
// there is only one category, all events belong to it
return 0;
}
int PaintEventsModelProxy::getEventRow(int index) const
{
Q_UNUSED(index);
return 1;
}
qint64 PaintEventsModelProxy::getDuration(int index) const
{
return d->eventList[index].duration;
}
qint64 PaintEventsModelProxy::getStartTime(int index) const
{
return d->eventList[index].startTime;
}
qint64 PaintEventsModelProxy::getEndTime(int index) const
{
return d->eventList[index].startTime + d->eventList[index].duration;
}
int PaintEventsModelProxy::getEventId(int index) const
{
// there is only one event Id for all painting events
Q_UNUSED(index);
return 0;
}
QColor PaintEventsModelProxy::getColor(int index) const
{
double fpsFraction = d->eventList[index].framerate / 60.0;
if (fpsFraction > 1.0)
fpsFraction = 1.0;
if (fpsFraction < 0.0)
fpsFraction = 0.0;
return QColor::fromHsl((fpsFraction*96)+10, 76, 166);
}
float PaintEventsModelProxy::getHeight(int index) const
{
float scale = d->maxAnimationCount - d->minAnimationCount;
float fraction = 1.0f;
if (scale > 1)
fraction = (float)(d->eventList[index].animationcount -
d->minAnimationCount) / scale;
return fraction * 0.85f + 0.15f;
}
const QVariantList PaintEventsModelProxy::getLabelsForCategory(int category) const
{
Q_UNUSED(category);
QVariantList result;
if (!isEmpty()) {
QVariantMap element;
element.insert(QLatin1String("displayName"), QVariant(QLatin1String("Animations")));
element.insert(QLatin1String("description"), QVariant(QLatin1String("Animations")));
element.insert(QLatin1String("id"), QVariant(0));
result << element;
}
return result;
}
QString PaintEventsModelProxy::PaintEventsModelProxyPrivate::displayTime(double time)
{
if (time < 1e6)
return QString::number(time/1e3,'f',3) + trUtf8(" \xc2\xb5s");
if (time < 1e9)
return QString::number(time/1e6,'f',3) + tr(" ms");
return QString::number(time/1e9,'f',3) + tr(" s");
}
void PaintEventsModelProxy::PaintEventsModelProxyPrivate::computeAnimationCountLimit()
{
minAnimationCount = 1;
maxAnimationCount = 1;
if (eventList.isEmpty())
return;
for (int i=0; i < eventList.count(); i++) {
if (eventList[i].animationcount < minAnimationCount)
minAnimationCount = eventList[i].animationcount;
if (eventList[i].animationcount > maxAnimationCount)
maxAnimationCount = eventList[i].animationcount;
}
}
const QVariantList PaintEventsModelProxy::getEventDetails(int index) const
{
QVariantList result;
// int eventId = getEventId(index);
static const char trContext[] = "RangeDetails";
{
QVariantMap valuePair;
valuePair.insert(QLatin1String("title"), QVariant(categoryLabel(0)));
result << valuePair;
}
// duration
{
QVariantMap valuePair;
valuePair.insert(QCoreApplication::translate(trContext, "Duration:"), QVariant(d->displayTime(d->eventList[index].duration)));
result << valuePair;
}
// duration
{
QVariantMap valuePair;
valuePair.insert(QCoreApplication::translate(trContext, "Framerate:"), QVariant(QString::fromLatin1("%1 FPS").arg(d->eventList[index].framerate)));
result << valuePair;
}
// duration
{
QVariantMap valuePair;
valuePair.insert(QCoreApplication::translate(trContext, "Animations:"), QVariant(QString::fromLatin1("%1").arg(d->eventList[index].animationcount)));
result << valuePair;
}
return result;
}
const QVariantMap PaintEventsModelProxy::getEventLocation(int /*index*/) const
{
QVariantMap map;
return map;
}
int PaintEventsModelProxy::getEventIdForHash(const QString &/*eventHash*/) const
{
// paint events do not have an eventHash
return -1;
}
int PaintEventsModelProxy::getEventIdForLocation(const QString &/*filename*/, int /*line*/, int /*column*/) const
{
// paint events do not have a defined location
return -1;
}
}
}

View File

@@ -1,123 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERPAINTEVENTSMODELPROXY_H
#define QMLPROFILERPAINTEVENTSMODELPROXY_H
#include <QObject>
#include "abstracttimelinemodel.h"
#include <qmldebug/qmlprofilereventtypes.h>
#include <qmldebug/qmlprofilereventlocation.h>
//#include <QHash>
//#include <QVector>
#include <QVariantList>
//#include <QVariantMap>
#include "qmlprofilersimplemodel.h"
#include <QColor>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerModelManager;
class PaintEventsModelProxy : public AbstractTimelineModel
{
// Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged)
Q_OBJECT
public:
struct QmlPaintEventData {
qint64 startTime;
qint64 duration;
int framerate;
int animationcount;
};
PaintEventsModelProxy(QObject *parent = 0);
~PaintEventsModelProxy();
int categories() const;
QStringList categoryTitles() const;
QString name() const;
const QVector<QmlPaintEventData> getData() const;
const QVector<QmlPaintEventData> getData(qint64 fromTime, qint64 toTime) const;
void loadData();
Q_INVOKABLE int count() const;
void clear();
bool isEmpty() const;
Q_INVOKABLE qint64 lastTimeMark() const;
Q_INVOKABLE bool expanded(int category) const;
Q_INVOKABLE void setExpanded(int category, bool expanded);
Q_INVOKABLE int categoryDepth(int categoryIndex) const;
Q_INVOKABLE int categoryCount() const;
Q_INVOKABLE const QString categoryLabel(int categoryIndex) const;
int findFirstIndex(qint64 startTime) const;
int findFirstIndexNoParents(qint64 startTime) const;
int findLastIndex(qint64 endTime) const;
int getEventType(int index) const;
Q_INVOKABLE int getEventCategory(int index) const;
int getEventRow(int index) const;
Q_INVOKABLE qint64 getDuration(int index) const;
Q_INVOKABLE qint64 getStartTime(int index) const;
Q_INVOKABLE qint64 getEndTime(int index) const;
Q_INVOKABLE int getEventId(int index) const;
Q_INVOKABLE QColor getColor(int index) const;
Q_INVOKABLE float getHeight(int index) const;
Q_INVOKABLE const QVariantList getLabelsForCategory(int category) const;
Q_INVOKABLE const QVariantList getEventDetails(int index) const;
Q_INVOKABLE const QVariantMap getEventLocation(int index) const;
Q_INVOKABLE int getEventIdForHash(const QString &eventHash) const;
Q_INVOKABLE int getEventIdForLocation(const QString &filename, int line, int column) const;
private slots:
bool eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const;
protected slots:
void dataChanged();
private:
class PaintEventsModelProxyPrivate;
PaintEventsModelProxyPrivate *d;
};
}
}
#endif

View File

@@ -1,83 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilerplugin.h"
#include "qmlprofilerruncontrolfactory.h"
#include "qmlprofilertool.h"
#include "abstracttimelinemodel.h"
#include <analyzerbase/analyzermanager.h>
#include <extensionsystem/pluginmanager.h>
#include <QtPlugin>
using namespace Analyzer;
using namespace QmlProfiler;
using namespace QmlProfiler::Internal;
bool QmlProfilerPlugin::debugOutput = false;
QmlProfilerPlugin *QmlProfilerPlugin::instance = 0;
bool QmlProfilerPlugin::initialize(const QStringList &arguments, QString *errorString)
{
Q_UNUSED(arguments)
Q_UNUSED(errorString)
IAnalyzerTool *tool = new QmlProfilerTool(this);
AnalyzerManager::addTool(tool, StartLocal);
AnalyzerManager::addTool(tool, StartRemote);
addAutoReleasedObject(new QmlProfilerRunControlFactory());
QmlProfilerPlugin::instance = this;
return true;
}
void QmlProfilerPlugin::extensionsInitialized()
{
timelineModels = ExtensionSystem::PluginManager::getObjects<AbstractTimelineModel>();
}
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;
}
QList<AbstractTimelineModel *> QmlProfilerPlugin::getModels() const
{
return timelineModels;
}
Q_EXPORT_PLUGIN(QmlProfilerPlugin)

View File

@@ -1,69 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERPLUGIN_H
#define QMLPROFILERPLUGIN_H
#include "qmlprofiler_global.h"
#include <extensionsystem/iplugin.h>
#include "abstracttimelinemodel.h"
namespace QmlProfiler {
namespace Internal {
class QmlProfilerPlugin : public ExtensionSystem::IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "QmlProfiler.json")
public:
QmlProfilerPlugin() {}
bool initialize(const QStringList &arguments, QString *errorString);
void extensionsInitialized();
ShutdownFlag aboutToShutdown();
static bool debugOutput;
static QmlProfilerPlugin *instance;
QList<AbstractTimelineModel *> getModels() const;
private:
QList<AbstractTimelineModel*> timelineModels;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILERPLUGIN_H

View File

@@ -1,182 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilerprocessedmodel.h"
#include <qmldebug/qmlprofilereventtypes.h>
#include <utils/qtcassert.h>
#include <QUrl>
#include <QDebug>
namespace QmlProfiler {
namespace Internal {
QmlDebug::QmlEventLocation getLocation(const QmlProfilerSimpleModel::QmlEventData &event);
QString getDisplayName(const QmlProfilerSimpleModel::QmlEventData &event);
QString getInitialDetails(const QmlProfilerSimpleModel::QmlEventData &event);
QmlDebug::QmlEventLocation getLocation(const QmlProfilerSimpleModel::QmlEventData &event)
{
QmlDebug::QmlEventLocation eventLocation = event.location;
if ((event.eventType == QmlDebug::Creating || event.eventType == QmlDebug::Compiling)
&& eventLocation.filename.isEmpty()) {
eventLocation.filename = getInitialDetails(event);
eventLocation.line = 1;
eventLocation.column = 1;
}
return eventLocation;
}
QString getDisplayName(const QmlProfilerSimpleModel::QmlEventData &event)
{
const QmlDebug::QmlEventLocation eventLocation = getLocation(event);
QString displayName;
// generate hash
if (eventLocation.filename.isEmpty()) {
displayName = QmlProfilerProcessedModel::tr("<bytecode>");
} else {
const QString filePath = QUrl(eventLocation.filename).path();
displayName = filePath.mid(filePath.lastIndexOf(QLatin1Char('/')) + 1) + QLatin1Char(':') +
QString::number(eventLocation.line);
}
return displayName;
}
QString getInitialDetails(const QmlProfilerSimpleModel::QmlEventData &event)
{
QString details;
// generate details string
if (event.data.isEmpty())
details = QmlProfilerProcessedModel::tr("Source code not available.");
else {
details = event.data.join(QLatin1String(" ")).replace(QLatin1Char('\n'),QLatin1Char(' ')).simplified();
QRegExp rewrite(QLatin1String("\\(function \\$(\\w+)\\(\\) \\{ (return |)(.+) \\}\\)"));
bool match = rewrite.exactMatch(details);
if (match)
details = rewrite.cap(1) + QLatin1String(": ") + rewrite.cap(3);
if (details.startsWith(QLatin1String("file://")))
details = details.mid(details.lastIndexOf(QLatin1Char('/')) + 1);
}
return details;
}
bool compareStartTimes(const QmlProfilerSimpleModel::QmlEventData &t1, const QmlProfilerSimpleModel::QmlEventData &t2)
{
return t1.startTime < t2.startTime;
}
//////////////////////////////////////////////////////////////////////////////
QmlProfilerProcessedModel::QmlProfilerProcessedModel(Utils::FileInProjectFinder *fileFinder, QObject *parent)
: QmlProfilerSimpleModel(parent)
, m_detailsRewriter(new QmlProfilerDetailsRewriter(this, fileFinder))
, m_emitChanged(false)
{
connect(m_detailsRewriter, SIGNAL(rewriteDetailsString(int,QString)),
this, SLOT(detailsChanged(int,QString)));
connect(m_detailsRewriter, SIGNAL(eventDetailsChanged()),
this, SLOT(detailsDone()));
}
QmlProfilerProcessedModel::~QmlProfilerProcessedModel()
{
}
void QmlProfilerProcessedModel::clear()
{
m_detailsRewriter->clearRequests();
QmlProfilerSimpleModel::clear();
emit changed();
m_emitChanged = false;
}
void QmlProfilerProcessedModel::complete()
{
// post-processing
// sort events by start time
qSort(eventList.begin(), eventList.end(), compareStartTimes);
// rewrite strings
int n = eventList.count();
for (int i = 0; i < n; i++) {
QmlEventData *event = &eventList[i];
event->location = getLocation(*event);
event->displayName = getDisplayName(*event);
event->data = QStringList() << getInitialDetails(*event);
//
// request further details from files
//
if (event->eventType != QmlDebug::Binding && event->eventType != QmlDebug::HandlingSignal)
continue;
// This skips anonymous bindings in Qt4.8 (we don't have valid location data for them)
if (event->location.filename.isEmpty())
continue;
// Skip non-anonymous bindings from Qt4.8 (we already have correct details for them)
if (event->location.column == -1)
continue;
m_detailsRewriter->requestDetailsForLocation(i, event->location);
}
m_detailsRewriter->reloadDocuments();
QmlProfilerSimpleModel::complete();
emit changed();
m_emitChanged = false;
}
void QmlProfilerProcessedModel::detailsChanged(int requestId, const QString &newString)
{
QTC_ASSERT(requestId < eventList.count(), return);
QmlEventData *event = &eventList[requestId];
event->data = QStringList(newString);
m_emitChanged = true;
}
void QmlProfilerProcessedModel::detailsDone()
{
if (m_emitChanged) {
emit changed();
m_emitChanged = false;
}
}
}
}

View File

@@ -1,62 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERPROCESSEDMODEL_H
#define QMLPROFILERPROCESSEDMODEL_H
#include "qmlprofilersimplemodel.h"
#include "qmlprofilerdetailsrewriter.h"
namespace QmlProfiler {
namespace Internal {
class QmlProfilerProcessedModel : public QmlProfilerSimpleModel
{
Q_OBJECT
public:
explicit QmlProfilerProcessedModel(Utils::FileInProjectFinder *fileFinder, QObject *parent = 0);
~QmlProfilerProcessedModel();
virtual void clear();
virtual void complete();
private slots:
void detailsChanged(int requestId, const QString &newString);
void detailsDone();
private:
QmlProfilerDetailsRewriter *m_detailsRewriter;
bool m_emitChanged;
};
}
}
#endif

View File

@@ -1,145 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilerruncontrolfactory.h"
#include "localqmlprofilerrunner.h"
#include "qmlprofilerengine.h"
#include <analyzerbase/ianalyzertool.h>
#include <analyzerbase/analyzermanager.h>
#include <analyzerbase/analyzerstartparameters.h>
#include <analyzerbase/analyzerruncontrol.h>
#include <analyzerbase/analyzersettings.h>
#include <debugger/debuggerrunconfigurationaspect.h>
#include <projectexplorer/environmentaspect.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/localapplicationrunconfiguration.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <qmlprojectmanager/qmlprojectrunconfiguration.h>
#include <utils/qtcassert.h>
#include <QTcpServer>
using namespace Analyzer;
using namespace ProjectExplorer;
namespace QmlProfiler {
namespace Internal {
QmlProfilerRunControlFactory::QmlProfilerRunControlFactory(QObject *parent) :
IRunControlFactory(parent)
{
}
bool QmlProfilerRunControlFactory::canRun(RunConfiguration *runConfiguration, RunMode mode) const
{
return mode == QmlProfilerRunMode
&& (qobject_cast<QmlProjectManager::QmlProjectRunConfiguration *>(runConfiguration)
|| qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration));
}
static AnalyzerStartParameters createQmlProfilerStartParameters(RunConfiguration *runConfiguration)
{
AnalyzerStartParameters sp;
EnvironmentAspect *environment = runConfiguration->extraAspect<EnvironmentAspect>();
// FIXME: This is only used to communicate the connParams settings.
if (QmlProjectManager::QmlProjectRunConfiguration *rc1 =
qobject_cast<QmlProjectManager::QmlProjectRunConfiguration *>(runConfiguration)) {
// This is a "plain" .qmlproject.
if (environment)
sp.environment = environment->environment();
sp.workingDirectory = rc1->workingDirectory();
sp.debuggee = rc1->observerPath();
sp.debuggeeArgs = rc1->viewerArguments();
sp.displayName = rc1->displayName();
} else if (LocalApplicationRunConfiguration *rc2 =
qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration)) {
if (environment)
sp.environment = environment->environment();
sp.workingDirectory = rc2->workingDirectory();
sp.debuggee = rc2->executable();
sp.debuggeeArgs = rc2->commandLineArguments();
sp.displayName = rc2->displayName();
} else {
// What could that be?
QTC_ASSERT(false, return sp);
}
const IDevice::ConstPtr device = DeviceKitInformation::device(runConfiguration->target()->kit());
if (device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
QTcpServer server;
if (!server.listen(QHostAddress::LocalHost) && !server.listen(QHostAddress::LocalHostIPv6)) {
qWarning() << "Cannot open port on host for QML profiling.";
return sp;
}
sp.analyzerHost = server.serverAddress().toString();
sp.analyzerPort = server.serverPort();
}
sp.startMode = StartLocal;
return sp;
}
RunControl *QmlProfilerRunControlFactory::create(RunConfiguration *runConfiguration, RunMode mode, QString *errorMessage)
{
QTC_ASSERT(canRun(runConfiguration, mode), return 0);
AnalyzerStartParameters sp = createQmlProfilerStartParameters(runConfiguration);
sp.runMode = mode;
// only desktop device is supported
const IDevice::ConstPtr device = DeviceKitInformation::device(runConfiguration->target()->kit());
QTC_ASSERT(device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE, return 0);
AnalyzerRunControl *rc = AnalyzerManager::createRunControl(sp, runConfiguration);
QmlProfilerRunControl *engine = qobject_cast<QmlProfilerRunControl *>(rc);
if (!engine) {
delete rc;
return 0;
}
LocalQmlProfilerRunner *runner = LocalQmlProfilerRunner::createLocalRunner(runConfiguration, sp, errorMessage, engine);
if (!runner)
return 0;
connect(runner, SIGNAL(stopped()), engine, SLOT(notifyRemoteFinished()));
connect(runner, SIGNAL(appendMessage(QString,Utils::OutputFormat)),
engine, SLOT(logApplicationMessage(QString,Utils::OutputFormat)));
connect(engine, SIGNAL(starting(const Analyzer::AnalyzerRunControl*)), runner,
SLOT(start()));
connect(rc, SIGNAL(finished()), runner, SLOT(stop()));
return rc;
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,57 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERRUNCONTROLFACTORY_H
#define QMLPROFILERRUNCONTROLFACTORY_H
#include <projectexplorer/runconfiguration.h>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerRunControlFactory : public ProjectExplorer::IRunControlFactory
{
Q_OBJECT
public:
typedef ProjectExplorer::RunConfiguration RunConfiguration;
explicit QmlProfilerRunControlFactory(QObject *parent = 0);
// IRunControlFactory implementation
bool canRun(RunConfiguration *runConfiguration, ProjectExplorer::RunMode mode) const;
ProjectExplorer::RunControl *create(RunConfiguration *runConfiguration,
ProjectExplorer::RunMode mode,
QString *errorMessage);
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILERRUNCONTROLFACTORY_H

View File

@@ -1,117 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilersimplemodel.h"
#include "qmlprofilermodelmanager.h"
#include <QStringList>
#include <QVector>
#include <QDebug>
#include "qmldebug/qmlprofilereventtypes.h"
namespace QmlProfiler {
namespace Internal {
QmlProfilerSimpleModel::QmlProfilerSimpleModel(QObject *parent)
: QObject(parent)
{
m_modelManager = qobject_cast<QmlProfilerModelManager *>(parent);
Q_ASSERT(m_modelManager);
m_modelId = m_modelManager->registerModelProxy();
}
QmlProfilerSimpleModel::~QmlProfilerSimpleModel()
{
}
void QmlProfilerSimpleModel::clear()
{
m_modelManager->modelProxyCountUpdated(m_modelId, 0, 1);
eventList.clear();
emit changed();
}
bool QmlProfilerSimpleModel::isEmpty() const
{
return eventList.isEmpty();
}
const QVector<QmlProfilerSimpleModel::QmlEventData> &QmlProfilerSimpleModel::getEvents() const
{
return eventList;
}
int QmlProfilerSimpleModel::count() const
{
return eventList.count();
}
void QmlProfilerSimpleModel::addQmlEvent(int type, int bindingType, qint64 startTime, qint64 duration, const QStringList &data, const QmlDebug::QmlEventLocation &location, qint64 ndata1, qint64 ndata2, qint64 ndata3, qint64 ndata4, qint64 ndata5)
{
QString displayName;
if (type == QmlDebug::Painting && bindingType == QmlDebug::AnimationFrame) {
displayName = tr("Animations");
} else {
displayName = QString::fromLatin1("%1:%2").arg(
location.filename,
QString::number(location.line));
}
QmlEventData eventData = {displayName, type, bindingType, startTime, duration, data, location, ndata1, ndata2, ndata3, ndata4, ndata5};
eventList.append(eventData);
m_modelManager->modelProxyCountUpdated(m_modelId, startTime, m_modelManager->estimatedProfilingTime());
}
qint64 QmlProfilerSimpleModel::lastTimeMark() const
{
if (eventList.isEmpty())
return 0;
return eventList.last().startTime + eventList.last().duration;
}
void QmlProfilerSimpleModel::complete()
{
m_modelManager->modelProxyCountUpdated(m_modelId, 1, 1);
emit changed();
}
QString QmlProfilerSimpleModel::getHashString(const QmlProfilerSimpleModel::QmlEventData &event)
{
return QString::fromLatin1("%1:%2:%3:%4:%5").arg(
event.location.filename,
QString::number(event.location.line),
QString::number(event.location.column),
QString::number(event.eventType),
QString::number(event.bindingType));
}
}
}

View File

@@ -1,90 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERSIMPLEMODEL_H
#define QMLPROFILERSIMPLEMODEL_H
#include "qmlprofiler_global.h"
#include <QObject>
#include <QVector>
#include <QStringList>
#include "qmldebug/qmlprofilereventlocation.h"
namespace QmlProfiler {
namespace Internal {
class QmlProfilerModelManager;
// stores the data from the client as-is
class QMLPROFILER_EXPORT QmlProfilerSimpleModel : public QObject
{
Q_OBJECT
public:
struct QmlEventData {
QString displayName;
int eventType;
int bindingType;
qint64 startTime;
qint64 duration;
QStringList data;
QmlDebug::QmlEventLocation location;
qint64 numericData1;
qint64 numericData2;
qint64 numericData3;
qint64 numericData4;
qint64 numericData5;
};
explicit QmlProfilerSimpleModel(QObject *parent = 0);
~QmlProfilerSimpleModel();
virtual void clear();
bool isEmpty() const;
const QVector<QmlEventData> &getEvents() const;
int count() const;
void addQmlEvent(int type, int bindingType, qint64 startTime, qint64 duration, const QStringList &data, const QmlDebug::QmlEventLocation &location,
qint64 ndata1, qint64 ndata2, qint64 ndata3, qint64 ndata4, qint64 ndata5);
qint64 lastTimeMark() const;
virtual void complete();
static QString getHashString(const QmlProfilerSimpleModel::QmlEventData &event);
signals:
void changed();
protected:
QVector<QmlEventData> eventList;
QmlProfilerModelManager *m_modelManager;
int m_modelId;
};
}
}
#endif

View File

@@ -1,177 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilerstatemanager.h"
#include <QDebug>
#include <utils/qtcassert.h>
// uncomment for printing the state changes to debug output
//#define _DEBUG_PROFILERSTATE_
namespace QmlProfiler {
namespace Internal {
inline QString stringForState(int state) {
switch (state) {
case QmlProfilerStateManager::Idle: return QLatin1String("Idle");
case QmlProfilerStateManager::AppStarting: return QLatin1String("AppStarting");
case QmlProfilerStateManager::AppRunning: return QLatin1String("AppRunning");
case QmlProfilerStateManager::AppStopRequested: return QLatin1String("AppStopRequested");
case QmlProfilerStateManager::AppReadyToStop: return QLatin1String("AppReadyToStop");
case QmlProfilerStateManager::AppStopped: return QLatin1String("AppStopped");
case QmlProfilerStateManager::AppDying: return QLatin1String("AppDying");
case QmlProfilerStateManager::AppKilled: return QLatin1String("AppKilled");
default: break;
}
return QString();
}
class QmlProfilerStateManager::QmlProfilerStateManagerPrivate
{
public:
QmlProfilerStateManagerPrivate(QmlProfilerStateManager *qq) : q(qq) {}
~QmlProfilerStateManagerPrivate() {}
QmlProfilerStateManager *q;
QmlProfilerStateManager::QmlProfilerState m_currentState;
bool m_clientRecording;
bool m_serverRecording;
};
QmlProfilerStateManager::QmlProfilerStateManager(QObject *parent) :
QObject(parent),d(new QmlProfilerStateManagerPrivate(this))
{
d->m_currentState = Idle;
d->m_clientRecording = true;
d->m_serverRecording = false;
}
QmlProfilerStateManager::~QmlProfilerStateManager()
{
delete d;
}
QmlProfilerStateManager::QmlProfilerState QmlProfilerStateManager::currentState()
{
return d->m_currentState;
}
bool QmlProfilerStateManager::clientRecording()
{
return d->m_clientRecording;
}
bool QmlProfilerStateManager::serverRecording()
{
return d->m_serverRecording;
}
QString QmlProfilerStateManager::currentStateAsString()
{
return stringForState(d->m_currentState);
}
void QmlProfilerStateManager::setCurrentState(QmlProfilerState newState)
{
#ifdef _DEBUG_PROFILERSTATE_
qDebug() << "Profiler state change request from" << stringForState(d->m_currentState) << "to" << stringForState(newState);
#endif
QTC_ASSERT(d->m_currentState != newState, /**/);
switch (newState) {
case Idle:
QTC_ASSERT(d->m_currentState == AppStarting ||
d->m_currentState == AppStopped ||
d->m_currentState == AppKilled,
qDebug() << "from" << stringForState(d->m_currentState));
break;
case AppStarting:
QTC_ASSERT(d->m_currentState == Idle,
qDebug() << "from" << stringForState(d->m_currentState));
break;
case AppRunning:
QTC_ASSERT(d->m_currentState == AppStarting,
qDebug() << "from" << stringForState(d->m_currentState));
break;
case AppStopRequested:
QTC_ASSERT(d->m_currentState == AppRunning,
qDebug() << "from" << stringForState(d->m_currentState));
break;
case AppReadyToStop:
QTC_ASSERT(d->m_currentState == AppStopRequested,
qDebug() << "from" << stringForState(d->m_currentState));
break;
case AppStopped:
QTC_ASSERT(d->m_currentState == AppReadyToStop ||
d->m_currentState == AppDying,
qDebug() << "from" << stringForState(d->m_currentState));
break;
case AppDying:
QTC_ASSERT(d->m_currentState == AppRunning,
qDebug() << "from" << stringForState(d->m_currentState));
break;
case AppKilled:
QTC_ASSERT(d->m_currentState == AppDying,
qDebug() << "from" << stringForState(d->m_currentState));
break;
default: {
const QString message = QString::fromLatin1("Switching to unknown state in %1:%2").arg(QString::fromLatin1(__FILE__), QString::number(__LINE__));
qWarning("%s", qPrintable(message));
}
break;
}
d->m_currentState = newState;
emit stateChanged();
}
void QmlProfilerStateManager::setClientRecording(bool recording)
{
#ifdef _DEBUG_PROFILERSTATE_
qDebug() << "Setting client recording flag from" << d->m_serverRecording << "to" << recording;
#endif
if (d->m_clientRecording != recording) {
d->m_clientRecording = recording;
emit clientRecordingChanged();
}
}
void QmlProfilerStateManager::setServerRecording(bool recording)
{
#ifdef _DEBUG_PROFILERSTATE_
qDebug() << "Setting server recording flag from" << d->m_serverRecording << "to" << recording;
#endif
if (d->m_serverRecording != recording) {
d->m_serverRecording = recording;
emit serverRecordingChanged();
}
}
}
}

View File

@@ -1,80 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERSTATEMANAGER_H
#define QMLPROFILERSTATEMANAGER_H
#include <QObject>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerStateManager : public QObject
{
Q_OBJECT
public:
enum QmlProfilerState {
Idle,
AppStarting,
AppRunning,
AppStopRequested,
AppReadyToStop,
AppStopped,
AppDying,
AppKilled
};
explicit QmlProfilerStateManager(QObject *parent = 0);
~QmlProfilerStateManager();
QmlProfilerState currentState();
bool clientRecording();
bool serverRecording();
QString currentStateAsString();
signals:
void stateChanged();
void clientRecordingChanged();
void serverRecordingChanged();
public slots:
void setCurrentState(QmlProfilerState newState);
void setClientRecording(bool recording);
void setServerRecording(bool recording);
private:
class QmlProfilerStateManagerPrivate;
QmlProfilerStateManagerPrivate *d;
};
}
}
#endif // QMLPROFILERSTATEMANAGER_H

View File

@@ -1,291 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilerstatewidget.h"
#include <QPainter>
#include <QVBoxLayout>
#include <QLabel>
#include <QProgressBar>
#include <QTime>
#include <QDebug>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerStateWidget::QmlProfilerStateWidgetPrivate
{
public:
QmlProfilerStateWidgetPrivate(QmlProfilerStateWidget *qq) { Q_UNUSED(qq); }
QLabel *text;
QProgressBar *progressBar;
QPixmap shadowPic;
QmlProfilerStateManager *m_profilerState;
QmlProfilerModelManager *m_modelManager;
bool isRecording;
bool appKilled;
bool emptyList;
bool traceAvailable;
bool loadingDone;
QTime profilingTimer;
qint64 estimatedProfilingTime;
};
QmlProfilerStateWidget::QmlProfilerStateWidget(QmlProfilerStateManager *stateManager,
QmlProfilerModelManager *modelManager, QWidget *parent)
: QWidget(parent), d(new QmlProfilerStateWidgetPrivate(this))
{
setObjectName(QLatin1String("QML Profiler State Display"));
// UI elements
QVBoxLayout *layout = new QVBoxLayout(this);
resize(200,70);
d->shadowPic.load(QLatin1String(":/qmlprofiler/dialog_shadow.png"));
d->text = new QLabel(this);
d->text->setAlignment(Qt::AlignCenter);
layout->addWidget(d->text);
d->progressBar = new QProgressBar(this);
layout->addWidget(d->progressBar);
d->progressBar->setMaximum(1000);
d->progressBar->setVisible(false);
setLayout(layout);
// internal state
d->isRecording = false;
d->appKilled = false;
d->traceAvailable = false;
d->loadingDone = true;
d->emptyList = true;
// profiler state
d->m_modelManager = modelManager;
connect(d->m_modelManager,SIGNAL(stateChanged()), this, SLOT(dataStateChanged()));
connect(d->m_modelManager,SIGNAL(countChanged()), this, SLOT(dataStateChanged()));
connect(d->m_modelManager,SIGNAL(progressChanged()), this, SLOT(dataStateChanged()));
connect(this, SIGNAL(newTimeEstimation(qint64)), d->m_modelManager, SLOT(newTimeEstimation(qint64)));
d->m_profilerState = stateManager;
connect(d->m_profilerState,SIGNAL(stateChanged()), this, SLOT(profilerStateChanged()));
connect(d->m_profilerState, SIGNAL(serverRecordingChanged()),
this, SLOT(profilerStateChanged()));
updateDisplay();
connect(parent,SIGNAL(resized()),this,SLOT(reposition()));
}
QmlProfilerStateWidget::~QmlProfilerStateWidget()
{
delete d;
}
void QmlProfilerStateWidget::reposition()
{
QWidget *parentWidget = qobject_cast<QWidget *>(parent());
// positioning it at 2/3 height (it looks better)
move(parentWidget->width()/2 - width()/2, parentWidget->height()/3 - height()/2);
}
void QmlProfilerStateWidget::paintEvent(QPaintEvent *event)
{
QWidget::paintEvent(event);
QPainter painter(this);
painter.save();
// Shadow
// there is no actual qpainter borderimage, hacking it here
int borderWidth = 4;
// topleft
painter.drawPixmap(QRect(0, 0, borderWidth, borderWidth),
d->shadowPic,
QRect(0, 0, borderWidth, borderWidth));
// topright
painter.drawPixmap(QRect(width()-borderWidth, 0, borderWidth, borderWidth),
d->shadowPic,
QRect(d->shadowPic.width()-borderWidth, 0, borderWidth, borderWidth));
// bottomleft
painter.drawPixmap(QRect(0, height()-borderWidth, borderWidth, borderWidth),
d->shadowPic,
QRect(0, d->shadowPic.height()-borderWidth, borderWidth, borderWidth));
// bottomright
painter.drawPixmap(QRect(width()-borderWidth, height()-borderWidth, borderWidth, borderWidth),
d->shadowPic,
QRect(d->shadowPic.width()-borderWidth,
d->shadowPic.height()-borderWidth,
borderWidth,
borderWidth));
// top
painter.drawPixmap(QRect(borderWidth, 0, width()-2*borderWidth, borderWidth),
d->shadowPic,
QRect(borderWidth, 0, d->shadowPic.width()-2*borderWidth, borderWidth));
// bottom
painter.drawPixmap(QRect(borderWidth, height()-borderWidth, width()-2*borderWidth, borderWidth),
d->shadowPic,
QRect(borderWidth,
d->shadowPic.height()-borderWidth,
d->shadowPic.width()-2*borderWidth,
borderWidth));
// left
painter.drawPixmap(QRect(0, borderWidth, borderWidth, height()-2*borderWidth),
d->shadowPic,
QRect(0, borderWidth, borderWidth, d->shadowPic.height()-2*borderWidth));
// right
painter.drawPixmap(QRect(width()-borderWidth, borderWidth, borderWidth, height()-2*borderWidth),
d->shadowPic,
QRect(d->shadowPic.width()-borderWidth,
borderWidth,
borderWidth,
d->shadowPic.height()-2*borderWidth));
// center
painter.drawPixmap(QRect(borderWidth, borderWidth, width()-2*borderWidth, height()-2*borderWidth),
d->shadowPic,
QRect(borderWidth,
borderWidth,
d->shadowPic.width()-2*borderWidth,
d->shadowPic.height()-2*borderWidth));
// Background
painter.setBrush(QColor("#E0E0E0"));
painter.setPen(QColor("#666666"));
painter.drawRoundedRect(QRect(borderWidth, 0, width()-2*borderWidth, height()-borderWidth), 6, 6);
// restore painter
painter.restore();
}
void QmlProfilerStateWidget::updateDisplay()
{
// When datamodel is acquiring data
if (!d->loadingDone && !d->emptyList && !d->appKilled) {
setVisible(true);
d->text->setText(tr("Loading data"));
if (d->isRecording) {
d->isRecording = false;
d->estimatedProfilingTime = d->profilingTimer.elapsed();
emit newTimeEstimation(d->estimatedProfilingTime);
}
d->progressBar->setValue(d->m_modelManager->progress() * 1000);
d->progressBar->setVisible(true);
resize(300,70);
reposition();
return;
}
// When application is being profiled
if (d->isRecording) {
setVisible(true);
d->progressBar->setVisible(false);
d->text->setText(tr("Profiling application"));
resize(200,70);
reposition();
return;
}
// After profiling, there is an empty trace
if (d->traceAvailable && d->loadingDone && d->emptyList) {
setVisible(true);
d->progressBar->setVisible(false);
d->text->setText(tr("No QML events recorded"));
resize(200,70);
reposition();
return;
}
// Application died before all data could be read
if (!d->loadingDone && !d->emptyList && d->appKilled) {
setVisible(true);
d->text->setText(tr("Application stopped before loading all data"));
if (d->isRecording) {
d->isRecording = false;
d->estimatedProfilingTime = d->profilingTimer.elapsed();
emit newTimeEstimation(d->estimatedProfilingTime);
}
d->progressBar->setValue(d->m_modelManager->progress() * 1000);
d->progressBar->setVisible(true);
resize(300,70);
reposition();
return;
}
// Everything empty (base state), commented out now but needed in the future.
// if (d->emptyList && d->loadingDone) {
// setVisible(true);
// d->progressBar->setVisible(false);
// d->text->setText(tr("Profiler ready"));
// resize(200,70);
// parentResized();
// return;
// }
// There is a trace on view, hide this dialog
d->progressBar->setVisible(false);
setVisible(false);
}
void QmlProfilerStateWidget::dataStateChanged()
{
// consider possible rounding errors
d->loadingDone = d->m_modelManager->progress() >= 0.99 ||
d->m_modelManager->state() == QmlProfilerDataState::Empty;
d->traceAvailable = d->m_modelManager->traceTime()->duration() > 0;
d->emptyList = d->m_modelManager->isEmpty() || d->m_modelManager->progress() == 0;
updateDisplay();
}
void QmlProfilerStateWidget::profilerStateChanged()
{
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppKilled)
d->appKilled = true;
else
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppStarting)
d->appKilled = false;
d->isRecording = d->m_profilerState->serverRecording();
if (d->isRecording)
d->profilingTimer.start();
else {
// estimated time in ns
d->estimatedProfilingTime = d->profilingTimer.elapsed() * 1e6;
emit newTimeEstimation(d->estimatedProfilingTime);
}
updateDisplay();
}
}
}

View File

@@ -1,69 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERSTATEWIDGET_H
#define QMLPROFILERSTATEWIDGET_H
#include <QWidget>
#include "qmlprofilerstatemanager.h"
#include "qmlprofilermodelmanager.h"
namespace QmlProfiler {
namespace Internal {
class QmlProfilerStateWidget : public QWidget
{
Q_OBJECT
public:
explicit QmlProfilerStateWidget(QmlProfilerStateManager *stateManager,
QmlProfilerModelManager *modelManager, QWidget *parent = 0);
~QmlProfilerStateWidget();
private slots:
void updateDisplay();
void dataStateChanged();
void profilerStateChanged();
void reposition();
signals:
void newTimeEstimation(qint64);
protected:
void paintEvent(QPaintEvent *event);
private:
class QmlProfilerStateWidgetPrivate;
QmlProfilerStateWidgetPrivate *d;
};
}
}
#endif // QMLPROFILERSTATEWIDGET_H

View File

@@ -1,721 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilertimelinemodelproxy.h"
#include "qmlprofilermodelmanager.h"
#include "qmlprofilersimplemodel.h"
#include <QCoreApplication>
#include <QVector>
#include <QHash>
#include <QUrl>
#include <QString>
#include <QStack>
#include <QDebug>
namespace QmlProfiler {
namespace Internal {
struct CategorySpan {
bool expanded;
int expandedRows;
int contractedRows;
int rowStart;
bool empty;
};
class BasicTimelineModel::BasicTimelineModelPrivate
{
public:
BasicTimelineModelPrivate(BasicTimelineModel *qq) : q(qq) {}
~BasicTimelineModelPrivate() {}
// convenience functions
void prepare();
void computeNestingContracted();
void computeExpandedLevels();
void buildEndTimeList();
void findBindingLoops();
void computeRowStarts();
QString displayTime(double time);
QVector <BasicTimelineModel::QmlRangeEventData> eventDict;
QVector <QString> eventHashes;
QVector <BasicTimelineModel::QmlRangeEventStartInstance> startTimeData;
QVector <BasicTimelineModel::QmlRangeEventEndInstance> endTimeData;
QVector <CategorySpan> categorySpan;
BasicTimelineModel *q;
};
BasicTimelineModel::BasicTimelineModel(QObject *parent)
: AbstractTimelineModel(parent), d(new BasicTimelineModelPrivate(this))
{
}
BasicTimelineModel::~BasicTimelineModel()
{
delete d;
}
int BasicTimelineModel::categories() const
{
return categoryCount();
}
QStringList BasicTimelineModel::categoryTitles() const
{
QStringList retString;
for (int i=0; i<categories(); i++)
retString << categoryLabel(i);
return retString;
}
QString BasicTimelineModel::name() const
{
return QLatin1String("BasicTimelineModel");
}
const QVector<BasicTimelineModel::QmlRangeEventStartInstance> BasicTimelineModel::getData() const
{
return d->startTimeData;
}
const QVector<BasicTimelineModel::QmlRangeEventStartInstance> BasicTimelineModel::getData(qint64 fromTime, qint64 toTime) const
{
int fromIndex = findFirstIndex(fromTime);
int toIndex = findLastIndex(toTime);
if (fromIndex != -1 && toIndex > fromIndex)
return d->startTimeData.mid(fromIndex, toIndex - fromIndex + 1);
else
return QVector<BasicTimelineModel::QmlRangeEventStartInstance>();
}
void BasicTimelineModel::clear()
{
d->eventDict.clear();
d->eventHashes.clear();
d->startTimeData.clear();
d->endTimeData.clear();
d->categorySpan.clear();
m_modelManager->modelProxyCountUpdated(m_modelId, 0, 1);
}
void BasicTimelineModel::dataChanged()
{
if (m_modelManager->state() == QmlProfilerDataState::ProcessingData)
loadData();
if (m_modelManager->state() == QmlProfilerDataState::Empty)
clear();
emit stateChanged();
emit dataAvailable();
emit emptyChanged();
emit expandedChanged();
}
void BasicTimelineModel::BasicTimelineModelPrivate::prepare()
{
categorySpan.clear();
for (int i = 0; i < QmlDebug::MaximumQmlEventType; i++) {
CategorySpan newCategory = {false, 1, 1, i, true};
categorySpan << newCategory;
}
}
bool compareStartTimes(const BasicTimelineModel::QmlRangeEventStartInstance&t1, const BasicTimelineModel::QmlRangeEventStartInstance &t2)
{
return t1.startTime < t2.startTime;
}
bool compareEndTimes(const BasicTimelineModel::QmlRangeEventEndInstance &t1, const BasicTimelineModel::QmlRangeEventEndInstance &t2)
{
return t1.endTime < t2.endTime;
}
bool BasicTimelineModel::eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const
{
// only accept Qt4.x Painting events
if (event.eventType == QmlDebug::Painting)
return event.bindingType == QmlDebug::QPainterEvent;
return (event.eventType <= QmlDebug::HandlingSignal);
}
void BasicTimelineModel::loadData()
{
clear();
QmlProfilerSimpleModel *simpleModel = m_modelManager->simpleModel();
if (simpleModel->isEmpty())
return;
int lastEventId = 0;
d->prepare();
// collect events
const QVector<QmlProfilerSimpleModel::QmlEventData> eventList = simpleModel->getEvents();
foreach (const QmlProfilerSimpleModel::QmlEventData &event, eventList) {
if (!eventAccepted(event))
continue;
QString eventHash = QmlProfilerSimpleModel::getHashString(event);
// store in dictionary
if (!d->eventHashes.contains(eventHash)) {
QmlRangeEventData rangeEventData = {
event.displayName,
event.data.join(QLatin1String(" ")),
event.location,
(QmlDebug::QmlEventType)event.eventType,
lastEventId++ // event id
};
d->eventDict << rangeEventData;
d->eventHashes << eventHash;
}
// store starttime-based instance
QmlRangeEventStartInstance eventStartInstance = {
event.startTime,
event.duration,
d->eventHashes.indexOf(eventHash), // event id
QmlDebug::Constants::QML_MIN_LEVEL, // displayRowExpanded;
QmlDebug::Constants::QML_MIN_LEVEL, // displayRowCollapsed;
1,
-1 // bindingLoopHead
};
d->startTimeData.append(eventStartInstance);
m_modelManager->modelProxyCountUpdated(m_modelId, d->startTimeData.count(), eventList.count() * 7);
}
qSort(d->startTimeData.begin(), d->startTimeData.end(), compareStartTimes);
m_modelManager->modelProxyCountUpdated(m_modelId, 2, 7);
// compute nestingLevel - nonexpanded
d->computeNestingContracted();
m_modelManager->modelProxyCountUpdated(m_modelId, 3, 7);
// compute nestingLevel - expanded
d->computeExpandedLevels();
m_modelManager->modelProxyCountUpdated(m_modelId, 4, 7);
// populate endtimelist
d->buildEndTimeList();
m_modelManager->modelProxyCountUpdated(m_modelId, 5, 7);
d->findBindingLoops();
m_modelManager->modelProxyCountUpdated(m_modelId, 6, 7);
d->computeRowStarts();
m_modelManager->modelProxyCountUpdated(m_modelId, 1, 1);
emit countChanged();
}
void BasicTimelineModel::BasicTimelineModelPrivate::computeNestingContracted()
{
int i;
int eventCount = startTimeData.count();
QHash<int, qint64> endtimesPerLevel;
QList<int> nestingLevels;
QList< QHash<int, qint64> > endtimesPerNestingLevel;
int level = QmlDebug::Constants::QML_MIN_LEVEL;
endtimesPerLevel[QmlDebug::Constants::QML_MIN_LEVEL] = 0;
int lastBaseEventIndex = 0;
qint64 lastBaseEventEndTime = q->m_modelManager->traceTime()->startTime();
for (i = 0; i < QmlDebug::MaximumQmlEventType; i++) {
nestingLevels << QmlDebug::Constants::QML_MIN_LEVEL;
QHash<int, qint64> dummyHash;
dummyHash[QmlDebug::Constants::QML_MIN_LEVEL] = 0;
endtimesPerNestingLevel << dummyHash;
}
for (i = 0; i < eventCount; i++) {
qint64 st = startTimeData[i].startTime;
int type = q->getEventType(i);
// general level
if (endtimesPerLevel[level] > st) {
level++;
} else {
while (level > QmlDebug::Constants::QML_MIN_LEVEL && endtimesPerLevel[level-1] <= st)
level--;
}
endtimesPerLevel[level] = st + startTimeData[i].duration;
// per type
if (endtimesPerNestingLevel[type][nestingLevels[type]] > st) {
nestingLevels[type]++;
} else {
while (nestingLevels[type] > QmlDebug::Constants::QML_MIN_LEVEL &&
endtimesPerNestingLevel[type][nestingLevels[type]-1] <= st)
nestingLevels[type]--;
}
endtimesPerNestingLevel[type][nestingLevels[type]] =
st + startTimeData[i].duration;
startTimeData[i].displayRowCollapsed = nestingLevels[type];
if (level == QmlDebug::Constants::QML_MIN_LEVEL) {
if (lastBaseEventEndTime < startTimeData[i].startTime) {
lastBaseEventIndex = i;
lastBaseEventEndTime = startTimeData[i].startTime + startTimeData[i].duration;
}
}
startTimeData[i].baseEventIndex = lastBaseEventIndex;
}
// nestingdepth
for (i = 0; i < eventCount; i++) {
int eventType = q->getEventType(i);
categorySpan[eventType].empty = false;
if (categorySpan[eventType].contractedRows <= startTimeData[i].displayRowCollapsed)
categorySpan[eventType].contractedRows = startTimeData[i].displayRowCollapsed + 1;
}
}
void BasicTimelineModel::BasicTimelineModelPrivate::computeExpandedLevels()
{
QHash<int, int> eventRow;
int eventCount = startTimeData.count();
for (int i = 0; i < eventCount; i++) {
int eventId = startTimeData[i].eventId;
int eventType = eventDict[eventId].eventType;
if (!eventRow.contains(eventId)) {
categorySpan[eventType].empty = false;
eventRow[eventId] = categorySpan[eventType].expandedRows++;
}
startTimeData[i].displayRowExpanded = eventRow[eventId];
}
}
void BasicTimelineModel::BasicTimelineModelPrivate::buildEndTimeList()
{
endTimeData.clear();
int eventCount = startTimeData.count();
for (int i = 0; i < eventCount; i++) {
BasicTimelineModel::QmlRangeEventEndInstance endInstance = {
i,
startTimeData[i].startTime + startTimeData[i].duration
};
endTimeData << endInstance;
}
qSort(endTimeData.begin(), endTimeData.end(), compareEndTimes);
}
void BasicTimelineModel::BasicTimelineModelPrivate::findBindingLoops()
{
typedef QPair<QString, int> CallStackEntry;
QStack<CallStackEntry> callStack;
for (int i = 0; i < startTimeData.size(); ++i) {
QmlRangeEventStartInstance *event = &startTimeData[i];
BasicTimelineModel::QmlRangeEventData data = eventDict.at(event->eventId);
static QVector<QmlDebug::QmlEventType> acceptedTypes =
QVector<QmlDebug::QmlEventType>() << QmlDebug::Compiling << QmlDebug::Creating
<< QmlDebug::Binding << QmlDebug::HandlingSignal;
if (!acceptedTypes.contains(data.eventType))
continue;
const QString eventHash = eventHashes.at(event->eventId);
const QmlRangeEventStartInstance *potentialParent = callStack.isEmpty()
? 0 : &startTimeData[callStack.top().second];
while (potentialParent
&& !(potentialParent->startTime + potentialParent->duration > event->startTime)) {
callStack.pop();
potentialParent = callStack.isEmpty() ? 0
: &startTimeData[callStack.top().second];
}
// check whether event is already in stack
for (int ii = 0; ii < callStack.size(); ++ii) {
if (callStack.at(ii).first == eventHash) {
event->bindingLoopHead = callStack.at(ii).second;
break;
}
}
CallStackEntry newEntry(eventHash, i);
callStack.push(newEntry);
}
}
void BasicTimelineModel::BasicTimelineModelPrivate::computeRowStarts()
{
int rowStart = 0;
for (int i = 0; i < categorySpan.count(); i++) {
categorySpan[i].rowStart = rowStart;
rowStart += q->categoryDepth(i);
}
}
/////////////////// QML interface
bool BasicTimelineModel::isEmpty() const
{
return count() == 0;
}
int BasicTimelineModel::count() const
{
return d->startTimeData.count();
}
qint64 BasicTimelineModel::lastTimeMark() const
{
return d->startTimeData.last().startTime + d->startTimeData.last().duration;
}
bool BasicTimelineModel::expanded(int category) const
{
if (d->categorySpan.count() <= category)
return false;
return d->categorySpan[category].expanded;
}
void BasicTimelineModel::setExpanded(int category, bool expanded)
{
if (d->categorySpan.count() <= category)
return;
d->categorySpan[category].expanded = expanded;
d->computeRowStarts();
emit expandedChanged();
}
int BasicTimelineModel::categoryDepth(int categoryIndex) const
{
if (d->categorySpan.count() <= categoryIndex)
return 1;
// special for paint events: show only when empty model or there's actual events
if (categoryIndex == QmlDebug::Painting && d->categorySpan[categoryIndex].empty && !isEmpty())
return 0;
if (d->categorySpan[categoryIndex].expanded)
return d->categorySpan[categoryIndex].expandedRows;
else
return d->categorySpan[categoryIndex].contractedRows;
}
int BasicTimelineModel::categoryCount() const
{
return 5;
}
const QString BasicTimelineModel::categoryLabel(int categoryIndex) const
{
switch (categoryIndex) {
case 0: return QCoreApplication::translate("MainView", "Painting"); break;
case 1: return QCoreApplication::translate("MainView", "Compiling"); break;
case 2: return QCoreApplication::translate("MainView", "Creating"); break;
case 3: return QCoreApplication::translate("MainView", "Binding"); break;
case 4: return QCoreApplication::translate("MainView", "Handling Signal"); break;
default: return QString();
}
}
int BasicTimelineModel::findFirstIndex(qint64 startTime) const
{
int candidate = -1;
// in the "endtime" list, find the first event that ends after startTime
if (d->endTimeData.isEmpty())
return -1;
if (d->endTimeData.count() == 1 || d->endTimeData.first().endTime >= startTime)
candidate = 0;
else
if (d->endTimeData.last().endTime <= startTime)
return -1;
if (candidate == -1)
{
int fromIndex = 0;
int toIndex = d->endTimeData.count()-1;
while (toIndex - fromIndex > 1) {
int midIndex = (fromIndex + toIndex)/2;
if (d->endTimeData[midIndex].endTime < startTime)
fromIndex = midIndex;
else
toIndex = midIndex;
}
candidate = toIndex;
}
int eventIndex = d->endTimeData[candidate].startTimeIndex;
return d->startTimeData[eventIndex].baseEventIndex;
}
int BasicTimelineModel::findFirstIndexNoParents(qint64 startTime) const
{
int candidate = -1;
// in the "endtime" list, find the first event that ends after startTime
if (d->endTimeData.isEmpty())
return -1;
if (d->endTimeData.count() == 1 || d->endTimeData.first().endTime >= startTime)
candidate = 0;
else
if (d->endTimeData.last().endTime <= startTime)
return -1;
if (candidate == -1) {
int fromIndex = 0;
int toIndex = d->endTimeData.count()-1;
while (toIndex - fromIndex > 1) {
int midIndex = (fromIndex + toIndex)/2;
if (d->endTimeData[midIndex].endTime < startTime)
fromIndex = midIndex;
else
toIndex = midIndex;
}
candidate = toIndex;
}
int ndx = d->endTimeData[candidate].startTimeIndex;
return ndx;
}
int BasicTimelineModel::findLastIndex(qint64 endTime) const
{
// in the "starttime" list, find the last event that starts before endtime
if (d->startTimeData.isEmpty())
return -1;
if (d->startTimeData.first().startTime >= endTime)
return -1;
if (d->startTimeData.count() == 1)
return 0;
if (d->startTimeData.last().startTime <= endTime)
return d->startTimeData.count()-1;
int fromIndex = 0;
int toIndex = d->startTimeData.count()-1;
while (toIndex - fromIndex > 1) {
int midIndex = (fromIndex + toIndex)/2;
if (d->startTimeData[midIndex].startTime < endTime)
fromIndex = midIndex;
else
toIndex = midIndex;
}
return fromIndex;
}
int BasicTimelineModel::getEventType(int index) const
{
return d->eventDict[d->startTimeData[index].eventId].eventType;
}
int BasicTimelineModel::getEventCategory(int index) const
{
int evTy = getEventType(index);
// special: paint events shown?
if (d->categorySpan[0].empty && !isEmpty())
return evTy - 1;
return evTy;
}
int BasicTimelineModel::getEventRow(int index) const
{
if (d->categorySpan[getEventType(index)].expanded)
return d->startTimeData[index].displayRowExpanded + d->categorySpan[getEventType(index)].rowStart;
else
return d->startTimeData[index].displayRowCollapsed + d->categorySpan[getEventType(index)].rowStart;
}
qint64 BasicTimelineModel::getDuration(int index) const
{
return d->startTimeData[index].duration;
}
qint64 BasicTimelineModel::getStartTime(int index) const
{
return d->startTimeData[index].startTime;
}
qint64 BasicTimelineModel::getEndTime(int index) const
{
return d->startTimeData[index].startTime + d->startTimeData[index].duration;
}
int BasicTimelineModel::getEventId(int index) const
{
return d->startTimeData[index].eventId;
}
int BasicTimelineModel::getBindingLoopDest(int index) const
{
return d->startTimeData[index].bindingLoopHead;
}
QColor BasicTimelineModel::getColor(int index) const
{
int ndx = getEventId(index);
return QColor::fromHsl((ndx*25)%360, 76, 166);
}
float BasicTimelineModel::getHeight(int index) const
{
Q_UNUSED(index);
// 100% height for regular events
return 1.0f;
}
const QVariantList BasicTimelineModel::getLabelsForCategory(int category) const
{
QVariantList result;
if (d->categorySpan.count() > category && d->categorySpan[category].expanded) {
int eventCount = d->eventDict.count();
for (int i = 0; i < eventCount; i++) {
if (d->eventDict[i].eventType == category) {
QVariantMap element;
element.insert(QLatin1String("displayName"), QVariant(d->eventDict[i].displayName));
element.insert(QLatin1String("description"), QVariant(d->eventDict[i].details));
element.insert(QLatin1String("id"), QVariant(d->eventDict[i].eventId));
result << element;
}
}
}
return result;
}
QString BasicTimelineModel::BasicTimelineModelPrivate::displayTime(double time)
{
if (time < 1e6)
return QString::number(time/1e3,'f',3) + trUtf8(" \xc2\xb5s");
if (time < 1e9)
return QString::number(time/1e6,'f',3) + tr(" ms");
return QString::number(time/1e9,'f',3) + tr(" s");
}
const QVariantList BasicTimelineModel::getEventDetails(int index) const
{
QVariantList result;
int eventId = getEventId(index);
static const char trContext[] = "RangeDetails";
{
QVariantMap valuePair;
valuePair.insert(QLatin1String("title"), QVariant(categoryLabel(d->eventDict[eventId].eventType)));
result << valuePair;
}
// duration
{
QVariantMap valuePair;
valuePair.insert(QCoreApplication::translate(trContext, "Duration:"), QVariant(d->displayTime(d->startTimeData[index].duration)));
result << valuePair;
}
// details
{
QVariantMap valuePair;
QString detailsString = d->eventDict[eventId].details;
if (detailsString.length() > 40)
detailsString = detailsString.left(40) + QLatin1String("...");
valuePair.insert(QCoreApplication::translate(trContext, "Details:"), QVariant(detailsString));
result << valuePair;
}
// location
{
QVariantMap valuePair;
valuePair.insert(QCoreApplication::translate(trContext, "Location:"), QVariant(d->eventDict[eventId].displayName));
result << valuePair;
}
// isbindingloop
{}
return result;
}
const QVariantMap BasicTimelineModel::getEventLocation(int index) const
{
QVariantMap result;
int eventId = getEventId(index);
QmlDebug::QmlEventLocation location
= d->eventDict.at(eventId).location;
result.insert(QLatin1String("file"), location.filename);
result.insert(QLatin1String("line"), location.line);
result.insert(QLatin1String("column"), location.column);
return result;
}
int BasicTimelineModel::getEventIdForHash(const QString &eventHash) const
{
return d->eventHashes.indexOf(eventHash);
}
int BasicTimelineModel::getEventIdForLocation(const QString &filename, int line, int column) const
{
// if this is called from v8 view, we don't have the column number, it will be -1
foreach (const QmlRangeEventData &eventData, d->eventDict) {
if (eventData.location.filename == filename &&
eventData.location.line == line &&
(column == -1 || eventData.location.column == column))
return eventData.eventId;
}
return -1;
}
}
}

View File

@@ -1,146 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERTIMELINEMODELPROXY_H
#define QMLPROFILERTIMELINEMODELPROXY_H
#include <QObject>
#include "abstracttimelinemodel.h"
#include <qmldebug/qmlprofilereventtypes.h>
#include <qmldebug/qmlprofilereventlocation.h>
//#include <QHash>
//#include <QVector>
#include <QVariantList>
//#include <QVariantMap>
#include "qmlprofilersimplemodel.h"
#include <QColor>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerModelManager;
class BasicTimelineModel : public AbstractTimelineModel
{
// Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged)
Q_OBJECT
public:
struct QmlRangeEventData
{
QString displayName;
QString details;
QmlDebug::QmlEventLocation location;
QmlDebug::QmlEventType eventType;
int eventId; // separate
};
struct QmlRangeEventStartInstance {
qint64 startTime;
qint64 duration;
int eventId;
// not-expanded, per type
int displayRowExpanded;
int displayRowCollapsed;
int baseEventIndex; // used by findfirstindex
int bindingLoopHead;
};
struct QmlRangeEventEndInstance {
int startTimeIndex;
qint64 endTime;
};
BasicTimelineModel(QObject *parent = 0);
~BasicTimelineModel();
int categories() const;
QStringList categoryTitles() const;
QString name() const;
const QVector<QmlRangeEventStartInstance> getData() const;
const QVector<QmlRangeEventStartInstance> getData(qint64 fromTime, qint64 toTime) const;
void loadData();
Q_INVOKABLE int count() const;
void clear();
// QML interface
bool isEmpty() const;
Q_INVOKABLE qint64 lastTimeMark() const;
Q_INVOKABLE bool expanded(int category) const;
Q_INVOKABLE void setExpanded(int category, bool expanded);
Q_INVOKABLE int categoryDepth(int categoryIndex) const;
Q_INVOKABLE int categoryCount() const;
Q_INVOKABLE const QString categoryLabel(int categoryIndex) const;
int findFirstIndex(qint64 startTime) const;
int findFirstIndexNoParents(qint64 startTime) const;
int findLastIndex(qint64 endTime) const;
int getEventType(int index) const;
int getEventCategory(int index) const;
int getEventRow(int index) const;
Q_INVOKABLE qint64 getDuration(int index) const;
Q_INVOKABLE qint64 getStartTime(int index) const;
Q_INVOKABLE qint64 getEndTime(int index) const;
Q_INVOKABLE int getEventId(int index) const;
int getBindingLoopDest(int index) const;
Q_INVOKABLE QColor getColor(int index) const;
Q_INVOKABLE float getHeight(int index) const;
Q_INVOKABLE const QVariantList getLabelsForCategory(int category) const;
Q_INVOKABLE const QVariantList getEventDetails(int index) const;
Q_INVOKABLE const QVariantMap getEventLocation(int index) const;
Q_INVOKABLE int getEventIdForHash(const QString &eventHash) const;
Q_INVOKABLE int getEventIdForLocation(const QString &filename, int line, int column) const;
private slots:
bool eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const;
protected slots:
void dataChanged();
private:
class BasicTimelineModelPrivate;
BasicTimelineModelPrivate *d;
};
}
}
#endif

View File

@@ -1,657 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilertool.h"
#include "qmlprofilerstatemanager.h"
#include "qmlprofilerengine.h"
#include "qmlprofilerconstants.h"
#include "qmlprofilerattachdialog.h"
#include "qmlprofilerviewmanager.h"
#include "qmlprofilerclientmanager.h"
#include "qmlprofilermodelmanager.h"
#include "qmlprofilerdetailsrewriter.h"
#include "timelinerenderer.h"
#include <analyzerbase/analyzermanager.h>
#include <analyzerbase/analyzerruncontrol.h>
#include "canvas/qdeclarativecontext2d_p.h"
#include "canvas/qmlprofilercanvas.h"
#include <qmlprojectmanager/qmlprojectrunconfiguration.h>
#include <utils/fancymainwindow.h>
#include <utils/fileinprojectfinder.h>
#include <utils/qtcassert.h>
#include <projectexplorer/environmentaspect.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
#include <projectexplorer/session.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/localapplicationrunconfiguration.h>
#include <texteditor/itexteditor.h>
#include <android/androidconstants.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <coreplugin/helpmanager.h>
#include <coreplugin/modemanager.h>
#include <coreplugin/imode.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <qtsupport/qtkitinformation.h>
#include <QApplication>
#include <QHBoxLayout>
#include <QLabel>
#include <QToolButton>
#include <QMessageBox>
#include <QFileDialog>
#include <QMenu>
#include <QTimer>
#include <QTime>
#include <QTcpServer>
using namespace Core;
using namespace Core::Constants;
using namespace Analyzer;
using namespace Analyzer::Constants;
using namespace QmlProfiler::Internal;
using namespace QmlProfiler::Constants;
using namespace QmlDebug;
using namespace ProjectExplorer;
using namespace QmlProjectManager;
class QmlProfilerTool::QmlProfilerToolPrivate
{
public:
QmlProfilerStateManager *m_profilerState;
QmlProfilerClientManager *m_profilerConnections;
QmlProfilerModelManager *m_profilerModelManager;
QmlProfilerViewManager *m_viewContainer;
Utils::FileInProjectFinder m_projectFinder;
QToolButton *m_recordButton;
QToolButton *m_clearButton;
// elapsed time display
QTimer m_recordingTimer;
QTime m_recordingElapsedTime;
QLabel *m_timeLabel;
// save and load actions
QAction *m_saveQmlTrace;
QAction *m_loadQmlTrace;
};
QmlProfilerTool::QmlProfilerTool(QObject *parent)
: IAnalyzerTool(parent), d(new QmlProfilerToolPrivate)
{
setObjectName(QLatin1String("QmlProfilerTool"));
d->m_profilerState = 0;
d->m_viewContainer = 0;
qmlRegisterType<QmlProfilerCanvas>("Monitor", 1, 0, "Canvas2D");
qmlRegisterType<Context2D>();
qmlRegisterType<CanvasGradient>();
qmlRegisterType<TimelineRenderer>("Monitor", 1, 0,"TimelineRenderer");
d->m_profilerState = new QmlProfilerStateManager(this);
connect(d->m_profilerState, SIGNAL(stateChanged()), this, SLOT(profilerStateChanged()));
connect(d->m_profilerState, SIGNAL(clientRecordingChanged()), this, SLOT(clientRecordingChanged()));
connect(d->m_profilerState, SIGNAL(serverRecordingChanged()), this, SLOT(serverRecordingChanged()));
d->m_profilerConnections = new QmlProfilerClientManager(this);
d->m_profilerConnections->registerProfilerStateManager(d->m_profilerState);
connect(d->m_profilerConnections, SIGNAL(connectionClosed()), this, SLOT(clientsDisconnected()));
d->m_profilerModelManager = new QmlProfilerModelManager(&d->m_projectFinder, this);
connect(d->m_profilerModelManager, SIGNAL(stateChanged()), this, SLOT(profilerDataModelStateChanged()));
connect(d->m_profilerModelManager, SIGNAL(error(QString)), this, SLOT(showErrorDialog(QString)));
d->m_profilerConnections->setModelManager(d->m_profilerModelManager);
Command *command = 0;
const Context globalContext(C_GLOBAL);
ActionContainer *menu = Core::ActionManager::actionContainer(M_DEBUG_ANALYZER);
ActionContainer *options = Core::ActionManager::createMenu(M_DEBUG_ANALYZER_QML_OPTIONS);
options->menu()->setTitle(tr("QML Profiler Options"));
menu->addMenu(options, G_ANALYZER_OPTIONS);
options->menu()->setEnabled(true);
QAction *act = d->m_loadQmlTrace = new QAction(tr("Load QML Trace"), options);
command = Core::ActionManager::registerAction(act, "Analyzer.Menu.StartAnalyzer.QMLProfilerOptions.LoadQMLTrace", globalContext);
connect(act, SIGNAL(triggered()), this, SLOT(showLoadDialog()));
options->addAction(command);
act = d->m_saveQmlTrace = new QAction(tr("Save QML Trace"), options);
d->m_saveQmlTrace->setEnabled(false);
command = Core::ActionManager::registerAction(act, "Analyzer.Menu.StartAnalyzer.QMLProfilerOptions.SaveQMLTrace", globalContext);
connect(act, SIGNAL(triggered()), this, SLOT(showSaveDialog()));
options->addAction(command);
d->m_recordingTimer.setInterval(100);
connect(&d->m_recordingTimer, SIGNAL(timeout()), this, SLOT(updateTimeDisplay()));
}
QmlProfilerTool::~QmlProfilerTool()
{
delete d;
}
Core::Id QmlProfilerTool::id() const
{
return Core::Id("QmlProfiler");
}
RunMode QmlProfilerTool::runMode() const
{
return QmlProfilerRunMode;
}
QString QmlProfilerTool::displayName() const
{
return tr("QML Profiler");
}
QString QmlProfilerTool::description() const
{
return tr("The QML Profiler can be used to find performance bottlenecks in "
"applications using QML.");
}
IAnalyzerTool::ToolMode QmlProfilerTool::toolMode() const
{
return AnyMode;
}
AnalyzerRunControl *QmlProfilerTool::createRunControl(const AnalyzerStartParameters &sp,
RunConfiguration *runConfiguration)
{
QmlProfilerRunControl *engine = new QmlProfilerRunControl(sp, runConfiguration);
engine->registerProfilerStateManager(d->m_profilerState);
bool isTcpConnection = true;
if (runConfiguration) {
// Check minimum Qt Version. We cannot really be sure what the Qt version
// at runtime is, but guess that the active build configuraiton has been used.
QtSupport::QtVersionNumber minimumVersion(4, 7, 4);
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(runConfiguration->target()->kit());
if (version) {
if (version->isValid() && version->qtVersion() < minimumVersion) {
int result = QMessageBox::warning(QApplication::activeWindow(), tr("QML Profiler"),
tr("The QML profiler requires Qt 4.7.4 or newer.\n"
"The Qt version configured in your active build configuration is too old.\n"
"Do you want to continue?"), QMessageBox::Yes, QMessageBox::No);
if (result == QMessageBox::No)
return 0;
}
}
}
// FIXME: Check that there's something sensible in sp.connParams
if (isTcpConnection)
d->m_profilerConnections->setTcpConnection(sp.analyzerHost, sp.analyzerPort);
//
// Initialize m_projectFinder
//
QString projectDirectory;
if (runConfiguration) {
Project *project = runConfiguration->target()->project();
projectDirectory = project->projectDirectory();
}
populateFileFinder(projectDirectory, sp.sysroot);
connect(engine, SIGNAL(processRunning(quint16)), d->m_profilerConnections, SLOT(connectClient(quint16)));
connect(d->m_profilerConnections, SIGNAL(connectionFailed()), engine, SLOT(cancelProcess()));
return engine;
}
static QString sysroot(RunConfiguration *runConfig)
{
QTC_ASSERT(runConfig, return QString());
ProjectExplorer::Kit *k = runConfig->target()->kit();
if (k && ProjectExplorer::SysRootKitInformation::hasSysRoot(k))
return ProjectExplorer::SysRootKitInformation::sysRoot(runConfig->target()->kit()).toString();
return QString();
}
QWidget *QmlProfilerTool::createWidgets()
{
QTC_ASSERT(!d->m_viewContainer, return 0);
d->m_viewContainer = new QmlProfilerViewManager(this,
this,
d->m_profilerModelManager,
d->m_profilerState);
connect(d->m_viewContainer, SIGNAL(gotoSourceLocation(QString,int,int)),
this, SLOT(gotoSourceLocation(QString,int,int)));
//
// Toolbar
//
QWidget *toolbarWidget = new QWidget;
toolbarWidget->setObjectName(QLatin1String("QmlProfilerToolBarWidget"));
QHBoxLayout *layout = new QHBoxLayout;
layout->setMargin(0);
layout->setSpacing(0);
d->m_recordButton = new QToolButton(toolbarWidget);
d->m_recordButton->setCheckable(true);
connect(d->m_recordButton,SIGNAL(clicked(bool)), this, SLOT(recordingButtonChanged(bool)));
d->m_recordButton->setChecked(true);
setRecording(d->m_profilerState->clientRecording());
layout->addWidget(d->m_recordButton);
d->m_clearButton = new QToolButton(toolbarWidget);
d->m_clearButton->setIcon(QIcon(QLatin1String(":/qmlprofiler/clean_pane_small.png")));
d->m_clearButton->setToolTip(tr("Discard data"));
connect(d->m_clearButton,SIGNAL(clicked()), this, SLOT(clearData()));
layout->addWidget(d->m_clearButton);
d->m_timeLabel = new QLabel();
QPalette palette = d->m_timeLabel->palette();
palette.setColor(QPalette::WindowText, Qt::white);
d->m_timeLabel->setPalette(palette);
d->m_timeLabel->setIndent(10);
updateTimeDisplay();
layout->addWidget(d->m_timeLabel);
toolbarWidget->setLayout(layout);
// When the widgets are requested we assume that the session data
// is available, then we can populate the file finder
populateFileFinder();
return toolbarWidget;
}
void QmlProfilerTool::populateFileFinder(QString projectDirectory, QString activeSysroot)
{
// Initialize filefinder with some sensible default
QStringList sourceFiles;
SessionManager *sessionManager = ProjectExplorerPlugin::instance()->session();
QList<Project *> projects = sessionManager->projects();
if (Project *startupProject = ProjectExplorerPlugin::instance()->startupProject()) {
// startup project first
projects.removeOne(ProjectExplorerPlugin::instance()->startupProject());
projects.insert(0, startupProject);
}
foreach (Project *project, projects)
sourceFiles << project->files(Project::ExcludeGeneratedFiles);
if (!projects.isEmpty()) {
if (projectDirectory.isEmpty())
projectDirectory = projects.first()->projectDirectory();
if (activeSysroot.isEmpty()) {
if (Target *target = projects.first()->activeTarget())
if (RunConfiguration *rc = target->activeRunConfiguration())
activeSysroot = sysroot(rc);
}
}
d->m_projectFinder.setProjectDirectory(projectDirectory);
d->m_projectFinder.setProjectFiles(sourceFiles);
d->m_projectFinder.setSysroot(activeSysroot);
}
void QmlProfilerTool::recordingButtonChanged(bool recording)
{
d->m_profilerState->setClientRecording(recording);
}
void QmlProfilerTool::setRecording(bool recording)
{
// update display
d->m_recordButton->setToolTip( recording ? tr("Disable profiling") : tr("Enable profiling"));
d->m_recordButton->setIcon(QIcon(recording ? QLatin1String(":/qmlprofiler/recordOn.png") :
QLatin1String(":/qmlprofiler/recordOff.png")));
d->m_recordButton->setChecked(recording);
// manage timer
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
if (recording) {
d->m_recordingTimer.start();
d->m_recordingElapsedTime.start();
} else {
d->m_recordingTimer.stop();
}
}
}
void QmlProfilerTool::gotoSourceLocation(const QString &fileUrl, int lineNumber, int columnNumber)
{
if (lineNumber < 0 || fileUrl.isEmpty())
return;
const QString projectFileName = d->m_projectFinder.findFile(fileUrl);
QFileInfo fileInfo(projectFileName);
if (!fileInfo.exists() || !fileInfo.isReadable())
return;
IEditor *editor = EditorManager::openEditor(projectFileName);
TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor);
if (textEditor) {
EditorManager::instance()->addCurrentPositionToNavigationHistory();
// textEditor counts columns starting with 0, but the ASTs store the
// location starting with 1, therefore the -1 in the call to gotoLine
textEditor->gotoLine(lineNumber, columnNumber - 1);
textEditor->widget()->setFocus();
}
}
void QmlProfilerTool::updateTimeDisplay()
{
double seconds = 0;
if (d->m_profilerState->serverRecording() &&
d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
seconds = d->m_recordingElapsedTime.elapsed() / 1000.0;
} else if (d->m_profilerModelManager->state() != QmlProfilerDataState::Empty ) {
//seconds = d->m_profilerModelManager->traceDuration() / 1.0e9;
seconds = d->m_profilerModelManager->traceTime()->duration() / 1.0e9;
}
QString timeString = QString::number(seconds,'f',1);
QString profilerTimeStr = QmlProfilerTool::tr("%1 s").arg(timeString, 6);
d->m_timeLabel->setText(tr("Elapsed: %1").arg(profilerTimeStr));
}
void QmlProfilerTool::clearData()
{
d->m_profilerModelManager->clear();
d->m_profilerConnections->discardPendingData();
}
void QmlProfilerTool::clearDisplay()
{
d->m_profilerConnections->clearBufferedData();
d->m_viewContainer->clear();
updateTimeDisplay();
}
static void startRemoteTool(IAnalyzerTool *tool, StartMode mode)
{
Q_UNUSED(tool);
Id kitId;
quint16 port;
Kit *kit = 0;
{
QSettings *settings = ICore::settings();
kitId = Id::fromSetting(settings->value(QLatin1String("AnalyzerQmlAttachDialog/kitId")));
port = settings->value(QLatin1String("AnalyzerQmlAttachDialog/port"), 3768).toUInt();
QmlProfilerAttachDialog dialog;
dialog.setKitId(kitId);
dialog.setPort(port);
if (dialog.exec() != QDialog::Accepted)
return;
kit = dialog.kit();
port = dialog.port();
settings->setValue(QLatin1String("AnalyzerQmlAttachDialog/kitId"), kit->id().toSetting());
settings->setValue(QLatin1String("AnalyzerQmlAttachDialog/port"), port);
}
AnalyzerStartParameters sp;
sp.startMode = mode;
IDevice::ConstPtr device = DeviceKitInformation::device(kit);
if (device) {
sp.connParams = device->sshParameters();
if (device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE
|| device->type() == Android::Constants::ANDROID_DEVICE_TYPE) {
sp.analyzerHost = QLatin1String("localhost");
} else {
sp.analyzerHost = sp.connParams.host;
}
}
sp.sysroot = SysRootKitInformation::sysRoot(kit).toString();
sp.analyzerPort = port;
//AnalyzerRunControl *rc = new AnalyzerRunControl(tool, sp, 0);
AnalyzerRunControl *rc = tool->createRunControl(sp, 0);
QObject::connect(AnalyzerManager::stopAction(), SIGNAL(triggered()), rc, SLOT(stopIt()));
ProjectExplorerPlugin::instance()->startRunControl(rc, tool->runMode());
}
void QmlProfilerTool::startTool(StartMode mode)
{
using namespace ProjectExplorer;
// Make sure mode is shown.
AnalyzerManager::showMode();
if (mode == StartLocal) {
ProjectExplorerPlugin *pe = ProjectExplorerPlugin::instance();
// ### not sure if we're supposed to check if the RunConFiguration isEnabled
Project *pro = pe->startupProject();
pe->runProject(pro, runMode());
} else if (mode == StartRemote) {
startRemoteTool(this, mode);
}
}
void QmlProfilerTool::logStatus(const QString &msg)
{
MessageManager *messageManager = MessageManager::instance();
messageManager->printToOutputPane(msg, Core::MessageManager::Flash);
}
void QmlProfilerTool::logError(const QString &msg)
{
MessageManager *messageManager = MessageManager::instance();
messageManager->printToOutputPane(msg, Core::MessageManager::NoModeSwitch);
}
void QmlProfilerTool::showErrorDialog(const QString &error)
{
QMessageBox *errorDialog = new QMessageBox(Core::ICore::mainWindow());
errorDialog->setIcon(QMessageBox::Warning);
errorDialog->setWindowTitle(tr("QML Profiler"));
errorDialog->setText(error);
errorDialog->setStandardButtons(QMessageBox::Ok);
errorDialog->setDefaultButton(QMessageBox::Ok);
errorDialog->setModal(false);
errorDialog->show();
}
void QmlProfilerTool::showSaveOption()
{
d->m_saveQmlTrace->setEnabled(!d->m_profilerModelManager->isEmpty());
}
void QmlProfilerTool::showSaveDialog()
{
QString filename = QFileDialog::getSaveFileName(Core::ICore::mainWindow(), tr("Save QML Trace"), QString(),
tr("QML traces (*%1)").arg(QLatin1String(TraceFileExtension)));
if (!filename.isEmpty()) {
if (!filename.endsWith(QLatin1String(TraceFileExtension)))
filename += QLatin1String(TraceFileExtension);
d->m_profilerModelManager->save(filename);
}
}
void QmlProfilerTool::showLoadDialog()
{
if (ModeManager::currentMode()->id() != MODE_ANALYZE)
AnalyzerManager::showMode();
AnalyzerManager::selectTool(this, StartRemote);
QString filename = QFileDialog::getOpenFileName(Core::ICore::mainWindow(), tr("Load QML Trace"), QString(),
tr("QML traces (*%1)").arg(QLatin1String(TraceFileExtension)));
if (!filename.isEmpty()) {
// delayed load (prevent graphical artifacts due to long load time)
d->m_profilerModelManager->setFilename(filename);
QTimer::singleShot(100, d->m_profilerModelManager, SLOT(load()));
}
}
void QmlProfilerTool::clientsDisconnected()
{
// If the application stopped by itself, check if we have all the data
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppDying) {
if (d->m_profilerModelManager->state() == QmlProfilerDataState::AcquiringData)
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppKilled);
else
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppStopped);
// ... and return to the "base" state
d->m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
}
// If the connection is closed while the app is still running, no special action is needed
}
void QmlProfilerTool::profilerDataModelStateChanged()
{
switch (d->m_profilerModelManager->state()) {
case QmlProfilerDataState::Empty :
clearDisplay();
break;
case QmlProfilerDataState::AcquiringData :
case QmlProfilerDataState::ProcessingData :
// nothing to be done for these two
break;
case QmlProfilerDataState::Done :
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppStopRequested)
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppReadyToStop);
showSaveOption();
updateTimeDisplay();
break;
default:
break;
}
}
QList <QAction *> QmlProfilerTool::profilerContextMenuActions() const
{
QList <QAction *> commonActions;
commonActions << d->m_loadQmlTrace << d->m_saveQmlTrace;
return commonActions;
}
void QmlProfilerTool::showNonmodalWarning(const QString &warningMsg)
{
QMessageBox *noExecWarning = new QMessageBox(Core::ICore::mainWindow());
noExecWarning->setIcon(QMessageBox::Warning);
noExecWarning->setWindowTitle(tr("QML Profiler"));
noExecWarning->setText(warningMsg);
noExecWarning->setStandardButtons(QMessageBox::Ok);
noExecWarning->setDefaultButton(QMessageBox::Ok);
noExecWarning->setModal(false);
noExecWarning->show();
}
QMessageBox *QmlProfilerTool::requestMessageBox()
{
return new QMessageBox(Core::ICore::mainWindow());
}
void QmlProfilerTool::handleHelpRequest(const QString &link)
{
HelpManager *helpManager = HelpManager::instance();
helpManager->handleHelpRequest(link);
}
void QmlProfilerTool::profilerStateChanged()
{
switch (d->m_profilerState->currentState()) {
case QmlProfilerStateManager::AppDying : {
// If already disconnected when dying, check again that all data was read
if (!d->m_profilerConnections->isConnected())
QTimer::singleShot(0, this, SLOT(clientsDisconnected()));
break;
}
case QmlProfilerStateManager::AppKilled : {
showNonmodalWarning(tr("Application finished before loading profiled data.\nPlease use the stop button instead."));
d->m_profilerModelManager->clear();
break;
}
case QmlProfilerStateManager::Idle :
// when the app finishes, set recording display to client status
setRecording(d->m_profilerState->clientRecording());
break;
default:
// no special action needed for other states
break;
}
}
void QmlProfilerTool::clientRecordingChanged()
{
// if application is running, display server record changes
// if application is stopped, display client record changes
if (d->m_profilerState->currentState() != QmlProfilerStateManager::AppRunning)
setRecording(d->m_profilerState->clientRecording());
}
void QmlProfilerTool::serverRecordingChanged()
{
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
setRecording(d->m_profilerState->serverRecording());
// clear the old data each time we start a new profiling session
if (d->m_profilerState->serverRecording()) {
d->m_clearButton->setEnabled(false);
clearData();
d->m_profilerModelManager->prepareForWriting();
} else {
d->m_clearButton->setEnabled(true);
}
} else {
d->m_clearButton->setEnabled(true);
}
}

View File

@@ -1,106 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERTOOL_H
#define QMLPROFILERTOOL_H
#include <analyzerbase/ianalyzertool.h>
#include <analyzerbase/analyzerruncontrol.h>
QT_BEGIN_NAMESPACE
class QMessageBox;
QT_END_NAMESPACE
namespace QmlProfiler {
namespace Internal {
class QmlProfilerTool : public Analyzer::IAnalyzerTool
{
Q_OBJECT
public:
explicit QmlProfilerTool(QObject *parent);
~QmlProfilerTool();
Core::Id id() const;
ProjectExplorer::RunMode runMode() const;
QString displayName() const;
QString description() const;
ToolMode toolMode() const;
void extensionsInitialized() {}
Analyzer::AnalyzerRunControl *createRunControl(const Analyzer::AnalyzerStartParameters &sp,
ProjectExplorer::RunConfiguration *runConfiguration = 0);
QWidget *createWidgets();
void startTool(Analyzer::StartMode mode);
QList <QAction *> profilerContextMenuActions() const;
// display dialogs / log output
static QMessageBox *requestMessageBox();
static void handleHelpRequest(const QString &link);
static void logStatus(const QString &msg);
static void logError(const QString &msg);
static void showNonmodalWarning(const QString &warningMsg);
public slots:
void profilerStateChanged();
void clientRecordingChanged();
void serverRecordingChanged();
void clientsDisconnected();
void recordingButtonChanged(bool recording);
void setRecording(bool recording);
void gotoSourceLocation(const QString &fileUrl, int lineNumber, int columnNumber);
private slots:
void clearData();
void showErrorDialog(const QString &error);
void profilerDataModelStateChanged();
void updateTimeDisplay();
void showSaveOption();
void showSaveDialog();
void showLoadDialog();
private:
void clearDisplay();
void populateFileFinder(QString projectDirectory = QString(), QString activeSysroot = QString());
class QmlProfilerToolPrivate;
QmlProfilerToolPrivate *d;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILERTOOL_H

View File

@@ -1,562 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilertracefile.h"
#include <utils/qtcassert.h>
#include <QIODevice>
#include <QStringList>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
// import QmlEventType, QmlBindingType enums, QmlEventLocation
using namespace QmlDebug;
const char PROFILER_FILE_VERSION[] = "1.02";
const char TYPE_PAINTING_STR[] = "Painting";
const char TYPE_COMPILING_STR[] = "Compiling";
const char TYPE_CREATING_STR[] = "Creating";
const char TYPE_BINDING_STR[] = "Binding";
const char TYPE_HANDLINGSIGNAL_STR[] = "HandlingSignal";
const char TYPE_PIXMAPCACHE_STR[] = "PixmapCache";
const char TYPE_SCENEGRAPH_STR[] = "SceneGraph";
#define _(X) QLatin1String(X)
//
// "be strict in your output but tolerant in your inputs"
//
namespace QmlProfiler {
namespace Internal {
static QmlEventType qmlEventTypeAsEnum(const QString &typeString)
{
if (typeString == _(TYPE_PAINTING_STR)) {
return Painting;
} else if (typeString == _(TYPE_COMPILING_STR)) {
return Compiling;
} else if (typeString == _(TYPE_CREATING_STR)) {
return Creating;
} else if (typeString == _(TYPE_BINDING_STR)) {
return Binding;
} else if (typeString == _(TYPE_HANDLINGSIGNAL_STR)) {
return HandlingSignal;
} else if (typeString == _(TYPE_PIXMAPCACHE_STR)) {
return PixmapCacheEvent;
} else if (typeString == _(TYPE_SCENEGRAPH_STR)) {
return SceneGraphFrameEvent;
} else {
bool isNumber = false;
int type = typeString.toUInt(&isNumber);
if (isNumber)
return (QmlEventType)type;
else
return MaximumQmlEventType;
}
}
static QString qmlEventTypeAsString(QmlEventType typeEnum)
{
switch (typeEnum) {
case Painting:
return _(TYPE_PAINTING_STR);
break;
case Compiling:
return _(TYPE_COMPILING_STR);
break;
case Creating:
return _(TYPE_CREATING_STR);
break;
case Binding:
return _(TYPE_BINDING_STR);
break;
case HandlingSignal:
return _(TYPE_HANDLINGSIGNAL_STR);
break;
case PixmapCacheEvent:
return _(TYPE_PIXMAPCACHE_STR);
break;
case SceneGraphFrameEvent:
return _(TYPE_SCENEGRAPH_STR);
break;
default:
return QString::number((int)typeEnum);
}
}
QmlProfilerFileReader::QmlProfilerFileReader(QObject *parent) :
QObject(parent),
m_v8Model(0)
{
}
void QmlProfilerFileReader::setV8DataModel(QV8ProfilerDataModel *dataModel)
{
m_v8Model = dataModel;
}
bool QmlProfilerFileReader::load(QIODevice *device)
{
QXmlStreamReader stream(device);
bool validVersion = true;
while (validVersion && !stream.atEnd() && !stream.hasError()) {
QXmlStreamReader::TokenType token = stream.readNext();
QString elementName = stream.name().toString();
switch (token) {
case QXmlStreamReader::StartDocument : continue;
case QXmlStreamReader::StartElement : {
if (elementName == _("trace")) {
QXmlStreamAttributes attributes = stream.attributes();
if (attributes.hasAttribute(_("version")))
validVersion = attributes.value(_("version")).toString()
== _(PROFILER_FILE_VERSION);
else
validVersion = false;
if (attributes.hasAttribute(_("traceStart")))
emit traceStartTime(attributes.value(_("traceStart")).toString().toLongLong());
if (attributes.hasAttribute(_("traceEnd")))
emit traceEndTime(attributes.value(_("traceEnd")).toString().toLongLong());
}
if (elementName == _("eventData")) {
loadEventData(stream);
break;
}
if (elementName == _("profilerDataModel")) {
loadProfilerDataModel(stream);
break;
}
if (elementName == _("v8profile")) {
if (m_v8Model)
m_v8Model->load(stream);
break;
}
break;
}
default: break;
}
}
if (stream.hasError()) {
emit error(tr("Error while parsing trace data file: %1").arg(stream.errorString()));
return false;
} else {
processQmlEvents();
return true;
}
}
void QmlProfilerFileReader::loadEventData(QXmlStreamReader &stream)
{
QTC_ASSERT(stream.name().toString() == _("eventData"), return);
QXmlStreamAttributes attributes = stream.attributes();
if (attributes.hasAttribute(_("totalTime"))) {
// not used any more
}
int eventIndex = -1;
QmlEvent event = {
QString(), // displayname
QString(), // filename
QString(), // details
Painting, // type
QmlBinding, // bindingType, set for backwards compatibility
0, // line
0 // column
};
const QmlEvent defaultEvent = event;
while (!stream.atEnd() && !stream.hasError()) {
QXmlStreamReader::TokenType token = stream.readNext();
const QString elementName = stream.name().toString();
switch (token) {
case QXmlStreamReader::StartElement: {
if (elementName == _("event")) {
event = defaultEvent;
const QXmlStreamAttributes attributes = stream.attributes();
if (attributes.hasAttribute(_("index"))) {
eventIndex = attributes.value(_("index")).toString().toInt();
} else {
// ignore event
eventIndex = -1;
}
break;
}
stream.readNext();
if (stream.tokenType() != QXmlStreamReader::Characters)
break;
const QString readData = stream.text().toString();
if (elementName == _("displayname")) {
event.displayName = readData;
break;
}
if (elementName == _("type")) {
event.type = qmlEventTypeAsEnum(readData);
break;
}
if (elementName == _("filename")) {
event.filename = readData;
break;
}
if (elementName == _("line")) {
event.line = readData.toInt();
break;
}
if (elementName == _("column")) {
event.column = readData.toInt();
break;
}
if (elementName == _("details")) {
event.details = readData;
break;
}
if (elementName == _("bindingType") ||
elementName == _("animationFrame") ||
elementName == _("cacheEventType") ||
elementName == _("sgEventType")) {
event.bindingType = readData.toInt();
break;
}
break;
}
case QXmlStreamReader::EndElement: {
if (elementName == _("event")) {
if (eventIndex >= 0) {
if (eventIndex >= m_qmlEvents.size())
m_qmlEvents.resize(eventIndex + 1);
m_qmlEvents[eventIndex] = event;
}
break;
}
if (elementName == _("eventData")) {
// done reading eventData
return;
}
break;
}
default: break;
} // switch
}
}
void QmlProfilerFileReader::loadProfilerDataModel(QXmlStreamReader &stream)
{
QTC_ASSERT(stream.name().toString() == _("profilerDataModel"), return);
while (!stream.atEnd() && !stream.hasError()) {
QXmlStreamReader::TokenType token = stream.readNext();
const QString elementName = stream.name().toString();
switch (token) {
case QXmlStreamReader::StartElement: {
if (elementName == _("range")) {
Range range = { 0, 0, 0, 0, 0, 0, 0 };
const QXmlStreamAttributes attributes = stream.attributes();
if (!attributes.hasAttribute(_("startTime"))
|| !attributes.hasAttribute(_("eventIndex"))) {
// ignore incomplete entry
continue;
}
range.startTime = attributes.value(_("startTime")).toString().toLongLong();
if (attributes.hasAttribute(_("duration")))
range.duration = attributes.value(_("duration")).toString().toLongLong();
// attributes for special events
if (attributes.hasAttribute(_("framerate")))
range.numericData1 = attributes.value(_("framerate")).toString().toLongLong();
if (attributes.hasAttribute(_("animationcount")))
range.numericData2 = attributes.value(_("animationcount")).toString().toLongLong();
if (attributes.hasAttribute(_("width")))
range.numericData1 = attributes.value(_("width")).toString().toLongLong();
if (attributes.hasAttribute(_("height")))
range.numericData2 = attributes.value(_("height")).toString().toLongLong();
if (attributes.hasAttribute(_("refCount")))
range.numericData3 = attributes.value(_("refCount")).toString().toLongLong();
if (attributes.hasAttribute(_("timing1")))
range.numericData1 = attributes.value(_("timing1")).toString().toLongLong();
if (attributes.hasAttribute(_("timing2")))
range.numericData2 = attributes.value(_("timing2")).toString().toLongLong();
if (attributes.hasAttribute(_("timing3")))
range.numericData3 = attributes.value(_("timing3")).toString().toLongLong();
if (attributes.hasAttribute(_("timing4")))
range.numericData4 = attributes.value(_("timing4")).toString().toLongLong();
if (attributes.hasAttribute(_("timing5")))
range.numericData5 = attributes.value(_("timing5")).toString().toLongLong();
int eventIndex = attributes.value(_("eventIndex")).toString().toInt();
m_ranges.append(QPair<Range,int>(range, eventIndex));
}
break;
}
case QXmlStreamReader::EndElement: {
if (elementName == _("profilerDataModel")) {
// done reading profilerDataModel
return;
}
break;
}
default: break;
} // switch
}
}
void QmlProfilerFileReader::processQmlEvents()
{
for (int i = 0; i < m_ranges.size(); ++i) {
Range range = m_ranges[i].first;
int eventIndex = m_ranges[i].second;
if (eventIndex < 0 || eventIndex >= m_qmlEvents.size()) {
qWarning() << ".qtd file - range index" << eventIndex
<< "is outside of bounds (0, " << m_qmlEvents.size() << ")";
continue;
}
QmlEvent &event = m_qmlEvents[eventIndex];
emit rangedEvent(event.type, event.bindingType, range.startTime, range.duration,
QStringList(event.displayName),
QmlEventLocation(event.filename, event.line, event.column),
range.numericData1,range.numericData2, range.numericData3, range.numericData4, range.numericData5);
}
}
QmlProfilerFileWriter::QmlProfilerFileWriter(QObject *parent) :
QObject(parent),
m_startTime(0),
m_endTime(0),
m_measuredTime(0),
m_v8Model(0)
{
m_acceptedTypes << QmlDebug::Compiling << QmlDebug::Creating << QmlDebug::Binding << QmlDebug::HandlingSignal;
}
void QmlProfilerFileWriter::setTraceTime(qint64 startTime, qint64 endTime, qint64 measuredTime)
{
m_startTime = startTime;
m_endTime = endTime;
m_measuredTime = measuredTime;
}
void QmlProfilerFileWriter::setV8DataModel(QV8ProfilerDataModel *dataModel)
{
m_v8Model = dataModel;
}
void QmlProfilerFileWriter::setQmlEvents(const QVector<QmlProfilerSimpleModel::QmlEventData> &events)
{
foreach (const QmlProfilerSimpleModel::QmlEventData &event, events) {
const QString hashStr = QmlProfilerSimpleModel::getHashString(event);
if (!m_qmlEvents.contains(hashStr)) {
QmlEvent e = { event.displayName,
event.location.filename,
event.data.join(_("")),
static_cast<QmlDebug::QmlEventType>(event.eventType),
event.bindingType,
event.location.line,
event.location.column
};
m_qmlEvents.insert(hashStr, e);
}
Range r = { event.startTime, event.duration, event.numericData1, event.numericData2, event.numericData3, event.numericData4, event.numericData5 };
m_ranges.append(QPair<Range, QString>(r, hashStr));
}
calculateMeasuredTime(events);
}
void QmlProfilerFileWriter::save(QIODevice *device)
{
QXmlStreamWriter stream(device);
stream.setAutoFormatting(true);
stream.writeStartDocument();
stream.writeStartElement(_("trace"));
stream.writeAttribute(_("version"), _(PROFILER_FILE_VERSION));
stream.writeAttribute(_("traceStart"), QString::number(m_startTime));
stream.writeAttribute(_("traceEnd"), QString::number(m_endTime));
stream.writeStartElement(_("eventData"));
stream.writeAttribute(_("totalTime"), QString::number(m_measuredTime));
QHash<QString,QmlEvent>::const_iterator eventIter = m_qmlEvents.constBegin();
for (; eventIter != m_qmlEvents.constEnd(); ++eventIter) {
QmlEvent event = eventIter.value();
stream.writeStartElement(_("event"));
stream.writeAttribute(_("index"), QString::number(m_qmlEvents.keys().indexOf(eventIter.key())));
stream.writeTextElement(_("displayname"), event.displayName);
stream.writeTextElement(_("type"), qmlEventTypeAsString(event.type));
if (!event.filename.isEmpty()) {
stream.writeTextElement(_("filename"), event.filename);
stream.writeTextElement(_("line"), QString::number(event.line));
stream.writeTextElement(_("column"), QString::number(event.column));
}
stream.writeTextElement(_("details"), event.details);
if (event.type == Binding)
stream.writeTextElement(_("bindingType"), QString::number(event.bindingType));
if (event.type == Painting && event.bindingType == AnimationFrame)
stream.writeTextElement(_("animationFrame"), QString::number(event.bindingType));
if (event.type == PixmapCacheEvent)
stream.writeTextElement(_("cacheEventType"), QString::number(event.bindingType));
if (event.type == SceneGraphFrameEvent)
stream.writeTextElement(_("sgEventType"), QString::number(event.bindingType));
stream.writeEndElement();
}
stream.writeEndElement(); // eventData
stream.writeStartElement(_("profilerDataModel"));
QVector<QPair<Range, QString> >::const_iterator rangeIter = m_ranges.constBegin();
for (; rangeIter != m_ranges.constEnd(); ++rangeIter) {
Range range = rangeIter->first;
QString eventHash = rangeIter->second;
stream.writeStartElement(_("range"));
stream.writeAttribute(_("startTime"), QString::number(range.startTime));
if (range.duration > 0) // no need to store duration of instantaneous events
stream.writeAttribute(_("duration"), QString::number(range.duration));
stream.writeAttribute(_("eventIndex"), QString::number(m_qmlEvents.keys().indexOf(eventHash)));
QmlEvent event = m_qmlEvents.value(eventHash);
// special: animation event
if (event.type == QmlDebug::Painting && event.bindingType == QmlDebug::AnimationFrame) {
stream.writeAttribute(_("framerate"), QString::number(range.numericData1));
stream.writeAttribute(_("animationcount"), QString::number(range.numericData2));
}
// special: pixmap cache event
if (event.type == QmlDebug::PixmapCacheEvent) {
// pixmap image size
if (event.bindingType == 0) {
stream.writeAttribute(_("width"), QString::number(range.numericData1));
stream.writeAttribute(_("height"), QString::number(range.numericData2));
}
// reference count (1) / cache size changed (2)
if (event.bindingType == 1 || event.bindingType == 2)
stream.writeAttribute(_("refCount"), QString::number(range.numericData3));
}
if (event.type == QmlDebug::SceneGraphFrameEvent) {
// special: scenegraph frame events
if (range.numericData1 > 0)
stream.writeAttribute(_("timing1"), QString::number(range.numericData1));
if (range.numericData2 > 0)
stream.writeAttribute(_("timing2"), QString::number(range.numericData2));
if (range.numericData3 > 0)
stream.writeAttribute(_("timing3"), QString::number(range.numericData3));
if (range.numericData4 > 0)
stream.writeAttribute(_("timing4"), QString::number(range.numericData4));
if (range.numericData5 > 0)
stream.writeAttribute(_("timing5"), QString::number(range.numericData5));
}
stream.writeEndElement();
}
stream.writeEndElement(); // profilerDataModel
m_v8Model->save(stream);
stream.writeEndElement(); // trace
stream.writeEndDocument();
}
void QmlProfilerFileWriter::calculateMeasuredTime(const QVector<QmlProfilerSimpleModel::QmlEventData> &events)
{
// measured time isn't used, but old clients might still need it
// -> we calculate it explicitly
qint64 duration = 0;
QHash<int, qint64> endtimesPerLevel;
int level = QmlDebug::Constants::QML_MIN_LEVEL;
endtimesPerLevel[0] = 0;
foreach (const QmlProfilerSimpleModel::QmlEventData &event, events) {
// whitelist
if (!m_acceptedTypes.contains(event.eventType))
continue;
// level computation
if (endtimesPerLevel[level] > event.startTime) {
level++;
} else {
while (level > QmlDebug::Constants::QML_MIN_LEVEL && endtimesPerLevel[level-1] <= event.startTime)
level--;
}
endtimesPerLevel[level] = event.startTime + event.duration;
if (level == QmlDebug::Constants::QML_MIN_LEVEL) {
duration += event.duration;
}
}
m_measuredTime = duration;
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,134 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERTRACEFILE_H
#define QMLPROFILERTRACEFILE_H
#include <QObject>
#include <QVector>
#include <QString>
#include <qmldebug/qmlprofilereventlocation.h>
#include <qmldebug/qmlprofilereventtypes.h>
#include "qmlprofilersimplemodel.h"
#include "qv8profilerdatamodel.h"
QT_FORWARD_DECLARE_CLASS(QIODevice)
QT_FORWARD_DECLARE_CLASS(QXmlStreamReader)
namespace QmlProfiler {
namespace Internal {
struct QmlEvent {
QString displayName;
QString filename;
QString details;
QmlDebug::QmlEventType type;
int bindingType;
int line;
int column;
};
struct Range {
qint64 startTime;
qint64 duration;
// numeric data used by animations, pixmap cache, scenegraph
qint64 numericData1;
qint64 numericData2;
qint64 numericData3;
qint64 numericData4;
qint64 numericData5;
};
class QmlProfilerFileReader : public QObject
{
Q_OBJECT
public:
explicit QmlProfilerFileReader(QObject *parent = 0);
void setV8DataModel(QV8ProfilerDataModel *dataModel);
bool load(QIODevice *device);
signals:
void traceStartTime(qint64 traceStartTime);
void traceEndTime(qint64 traceStartTime);
void rangedEvent(int type, int bindingType, qint64 startTime, qint64 length,
const QStringList &data, const QmlDebug::QmlEventLocation &location,
qint64 param1, qint64 param2, qint64 param3, qint64 param4, qint64 param5);
void error(const QString &error);
private:
void loadEventData(QXmlStreamReader &reader);
void loadProfilerDataModel(QXmlStreamReader &reader);
void processQmlEvents();
QV8ProfilerDataModel *m_v8Model;
QVector<QmlEvent> m_qmlEvents;
QVector<QPair<Range, int> > m_ranges;
};
class QmlProfilerFileWriter : public QObject
{
Q_OBJECT
public:
explicit QmlProfilerFileWriter(QObject *parent = 0);
void setTraceTime(qint64 startTime, qint64 endTime, qint64 measturedTime);
void setV8DataModel(QV8ProfilerDataModel *dataModel);
void setQmlEvents(const QVector<QmlProfilerSimpleModel::QmlEventData> &events);
void save(QIODevice *device);
private:
void calculateMeasuredTime(const QVector<QmlProfilerSimpleModel::QmlEventData> &events);
qint64 m_startTime, m_endTime, m_measuredTime;
QV8ProfilerDataModel *m_v8Model;
QHash<QString,QmlEvent> m_qmlEvents;
QVector<QPair<Range, QString> > m_ranges;
QVector <int> m_acceptedTypes;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILERTRACEFILE_H

View File

@@ -1,617 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilertraceview.h"
#include "qmlprofilertool.h"
#include "qmlprofilerstatemanager.h"
#include "qmlprofilermodelmanager.h"
#include "qmlprofilertimelinemodelproxy.h"
#include "timelinemodelaggregator.h"
// Needed for the load&save actions in the context menu
#include <analyzerbase/ianalyzertool.h>
// Communication with the other views (limit events to range)
#include "qmlprofilerviewmanager.h"
#include <utils/styledbar.h>
#include <QDeclarativeContext>
#include <QToolButton>
#include <QEvent>
#include <QVBoxLayout>
#include <QGraphicsObject>
#include <QScrollBar>
#include <QSlider>
#include <QMenu>
#include <math.h>
using namespace QmlDebug;
namespace QmlProfiler {
namespace Internal {
const int sliderTicks = 10000;
const qreal sliderExp = 3;
/////////////////////////////////////////////////////////
bool MouseWheelResizer::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::Wheel) {
QWheelEvent *ev = static_cast<QWheelEvent *>(event);
if (ev->modifiers() & Qt::ControlModifier) {
emit mouseWheelMoved(ev->pos().x(), ev->pos().y(), ev->delta());
return true;
}
}
return QObject::eventFilter(obj, event);
}
/////////////////////////////////////////////////////////
void ZoomControl::setRange(qint64 startTime, qint64 endTime)
{
if (m_startTime != startTime || m_endTime != endTime) {
m_startTime = startTime;
m_endTime = endTime;
emit rangeChanged();
}
}
/////////////////////////////////////////////////////////
ScrollableDeclarativeView::ScrollableDeclarativeView(QWidget *parent)
: QDeclarativeView(parent)
{
}
ScrollableDeclarativeView::~ScrollableDeclarativeView()
{
}
void ScrollableDeclarativeView::scrollContentsBy(int dx, int dy)
{
// special workaround to track the scrollbar
if (rootObject()) {
int scrollY = rootObject()->property("scrollY").toInt();
rootObject()->setProperty("scrollY", QVariant(scrollY - dy));
}
QDeclarativeView::scrollContentsBy(dx,dy);
}
/////////////////////////////////////////////////////////
class QmlProfilerTraceView::QmlProfilerTraceViewPrivate
{
public:
QmlProfilerTraceViewPrivate(QmlProfilerTraceView *qq) : q(qq) {}
QmlProfilerTraceView *q;
QmlProfilerStateManager *m_profilerState;
Analyzer::IAnalyzerTool *m_profilerTool;
QmlProfilerViewManager *m_viewContainer;
QSize m_sizeHint;
ScrollableDeclarativeView *m_mainView;
QDeclarativeView *m_timebar;
QDeclarativeView *m_overview;
QmlProfilerModelManager *m_modelManager;
TimelineModelAggregator *m_modelProxy;
ZoomControl *m_zoomControl;
QToolButton *m_buttonRange;
QToolButton *m_buttonLock;
QWidget *m_zoomToolbar;
int m_currentZoomLevel;
};
QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerTool *profilerTool, QmlProfilerViewManager *container, QmlProfilerModelManager *modelManager, QmlProfilerStateManager *profilerState)
: QWidget(parent), d(new QmlProfilerTraceViewPrivate(this))
{
setObjectName(QLatin1String("QML Profiler"));
d->m_zoomControl = new ZoomControl(this);
connect(d->m_zoomControl, SIGNAL(rangeChanged()), this, SLOT(updateRange()));
QVBoxLayout *groupLayout = new QVBoxLayout;
groupLayout->setContentsMargins(0, 0, 0, 0);
groupLayout->setSpacing(0);
d->m_mainView = new ScrollableDeclarativeView(this);
d->m_mainView->setResizeMode(QDeclarativeView::SizeViewToRootObject);
d->m_mainView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
d->m_mainView->setBackgroundBrush(QBrush(Qt::white));
d->m_mainView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
d->m_mainView->setFocus();
MouseWheelResizer *resizer = new MouseWheelResizer(this);
connect(resizer,SIGNAL(mouseWheelMoved(int,int,int)), this, SLOT(mouseWheelMoved(int,int,int)));
d->m_mainView->viewport()->installEventFilter(resizer);
QHBoxLayout *toolsLayout = new QHBoxLayout;
d->m_timebar = new QDeclarativeView(this);
d->m_timebar->setResizeMode(QDeclarativeView::SizeRootObjectToView);
d->m_timebar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
d->m_timebar->setFixedHeight(24);
d->m_overview = new QDeclarativeView(this);
d->m_overview->setResizeMode(QDeclarativeView::SizeRootObjectToView);
d->m_overview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
d->m_overview->setMaximumHeight(50);
d->m_zoomToolbar = createZoomToolbar();
d->m_zoomToolbar->move(0, d->m_timebar->height());
d->m_zoomToolbar->setVisible(false);
toolsLayout->addWidget(createToolbar());
toolsLayout->addWidget(d->m_timebar);
emit enableToolbar(false);
groupLayout->addLayout(toolsLayout);
groupLayout->addWidget(d->m_mainView);
groupLayout->addWidget(d->m_overview);
setLayout(groupLayout);
d->m_profilerTool = profilerTool;
d->m_viewContainer = container;
d->m_modelManager = modelManager;
d->m_modelProxy = new TimelineModelAggregator(this);
d->m_modelProxy->setModelManager(modelManager);
connect(d->m_modelManager, SIGNAL(stateChanged()),
this, SLOT(profilerDataModelStateChanged()));
d->m_mainView->rootContext()->setContextProperty(QLatin1String("qmlProfilerModelProxy"),
d->m_modelProxy);
d->m_overview->rootContext()->setContextProperty(QLatin1String("qmlProfilerModelProxy"),
d->m_modelProxy);
d->m_profilerState = profilerState;
connect(d->m_profilerState, SIGNAL(stateChanged()),
this, SLOT(profilerStateChanged()));
connect(d->m_profilerState, SIGNAL(clientRecordingChanged()),
this, SLOT(clientRecordingChanged()));
connect(d->m_profilerState, SIGNAL(serverRecordingChanged()),
this, SLOT(serverRecordingChanged()));
// Minimum height: 5 rows of 20 pixels + scrollbar of 50 pixels + 20 pixels margin
setMinimumHeight(170);
d->m_currentZoomLevel = 0;
}
QmlProfilerTraceView::~QmlProfilerTraceView()
{
delete d;
}
/////////////////////////////////////////////////////////
// Initialize widgets
void QmlProfilerTraceView::reset()
{
d->m_mainView->rootContext()->setContextProperty(QLatin1String("zoomControl"), d->m_zoomControl);
d->m_timebar->rootContext()->setContextProperty(QLatin1String("zoomControl"), d->m_zoomControl);
d->m_overview->rootContext()->setContextProperty(QLatin1String("zoomControl"), d->m_zoomControl);
d->m_timebar->setSource(QUrl(QLatin1String("qrc:/qmlprofiler/TimeDisplay.qml")));
d->m_overview->setSource(QUrl(QLatin1String("qrc:/qmlprofiler/Overview.qml")));
d->m_mainView->setSource(QUrl(QLatin1String("qrc:/qmlprofiler/MainView.qml")));
QGraphicsObject *rootObject = d->m_mainView->rootObject();
rootObject->setProperty("width", QVariant(width()));
rootObject->setProperty("candidateHeight", QVariant(height() - d->m_timebar->height() - d->m_overview->height()));
connect(rootObject, SIGNAL(updateCursorPosition()), this, SLOT(updateCursorPosition()));
connect(rootObject, SIGNAL(updateRangeButton()), this, SLOT(updateRangeButton()));
connect(rootObject, SIGNAL(updateLockButton()), this, SLOT(updateLockButton()));
connect(this, SIGNAL(jumpToPrev()), rootObject, SLOT(prevEvent()));
connect(this, SIGNAL(jumpToNext()), rootObject, SLOT(nextEvent()));
connect(rootObject, SIGNAL(selectedEventChanged(int)), this, SIGNAL(selectedEventChanged(int)));
connect(rootObject, SIGNAL(changeToolTip(QString)), this, SLOT(updateToolTip(QString)));
connect(rootObject, SIGNAL(updateVerticalScroll(int)), this, SLOT(updateVerticalScroll(int)));
}
QWidget *QmlProfilerTraceView::createToolbar()
{
Utils::StyledBar *bar = new Utils::StyledBar(this);
bar->setStyleSheet(QLatin1String("background: #9B9B9B"));
bar->setSingleRow(true);
bar->setFixedWidth(150);
bar->setFixedHeight(24);
QHBoxLayout *toolBarLayout = new QHBoxLayout(bar);
toolBarLayout->setMargin(0);
toolBarLayout->setSpacing(0);
QToolButton *buttonPrev= new QToolButton;
buttonPrev->setIcon(QIcon(QLatin1String(":/qmlprofiler/ico_prev.png")));
buttonPrev->setToolTip(tr("Jump to previous event"));
connect(buttonPrev, SIGNAL(clicked()), this, SIGNAL(jumpToPrev()));
connect(this, SIGNAL(enableToolbar(bool)), buttonPrev, SLOT(setEnabled(bool)));
QToolButton *buttonNext= new QToolButton;
buttonNext->setIcon(QIcon(QLatin1String(":/qmlprofiler/ico_next.png")));
buttonNext->setToolTip(tr("Jump to next event"));
connect(buttonNext, SIGNAL(clicked()), this, SIGNAL(jumpToNext()));
connect(this, SIGNAL(enableToolbar(bool)), buttonNext, SLOT(setEnabled(bool)));
QToolButton *buttonZoomControls = new QToolButton;
buttonZoomControls->setIcon(QIcon(QLatin1String(":/qmlprofiler/ico_zoom.png")));
buttonZoomControls->setToolTip(tr("Show zoom slider"));
buttonZoomControls->setCheckable(true);
buttonZoomControls->setChecked(false);
connect(buttonZoomControls, SIGNAL(toggled(bool)), d->m_zoomToolbar, SLOT(setVisible(bool)));
connect(this, SIGNAL(enableToolbar(bool)), buttonZoomControls, SLOT(setEnabled(bool)));
d->m_buttonRange = new QToolButton;
d->m_buttonRange->setIcon(QIcon(QLatin1String(":/qmlprofiler/ico_rangeselection.png")));
d->m_buttonRange->setToolTip(tr("Select range"));
d->m_buttonRange->setCheckable(true);
d->m_buttonRange->setChecked(false);
connect(d->m_buttonRange, SIGNAL(clicked(bool)), this, SLOT(toggleRangeMode(bool)));
connect(this, SIGNAL(enableToolbar(bool)), d->m_buttonRange, SLOT(setEnabled(bool)));
connect(this, SIGNAL(rangeModeChanged(bool)), d->m_buttonRange, SLOT(setChecked(bool)));
d->m_buttonLock = new QToolButton;
d->m_buttonLock->setIcon(QIcon(QLatin1String(":/qmlprofiler/ico_selectionmode.png")));
d->m_buttonLock->setToolTip(tr("View event information on mouseover"));
d->m_buttonLock->setCheckable(true);
d->m_buttonLock->setChecked(false);
connect(d->m_buttonLock, SIGNAL(clicked(bool)), this, SLOT(toggleLockMode(bool)));
connect(this, SIGNAL(enableToolbar(bool)), d->m_buttonLock, SLOT(setEnabled(bool)));
connect(this, SIGNAL(lockModeChanged(bool)), d->m_buttonLock, SLOT(setChecked(bool)));
toolBarLayout->addWidget(buttonPrev);
toolBarLayout->addWidget(buttonNext);
toolBarLayout->addWidget(new Utils::StyledSeparator());
toolBarLayout->addWidget(buttonZoomControls);
toolBarLayout->addWidget(new Utils::StyledSeparator());
toolBarLayout->addWidget(d->m_buttonRange);
toolBarLayout->addWidget(d->m_buttonLock);
return bar;
}
QWidget *QmlProfilerTraceView::createZoomToolbar()
{
Utils::StyledBar *bar = new Utils::StyledBar(this);
bar->setStyleSheet(QLatin1String("background: #9B9B9B"));
bar->setSingleRow(true);
bar->setFixedWidth(150);
bar->setFixedHeight(24);
QHBoxLayout *toolBarLayout = new QHBoxLayout(bar);
toolBarLayout->setMargin(0);
toolBarLayout->setSpacing(0);
QSlider *zoomSlider = new QSlider(Qt::Horizontal);
zoomSlider->setFocusPolicy(Qt::NoFocus);
zoomSlider->setRange(1, sliderTicks);
zoomSlider->setInvertedAppearance(true);
zoomSlider->setPageStep(sliderTicks/100);
connect(this, SIGNAL(enableToolbar(bool)), zoomSlider, SLOT(setEnabled(bool)));
connect(zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(setZoomLevel(int)));
connect(this, SIGNAL(zoomLevelChanged(int)), zoomSlider, SLOT(setValue(int)));
zoomSlider->setStyleSheet(QLatin1String("\
QSlider:horizontal {\
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #444444, stop: 1 #5a5a5a);\
border: 1px #313131;\
height: 20px;\
margin: 0px 0px 0px 0px;\
}\
QSlider::add-page:horizontal {\
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #5a5a5a, stop: 1 #444444);\
border: 1px #313131;\
}\
QSlider::sub-page:horizontal {\
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #5a5a5a, stop: 1 #444444);\
border: 1px #313131;\
}\
"));
toolBarLayout->addWidget(zoomSlider);
return bar;
}
/////////////////////////////////////////////////////////
bool QmlProfilerTraceView::hasValidSelection() const
{
QGraphicsObject *rootObject = d->m_mainView->rootObject();
if (rootObject)
return rootObject->property("selectionRangeReady").toBool();
return false;
}
qint64 QmlProfilerTraceView::selectionStart() const
{
QGraphicsObject *rootObject = d->m_mainView->rootObject();
if (rootObject)
return rootObject->property("selectionRangeStart").toLongLong();
return 0;
}
qint64 QmlProfilerTraceView::selectionEnd() const
{
QGraphicsObject *rootObject = d->m_mainView->rootObject();
if (rootObject)
return rootObject->property("selectionRangeEnd").toLongLong();
return 0;
}
void QmlProfilerTraceView::clearDisplay()
{
d->m_zoomControl->setRange(0,0);
updateVerticalScroll(0);
d->m_mainView->rootObject()->setProperty("scrollY", QVariant(0));
QMetaObject::invokeMethod(d->m_mainView->rootObject(), "clearAll");
QMetaObject::invokeMethod(d->m_overview->rootObject(), "clearDisplay");
}
void QmlProfilerTraceView::selectNextEventByHash(const QString &hash)
{
QGraphicsObject *rootObject = d->m_mainView->rootObject();
if (rootObject)
QMetaObject::invokeMethod(rootObject, "selectNextByHash",
Q_ARG(QVariant,QVariant(hash)));
}
void QmlProfilerTraceView::selectNextEventByLocation(const QString &filename, const int line, const int column)
{
int eventId = d->m_modelProxy->getEventIdForLocation(filename, line, column);
if (eventId != -1) {
QGraphicsObject *rootObject = d->m_mainView->rootObject();
if (rootObject)
QMetaObject::invokeMethod(rootObject, "selectNextById",
Q_ARG(QVariant,QVariant(eventId)));
}
}
/////////////////////////////////////////////////////////
// Goto source location
void QmlProfilerTraceView::updateCursorPosition()
{
QGraphicsObject *rootObject = d->m_mainView->rootObject();
emit gotoSourceLocation(rootObject->property("fileName").toString(),
rootObject->property("lineNumber").toInt(),
rootObject->property("columnNumber").toInt());
}
/////////////////////////////////////////////////////////
// Toolbar buttons
void QmlProfilerTraceView::toggleRangeMode(bool active)
{
QGraphicsObject *rootObject = d->m_mainView->rootObject();
bool rangeMode = rootObject->property("selectionRangeMode").toBool();
if (active != rangeMode) {
if (active)
d->m_buttonRange->setIcon(QIcon(QLatin1String(":/qmlprofiler/ico_rangeselected.png")));
else
d->m_buttonRange->setIcon(QIcon(QLatin1String(":/qmlprofiler/ico_rangeselection.png")));
rootObject->setProperty("selectionRangeMode", QVariant(active));
}
}
void QmlProfilerTraceView::updateRangeButton()
{
bool rangeMode = d->m_mainView->rootObject()->property("selectionRangeMode").toBool();
if (rangeMode)
d->m_buttonRange->setIcon(QIcon(QLatin1String(":/qmlprofiler/ico_rangeselected.png")));
else
d->m_buttonRange->setIcon(QIcon(QLatin1String(":/qmlprofiler/ico_rangeselection.png")));
emit rangeModeChanged(rangeMode);
}
void QmlProfilerTraceView::toggleLockMode(bool active)
{
QGraphicsObject *rootObject = d->m_mainView->rootObject();
bool lockMode = !rootObject->property("selectionLocked").toBool();
if (active != lockMode) {
rootObject->setProperty("selectionLocked", QVariant(!active));
rootObject->setProperty("selectedItem", QVariant(-1));
}
}
void QmlProfilerTraceView::updateLockButton()
{
bool lockMode = !d->m_mainView->rootObject()->property("selectionLocked").toBool();
emit lockModeChanged(lockMode);
}
////////////////////////////////////////////////////////
// Zoom control
void QmlProfilerTraceView::setZoomLevel(int zoomLevel)
{
if (d->m_currentZoomLevel != zoomLevel && d->m_mainView->rootObject()) {
QVariant newFactor = pow(qreal(zoomLevel) / qreal(sliderTicks), sliderExp);
d->m_currentZoomLevel = zoomLevel;
QMetaObject::invokeMethod(d->m_mainView->rootObject(), "updateWindowLength", Q_ARG(QVariant, newFactor));
}
}
void QmlProfilerTraceView::updateRange()
{
if (!d->m_modelManager)
return;
qreal duration = d->m_zoomControl->endTime() - d->m_zoomControl->startTime();
if (duration <= 0)
return;
if (d->m_modelManager->traceTime()->duration() <= 0)
return;
int newLevel = pow(duration / d->m_modelManager->traceTime()->duration(), 1/sliderExp) * sliderTicks;
if (d->m_currentZoomLevel != newLevel) {
d->m_currentZoomLevel = newLevel;
emit zoomLevelChanged(newLevel);
}
}
void QmlProfilerTraceView::mouseWheelMoved(int mouseX, int mouseY, int wheelDelta)
{
Q_UNUSED(mouseY);
QGraphicsObject *rootObject = d->m_mainView->rootObject();
if (rootObject) {
QMetaObject::invokeMethod(rootObject, "wheelZoom",
Q_ARG(QVariant, QVariant(mouseX)),
Q_ARG(QVariant, QVariant(wheelDelta)));
}
}
////////////////////////////////////////////////////////
void QmlProfilerTraceView::updateToolTip(const QString &text)
{
setToolTip(text);
}
void QmlProfilerTraceView::updateVerticalScroll(int newPosition)
{
d->m_mainView->verticalScrollBar()->setValue(newPosition);
}
void QmlProfilerTraceView::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
QGraphicsObject *rootObject = d->m_mainView->rootObject();
if (rootObject) {
rootObject->setProperty("width", QVariant(event->size().width()));
int newHeight = event->size().height() - d->m_timebar->height() - d->m_overview->height();
rootObject->setProperty("candidateHeight", QVariant(newHeight));
}
emit resized();
}
////////////////////////////////////////////////////////////////
// Context menu
void QmlProfilerTraceView::contextMenuEvent(QContextMenuEvent *ev)
{
QMenu menu;
QAction *viewAllAction = 0;
QmlProfilerTool *profilerTool = qobject_cast<QmlProfilerTool *>(d->m_profilerTool);
if (profilerTool)
menu.addActions(profilerTool->profilerContextMenuActions());
menu.addSeparator();
QAction *getLocalStatsAction = menu.addAction(tr("Limit Events Pane to Current Range"));
if (!d->m_viewContainer->hasValidSelection())
getLocalStatsAction->setEnabled(false);
QAction *getGlobalStatsAction = menu.addAction(tr("Reset Events Pane"));
if (d->m_viewContainer->hasGlobalStats())
getGlobalStatsAction->setEnabled(false);
if (!d->m_modelProxy->isEmpty()) {
menu.addSeparator();
viewAllAction = menu.addAction(tr("Reset Zoom"));
}
QAction *selectedAction = menu.exec(ev->globalPos());
if (selectedAction) {
if (selectedAction == viewAllAction) {
d->m_zoomControl->setRange(
d->m_modelManager->traceTime()->startTime(),
d->m_modelManager->traceTime()->endTime());
}
if (selectedAction == getLocalStatsAction) {
d->m_viewContainer->getStatisticsInRange(
d->m_viewContainer->selectionStart(),
d->m_viewContainer->selectionEnd());
}
if (selectedAction == getGlobalStatsAction) {
d->m_viewContainer->getStatisticsInRange(-1, -1);
}
}
}
/////////////////////////////////////////////////
// Tell QML the state of the profiler
void QmlProfilerTraceView::setRecording(bool recording)
{
QGraphicsObject *rootObject = d->m_mainView->rootObject();
if (rootObject)
rootObject->setProperty("recordingEnabled", QVariant(recording));
}
void QmlProfilerTraceView::setAppKilled()
{
QGraphicsObject *rootObject = d->m_mainView->rootObject();
if (rootObject)
rootObject->setProperty("appKilled",QVariant(true));
}
////////////////////////////////////////////////////////////////
// Profiler State
void QmlProfilerTraceView::profilerDataModelStateChanged()
{
switch (d->m_modelManager->state()) {
case QmlProfilerDataState::Empty:
emit enableToolbar(false);
break;
case QmlProfilerDataState::AcquiringData: break;
case QmlProfilerDataState::ProcessingData: break;
case QmlProfilerDataState::Done:
emit enableToolbar(true);
break;
default:
break;
}
}
void QmlProfilerTraceView::profilerStateChanged()
{
switch (d->m_profilerState->currentState()) {
case QmlProfilerStateManager::AppKilled : {
if (d->m_modelManager->state() == QmlProfilerDataState::AcquiringData)
setAppKilled();
break;
}
default:
// no special action needed for other states
break;
}
}
void QmlProfilerTraceView::clientRecordingChanged()
{
// nothing yet
}
void QmlProfilerTraceView::serverRecordingChanged()
{
setRecording(d->m_profilerState->serverRecording());
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,158 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERTRACEVIEW_H
#define QMLPROFILERTRACEVIEW_H
#include <QDeclarativeView>
namespace Analyzer {
class IAnalyzerTool;
}
namespace QmlProfiler {
namespace Internal {
class QmlProfilerStateManager;
class QmlProfilerViewManager;
// capture mouse wheel events
class MouseWheelResizer : public QObject {
Q_OBJECT
public:
MouseWheelResizer(QObject *parent=0):QObject(parent){}
protected:
bool eventFilter(QObject *obj, QEvent *event);
signals:
void mouseWheelMoved(int x, int y, int delta);
};
// centralized zoom control
class ZoomControl : public QObject {
Q_OBJECT
public:
ZoomControl(QObject *parent=0):QObject(parent),m_startTime(0),m_endTime(0) {}
~ZoomControl(){}
Q_INVOKABLE void setRange(qint64 startTime, qint64 endTime);
Q_INVOKABLE qint64 startTime() { return m_startTime; }
Q_INVOKABLE qint64 endTime() { return m_endTime; }
signals:
void rangeChanged();
private:
qint64 m_startTime;
qint64 m_endTime;
};
class ScrollableDeclarativeView : public QDeclarativeView
{
Q_OBJECT
public:
explicit ScrollableDeclarativeView(QWidget *parent = 0);
~ScrollableDeclarativeView();
protected:
void scrollContentsBy(int dx, int dy);
};
class QmlProfilerModelManager;
class QmlProfilerTraceView : public QWidget
{
Q_OBJECT
public:
explicit QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerTool *profilerTool, QmlProfilerViewManager *container, QmlProfilerModelManager *modelManager, QmlProfilerStateManager *profilerState);
~QmlProfilerTraceView();
void reset();
bool hasValidSelection() const;
qint64 selectionStart() const;
qint64 selectionEnd() const;
public slots:
void clearDisplay();
void selectNextEventByHash(const QString &eventHash);
void selectNextEventByLocation(const QString &filename, const int line, const int column);
private slots:
void updateCursorPosition();
void toggleRangeMode(bool);
void updateRangeButton();
void toggleLockMode(bool);
void updateLockButton();
void setZoomLevel(int zoomLevel);
void updateRange();
void mouseWheelMoved(int mouseX, int mouseY, int wheelDelta);
void updateToolTip(const QString &text);
void updateVerticalScroll(int newPosition);
void profilerDataModelStateChanged();
protected:
virtual void resizeEvent(QResizeEvent *event);
private slots:
void profilerStateChanged();
void clientRecordingChanged();
void serverRecordingChanged();
signals:
void gotoSourceLocation(const QString &fileUrl, int lineNumber, int columNumber);
void selectedEventChanged(int eventId);
void jumpToPrev();
void jumpToNext();
void rangeModeChanged(bool);
void lockModeChanged(bool);
void enableToolbar(bool);
void zoomLevelChanged(int);
void resized();
private:
void contextMenuEvent(QContextMenuEvent *);
QWidget *createToolbar();
QWidget *createZoomToolbar();
void setRecording(bool recording);
void setAppKilled();
private:
class QmlProfilerTraceViewPrivate;
QmlProfilerTraceViewPrivate *d;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILERTRACEVIEW_H

View File

@@ -1,91 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilertreeview.h"
#include <QCoreApplication>
#include <QHeaderView>
namespace QmlProfiler {
namespace Internal {
QmlProfilerTreeView::QmlProfilerTreeView(QWidget *parent)
: QTreeView(parent)
{
setFrameStyle(QFrame::NoFrame);
header()->setResizeMode(QHeaderView::Interactive);
header()->setDefaultSectionSize(100);
header()->setMinimumSectionSize(50);
}
// Translate from "old" context to keep 2.8 string freeze
QString QmlProfilerTreeView::displayHeader(Fields header) const
{
static const char ctxt1[] = "QmlProfiler::Internal::QmlProfilerEventsParentsAndChildrenView";
static const char ctxt2[] = "QmlProfiler::Internal::QmlProfilerEventsMainView";
switch (header) {
case Callee:
return QCoreApplication::translate(ctxt1, "Callee");
case CalleeDescription:
return QCoreApplication::translate(ctxt1, "Callee Description");
case Caller:
return QCoreApplication::translate(ctxt1, "Caller");
case CallerDescription:
return QCoreApplication::translate(ctxt1, "Caller Description");
case CallCount:
return QCoreApplication::translate(ctxt2, "Calls");
case Details:
return QCoreApplication::translate(ctxt2, "Details");
case Location:
return QCoreApplication::translate(ctxt2, "Location");
case MaxTime:
return QCoreApplication::translate(ctxt2, "Longest Time");
case TimePerCall:
return QCoreApplication::translate(ctxt2, "Mean Time");
case SelfTime:
return QCoreApplication::translate(ctxt2, "Self Time");
case SelfTimeInPercent:
return QCoreApplication::translate(ctxt2, "Self Time in Percent");
case MinTime:
return QCoreApplication::translate(ctxt2, "Shortest Time");
case TimeInPercent:
return QCoreApplication::translate(ctxt2, "Time in Percent");
case TotalTime:
return QCoreApplication::translate(ctxt2, "Total Time");
case Type:
return QCoreApplication::translate(ctxt2, "Type");
case MedianTime:
return QCoreApplication::translate(ctxt2, "Median Time");
}
return QString();
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,72 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERTREEVIEW
#define QMLPROFILERTREEVIEW
#include <QTreeView>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerTreeView : public QTreeView
{
Q_OBJECT
protected:
QmlProfilerTreeView(QWidget *parent = 0);
enum Fields {
Name,
Callee,
CalleeDescription,
Caller,
CallerDescription,
CallCount,
Details,
Location,
MaxTime,
TimePerCall,
SelfTime,
SelfTimeInPercent,
MinTime,
TimeInPercent,
TotalTime,
Type,
MedianTime,
MaxFields
};
QString displayHeader(Fields header) const;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILERTREEVIEW

File diff suppressed because it is too large Load Diff

View File

@@ -1,202 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILEREVENTVIEW_H
#define QMLPROFILEREVENTVIEW_H
#include <QTreeView>
#include <QStandardItemModel>
#include <qmldebug/qmlprofilereventtypes.h>
#include "qmlprofilermodelmanager.h"
#include "qmlprofilereventsmodelproxy.h"
#include <analyzerbase/ianalyzertool.h>
#include "qmlprofilerviewmanager.h"
namespace QmlProfiler {
namespace Internal {
class QmlProfilerEventsMainView;
class QmlProfilerEventChildrenView;
class QmlProfilerEventRelativesView;
enum ItemRole {
EventHashStrRole = Qt::UserRole+1,
FilenameRole = Qt::UserRole+2,
LineRole = Qt::UserRole+3,
ColumnRole = Qt::UserRole+4,
EventIdRole = Qt::UserRole+5
};
class QmlProfilerEventsWidget : public QWidget
{
Q_OBJECT
public:
explicit QmlProfilerEventsWidget(QWidget *parent,
Analyzer::IAnalyzerTool *profilerTool,
QmlProfilerViewManager *container,
QmlProfilerModelManager *profilerModelManager );
~QmlProfilerEventsWidget();
void clear();
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
QModelIndex selectedItem() const;
bool mouseOnTable(const QPoint &position) const;
void copyTableToClipboard() const;
void copyRowToClipboard() const;
bool hasGlobalStats() const;
void setShowExtendedStatistics(bool show);
bool showExtendedStatistics() const;
signals:
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
void showEventInTimeline(int eventId);
void resized();
public slots:
void updateSelectedEvent(const QString &eventHash) const;
void selectBySourceLocation(const QString &filename, int line, int column);
private slots:
void profilerDataModelStateChanged();
protected:
void contextMenuEvent(QContextMenuEvent *ev);
virtual void resizeEvent(QResizeEvent *event);
private:
class QmlProfilerEventsWidgetPrivate;
QmlProfilerEventsWidgetPrivate *d;
};
class QmlProfilerEventsMainView : public QTreeView
{
Q_OBJECT
public:
enum Fields {
Name,
Type,
Percent,
TotalDuration,
SelfPercent,
SelfDuration,
CallCount,
TimePerCall,
MaxTime,
MinTime,
MedianTime,
Details,
MaxFields
};
explicit QmlProfilerEventsMainView(QWidget *parent,
QmlProfilerEventsModelProxy *modelProxy);
~QmlProfilerEventsMainView();
void setFieldViewable(Fields field, bool show);
void setShowAnonymousEvents( bool showThem );
QModelIndex selectedItem() const;
void copyTableToClipboard() const;
void copyRowToClipboard() const;
static QString displayTime(double time);
static QString nameForType(int typeNumber);
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
bool isRangeGlobal(qint64 rangeStart, qint64 rangeEnd) const;
// int selectedEventId() const;
const QString &selectedEventHash() const;
void setShowExtendedStatistics(bool);
bool showExtendedStatistics() const;
signals:
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
void eventSelected(const QString &eventHash);
void showEventInTimeline(int eventId);
public slots:
void clear();
void jumpToItem(const QModelIndex &index);
void selectEvent(const QString &eventHash);
void selectEventByLocation(const QString &filename, int line);
void buildModel();
void changeDetailsForEvent(int eventId, const QString &newString);
private slots:
void profilerDataModelStateChanged();
private:
void setHeaderLabels();
void parseModelProxy();
private:
class QmlProfilerEventsMainViewPrivate;
QmlProfilerEventsMainViewPrivate *d;
};
class QmlProfilerEventRelativesView : public QTreeView
{
Q_OBJECT
public:
explicit QmlProfilerEventRelativesView(QmlProfilerModelManager *modelManager,
QmlProfilerEventRelativesModelProxy *modelProxy,
QWidget *parent );
~QmlProfilerEventRelativesView();
signals:
void eventClicked(const QString &eventHash);
public slots:
void displayEvent(const QString &eventHash);
void jumpToItem(const QModelIndex &);
void clear();
private:
void rebuildTree(QmlProfilerEventParentsModelProxy::QmlEventRelativesMap eventMap);
void updateHeader();
QStandardItemModel *treeModel();
// QmlProfilerModelManager *m_profilerModelManager;
class QmlProfilerEventParentsViewPrivate;
QmlProfilerEventParentsViewPrivate *d;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILEREVENTVIEW_H

View File

@@ -1,177 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qmlprofilerviewmanager.h"
#include "qmlprofilertraceview.h"
#include "qmlprofilereventview.h"
#include "qmlprofilertool.h"
#include "qmlprofilerstatemanager.h"
#include "qmlprofilermodelmanager.h"
#include "qmlprofilerstatewidget.h"
#include "qv8profilereventview.h"
#include <utils/qtcassert.h>
#include <utils/fancymainwindow.h>
#include <analyzerbase/analyzermanager.h>
#include <QDockWidget>
using namespace Analyzer;
namespace QmlProfiler {
namespace Internal {
class QmlProfilerViewManager::QmlProfilerViewManagerPrivate {
public:
QmlProfilerViewManagerPrivate(QmlProfilerViewManager *qq) { Q_UNUSED(qq); }
QmlProfilerTraceView *traceView;
QmlProfilerEventsWidget *eventsView;
QV8ProfilerEventsWidget *v8profilerView;
QmlProfilerStateManager *profilerState;
QmlProfilerModelManager *profilerModelManager;
QmlProfilerTool *profilerTool;
};
QmlProfilerViewManager::QmlProfilerViewManager(QObject *parent,
QmlProfilerTool *profilerTool,
QmlProfilerModelManager *modelManager,
QmlProfilerStateManager *profilerState)
: QObject(parent), d(new QmlProfilerViewManagerPrivate(this))
{
setObjectName(QLatin1String("QML Profiler View Manager"));
d->traceView = 0;
d->eventsView = 0;
d->v8profilerView = 0;
d->profilerState = profilerState;
d->profilerModelManager = modelManager;
d->profilerTool = profilerTool;
createViews();
}
QmlProfilerViewManager::~QmlProfilerViewManager()
{
delete d;
}
////////////////////////////////////////////////////////////
// Views
void QmlProfilerViewManager::createViews()
{
QTC_ASSERT(d->profilerModelManager, return);
QTC_ASSERT(d->profilerState, return);
Utils::FancyMainWindow *mw = AnalyzerManager::mainWindow();
d->traceView = new QmlProfilerTraceView(mw,
d->profilerTool,
this,
d->profilerModelManager,
d->profilerState);
connect(d->traceView, SIGNAL(gotoSourceLocation(QString,int,int)),
this, SIGNAL(gotoSourceLocation(QString,int,int)));
d->traceView->reset();
d->eventsView = new QmlProfilerEventsWidget(mw, d->profilerTool, this,
d->profilerModelManager);
connect(d->eventsView, SIGNAL(gotoSourceLocation(QString,int,int)), this,
SIGNAL(gotoSourceLocation(QString,int,int)));
connect(d->eventsView, SIGNAL(eventSelectedByHash(QString)), d->traceView,
SLOT(selectNextEventByHash(QString)));
connect(d->traceView, SIGNAL(gotoSourceLocation(QString,int,int)),
d->eventsView, SLOT(selectBySourceLocation(QString,int,int)));
d->v8profilerView = new QV8ProfilerEventsWidget(mw, d->profilerTool, this,
d->profilerModelManager);
connect(d->traceView, SIGNAL(gotoSourceLocation(QString,int,int)),
d->v8profilerView, SLOT(selectBySourceLocation(QString,int,int)));
connect(d->v8profilerView, SIGNAL(gotoSourceLocation(QString,int,int)),
d->traceView, SLOT(selectNextEventByLocation(QString,int,int)));
connect(d->v8profilerView, SIGNAL(gotoSourceLocation(QString,int,int)),
d->eventsView, SLOT(selectBySourceLocation(QString,int,int)));
connect(d->eventsView, SIGNAL(gotoSourceLocation(QString,int,int)),
d->v8profilerView, SLOT(selectBySourceLocation(QString,int,int)));
QDockWidget *eventsDock = AnalyzerManager::createDockWidget
(d->profilerTool, tr("Events"), d->eventsView, Qt::BottomDockWidgetArea);
QDockWidget *timelineDock = AnalyzerManager::createDockWidget
(d->profilerTool, tr("Timeline"), d->traceView, Qt::BottomDockWidgetArea);
QDockWidget *v8profilerDock = AnalyzerManager::createDockWidget(
d->profilerTool, tr("JavaScript"), d->v8profilerView, Qt::BottomDockWidgetArea);
eventsDock->show();
timelineDock->show();
v8profilerDock->show();
mw->splitDockWidget(mw->toolBarDockWidget(), timelineDock, Qt::Vertical);
mw->tabifyDockWidget(timelineDock, eventsDock);
mw->tabifyDockWidget(eventsDock, v8profilerDock);
new QmlProfilerStateWidget(d->profilerState, d->profilerModelManager, d->eventsView);
new QmlProfilerStateWidget(d->profilerState, d->profilerModelManager, d->traceView);
new QmlProfilerStateWidget(d->profilerState, d->profilerModelManager, d->v8profilerView);
}
bool QmlProfilerViewManager::hasValidSelection() const
{
return d->traceView->hasValidSelection();
}
qint64 QmlProfilerViewManager::selectionStart() const
{
return d->traceView->selectionStart();
}
qint64 QmlProfilerViewManager::selectionEnd() const
{
return d->traceView->selectionEnd();
}
bool QmlProfilerViewManager::hasGlobalStats() const
{
return d->eventsView->hasGlobalStats();
}
void QmlProfilerViewManager::getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd)
{
d->eventsView->getStatisticsInRange(rangeStart, rangeEnd);
}
void QmlProfilerViewManager::clear()
{
d->traceView->clearDisplay();
d->eventsView->clear();
d->v8profilerView->clear();
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,76 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QMLPROFILERVIEWMANAGER_H
#define QMLPROFILERVIEWMANAGER_H
#include <QObject>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerTool;
class QmlProfilerModelManager;
class QmlProfilerStateManager;
class QmlProfilerViewManager : public QObject
{
Q_OBJECT
public:
explicit QmlProfilerViewManager(QObject *parent,
QmlProfilerTool *profilerTool,
QmlProfilerModelManager *modelManager,
QmlProfilerStateManager *profilerState);
~QmlProfilerViewManager();
void createViews();
// used by the options "limit events to range"
bool hasValidSelection() const;
qint64 selectionStart() const;
qint64 selectionEnd() const;
bool hasGlobalStats() const;
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
public slots:
void clear();
signals:
void gotoSourceLocation(QString,int,int);
private:
class QmlProfilerViewManagerPrivate;
QmlProfilerViewManagerPrivate *d;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILERVIEWMANAGER_H

View File

@@ -1,489 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qv8profilerdatamodel.h"
#include <QStringList>
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(QmlProfiler::Internal::QV8EventData, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QmlProfiler::Internal::QV8EventSub, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
namespace QmlProfiler {
namespace Internal {
typedef QHash <QString, QV8EventSub *> EventHash;
static EventHash cloneEventHash(const EventHash &src)
{
EventHash result;
const EventHash::ConstIterator cend = src.constEnd();
for (EventHash::ConstIterator it = src.constBegin(); it != cend; ++it)
result.insert(it.key(), new QV8EventSub(it.value()));
return result;
}
QV8EventData &QV8EventData::operator=(const QV8EventData &ref)
{
if (this == &ref)
return *this;
displayName = ref.displayName;
eventHashStr = ref.eventHashStr;
filename = ref.filename;
functionName = ref.functionName;
line = ref.line;
totalTime = ref.totalTime;
totalPercent = ref.totalPercent;
selfTime = ref.selfTime;
SelfTimeInPercent = ref.SelfTimeInPercent;
eventId = ref.eventId;
qDeleteAll(parentHash);
parentHash = cloneEventHash(ref.parentHash);
qDeleteAll(childrenHash);
childrenHash = cloneEventHash(ref.childrenHash);
return *this;
}
QV8EventData::QV8EventData()
{
line = -1;
eventId = -1;
totalTime = 0;
selfTime = 0;
totalPercent = 0;
SelfTimeInPercent = 0;
}
QV8EventData::~QV8EventData()
{
qDeleteAll(parentHash.values());
parentHash.clear();
qDeleteAll(childrenHash.values());
childrenHash.clear();
}
class QV8ProfilerDataModel::QV8ProfilerDataModelPrivate
{
public:
QV8ProfilerDataModelPrivate(QV8ProfilerDataModel *qq) {Q_UNUSED(qq);}
void clearV8RootEvent();
void collectV8Statistics();
QHash<QString, QV8EventData *> v8EventHash;
QHash<int, QV8EventData *> v8parents;
QV8EventData v8RootEvent;
qint64 v8MeasuredTime;
};
QV8ProfilerDataModel::QV8ProfilerDataModel(QObject *parent)
: QObject(parent)
, d(new QV8ProfilerDataModelPrivate(this))
{
d->v8MeasuredTime = 0;
d->clearV8RootEvent();
}
QV8ProfilerDataModel::~QV8ProfilerDataModel()
{
delete d;
}
void QV8ProfilerDataModel::clear()
{
qDeleteAll(d->v8EventHash.values());
d->v8EventHash.clear();
d->v8parents.clear();
d->clearV8RootEvent();
d->v8MeasuredTime = 0;
emit changed();
}
bool QV8ProfilerDataModel::isEmpty() const
{
return d->v8EventHash.isEmpty();
}
QV8EventData *QV8ProfilerDataModel::v8EventDescription(int eventId) const
{
foreach (QV8EventData *event, d->v8EventHash.values()) {
if (event->eventId == eventId)
return event;
}
return 0;
}
qint64 QV8ProfilerDataModel::v8MeasuredTime() const
{
return d->v8MeasuredTime;
}
QList<QV8EventData *> QV8ProfilerDataModel::getV8Events() const
{
return d->v8EventHash.values();
}
QString getHashStringForV8Event(const QString &displayName, const QString &function)
{
return QString::fromLatin1("%1:%2").arg(displayName, function);
}
void QV8ProfilerDataModel::addV8Event(int depth,
const QString &function,
const QString &filename,
int lineNumber,
double totalTime,
double selfTime)
{
QString displayName = filename.mid(filename.lastIndexOf(QLatin1Char('/')) + 1) +
QLatin1Char(':') + QString::number(lineNumber);
QString hashStr = getHashStringForV8Event(displayName, function);
// time is given in milliseconds, but internally we store it in microseconds
totalTime *= 1e6;
selfTime *= 1e6;
// accumulate information
QV8EventData *eventData = d->v8EventHash[hashStr];
if (!eventData) {
eventData = new QV8EventData;
eventData->displayName = displayName;
eventData->eventHashStr = hashStr;
eventData->filename = filename;
eventData->functionName = function;
eventData->line = lineNumber;
eventData->totalTime = totalTime;
eventData->selfTime = selfTime;
d->v8EventHash[hashStr] = eventData;
} else {
eventData->totalTime += totalTime;
eventData->selfTime += selfTime;
}
d->v8parents[depth] = eventData;
QV8EventData *parentEvent = 0;
if (depth == 0) {
parentEvent = &d->v8RootEvent;
d->v8MeasuredTime += totalTime;
}
if (depth > 0 && d->v8parents.contains(depth-1))
parentEvent = d->v8parents.value(depth-1);
if (parentEvent != 0) {
if (!eventData->parentHash.contains(parentEvent->eventHashStr)) {
QV8EventSub *newParentSub = new QV8EventSub(parentEvent);
newParentSub->totalTime = totalTime;
eventData->parentHash.insert(parentEvent->eventHashStr, newParentSub);
} else {
QV8EventSub *newParentSub = eventData->parentHash.value(parentEvent->eventHashStr);
newParentSub->totalTime += totalTime;
}
if (!parentEvent->childrenHash.contains(eventData->eventHashStr)) {
QV8EventSub *newChildSub = new QV8EventSub(eventData);
newChildSub->totalTime = totalTime;
parentEvent->childrenHash.insert(eventData->eventHashStr, newChildSub);
} else {
QV8EventSub *newChildSub = parentEvent->childrenHash.value(eventData->eventHashStr);
newChildSub->totalTime += totalTime;
}
}
}
void QV8ProfilerDataModel::collectV8Statistics()
{
d->collectV8Statistics();
}
void QV8ProfilerDataModel::QV8ProfilerDataModelPrivate::collectV8Statistics()
{
if (!v8EventHash.isEmpty()) {
double totalTimes = v8MeasuredTime;
double selfTimes = 0;
foreach (QV8EventData *v8event, v8EventHash.values()) {
selfTimes += v8event->selfTime;
}
// prevent divisions by 0
if (totalTimes == 0)
totalTimes = 1;
if (selfTimes == 0)
selfTimes = 1;
// insert root event in eventlist
// the +1 ns is to get it on top of the sorted list
v8RootEvent.totalTime = v8MeasuredTime + 1;
v8RootEvent.selfTime = 0;
QString rootEventHash = getHashStringForV8Event(
tr("<program>"),
tr("Main Program"));
QV8EventData *v8RootEventPointer = v8EventHash[rootEventHash];
if (v8RootEventPointer) {
v8RootEvent = *v8RootEventPointer;
} else {
v8EventHash[rootEventHash] = new QV8EventData;
*v8EventHash[rootEventHash] = v8RootEvent;
}
foreach (QV8EventData *v8event, v8EventHash.values()) {
v8event->totalPercent = v8event->totalTime * 100.0 / totalTimes;
v8event->SelfTimeInPercent = v8event->selfTime * 100.0 / selfTimes;
}
int index = 0;
foreach (QV8EventData *v8event, v8EventHash.values()) {
v8event->eventId = index++;
}
v8RootEvent.eventId = v8EventHash[rootEventHash]->eventId;
} else {
// On empty data, still add a fake root event
clearV8RootEvent();
}
}
void QV8ProfilerDataModel::QV8ProfilerDataModelPrivate::clearV8RootEvent()
{
v8RootEvent.displayName = tr("<program>");
v8RootEvent.eventHashStr = tr("<program>");
v8RootEvent.functionName = tr("Main Program");
v8RootEvent.line = -1;
v8RootEvent.totalTime = 0;
v8RootEvent.totalPercent = 0;
v8RootEvent.selfTime = 0;
v8RootEvent.SelfTimeInPercent = 0;
v8RootEvent.eventId = -1;
qDeleteAll(v8RootEvent.parentHash.values());
qDeleteAll(v8RootEvent.childrenHash.values());
v8RootEvent.parentHash.clear();
v8RootEvent.childrenHash.clear();
}
void QV8ProfilerDataModel::save(QXmlStreamWriter &stream)
{
stream.writeStartElement(QLatin1String("v8profile")); // v8 profiler output
stream.writeAttribute(QLatin1String("totalTime"), QString::number(d->v8MeasuredTime));
foreach (QV8EventData *v8event, d->v8EventHash.values()) {
stream.writeStartElement(QLatin1String("event"));
stream.writeAttribute(QLatin1String("index"),
QString::number(
d->v8EventHash.keys().indexOf(
v8event->eventHashStr)));
stream.writeTextElement(QLatin1String("displayname"), v8event->displayName);
stream.writeTextElement(QLatin1String("functionname"), v8event->functionName);
if (!v8event->filename.isEmpty()) {
stream.writeTextElement(QLatin1String("filename"), v8event->filename);
stream.writeTextElement(QLatin1String("line"), QString::number(v8event->line));
}
stream.writeTextElement(QLatin1String("totalTime"), QString::number(v8event->totalTime));
stream.writeTextElement(QLatin1String("selfTime"), QString::number(v8event->selfTime));
if (!v8event->childrenHash.isEmpty()) {
stream.writeStartElement(QLatin1String("childrenEvents"));
QStringList childrenIndexes;
QStringList childrenTimes;
QStringList parentTimes;
foreach (QV8EventSub *v8child, v8event->childrenHash.values()) {
childrenIndexes << QString::number(v8child->reference->eventId);
childrenTimes << QString::number(v8child->totalTime);
parentTimes << QString::number(v8child->totalTime);
}
stream.writeAttribute(QLatin1String("list"), childrenIndexes.join(QLatin1String(", ")));
stream.writeAttribute(QLatin1String("childrenTimes"), childrenTimes.join(QLatin1String(", ")));
stream.writeAttribute(QLatin1String("parentTimes"), parentTimes.join(QLatin1String(", ")));
stream.writeEndElement();
}
stream.writeEndElement();
}
stream.writeEndElement(); // v8 profiler output
}
void QV8ProfilerDataModel::load(QXmlStreamReader &stream)
{
QHash <int, QV8EventData *> v8eventBuffer;
QHash <int, QString> childrenIndexes;
QHash <int, QString> childrenTimes;
QHash <int, QString> parentTimes;
QV8EventData *v8event = 0;
// time computation
d->v8MeasuredTime = 0;
double cumulatedV8Time = 0;
// get the v8 time
QXmlStreamAttributes attributes = stream.attributes();
if (attributes.hasAttribute(QLatin1String("totalTime")))
d->v8MeasuredTime = attributes.value(QLatin1String("totalTime")).toString().toDouble();
while (!stream.atEnd() && !stream.hasError()) {
QXmlStreamReader::TokenType token = stream.readNext();
QString elementName = stream.name().toString();
switch (token) {
case QXmlStreamReader::StartDocument : continue;
case QXmlStreamReader::StartElement : {
if (elementName == QLatin1String("event")) {
QXmlStreamAttributes attributes = stream.attributes();
if (attributes.hasAttribute(QLatin1String("index"))) {
int ndx = attributes.value(QLatin1String("index")).toString().toInt();
if (!v8eventBuffer.value(ndx))
v8eventBuffer[ndx] = new QV8EventData;
v8event = v8eventBuffer[ndx];
} else {
v8event = 0;
}
break;
}
if (!v8event)
break;
if (elementName == QLatin1String("childrenEvents")) {
QXmlStreamAttributes attributes = stream.attributes();
int eventIndex = v8eventBuffer.key(v8event);
if (attributes.hasAttribute(QLatin1String("list"))) {
// store for later parsing (we haven't read all the events yet)
childrenIndexes[eventIndex] = attributes.value(QLatin1String("list")).toString();
}
if (attributes.hasAttribute(QLatin1String("childrenTimes"))) {
childrenTimes[eventIndex] =
attributes.value(QLatin1String("childrenTimes")).toString();
}
if (attributes.hasAttribute(QLatin1String("parentTimes")))
parentTimes[eventIndex] = attributes.value(QLatin1String("parentTimes")).toString();
}
stream.readNext();
if (stream.tokenType() != QXmlStreamReader::Characters)
break;
QString readData = stream.text().toString();
if (elementName == QLatin1String("displayname")) {
v8event->displayName = readData;
break;
}
if (elementName == QLatin1String("functionname")) {
v8event->functionName = readData;
break;
}
if (elementName == QLatin1String("filename")) {
v8event->filename = readData;
break;
}
if (elementName == QLatin1String("line")) {
v8event->line = readData.toInt();
break;
}
if (elementName == QLatin1String("totalTime")) {
v8event->totalTime = readData.toDouble();
cumulatedV8Time += v8event->totalTime;
break;
}
if (elementName == QLatin1String("selfTime")) {
v8event->selfTime = readData.toDouble();
break;
}
break;
}
case QXmlStreamReader::EndElement : {
if (elementName == QLatin1String("v8profile")) {
// done reading the v8 profile data
break;
}
}
default: break;
}
}
// backwards compatibility
if (d->v8MeasuredTime == 0)
d->v8MeasuredTime = cumulatedV8Time;
// find v8events' children and parents
typedef QHash <int, QString>::ConstIterator ChildIndexConstIt;
const ChildIndexConstIt icend = childrenIndexes.constEnd();
for (ChildIndexConstIt it = childrenIndexes.constBegin(); it != icend; ++it) {
const int parentIndex = it.key();
const QStringList childrenStrings = it.value().split(QLatin1Char(','));
QStringList childrenTimesStrings = childrenTimes.value(parentIndex).split(QLatin1String(", "));
QStringList parentTimesStrings = parentTimes.value(parentIndex).split(QLatin1String(", "));
for (int ndx = 0; ndx < childrenStrings.count(); ndx++) {
int childIndex = childrenStrings[ndx].toInt();
if (v8eventBuffer.value(childIndex)) {
QV8EventSub *newChild = new QV8EventSub(v8eventBuffer[childIndex]);
QV8EventSub *newParent = new QV8EventSub(v8eventBuffer[parentIndex]);
if (childrenTimesStrings.count() > ndx)
newChild->totalTime = childrenTimesStrings[ndx].toDouble();
if (parentTimesStrings.count() > ndx)
newParent->totalTime = parentTimesStrings[ndx].toDouble();
v8eventBuffer[parentIndex]->childrenHash.insert(
newChild->reference->displayName,
newChild);
v8eventBuffer[childIndex]->parentHash.insert(
newParent->reference->displayName,
newParent);
}
}
}
// store v8 events
foreach (QV8EventData *storedV8Event, v8eventBuffer.values()) {
storedV8Event->eventHashStr =
getHashStringForV8Event(
storedV8Event->displayName, storedV8Event->functionName);
d->v8EventHash[storedV8Event->eventHashStr] = storedV8Event;
}
d->collectV8Statistics();
}
void QV8ProfilerDataModel::complete()
{
collectV8Statistics();
emit changed();
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,112 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QV8PROFILERDATAMODEL_H
#define QV8PROFILERDATAMODEL_H
#include <QObject>
#include <QHash>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
namespace QmlProfiler {
namespace Internal {
struct QV8EventSub;
struct QV8EventData
{
QV8EventData();
~QV8EventData();
QString displayName;
QString eventHashStr;
QString filename;
QString functionName;
int line;
double totalTime; // given in milliseconds
double totalPercent;
double selfTime;
double SelfTimeInPercent;
QHash <QString, QV8EventSub *> parentHash;
QHash <QString, QV8EventSub *> childrenHash;
int eventId;
QV8EventData &operator=(const QV8EventData &ref);
};
struct QV8EventSub {
QV8EventSub(QV8EventData *from) : reference(from), totalTime(0) {}
QV8EventSub(QV8EventSub *from) : reference(from->reference), totalTime(from->totalTime) {}
QV8EventData *reference;
qint64 totalTime;
};
class QV8ProfilerDataModel : public QObject
{
Q_OBJECT
public:
QV8ProfilerDataModel(QObject *parent = 0);
~QV8ProfilerDataModel();
void clear();
bool isEmpty() const;
QList<QV8EventData *> getV8Events() const;
QV8EventData *v8EventDescription(int eventId) const;
qint64 v8MeasuredTime() const;
void collectV8Statistics();
void save(QXmlStreamWriter &stream);
void load(QXmlStreamReader &stream);
void complete();
signals:
void changed();
public slots:
void addV8Event(int depth,
const QString &function,
const QString &filename,
int lineNumber,
double totalTime,
double selfTime);
private:
class QV8ProfilerDataModelPrivate;
QV8ProfilerDataModelPrivate *d;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QV8PROFILERDATAMODEL_H

View File

@@ -1,725 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "qv8profilereventview.h"
#include <QUrl>
#include <QHash>
#include <QStandardItem>
#include <QHeaderView>
#include <QApplication>
#include <QClipboard>
#include <QContextMenuEvent>
#include <QDebug>
#include <coreplugin/minisplitter.h>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include "qmlprofilerviewmanager.h"
#include "qmlprofilertool.h"
#include "qv8profilerdatamodel.h"
#include <QMenu>
#include <utils/qtcassert.h>
using namespace QmlDebug;
namespace QmlProfiler {
namespace Internal {
enum ItemRole {
EventHashStrRole = Qt::UserRole+1,
FilenameRole = Qt::UserRole+2,
LineRole = Qt::UserRole+3,
ColumnRole = Qt::UserRole+4,
EventIdRole = Qt::UserRole+5
};
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
class EventsViewItem : public QStandardItem
{
public:
EventsViewItem(const QString &text) : QStandardItem(text) {}
virtual bool operator<(const QStandardItem &other) const
{
if (data().type() == QVariant::String) {
// first column
if (column() == 0) {
return data(FilenameRole).toString() == other.data(FilenameRole).toString() ?
data(LineRole).toInt() < other.data(LineRole).toInt() :
data(FilenameRole).toString() < other.data(FilenameRole).toString();
} else {
return data().toString().toLower() < other.data().toString().toLower();
}
}
return data().toDouble() < other.data().toDouble();
}
};
////////////////////////////////////////////////////////////////////////////////////
class QV8ProfilerEventsWidget::QV8ProfilerEventsWidgetPrivate
{
public:
QV8ProfilerEventsWidgetPrivate(QV8ProfilerEventsWidget *qq):q(qq) {}
~QV8ProfilerEventsWidgetPrivate() {}
QV8ProfilerEventsWidget *q;
Analyzer::IAnalyzerTool *m_profilerTool;
QmlProfilerViewManager *m_viewContainer;
QV8ProfilerEventsMainView *m_eventTree;
QV8ProfilerEventRelativesView *m_eventChildren;
QV8ProfilerEventRelativesView *m_eventParents;
QV8ProfilerDataModel *v8Model;
};
QV8ProfilerEventsWidget::QV8ProfilerEventsWidget(QWidget *parent,
Analyzer::IAnalyzerTool *profilerTool,
QmlProfilerViewManager *container,
QmlProfilerModelManager *profilerModelManager )
: QWidget(parent), d(new QV8ProfilerEventsWidgetPrivate(this))
{
setObjectName(QLatin1String("QmlProfilerV8ProfileView"));
d->v8Model = profilerModelManager->v8Model();
d->m_eventTree = new QV8ProfilerEventsMainView(this, d->v8Model);
connect(d->m_eventTree, SIGNAL(gotoSourceLocation(QString,int,int)), this, SIGNAL(gotoSourceLocation(QString,int,int)));
d->m_eventChildren = new QV8ProfilerEventRelativesView(d->v8Model,
QV8ProfilerEventRelativesView::ChildrenView,
this);
d->m_eventParents = new QV8ProfilerEventRelativesView(d->v8Model,
QV8ProfilerEventRelativesView::ParentsView,
this);
connect(d->m_eventTree, SIGNAL(eventSelected(int)), d->m_eventChildren, SLOT(displayEvent(int)));
connect(d->m_eventTree, SIGNAL(eventSelected(int)), d->m_eventParents, SLOT(displayEvent(int)));
connect(d->m_eventChildren, SIGNAL(eventClicked(int)), d->m_eventTree, SLOT(selectEvent(int)));
connect(d->m_eventParents, SIGNAL(eventClicked(int)), d->m_eventTree, SLOT(selectEvent(int)));
// widget arrangement
QVBoxLayout *groupLayout = new QVBoxLayout;
groupLayout->setContentsMargins(0,0,0,0);
groupLayout->setSpacing(0);
Core::MiniSplitter *splitterVertical = new Core::MiniSplitter;
splitterVertical->addWidget(d->m_eventTree);
Core::MiniSplitter *splitterHorizontal = new Core::MiniSplitter;
splitterHorizontal->addWidget(d->m_eventParents);
splitterHorizontal->addWidget(d->m_eventChildren);
splitterHorizontal->setOrientation(Qt::Horizontal);
splitterVertical->addWidget(splitterHorizontal);
splitterVertical->setOrientation(Qt::Vertical);
splitterVertical->setStretchFactor(0,5);
splitterVertical->setStretchFactor(1,2);
groupLayout->addWidget(splitterVertical);
setLayout(groupLayout);
d->m_profilerTool = profilerTool;
d->m_viewContainer = container;
}
QV8ProfilerEventsWidget::~QV8ProfilerEventsWidget()
{
delete d;
}
void QV8ProfilerEventsWidget::clear()
{
d->m_eventTree->clear();
d->m_eventChildren->clear();
d->m_eventParents->clear();
}
QModelIndex QV8ProfilerEventsWidget::selectedItem() const
{
return d->m_eventTree->selectedItem();
}
void QV8ProfilerEventsWidget::contextMenuEvent(QContextMenuEvent *ev)
{
QTC_ASSERT(d->m_viewContainer, return;);
QMenu menu;
QAction *copyRowAction = 0;
QAction *copyTableAction = 0;
QmlProfilerTool *profilerTool = qobject_cast<QmlProfilerTool *>(d->m_profilerTool);
QPoint position = ev->globalPos();
if (profilerTool) {
QList <QAction *> commonActions = profilerTool->profilerContextMenuActions();
foreach (QAction *act, commonActions) {
menu.addAction(act);
}
}
if (mouseOnTable(position)) {
menu.addSeparator();
if (selectedItem().isValid())
copyRowAction = menu.addAction(QCoreApplication::translate("QmlProfiler::Internal::QmlProfilerEventsWidget", "Copy Row"));
copyTableAction = menu.addAction(QCoreApplication::translate("QmlProfiler::Internal::QmlProfilerEventsWidget", "Copy Table"));
}
QAction *selectedAction = menu.exec(position);
if (selectedAction) {
if (selectedAction == copyRowAction)
copyRowToClipboard();
if (selectedAction == copyTableAction)
copyTableToClipboard();
}
}
void QV8ProfilerEventsWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
emit resized();
}
bool QV8ProfilerEventsWidget::mouseOnTable(const QPoint &position) const
{
QPoint tableTopLeft = d->m_eventTree->mapToGlobal(QPoint(0,0));
QPoint tableBottomRight = d->m_eventTree->mapToGlobal(QPoint(d->m_eventTree->width(), d->m_eventTree->height()));
return (position.x() >= tableTopLeft.x() && position.x() <= tableBottomRight.x() && position.y() >= tableTopLeft.y() && position.y() <= tableBottomRight.y());
}
void QV8ProfilerEventsWidget::copyTableToClipboard() const
{
d->m_eventTree->copyTableToClipboard();
}
void QV8ProfilerEventsWidget::copyRowToClipboard() const
{
d->m_eventTree->copyRowToClipboard();
}
void QV8ProfilerEventsWidget::updateSelectedEvent(int eventId) const
{
if (d->m_eventTree->selectedEventId() != eventId)
d->m_eventTree->selectEvent(eventId);
}
void QV8ProfilerEventsWidget::selectBySourceLocation(const QString &filename, int line, int column)
{
// This slot is used to connect the javascript pane with the qml events pane
// Our javascript trace data does not store column information
// thus we ignore it here
Q_UNUSED(column);
d->m_eventTree->selectEventByLocation(filename, line);
}
////////////////////////////////////////////////////////////////////////////////////
class QV8ProfilerEventsMainView::QV8ProfilerEventsMainViewPrivate
{
public:
QV8ProfilerEventsMainViewPrivate(QV8ProfilerEventsMainView *qq) : q(qq) {}
void buildV8ModelFromList( const QList<QV8EventData *> &list );
int getFieldCount();
QString textForItem(QStandardItem *item, bool recursive) const;
QV8ProfilerEventsMainView *q;
QV8ProfilerDataModel *m_v8Model;
QStandardItemModel *m_model;
QList<bool> m_fieldShown;
QHash<int, int> m_columnIndex; // maps field enum to column index
int m_firstNumericColumn;
bool m_preventSelectBounce;
};
////////////////////////////////////////////////////////////////////////////////////
QV8ProfilerEventsMainView::QV8ProfilerEventsMainView(QWidget *parent,
QV8ProfilerDataModel *v8Model)
: QmlProfilerTreeView(parent), d(new QV8ProfilerEventsMainViewPrivate(this))
{
setObjectName(QLatin1String("QmlProfilerEventsTable"));
setSortingEnabled(false);
d->m_model = new QStandardItemModel(this);
setModel(d->m_model);
connect(this,SIGNAL(clicked(QModelIndex)), this,SLOT(jumpToItem(QModelIndex)));
d->m_v8Model = v8Model;
connect(d->m_v8Model, SIGNAL(changed()), this, SLOT(buildModel()));
d->m_firstNumericColumn = 0;
d->m_preventSelectBounce = false;
setFieldViewable(Name, true);
setFieldViewable(Type, false);
setFieldViewable(TimeInPercent, true);
setFieldViewable(TotalTime, true);
setFieldViewable(SelfTimeInPercent, true);
setFieldViewable(SelfTime, true);
setFieldViewable(CallCount, false);
setFieldViewable(TimePerCall, false);
setFieldViewable(MaxTime, false);
setFieldViewable(MinTime, false);
setFieldViewable(MedianTime, false);
setFieldViewable(Details, true);
buildModel();
}
QV8ProfilerEventsMainView::~QV8ProfilerEventsMainView()
{
clear();
delete d->m_model;
delete d;
}
void QV8ProfilerEventsMainView::setFieldViewable(Fields field, bool show)
{
if (field < MaxFields) {
int length = d->m_fieldShown.count();
if (field >= length) {
for (int i=length; i<MaxFields; i++)
d->m_fieldShown << false;
}
d->m_fieldShown[field] = show;
}
}
void QV8ProfilerEventsMainView::setHeaderLabels()
{
int fieldIndex = 0;
d->m_firstNumericColumn = 0;
d->m_columnIndex.clear();
if (d->m_fieldShown[Name]) {
d->m_columnIndex[Name] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Location)));
d->m_firstNumericColumn++;
}
if (d->m_fieldShown[Type]) {
d->m_columnIndex[Type] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Type)));
d->m_firstNumericColumn++;
}
if (d->m_fieldShown[TimeInPercent]) {
d->m_columnIndex[TimeInPercent] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TimeInPercent)));
}
if (d->m_fieldShown[TotalTime]) {
d->m_columnIndex[TotalTime] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TotalTime)));
}
if (d->m_fieldShown[SelfTimeInPercent]) {
d->m_columnIndex[Type] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(SelfTimeInPercent)));
}
if (d->m_fieldShown[SelfTime]) {
d->m_columnIndex[SelfTime] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(SelfTime)));
}
if (d->m_fieldShown[CallCount]) {
d->m_columnIndex[CallCount] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(CallCount)));
}
if (d->m_fieldShown[TimePerCall]) {
d->m_columnIndex[TimePerCall] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TimePerCall)));
}
if (d->m_fieldShown[MedianTime]) {
d->m_columnIndex[MedianTime] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MedianTime)));
}
if (d->m_fieldShown[MaxTime]) {
d->m_columnIndex[MaxTime] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MaxTime)));
}
if (d->m_fieldShown[MinTime]) {
d->m_columnIndex[MinTime] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MinTime)));
}
if (d->m_fieldShown[Details]) {
d->m_columnIndex[Details] = fieldIndex;
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Details)));
}
}
void QV8ProfilerEventsMainView::clear()
{
d->m_model->clear();
d->m_model->setColumnCount(d->getFieldCount());
setHeaderLabels();
setSortingEnabled(false);
}
int QV8ProfilerEventsMainView::QV8ProfilerEventsMainViewPrivate::getFieldCount()
{
int count = 0;
for (int i=0; i < m_fieldShown.count(); ++i)
if (m_fieldShown[i])
count++;
return count;
}
void QV8ProfilerEventsMainView::buildModel()
{
clear();
d->buildV8ModelFromList( d->m_v8Model->getV8Events() );
setRootIsDecorated(false);
setSortingEnabled(true);
sortByColumn(d->m_firstNumericColumn,Qt::DescendingOrder);
expandAll();
if (d->m_fieldShown[Name])
resizeColumnToContents(0);
if (d->m_fieldShown[Type])
resizeColumnToContents(d->m_fieldShown[Name]?1:0);
collapseAll();
}
void QV8ProfilerEventsMainView::QV8ProfilerEventsMainViewPrivate::buildV8ModelFromList(const QList<QV8EventData *> &list)
{
for (int index = 0; index < list.count(); index++) {
QV8EventData *v8event = list.at(index);
QList<QStandardItem *> newRow;
if (m_fieldShown[Name])
newRow << new EventsViewItem(v8event->displayName);
if (m_fieldShown[TimeInPercent]) {
newRow << new EventsViewItem(QString::number(v8event->totalPercent,'f',2)+QLatin1String(" %"));
newRow.last()->setData(QVariant(v8event->totalPercent));
}
if (m_fieldShown[TotalTime]) {
newRow << new EventsViewItem(displayTime(v8event->totalTime));
newRow.last()->setData(QVariant(v8event->totalTime));
}
if (m_fieldShown[SelfTimeInPercent]) {
newRow << new EventsViewItem(QString::number(v8event->SelfTimeInPercent,'f',2)+QLatin1String(" %"));
newRow.last()->setData(QVariant(v8event->SelfTimeInPercent));
}
if (m_fieldShown[SelfTime]) {
newRow << new EventsViewItem(displayTime(v8event->selfTime));
newRow.last()->setData(QVariant(v8event->selfTime));
}
if (m_fieldShown[Details]) {
newRow << new EventsViewItem(v8event->functionName);
newRow.last()->setData(QVariant(v8event->functionName));
}
if (!newRow.isEmpty()) {
// no edit
foreach (QStandardItem *item, newRow)
item->setEditable(false);
// metadata
newRow.at(0)->setData(QString::fromLatin1("%1:%2").arg(v8event->filename, QString::number(v8event->line)), EventHashStrRole);
newRow.at(0)->setData(QVariant(v8event->filename), FilenameRole);
newRow.at(0)->setData(QVariant(v8event->line), LineRole);
newRow.at(0)->setData(QVariant(-1),ColumnRole); // v8 events have no column info
newRow.at(0)->setData(QVariant(v8event->eventId), EventIdRole);
// append
m_model->invisibleRootItem()->appendRow(newRow);
}
}
}
QString QV8ProfilerEventsMainView::displayTime(double time)
{
if (time < 1e6)
return QString::number(time/1e3,'f',3) + trUtf8(" \xc2\xb5s");
if (time < 1e9)
return QString::number(time/1e6,'f',3) + tr(" ms");
return QString::number(time/1e9,'f',3) + tr(" s");
}
QString QV8ProfilerEventsMainView::nameForType(int typeNumber)
{
switch (typeNumber) {
case 0: return QV8ProfilerEventsMainView::tr("Paint");
case 1: return QV8ProfilerEventsMainView::tr("Compile");
case 2: return QV8ProfilerEventsMainView::tr("Create");
case 3: return QV8ProfilerEventsMainView::tr("Binding");
case 4: return QV8ProfilerEventsMainView::tr("Signal");
}
return QString();
}
int QV8ProfilerEventsMainView::selectedEventId() const
{
QModelIndex index = selectedItem();
if (!index.isValid())
return -1;
QStandardItem *item = d->m_model->item(index.row(), 0);
return item->data(EventIdRole).toInt();
}
void QV8ProfilerEventsMainView::jumpToItem(const QModelIndex &index)
{
if (d->m_preventSelectBounce)
return;
d->m_preventSelectBounce = true;
QStandardItem *clickedItem = d->m_model->itemFromIndex(index);
QStandardItem *infoItem;
if (clickedItem->parent())
infoItem = clickedItem->parent()->child(clickedItem->row(), 0);
else
infoItem = d->m_model->item(index.row(), 0);
// show in editor
int line = infoItem->data(LineRole).toInt();
int column = infoItem->data(ColumnRole).toInt();
QString fileName = infoItem->data(FilenameRole).toString();
if (line!=-1 && !fileName.isEmpty())
emit gotoSourceLocation(fileName, line, column);
// show in callers/callees subwindow
emit eventSelected(infoItem->data(EventIdRole).toInt());
d->m_preventSelectBounce = false;
}
void QV8ProfilerEventsMainView::selectEvent(int eventId)
{
for (int i=0; i<d->m_model->rowCount(); i++) {
QStandardItem *infoItem = d->m_model->item(i, 0);
if (infoItem->data(EventIdRole).toInt() == eventId) {
setCurrentIndex(d->m_model->indexFromItem(infoItem));
jumpToItem(currentIndex());
return;
}
}
}
void QV8ProfilerEventsMainView::selectEventByLocation(const QString &filename, int line)
{
if (d->m_preventSelectBounce)
return;
for (int i=0; i<d->m_model->rowCount(); i++) {
QStandardItem *infoItem = d->m_model->item(i, 0);
if (currentIndex() != d->m_model->indexFromItem(infoItem) &&
infoItem->data(FilenameRole).toString() == filename &&
infoItem->data(LineRole).toInt() == line) {
setCurrentIndex(d->m_model->indexFromItem(infoItem));
jumpToItem(currentIndex());
return;
}
}
}
QModelIndex QV8ProfilerEventsMainView::selectedItem() const
{
QModelIndexList sel = selectedIndexes();
if (sel.isEmpty())
return QModelIndex();
else
return sel.first();
}
QString QV8ProfilerEventsMainView::QV8ProfilerEventsMainViewPrivate::textForItem(QStandardItem *item, bool recursive = true) const
{
QString str;
if (recursive) {
// indentation
QStandardItem *itemParent = item->parent();
while (itemParent) {
str += QLatin1String(" ");
itemParent = itemParent->parent();
}
}
// item's data
int colCount = m_model->columnCount();
for (int j = 0; j < colCount; ++j) {
QStandardItem *colItem = item->parent() ? item->parent()->child(item->row(),j) : m_model->item(item->row(),j);
str += colItem->data(Qt::DisplayRole).toString();
if (j < colCount-1) str += QLatin1Char('\t');
}
str += QLatin1Char('\n');
// recursively print children
if (recursive && item->child(0))
for (int j = 0; j != item->rowCount(); j++)
str += textForItem(item->child(j));
return str;
}
void QV8ProfilerEventsMainView::copyTableToClipboard() const
{
QString str;
// headers
int columnCount = d->m_model->columnCount();
for (int i = 0; i < columnCount; ++i) {
str += d->m_model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
if (i < columnCount - 1)
str += QLatin1Char('\t');
else
str += QLatin1Char('\n');
}
// data
int rowCount = d->m_model->rowCount();
for (int i = 0; i != rowCount; ++i) {
str += d->textForItem(d->m_model->item(i));
}
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(str, QClipboard::Selection);
clipboard->setText(str, QClipboard::Clipboard);
}
void QV8ProfilerEventsMainView::copyRowToClipboard() const
{
QString str;
str = d->textForItem(d->m_model->itemFromIndex(selectedItem()), false);
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(str, QClipboard::Selection);
clipboard->setText(str, QClipboard::Clipboard);
}
////////////////////////////////////////////////////////////////////////////////////
QV8ProfilerEventRelativesView::QV8ProfilerEventRelativesView(QV8ProfilerDataModel *model,
SubViewType viewType,
QWidget *parent)
: QmlProfilerTreeView(parent)
, m_type(viewType)
, m_v8Model(model)
, m_model(new QStandardItemModel(this))
{
setModel(m_model);
updateHeader();
setSortingEnabled(false);
connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(jumpToItem(QModelIndex)));
}
QV8ProfilerEventRelativesView::~QV8ProfilerEventRelativesView()
{
}
void QV8ProfilerEventRelativesView::displayEvent(int index)
{
QV8EventData *event = m_v8Model->v8EventDescription(index);
QTC_CHECK(event);
QList<QV8EventSub*> events;
if (m_type == ParentsView)
events = event->parentHash.values();
else
events = event->childrenHash.values();
rebuildTree(events);
updateHeader();
resizeColumnToContents(0);
setSortingEnabled(true);
sortByColumn(1);
}
void QV8ProfilerEventRelativesView::rebuildTree(QList<QV8EventSub*> events)
{
clear();
QStandardItem *topLevelItem = m_model->invisibleRootItem();
foreach (QV8EventSub *event, events) {
QList<QStandardItem *> newRow;
newRow << new EventsViewItem(event->reference->displayName);
newRow << new EventsViewItem(QV8ProfilerEventsMainView::displayTime(event->totalTime));
newRow << new EventsViewItem(event->reference->functionName);
newRow.at(0)->setData(QVariant(event->reference->eventId), EventIdRole);
newRow.at(1)->setData(QVariant(event->totalTime));
foreach (QStandardItem *item, newRow)
item->setEditable(false);
topLevelItem->appendRow(newRow);
}
}
void QV8ProfilerEventRelativesView::clear()
{
m_model->clear();
}
void QV8ProfilerEventRelativesView::updateHeader()
{
m_model->setColumnCount(3);
int columnIndex = 0;
if (m_type == ChildrenView)
m_model->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(Callee)));
else
m_model->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(Caller)));
m_model->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(TotalTime)));
if (m_type == ChildrenView)
m_model->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(CalleeDescription)));
else
m_model->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(CallerDescription)));
}
void QV8ProfilerEventRelativesView::jumpToItem(const QModelIndex &index)
{
QStandardItem *infoItem = m_model->item(index.row(), 0);
emit eventClicked(infoItem->data(EventIdRole).toInt());
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,163 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef QV8PROFILEREVENTVIEW_H
#define QV8PROFILEREVENTVIEW_H
#include <QStandardItemModel>
#include <qmldebug/qmlprofilereventtypes.h>
#include "qmlprofilermodelmanager.h"
#include "qmlprofilereventsmodelproxy.h"
#include "qmlprofilertreeview.h"
#include <analyzerbase/ianalyzertool.h>
#include "qmlprofilerviewmanager.h"
namespace QmlProfiler {
namespace Internal {
class QV8ProfilerEventsMainView;
class QV8ProfilerEventRelativesView;
struct QV8EventSub;
class QV8ProfilerEventsWidget : public QWidget
{
Q_OBJECT
public:
explicit QV8ProfilerEventsWidget(QWidget *parent,
Analyzer::IAnalyzerTool *profilerTool,
QmlProfilerViewManager *container,
QmlProfilerModelManager *profilerModelManager );
~QV8ProfilerEventsWidget();
void clear();
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
QModelIndex selectedItem() const;
bool mouseOnTable(const QPoint &position) const;
void copyTableToClipboard() const;
void copyRowToClipboard() const;
signals:
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
void showEventInTimeline(int eventId);
void resized();
public slots:
void updateSelectedEvent(int eventId) const;
void selectBySourceLocation(const QString &filename, int line, int column);
protected:
void contextMenuEvent(QContextMenuEvent *ev);
virtual void resizeEvent(QResizeEvent *event);
private:
class QV8ProfilerEventsWidgetPrivate;
QV8ProfilerEventsWidgetPrivate *d;
};
class QV8ProfilerEventsMainView : public QmlProfilerTreeView
{
Q_OBJECT
public:
explicit QV8ProfilerEventsMainView(QWidget *parent,
QV8ProfilerDataModel *v8Model);
~QV8ProfilerEventsMainView();
void setFieldViewable(Fields field, bool show);
void setShowAnonymousEvents( bool showThem );
QModelIndex selectedItem() const;
void copyTableToClipboard() const;
void copyRowToClipboard() const;
static QString displayTime(double time);
static QString nameForType(int typeNumber);
int selectedEventId() const;
void setShowExtendedStatistics(bool);
bool showExtendedStatistics() const;
signals:
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
void eventSelected(int eventId);
public slots:
void clear();
void jumpToItem(const QModelIndex &index);
void selectEvent(int eventId);
void selectEventByLocation(const QString &filename, int line);
void buildModel();
private:
void setHeaderLabels();
private:
class QV8ProfilerEventsMainViewPrivate;
QV8ProfilerEventsMainViewPrivate *d;
};
class QV8ProfilerEventRelativesView : public QmlProfilerTreeView
{
Q_OBJECT
public:
enum SubViewType {
ParentsView,
ChildrenView
};
QV8ProfilerEventRelativesView(QV8ProfilerDataModel *model, SubViewType viewType,
QWidget *parent);
~QV8ProfilerEventRelativesView();
signals:
void eventClicked(int eventId);
public slots:
void displayEvent(int eventId);
void jumpToItem(const QModelIndex &);
void clear();
private:
void rebuildTree(QList<QV8EventSub*> events);
void updateHeader();
QV8ProfilerEventRelativesView::SubViewType m_type;
QV8ProfilerDataModel *m_v8Model;
QStandardItemModel *m_model;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QV8PROFILEREVENTVIEW_H

View File

@@ -1,380 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "timelinemodelaggregator.h"
#include <QStringList>
#include "qmlprofilertimelinemodelproxy.h"
#include "qmlprofilerpainteventsmodelproxy.h"
#include <QVariant>
#include "qmlprofilerplugin.h"
#include <QDebug>
namespace QmlProfiler {
namespace Internal {
class TimelineModelAggregator::TimelineModelAggregatorPrivate {
public:
TimelineModelAggregatorPrivate(TimelineModelAggregator *qq):q(qq) {}
~TimelineModelAggregatorPrivate() {}
TimelineModelAggregator *q;
int basicModelIndex;
QList <AbstractTimelineModel *> modelList;
QmlProfilerModelManager *modelManager;
};
TimelineModelAggregator::TimelineModelAggregator(QObject *parent)
//: AbstractTimelineModel(parent),d(new TimelineModelAggregatorPrivate(this))
: QObject(parent), d(new TimelineModelAggregatorPrivate(this))
{
}
TimelineModelAggregator::~TimelineModelAggregator()
{
delete d;
}
void TimelineModelAggregator::setModelManager(QmlProfilerModelManager *modelManager)
{
//AbstractTimelineModel::setModelManager(modelManager);
d->modelManager = modelManager;
connect(modelManager,SIGNAL(stateChanged()),this,SLOT(dataChanged()));
connect(modelManager,SIGNAL(countChanged()),this,SIGNAL(countChanged()));
connect(modelManager,SIGNAL(dataAvailable()),this,SIGNAL(dataAvailable()));
// external models pushed on top
foreach (AbstractTimelineModel *timelineModel, QmlProfilerPlugin::instance->getModels()) {
timelineModel->setModelManager(modelManager);
addModel(timelineModel);
}
PaintEventsModelProxy *paintEventsModelProxy = new PaintEventsModelProxy(this);
paintEventsModelProxy->setModelManager(modelManager);
addModel(paintEventsModelProxy);
BasicTimelineModel *basicTimelineModel = new BasicTimelineModel(this);
basicTimelineModel->setModelManager(modelManager);
addModel(basicTimelineModel);
// the basic model is the last one here
d->basicModelIndex = d->modelList.count() - 1;
}
void TimelineModelAggregator::addModel(AbstractTimelineModel *m)
{
d->modelList << m;
connect(m,SIGNAL(countChanged()),this,SIGNAL(countChanged()));
connect(m,SIGNAL(emptyChanged()),this,SIGNAL(emptyChanged()));
connect(m,SIGNAL(expandedChanged()),this,SIGNAL(expandedChanged()));
connect(m,SIGNAL(stateChanged()),this,SIGNAL(stateChanged()));
}
// order?
int TimelineModelAggregator::categories() const
{
int categoryCount = 0;
foreach (const AbstractTimelineModel *modelProxy, d->modelList)
categoryCount += modelProxy->categories();
return categoryCount;
}
int TimelineModelAggregator::visibleCategories() const
{
int categoryCount = 0;
foreach (const AbstractTimelineModel *modelProxy, d->modelList) {
for (int i = 0; i < modelProxy->categories(); i++)
if (modelProxy->categoryDepth(i) > 0)
categoryCount ++;
}
return categoryCount;
}
QStringList TimelineModelAggregator::categoryTitles() const
{
QStringList retString;
foreach (const AbstractTimelineModel *modelProxy, d->modelList)
retString += modelProxy->categoryTitles();
return retString;
}
QString TimelineModelAggregator::name() const
{
return QLatin1String("TimelineModelAggregator");
}
int TimelineModelAggregator::count(int modelIndex) const
{
if (modelIndex == -1) {
int totalCount = 0;
foreach (const AbstractTimelineModel *modelProxy, d->modelList)
totalCount += modelProxy->count();
return totalCount;
} else {
return d->modelList[modelIndex]->count();
}
}
bool TimelineModelAggregator::isEmpty() const
{
foreach (const AbstractTimelineModel *modelProxy, d->modelList)
if (!modelProxy->isEmpty())
return false;
return true;
}
bool TimelineModelAggregator::eventAccepted(const QmlProfilerSimpleModel::QmlEventData &/*event*/) const
{
// accept all events
return true;
}
int TimelineModelAggregator::basicModelIndex() const
{
return d->basicModelIndex;
}
qint64 TimelineModelAggregator::lastTimeMark() const
{
qint64 mark = -1;
foreach (const AbstractTimelineModel *modelProxy, d->modelList) {
if (!modelProxy->isEmpty()) {
qint64 mk = modelProxy->lastTimeMark();
if (mark > mk)
mark = mk;
}
}
return mark;
}
bool TimelineModelAggregator::expanded(int modelIndex, int category) const
{
return d->modelList[modelIndex]->expanded(category);
}
void TimelineModelAggregator::setExpanded(int modelIndex, int category, bool expanded)
{
// int modelIndex = modelIndexForCategory(category);
// category = correctedCategoryIndexForModel(modelIndex, categoryIndex);
d->modelList[modelIndex]->setExpanded(category, expanded);
}
int TimelineModelAggregator::categoryDepth(int modelIndex, int categoryIndex) const
{
return d->modelList[modelIndex]->categoryDepth(categoryIndex);
}
int TimelineModelAggregator::categoryCount(int modelIndex) const
{
return d->modelList[modelIndex]->categoryCount();
}
int TimelineModelAggregator::rowCount(int modelIndex) const
{
return d->modelList[modelIndex]->rowCount();
}
const QString TimelineModelAggregator::categoryLabel(int modelIndex, int categoryIndex) const
{
// int modelIndex = modelIndexForCategory(categoryIndex);
// categoryIndex = correctedCategoryIndexForModel(modelIndex, categoryIndex);
return d->modelList[modelIndex]->categoryLabel(categoryIndex);
}
int TimelineModelAggregator::modelIndexForCategory(int absoluteCategoryIndex) const
{
int categoryIndex = absoluteCategoryIndex;
for (int modelIndex = 0; modelIndex < d->modelList.count(); modelIndex++)
if (categoryIndex < d->modelList[modelIndex]->categoryCount()) {
return modelIndex;
} else {
categoryIndex -= d->modelList[modelIndex]->categoryCount();
}
return modelCount()-1;
}
int TimelineModelAggregator::correctedCategoryIndexForModel(int modelIndex, int absoluteCategoryIndex) const
{
int categoryIndex = absoluteCategoryIndex;
for (int mi = 0; mi < modelIndex; mi++)
categoryIndex -= d->modelList[mi]->categoryCount();
return categoryIndex;
}
int TimelineModelAggregator::findFirstIndex(int modelIndex, qint64 startTime) const
{
return d->modelList[modelIndex]->findFirstIndex(startTime);
}
int TimelineModelAggregator::findFirstIndexNoParents(int modelIndex, qint64 startTime) const
{
return d->modelList[modelIndex]->findFirstIndexNoParents(startTime);
}
int TimelineModelAggregator::findLastIndex(int modelIndex, qint64 endTime) const
{
return d->modelList[modelIndex]->findLastIndex(endTime);
}
int TimelineModelAggregator::getEventType(int modelIndex, int index) const
{
return d->modelList[modelIndex]->getEventType(index);
}
int TimelineModelAggregator::getEventCategoryInModel(int modelIndex, int index) const
{
return d->modelList[modelIndex]->getEventCategory(index);
}
int TimelineModelAggregator::getEventRow(int modelIndex, int index) const
{
return d->modelList[modelIndex]->getEventRow(index);
}
qint64 TimelineModelAggregator::getDuration(int modelIndex, int index) const
{
return d->modelList[modelIndex]->getDuration(index);
}
qint64 TimelineModelAggregator::getStartTime(int modelIndex, int index) const
{
return d->modelList[modelIndex]->getStartTime(index);
}
qint64 TimelineModelAggregator::getEndTime(int modelIndex, int index) const
{
return d->modelList[modelIndex]->getEndTime(index);
}
int TimelineModelAggregator::getEventId(int modelIndex, int index) const
{
return d->modelList[modelIndex]->getEventId(index);
}
int TimelineModelAggregator::getBindingLoopDest(int modelIndex,int index) const
{
return d->modelList[modelIndex]->getBindingLoopDest(index);
}
QColor TimelineModelAggregator::getColor(int modelIndex, int index) const
{
return d->modelList[modelIndex]->getColor(index);
}
QVariantList TimelineModelAggregator::getColorRGB(int modelIndex, int itemIndex) const
{
// return color as RGB list, for use in Qml
QColor c = getColor(modelIndex, itemIndex);
QVariantList res;
res.append(QVariant(c.red()));
res.append(QVariant(c.green()));
res.append(QVariant(c.blue()));
return res;
}
float TimelineModelAggregator::getHeight(int modelIndex, int index) const
{
return d->modelList[modelIndex]->getHeight(index);
}
const QVariantList TimelineModelAggregator::getLabelsForCategory(int modelIndex, int category) const
{
// int modelIndex = modelIndexForCategory(category);
// category = correctedCategoryIndexForModel(modelIndex, category);
return d->modelList[modelIndex]->getLabelsForCategory(category);
}
const QVariantList TimelineModelAggregator::getEventDetails(int modelIndex, int index) const
{
return d->modelList[modelIndex]->getEventDetails(index);
}
const QVariantMap TimelineModelAggregator::getEventLocation(int modelIndex, int index) const
{
return d->modelList[modelIndex]->getEventLocation(index);
}
int TimelineModelAggregator::getEventIdForHash(const QString &hash) const
{
foreach (const AbstractTimelineModel *model, d->modelList) {
int eventId = model->getEventIdForHash(hash);
if (eventId != -1)
return eventId;
}
return -1;
}
int TimelineModelAggregator::getEventIdForLocation(const QString &filename, int line, int column) const
{
foreach (const AbstractTimelineModel *model, d->modelList) {
int eventId = model->getEventIdForLocation(filename, line, column);
if (eventId != -1)
return eventId;
}
return -1;
}
void TimelineModelAggregator::dataChanged()
{
// this is a slot connected for every modelproxy
// nothing to do here, each model will take care of itself
}
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();
}
int TimelineModelAggregator::getState() const
{
return (int)d->modelManager->state();
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,123 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef TIMELINEMODELAGGREGATOR_H
#define TIMELINEMODELAGGREGATOR_H
#include "abstracttimelinemodel.h"
#include "qmlprofilermodelmanager.h"
namespace QmlProfiler {
namespace Internal {
class TimelineModelAggregator : public QObject //: public AbstractTimelineModel
{
Q_OBJECT
public:
TimelineModelAggregator(QObject *parent = 0);
~TimelineModelAggregator();
void setModelManager(QmlProfilerModelManager *modelManager);
void addModel(AbstractTimelineModel *m);
Q_INVOKABLE int categories() const;
Q_INVOKABLE int visibleCategories() const;
Q_INVOKABLE QStringList categoryTitles() const;
QString name() const;
Q_INVOKABLE int count(int modelIndex = -1) const;
void clear();
Q_INVOKABLE int modelCount() const;
Q_INVOKABLE qint64 traceStartTime() const;
Q_INVOKABLE qint64 traceEndTime() const;
Q_INVOKABLE qint64 traceDuration() const;
Q_INVOKABLE int getState() const;
bool isEmpty() const;
bool eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const;
Q_INVOKABLE int basicModelIndex() const;
Q_INVOKABLE qint64 lastTimeMark() const;
Q_INVOKABLE bool expanded(int modelIndex, int category) const;
Q_INVOKABLE void setExpanded(int modelIndex, int category, bool expanded);
Q_INVOKABLE int categoryDepth(int modelIndex, int categoryIndex) const;
Q_INVOKABLE int categoryCount(int modelIndex) const;
Q_INVOKABLE int rowCount(int modelIndex) const;
Q_INVOKABLE const QString categoryLabel(int modelIndex, int categoryIndex) const;
int findFirstIndex(int modelIndex, qint64 startTime) const;
int findFirstIndexNoParents(int modelIndex, qint64 startTime) const;
int findLastIndex(int modelIndex, qint64 endTime) const;
int getEventType(int modelIndex, int index) const;
Q_INVOKABLE int getEventCategoryInModel(int modelIndex, int index) const;
int getEventRow(int modelIndex, int index) const;
Q_INVOKABLE qint64 getDuration(int modelIndex, int index) const;
Q_INVOKABLE qint64 getStartTime(int modelIndex, int index) const;
Q_INVOKABLE qint64 getEndTime(int modelIndex, int index) const;
Q_INVOKABLE int getEventId(int modelIndex, int index) const;
Q_INVOKABLE int getBindingLoopDest(int modelIndex, int index) const;
Q_INVOKABLE QColor getColor(int modelIndex, int index) const;
Q_INVOKABLE QVariantList getColorRGB(int modelIndex, int itemIndex) const;
Q_INVOKABLE float getHeight(int modelIndex, int index) const;
Q_INVOKABLE const QVariantList getLabelsForCategory(int modelIndex, int category) const;
Q_INVOKABLE const QVariantList getEventDetails(int modelIndex, int index) const;
Q_INVOKABLE const QVariantMap getEventLocation(int modelIndex, int index) const;
Q_INVOKABLE int getEventIdForHash(const QString &hash) const;
Q_INVOKABLE int getEventIdForLocation(const QString &filename, int line, int column) const;
Q_INVOKABLE int modelIndexForCategory(int absoluteCategoryIndex) const;
Q_INVOKABLE int correctedCategoryIndexForModel(int modelIndex, int absoluteCategoryIndex) const;
signals:
void countChanged();
void dataAvailable();
void stateChanged();
void emptyChanged();
void expandedChanged();
protected slots:
void dataChanged();
private:
class TimelineModelAggregatorPrivate;
TimelineModelAggregatorPrivate *d;
};
}
}
#endif // TIMELINEMODELAGGREGATOR_H

View File

@@ -1,549 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "timelinerenderer.h"
#include <qdeclarativecontext.h>
#include <qdeclarativeproperty.h>
#include <QTimer>
#include <QPixmap>
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
#include <QVarLengthArray>
#include <math.h>
using namespace QmlProfiler::Internal;
const int DefaultRowHeight = 30;
TimelineRenderer::TimelineRenderer(QDeclarativeItem *parent) :
QDeclarativeItem(parent), m_startTime(0), m_endTime(0), m_spacing(0),
m_lastStartTime(0), m_lastEndTime(0)
, m_profilerModelProxy(0)
{
clearData();
setFlag(QGraphicsItem::ItemHasNoContents, false);
setAcceptedMouseButtons(Qt::LeftButton);
setAcceptHoverEvents(true);
}
void TimelineRenderer::componentComplete()
{
const QMetaObject *metaObject = this->metaObject();
int propertyCount = metaObject->propertyCount();
int requestPaintMethod = metaObject->indexOfMethod("requestPaint()");
for (int ii = TimelineRenderer::staticMetaObject.propertyCount(); ii < propertyCount; ++ii) {
QMetaProperty p = metaObject->property(ii);
if (p.hasNotifySignal())
QMetaObject::connect(this, p.notifySignalIndex(), this, requestPaintMethod, 0, 0);
}
QDeclarativeItem::componentComplete();
}
void TimelineRenderer::requestPaint()
{
update();
}
void TimelineRenderer::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
{
qint64 windowDuration = m_endTime - m_startTime;
if (windowDuration <= 0)
return;
m_spacing = qreal(width()) / windowDuration;
p->setPen(Qt::transparent);
for (int modelIndex = 0; modelIndex < m_profilerModelProxy->modelCount(); modelIndex++) {
int lastIndex = m_profilerModelProxy->findLastIndex(modelIndex, m_endTime);
if (lastIndex >= 0 && lastIndex < m_profilerModelProxy->count(modelIndex)) {
int firstIndex = m_profilerModelProxy->findFirstIndex(modelIndex, m_startTime);
if (firstIndex >= 0) {
drawItemsToPainter(p, modelIndex, firstIndex, lastIndex);
if (m_selectedModel == modelIndex)
drawSelectionBoxes(p, modelIndex, firstIndex, lastIndex);
drawBindingLoopMarkers(p, modelIndex, firstIndex, lastIndex);
}
}
}
m_lastStartTime = m_startTime;
m_lastEndTime = m_endTime;
}
void TimelineRenderer::drawItemsToPainter(QPainter *p, int modelIndex, int fromIndex, int toIndex)
{
int x, y, width, height;
p->save();
p->setPen(Qt::transparent);
int modelRowStart = 0;
for (int mi = 0; mi < modelIndex; mi++)
modelRowStart += m_profilerModelProxy->rowCount(mi);
for (int i = fromIndex; i <= toIndex; i++) {
x = (m_profilerModelProxy->getStartTime(modelIndex, i) - m_startTime) * m_spacing;
int rowNumber = m_profilerModelProxy->getEventRow(modelIndex, i);
y = (modelRowStart + rowNumber) * DefaultRowHeight;
width = m_profilerModelProxy->getDuration(modelIndex, i)*m_spacing;
if (width < 1)
width = 1;
height = DefaultRowHeight * m_profilerModelProxy->getHeight(modelIndex, i);
y += DefaultRowHeight - height;
// normal events
p->setBrush(m_profilerModelProxy->getColor(modelIndex, i));
p->drawRect(x, y, width, height);
}
p->restore();
}
void TimelineRenderer::drawSelectionBoxes(QPainter *p, int modelIndex, int fromIndex, int toIndex)
{
if (m_selectedItem == -1)
return;
int id = m_profilerModelProxy->getEventId(modelIndex, m_selectedItem);
int modelRowStart = 0;
for (int mi = 0; mi < modelIndex; mi++)
modelRowStart += m_profilerModelProxy->rowCount(mi);
p->save();
QColor selectionColor = Qt::blue;
if (m_selectionLocked)
selectionColor = QColor(96,0,255);
QPen strongPen(selectionColor, 3);
QPen lightPen(QBrush(selectionColor.lighter(130)), 2);
lightPen.setJoinStyle(Qt::MiterJoin);
p->setPen(lightPen);
p->setBrush(Qt::transparent);
int x, y, width;
QRect selectedItemRect(0,0,0,0);
for (int i = fromIndex; i <= toIndex; i++) {
if (m_profilerModelProxy->getEventId(modelIndex, i) != id)
continue;
x = (m_profilerModelProxy->getStartTime(modelIndex, i) - m_startTime) * m_spacing;
y = (modelRowStart + m_profilerModelProxy->getEventRow(modelIndex, i)) * DefaultRowHeight;
width = m_profilerModelProxy->getDuration(modelIndex, i)*m_spacing;
if (width<1)
width = 1;
if (i == m_selectedItem)
selectedItemRect = QRect(x, y-1, width, DefaultRowHeight+1);
else
p->drawRect(x,y,width,DefaultRowHeight);
}
// draw the selected item rectangle the last, so that it's overlayed
if (selectedItemRect.width() != 0) {
p->setPen(strongPen);
p->drawRect(selectedItemRect);
}
p->restore();
}
void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int modelIndex, int fromIndex, int toIndex)
{
int destindex;
int xfrom, xto;
int yfrom, yto;
int radius = DefaultRowHeight / 3;
QPen shadowPen = QPen(QColor("grey"),2);
QPen markerPen = QPen(QColor("orange"),2);
QBrush shadowBrush = QBrush(QColor("grey"));
QBrush markerBrush = QBrush(QColor("orange"));
p->save();
for (int i = fromIndex; i <= toIndex; i++) {
destindex = m_profilerModelProxy->getBindingLoopDest(modelIndex, i);
if (destindex >= 0) {
// from
xfrom = (m_profilerModelProxy->getStartTime(modelIndex, i) +
m_profilerModelProxy->getDuration(modelIndex, i)/2 -
m_startTime) * m_spacing;
yfrom = getYPosition(modelIndex, i);
yfrom += DefaultRowHeight / 2;
// to
xto = (m_profilerModelProxy->getStartTime(modelIndex, destindex) +
m_profilerModelProxy->getDuration(modelIndex, destindex)/2 -
m_startTime) * m_spacing;
yto = getYPosition(modelIndex, destindex);
yto += DefaultRowHeight / 2;
// radius
int eventWidth = m_profilerModelProxy->getDuration(modelIndex, i) * m_spacing;
radius = 5;
if (radius * 2 > eventWidth)
radius = eventWidth / 2;
if (radius < 2)
radius = 2;
// shadow
int shadowoffset = 2;
p->setPen(shadowPen);
p->setBrush(shadowBrush);
p->drawEllipse(QPoint(xfrom, yfrom + shadowoffset), radius, radius);
p->drawEllipse(QPoint(xto, yto + shadowoffset), radius, radius);
p->drawLine(QPoint(xfrom, yfrom + shadowoffset), QPoint(xto, yto + shadowoffset));
// marker
p->setPen(markerPen);
p->setBrush(markerBrush);
p->drawEllipse(QPoint(xfrom, yfrom), radius, radius);
p->drawEllipse(QPoint(xto, yto), radius, radius);
p->drawLine(QPoint(xfrom, yfrom), QPoint(xto, yto));
}
}
p->restore();
}
int TimelineRenderer::modelFromPosition(int y)
{
y = y / DefaultRowHeight;
for (int modelIndex = 0; modelIndex < m_profilerModelProxy->modelCount(); modelIndex++) {
y -= m_profilerModelProxy->rowCount(modelIndex);
if (y < 0)
return modelIndex;
}
return 0;
}
void TimelineRenderer::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
// special case: if there is a drag area below me, don't accept the
// events unless I'm actually clicking inside an item
if (m_currentSelection.eventIndex == -1 &&
event->pos().x()+x() >= m_startDragArea &&
event->pos().x()+x() <= m_endDragArea)
event->setAccepted(false);
}
void TimelineRenderer::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
manageClicked();
}
void TimelineRenderer::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
event->setAccepted(false);
}
void TimelineRenderer::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
manageHovered(event->pos().x(), event->pos().y());
if (m_currentSelection.eventIndex == -1)
event->setAccepted(false);
}
void TimelineRenderer::manageClicked()
{
if (m_currentSelection.eventIndex != -1) {
if (m_currentSelection.eventIndex == m_selectedItem && m_currentSelection.modelIndex == m_selectedModel)
setSelectionLocked(!m_selectionLocked);
else
setSelectionLocked(true);
emit itemPressed(m_currentSelection.modelIndex, m_currentSelection.eventIndex);
} else {
setSelectionLocked(false);
}
setSelectedModel(m_currentSelection.modelIndex);
setSelectedItem(m_currentSelection.eventIndex);
}
void TimelineRenderer::manageHovered(int x, int y)
{
if (m_endTime - m_startTime <=0 || m_lastEndTime - m_lastStartTime <= 0)
return;
qint64 time = x * (m_endTime - m_startTime) / width() + m_startTime;
int row = y / DefaultRowHeight;
int modelIndex = modelFromPosition(y);
// already covered? nothing to do
if (m_currentSelection.eventIndex != -1 &&
time >= m_currentSelection.startTime &&
time <= m_currentSelection.endTime &&
row == m_currentSelection.row) {
return;
}
// find if there's items in the time range
int eventFrom = m_profilerModelProxy->findFirstIndex(modelIndex, time);
int eventTo = m_profilerModelProxy->findLastIndex(modelIndex, time);
if (eventFrom == -1 ||
eventTo < eventFrom || eventTo >= m_profilerModelProxy->count()) {
m_currentSelection.eventIndex = -1;
return;
}
int modelRowStart = 0;
for (int mi = 0; mi < modelIndex; mi++)
modelRowStart += m_profilerModelProxy->rowCount(mi);
// find if we are in the right column
int itemRow;
for (int i=eventTo; i>=eventFrom; --i) {
if (ceil(m_profilerModelProxy->getEndTime(modelIndex, i)*m_spacing) < floor(time*m_spacing))
continue;
itemRow = modelRowStart + m_profilerModelProxy->getEventRow(modelIndex, i);
if (itemRow == row) {
// match
m_currentSelection.eventIndex = i;
m_currentSelection.startTime = m_profilerModelProxy->getStartTime(modelIndex, i);
m_currentSelection.endTime = m_profilerModelProxy->getEndTime(modelIndex, i);
m_currentSelection.row = row;
m_currentSelection.modelIndex = modelIndex;
if (!m_selectionLocked) {
setSelectedModel(modelIndex);
setSelectedItem(i);
}
return;
}
}
m_currentSelection.eventIndex = -1;
return;
}
void TimelineRenderer::clearData()
{
m_startTime = 0;
m_endTime = 0;
m_lastStartTime = 0;
m_lastEndTime = 0;
m_currentSelection.startTime = -1;
m_currentSelection.endTime = -1;
m_currentSelection.row = -1;
m_currentSelection.eventIndex = -1;
m_currentSelection.modelIndex = -1;
m_selectedItem = -1;
m_selectedModel = -1;
m_selectionLocked = true;
}
int TimelineRenderer::getYPosition(int modelIndex, int index) const
{
Q_ASSERT(m_profilerModelProxy);
if (index >= m_profilerModelProxy->count())
return 0;
int modelRowStart = 0;
for (int mi = 0; mi < modelIndex; mi++)
modelRowStart += m_profilerModelProxy->rowCount(mi);
int y = DefaultRowHeight * (modelRowStart + m_profilerModelProxy->getEventRow(modelIndex, index));
return y;
}
void TimelineRenderer::selectNext()
{
if (m_profilerModelProxy->count() == 0)
return;
qint64 searchTime = m_startTime;
if (m_selectedItem != -1)
searchTime = m_profilerModelProxy->getStartTime(m_selectedModel, m_selectedItem);
QVarLengthArray<int> itemIndexes(m_profilerModelProxy->modelCount());
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++) {
if (m_profilerModelProxy->count(i) > 0) {
if (m_selectedModel == i) {
itemIndexes[i] = (m_selectedItem + 1) % m_profilerModelProxy->count(i);
} else {
if (m_profilerModelProxy->getStartTime(i, 0) > searchTime)
itemIndexes[i] = 0;
else
itemIndexes[i] = (m_profilerModelProxy->findLastIndex(i, searchTime) + 1) % m_profilerModelProxy->count(i);
}
} else {
itemIndexes[i] = -1;
}
}
int candidateModelIndex = -1;
qint64 candidateStartTime = m_profilerModelProxy->traceEndTime();
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++) {
if (itemIndexes[i] == -1)
continue;
qint64 newStartTime = m_profilerModelProxy->getStartTime(i, itemIndexes[i]);
if (newStartTime > searchTime && newStartTime < candidateStartTime) {
candidateStartTime = newStartTime;
candidateModelIndex = i;
}
}
int itemIndex;
if (candidateModelIndex != -1) {
itemIndex = itemIndexes[candidateModelIndex];
} else {
// find the first index of them all (todo: the modelproxy should do this)
itemIndex = -1;
candidateStartTime = m_profilerModelProxy->traceEndTime();
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++)
if (m_profilerModelProxy->count(i) > 0 &&
m_profilerModelProxy->getStartTime(i,0) < candidateStartTime) {
candidateModelIndex = i;
itemIndex = 0;
candidateStartTime = m_profilerModelProxy->getStartTime(i,0);
}
}
setSelectedModel(candidateModelIndex);
setSelectedItem(itemIndex);
}
void TimelineRenderer::selectPrev()
{
if (m_profilerModelProxy->count() == 0)
return;
qint64 searchTime = m_endTime;
if (m_selectedItem != -1)
searchTime = m_profilerModelProxy->getEndTime(m_selectedModel, m_selectedItem);
QVarLengthArray<int> itemIndexes(m_profilerModelProxy->modelCount());
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++) {
if (m_selectedModel == i) {
itemIndexes[i] = m_selectedItem - 1;
if (itemIndexes[i] < 0)
itemIndexes[i] = m_profilerModelProxy->count(m_selectedModel) -1;
}
else
itemIndexes[i] = m_profilerModelProxy->findLastIndex(i, searchTime);
}
int candidateModelIndex = -1;
qint64 candidateStartTime = m_profilerModelProxy->traceStartTime();
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++) {
if (itemIndexes[i] == -1
|| itemIndexes[i] >= m_profilerModelProxy->count(i))
continue;
qint64 newStartTime = m_profilerModelProxy->getStartTime(i, itemIndexes[i]);
if (newStartTime < searchTime && newStartTime > candidateStartTime) {
candidateStartTime = newStartTime;
candidateModelIndex = i;
}
}
int itemIndex = -1;
if (candidateModelIndex != -1) {
itemIndex = itemIndexes[candidateModelIndex];
} else {
// find the last index of them all (todo: the modelproxy should do this)
candidateModelIndex = 0;
candidateStartTime = m_profilerModelProxy->traceStartTime();
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++)
if (m_profilerModelProxy->count(i) > 0 &&
m_profilerModelProxy->getStartTime(i,m_profilerModelProxy->count(i)-1) > candidateStartTime) {
candidateModelIndex = i;
itemIndex = m_profilerModelProxy->count(candidateModelIndex) - 1;
candidateStartTime = m_profilerModelProxy->getStartTime(i,m_profilerModelProxy->count(i)-1);
}
}
setSelectedModel(candidateModelIndex);
setSelectedItem(itemIndex);
}
int TimelineRenderer::nextItemFromId(int modelIndex, int eventId) const
{
int ndx = -1;
if (m_selectedItem == -1)
ndx = m_profilerModelProxy->findFirstIndexNoParents(modelIndex, m_startTime);
else
ndx = m_selectedItem + 1;
if (ndx < 0)
return -1;
if (ndx >= m_profilerModelProxy->count(modelIndex))
ndx = 0;
int startIndex = ndx;
do {
if (m_profilerModelProxy->getEventId(modelIndex, ndx) == eventId)
return ndx;
ndx = (ndx + 1) % m_profilerModelProxy->count(modelIndex);
} while (ndx != startIndex);
return -1;
}
int TimelineRenderer::prevItemFromId(int modelIndex, int eventId) const
{
int ndx = -1;
if (m_selectedItem == -1)
ndx = m_profilerModelProxy->findFirstIndexNoParents(modelIndex, m_startTime);
else
ndx = m_selectedItem - 1;
if (ndx < 0)
ndx = m_profilerModelProxy->count(modelIndex) - 1;
int startIndex = ndx;
do {
if (m_profilerModelProxy->getEventId(modelIndex, ndx) == eventId)
return ndx;
if (--ndx < 0)
ndx = m_profilerModelProxy->count(modelIndex)-1;
} while (ndx != startIndex);
return -1;
}
void TimelineRenderer::selectNextFromId(int modelIndex, int eventId)
{
int eventIndex = nextItemFromId(modelIndex, eventId);
if (eventIndex != -1) {
setSelectedModel(modelIndex);
setSelectedItem(eventIndex);
}
}
void TimelineRenderer::selectPrevFromId(int modelIndex, int eventId)
{
int eventIndex = prevItemFromId(modelIndex, eventId);
if (eventIndex != -1) {
setSelectedModel(modelIndex);
setSelectedItem(eventIndex);
}
}

View File

@@ -1,235 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 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.
**
****************************************************************************/
#ifndef TIMELINERENDERER_H
#define TIMELINERENDERER_H
#include <QDeclarativeItem>
#include <QScriptValue>
#include "qmlprofilertimelinemodelproxy.h"
#include "timelinemodelaggregator.h"
namespace QmlProfiler {
namespace Internal {
class TimelineRenderer : public QDeclarativeItem
{
Q_OBJECT
Q_PROPERTY(qint64 startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged)
Q_PROPERTY(qint64 endTime READ endTime WRITE setEndTime NOTIFY endTimeChanged)
Q_PROPERTY(QObject *profilerModelProxy READ profilerModelProxy WRITE setProfilerModelProxy NOTIFY profilerModelProxyChanged)
Q_PROPERTY(bool selectionLocked READ selectionLocked WRITE setSelectionLocked NOTIFY selectionLockedChanged)
Q_PROPERTY(int selectedItem READ selectedItem WRITE setSelectedItem NOTIFY selectedItemChanged)
Q_PROPERTY(int selectedModel READ selectedModel WRITE setSelectedModel NOTIFY selectedModelChanged)
Q_PROPERTY(int startDragArea READ startDragArea WRITE setStartDragArea NOTIFY startDragAreaChanged)
Q_PROPERTY(int endDragArea READ endDragArea WRITE setEndDragArea NOTIFY endDragAreaChanged)
public:
explicit TimelineRenderer(QDeclarativeItem *parent = 0);
qint64 startTime() const
{
return m_startTime;
}
qint64 endTime() const
{
return m_endTime;
}
bool selectionLocked() const
{
return m_selectionLocked;
}
int selectedItem() const
{
return m_selectedItem;
}
int selectedModel() const
{
return m_selectedModel;
}
int startDragArea() const
{
return m_startDragArea;
}
int endDragArea() const
{
return m_endDragArea;
}
TimelineModelAggregator *profilerModelProxy() const { return m_profilerModelProxy; }
void setProfilerModelProxy(QObject *profilerModelProxy)
{
if (m_profilerModelProxy) {
disconnect(m_profilerModelProxy, SIGNAL(expandedChanged()), this, SLOT(requestPaint()));
}
m_profilerModelProxy = qobject_cast<TimelineModelAggregator *>(profilerModelProxy);
if (m_profilerModelProxy) {
connect(m_profilerModelProxy, SIGNAL(expandedChanged()), this, SLOT(requestPaint()));
}
emit profilerModelProxyChanged(m_profilerModelProxy);
}
Q_INVOKABLE int getYPosition(int modelIndex, int index) const;
Q_INVOKABLE void selectNext();
Q_INVOKABLE void selectPrev();
Q_INVOKABLE int nextItemFromId(int modelIndex, int eventId) const;
Q_INVOKABLE int prevItemFromId(int modelIndex, int eventId) const;
Q_INVOKABLE void selectNextFromId(int modelIndex, int eventId);
Q_INVOKABLE void selectPrevFromId(int modelIndex, int eventId);
signals:
void startTimeChanged(qint64 arg);
void endTimeChanged(qint64 arg);
void profilerModelProxyChanged(TimelineModelAggregator *list);
void selectionLockedChanged(bool locked);
void selectedItemChanged(int modelIndex, int itemIndex);
void selectedModelChanged(int modelIndex);
void startDragAreaChanged(int startDragArea);
void endDragAreaChanged(int endDragArea);
void itemPressed(int modelIndex, int pressedItem);
public slots:
void clearData();
void requestPaint();
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) {
m_selectionLocked = locked;
update();
emit selectionLockedChanged(locked);
}
}
void setSelectedItem(int itemIndex)
{
if (m_selectedItem != itemIndex) {
m_selectedItem = itemIndex;
update();
emit selectedItemChanged(m_selectedModel, itemIndex);
}
}
void setSelectedModel(int modelIndex)
{
if (m_selectedModel != modelIndex) {
m_selectedModel = modelIndex;
update();
emit selectedModelChanged(modelIndex);
}
}
void setStartDragArea(int startDragArea)
{
if (m_startDragArea != startDragArea) {
m_startDragArea = startDragArea;
emit startDragAreaChanged(startDragArea);
}
}
void setEndDragArea(int endDragArea)
{
if (m_endDragArea != endDragArea) {
m_endDragArea = endDragArea;
emit endDragAreaChanged(endDragArea);
}
}
protected:
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
virtual void componentComplete();
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
private:
void drawItemsToPainter(QPainter *p, int modelIndex, int fromIndex, int toIndex);
void drawSelectionBoxes(QPainter *p, int modelIndex, int fromIndex, int toIndex);
void drawBindingLoopMarkers(QPainter *p, int modelIndex, int fromIndex, int toIndex);
int modelFromPosition(int y);
void manageClicked();
void manageHovered(int x, int y);
private:
qint64 m_startTime;
qint64 m_endTime;
qreal m_spacing;
qint64 m_lastStartTime;
qint64 m_lastEndTime;
TimelineModelAggregator *m_profilerModelProxy;
struct {
qint64 startTime;
qint64 endTime;
int row;
int eventIndex;
int modelIndex;
} m_currentSelection;
int m_selectedItem;
int m_selectedModel;
bool m_selectionLocked;
int m_startDragArea;
int m_endDragArea;
};
} // namespace Internal
} // namespace QmlProfiler
QML_DECLARE_TYPE(QmlProfiler::Internal::TimelineRenderer)
#endif // TIMELINERENDERER_H

View File

@@ -25,7 +25,7 @@
namespace QmlProfilerExtension { namespace QmlProfilerExtension {
namespace Internal { namespace Internal {
using namespace QmlProfiler::Internal; using namespace QmlProfiler;
class PixmapCacheModel::PixmapCacheModelPrivate { class PixmapCacheModel::PixmapCacheModelPrivate {
public: public:
@@ -91,7 +91,7 @@ bool PixmapCacheModel::isEmpty() const
return d->eventList.isEmpty(); return d->eventList.isEmpty();
} }
bool PixmapCacheModel::eventAccepted(const QmlProfiler::Internal::QmlProfilerSimpleModel::QmlEventData &event) const bool PixmapCacheModel::eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const
{ {
return (event.eventType == QmlDebug::PixmapCacheEvent); return (event.eventType == QmlDebug::PixmapCacheEvent);
} }

View File

@@ -69,7 +69,7 @@ public:
bool isEmpty() const; bool isEmpty() const;
bool eventAccepted(const QmlProfiler::Internal::QmlProfilerSimpleModel::QmlEventData &event) const; bool eventAccepted(const QmlProfiler::QmlProfilerSimpleModel::QmlEventData &event) const;
Q_INVOKABLE qint64 lastTimeMark() const; Q_INVOKABLE qint64 lastTimeMark() const;

Some files were not shown because too many files have changed in this diff Show More