QmlProfiler: Split AbstractTimelineModel in two classes

We need a general purpose TimelineModel and a specialized
QmlProfilerTimelineModel.

Change-Id: I2da02d65efa11e160cab5fa9f8a21075beb0e2bf
Reviewed-by: Kai Koehne <kai.koehne@theqtcompany.com>
This commit is contained in:
Ulf Hermann
2014-10-28 19:01:43 +01:00
committed by Ulf Hermann
parent af84726c51
commit 10d942e268
22 changed files with 797 additions and 748 deletions

View File

@@ -1,610 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "abstracttimelinemodel.h"
#include "abstracttimelinemodel_p.h"
#include <QLinkedList>
namespace QmlProfiler {
/*!
\class QmlProfiler::AbstractTimelineModel
\brief The AbstractTimelineModel class provides a sorted model for timeline data.
The AbstractTimelineModel lets you keep range data sorted by both start and end times, so that
visible ranges can easily be computed. The only precondition for that to work is that the ranges
must be perfectly nested. A "parent" range of a range R is defined as a range for which the
start time is smaller than R's start time and the end time is greater than R's end time. A set
of ranges is perfectly nested if all parent ranges of any given range have a common parent
range. Mind that you can always make that happen by defining a range that spans the whole
available time span. That, however, will make any code that uses firstStartTime() and
lastEndTime() for selecting subsets of the model always select all of it.
\note Indices returned from the various methods are only valid until a new range is inserted
before them. Inserting a new range before a given index moves the range pointed to by the
index by one. Incrementing the index by one will make it point to the item again.
*/
/*!
\fn qint64 AbstractTimelineModelPrivate::firstStartTime() const
Returns the begin of the first range in the model.
*/
/*!
\fn qint64 AbstractTimelineModelPrivate::lastEndTime() const
Returns the end of the last range in the model.
*/
/*!
\fn const AbstractTimelineModelPrivate::Range &AbstractTimelineModelPrivate::range(int index) const
Returns the range data at the specified index.
*/
/*!
\fn void AbstractTimelineModel::computeNesting()
Compute all ranges' parents.
\sa findFirstIndex
*/
void AbstractTimelineModel::computeNesting()
{
Q_D(AbstractTimelineModel);
QLinkedList<int> parents;
for (int range = 0; range != count(); ++range) {
AbstractTimelineModelPrivate::Range &current = d->ranges[range];
for (QLinkedList<int>::iterator parentIt = parents.begin();;) {
if (parentIt == parents.end()) {
parents.append(range);
break;
}
AbstractTimelineModelPrivate::Range &parent = d->ranges[*parentIt];
qint64 parentEnd = parent.start + parent.duration;
if (parentEnd < current.start) {
if (parent.start == current.start) {
if (parent.parent == -1) {
parent.parent = range;
} else {
AbstractTimelineModelPrivate::Range &ancestor = d->ranges[parent.parent];
if (ancestor.start == current.start &&
ancestor.duration < current.duration)
parent.parent = range;
}
// Just switch the old parent range for the new, larger one
*parentIt = range;
break;
} else {
parentIt = parents.erase(parentIt);
}
} else if (parentEnd >= current.start + current.duration) {
// no need to insert
current.parent = *parentIt;
break;
} else {
++parentIt;
}
}
}
}
int AbstractTimelineModel::collapsedRowCount() const
{
Q_D(const AbstractTimelineModel);
return d->collapsedRowCount;
}
void AbstractTimelineModel::setCollapsedRowCount(int rows)
{
Q_D(AbstractTimelineModel);
d->collapsedRowCount = rows;
}
int AbstractTimelineModel::expandedRowCount() const
{
Q_D(const AbstractTimelineModel);
return d->expandedRowCount;
}
void QmlProfiler::AbstractTimelineModel::setExpandedRowCount(int rows)
{
Q_D(AbstractTimelineModel);
d->expandedRowCount = rows;
}
void AbstractTimelineModel::AbstractTimelineModelPrivate::init(AbstractTimelineModel *q,
QmlProfilerModelManager *manager,
const QString &newDisplayName,
QmlDebug::Message newMessage,
QmlDebug::RangeType newRangeType)
{
q_ptr = q;
modelId = manager->registerModelProxy();
modelManager = manager;
expanded = false;
hidden = false;
displayName = newDisplayName;
message = newMessage;
rangeType = newRangeType;
expandedRowCount = 1;
collapsedRowCount = 1;
connect(modelManager->qmlModel(), SIGNAL(changed()), q, SLOT(_q_dataChanged()));
connect(q,SIGNAL(rowHeightChanged()),q,SIGNAL(heightChanged()));
connect(q,SIGNAL(expandedChanged()),q,SIGNAL(heightChanged()));
connect(q,SIGNAL(hiddenChanged()),q,SIGNAL(heightChanged()));
}
AbstractTimelineModel::AbstractTimelineModel(AbstractTimelineModelPrivate *dd,
QmlProfilerModelManager *manager, const QString &displayName, QmlDebug::Message message,
QmlDebug::RangeType rangeType, QObject *parent) :
QObject(parent), d_ptr(dd)
{
d_ptr->init(this, manager, displayName, message, rangeType);
}
AbstractTimelineModel::AbstractTimelineModel(QmlProfilerModelManager *manager,
const QString &displayName, QmlDebug::Message message, QmlDebug::RangeType rangeType,
QObject *parent) :
QObject(parent), d_ptr(new AbstractTimelineModelPrivate)
{
d_ptr->init(this, manager, displayName, message, rangeType);
}
AbstractTimelineModel::~AbstractTimelineModel()
{
Q_D(AbstractTimelineModel);
delete d;
}
QmlProfilerModelManager *AbstractTimelineModel::modelManager() const
{
Q_D(const AbstractTimelineModel);
return d->modelManager;
}
bool AbstractTimelineModel::isEmpty() const
{
return count() == 0;
}
int AbstractTimelineModel::modelId() const
{
Q_D(const AbstractTimelineModel);
return d->modelId;
}
int AbstractTimelineModel::rowHeight(int rowNumber) const
{
Q_D(const AbstractTimelineModel);
if (!expanded())
return AbstractTimelineModelPrivate::DefaultRowHeight;
if (d->rowOffsets.size() > rowNumber)
return d->rowOffsets[rowNumber] - (rowNumber > 0 ? d->rowOffsets[rowNumber - 1] : 0);
return AbstractTimelineModelPrivate::DefaultRowHeight;
}
int AbstractTimelineModel::rowOffset(int rowNumber) const
{
Q_D(const AbstractTimelineModel);
if (rowNumber == 0)
return 0;
if (!expanded())
return AbstractTimelineModelPrivate::DefaultRowHeight * rowNumber;
if (d->rowOffsets.size() >= rowNumber)
return d->rowOffsets[rowNumber - 1];
if (!d->rowOffsets.empty())
return d->rowOffsets.last() + (rowNumber - d->rowOffsets.size()) *
AbstractTimelineModelPrivate::DefaultRowHeight;
return rowNumber * AbstractTimelineModelPrivate::DefaultRowHeight;
}
void AbstractTimelineModel::setRowHeight(int rowNumber, int height)
{
Q_D(AbstractTimelineModel);
if (d->hidden || !d->expanded)
return;
if (height < AbstractTimelineModelPrivate::DefaultRowHeight)
height = AbstractTimelineModelPrivate::DefaultRowHeight;
int nextOffset = d->rowOffsets.empty() ? 0 : d->rowOffsets.last();
while (d->rowOffsets.size() <= rowNumber)
d->rowOffsets << (nextOffset += AbstractTimelineModelPrivate::DefaultRowHeight);
int difference = height - d->rowOffsets[rowNumber] +
(rowNumber > 0 ? d->rowOffsets[rowNumber - 1] : 0);
if (difference != 0) {
for (; rowNumber < d->rowOffsets.size(); ++rowNumber) {
d->rowOffsets[rowNumber] += difference;
}
emit rowHeightChanged();
}
}
int AbstractTimelineModel::height() const
{
Q_D(const AbstractTimelineModel);
int depth = rowCount();
if (d->hidden || !d->expanded || d->rowOffsets.empty())
return depth * AbstractTimelineModelPrivate::DefaultRowHeight;
return d->rowOffsets.last() + (depth - d->rowOffsets.size()) *
AbstractTimelineModelPrivate::DefaultRowHeight;
}
/*!
\fn int AbstractTimelineModel::count() const
Returns the number of ranges in the model.
*/
int AbstractTimelineModel::count() const
{
Q_D(const AbstractTimelineModel);
return d->ranges.count();
}
qint64 AbstractTimelineModel::duration(int index) const
{
Q_D(const AbstractTimelineModel);
return d->ranges[index].duration;
}
qint64 AbstractTimelineModel::startTime(int index) const
{
Q_D(const AbstractTimelineModel);
return d->ranges[index].start;
}
qint64 AbstractTimelineModel::endTime(int index) const
{
Q_D(const AbstractTimelineModel);
return d->ranges[index].start + d->ranges[index].duration;
}
/*!
Returns the type ID of the event with event ID \a index. The type ID is a globally valid ID which
can be used to communicate metainformation about events to other parts of the program. By default
it is -1, which means there is no global type information about the event.
*/
int AbstractTimelineModel::typeId(int index) const
{
Q_UNUSED(index)
return -1;
}
/*!
\fn int AbstractTimelineModel::firstIndex(qint64 startTime) const
Looks up the first range with an end time greater than the given time and
returns its parent's index. If no such range is found, it returns -1. If there
is no parent, it returns the found range's index. The parent of a range is the
range with the lowest start time that completely covers the child range.
"Completely covers" means:
parent.startTime <= child.startTime && parent.endTime >= child.endTime
*/
int AbstractTimelineModel::firstIndex(qint64 startTime) const
{
Q_D(const AbstractTimelineModel);
int index = firstIndexNoParents(startTime);
if (index == -1)
return -1;
int parent = d->ranges[index].parent;
return parent == -1 ? index : parent;
}
/*!
\fn int AbstractTimelineModel::firstIndexNoParents(qint64 startTime) const
Looks up the first range with an end time greater than the given time and
returns its index. If no such range is found, it returns -1.
*/
int AbstractTimelineModel::firstIndexNoParents(qint64 startTime) const
{
Q_D(const AbstractTimelineModel);
// in the "endtime" list, find the first event that ends after startTime
if (d->endTimes.isEmpty())
return -1;
if (d->endTimes.count() == 1 || d->endTimes.first().end > startTime)
return d->endTimes.first().startIndex;
if (d->endTimes.last().end <= startTime)
return -1;
return d->endTimes[d->lowerBound(d->endTimes, startTime) + 1].startIndex;
}
/*!
\fn int AbstractTimelineModel::lastIndex(qint64 endTime) const
Looks up the last range with a start time smaller than the given time and
returns its index. If no such range is found, it returns -1.
*/
int AbstractTimelineModel::lastIndex(qint64 endTime) const
{
Q_D(const AbstractTimelineModel);
// in the "starttime" list, find the last event that starts before endtime
if (d->ranges.isEmpty() || d->ranges.first().start >= endTime)
return -1;
if (d->ranges.count() == 1)
return 0;
if (d->ranges.last().start < endTime)
return d->ranges.count() - 1;
return d->lowerBound(d->ranges, endTime);
}
QVariantMap AbstractTimelineModel::location(int index) const
{
Q_UNUSED(index);
QVariantMap map;
return map;
}
/*!
Returns \c true if this model can contain events of global type Id \a typeIndex. Otherwise
returns \c false.
*/
bool AbstractTimelineModel::handlesTypeId(int typeIndex) const
{
if (typeIndex < 0)
return false;
Q_D(const AbstractTimelineModel);
return accepted(d->modelManager->qmlModel()->getEventTypes().at(typeIndex));
}
int AbstractTimelineModel::selectionIdForLocation(const QString &filename, int line, int column) const
{
Q_UNUSED(filename);
Q_UNUSED(line);
Q_UNUSED(column);
return -1;
}
int AbstractTimelineModel::bindingLoopDest(int index) const
{
Q_UNUSED(index);
return -1;
}
float AbstractTimelineModel::relativeHeight(int index) const
{
Q_UNUSED(index);
return 1.0f;
}
int AbstractTimelineModel::rowMinValue(int rowNumber) const
{
Q_UNUSED(rowNumber);
return 0;
}
int AbstractTimelineModel::rowMaxValue(int rowNumber) const
{
Q_UNUSED(rowNumber);
return 0;
}
int AbstractTimelineModel::defaultRowHeight()
{
return AbstractTimelineModelPrivate::DefaultRowHeight;
}
QmlDebug::RangeType AbstractTimelineModel::rangeType() const
{
Q_D(const AbstractTimelineModel);
return d->rangeType;
}
QmlDebug::Message AbstractTimelineModel::message() const
{
Q_D(const AbstractTimelineModel);
return d->message;
}
void AbstractTimelineModel::updateProgress(qint64 count, qint64 max) const
{
Q_D(const AbstractTimelineModel);
d->modelManager->modelProxyCountUpdated(d->modelId, count, max);
}
void AbstractTimelineModel::announceFeatures(quint64 features) const
{
Q_D(const AbstractTimelineModel);
d->modelManager->announceFeatures(d->modelId, features);
}
QColor AbstractTimelineModel::colorBySelectionId(int index) const
{
return colorByHue(selectionId(index) * AbstractTimelineModelPrivate::SelectionIdHueMultiplier);
}
QColor AbstractTimelineModel::colorByFraction(double fraction) const
{
return colorByHue(fraction * AbstractTimelineModelPrivate::FractionHueMultiplier +
AbstractTimelineModelPrivate::FractionHueMininimum);
}
QColor AbstractTimelineModel::colorByHue(int hue) const
{
return QColor::fromHsl(hue % 360, AbstractTimelineModelPrivate::Saturation,
AbstractTimelineModelPrivate::Lightness);
}
/*!
Inserts an event at the time specified by \a startTime with the given \a duration and returns
its index. The \a selectionId determines the selection group the new event belongs to.
\sa selectionId()
*/
int AbstractTimelineModel::insert(qint64 startTime, qint64 duration, int selectionId)
{
Q_D(AbstractTimelineModel);
/* Doing insert-sort here is preferable as most of the time the times will actually be
* presorted in the right way. So usually this will just result in appending. */
int index = d->insertSorted(d->ranges,
AbstractTimelineModelPrivate::Range(startTime, duration, selectionId));
if (index < d->ranges.size() - 1)
d->incrementStartIndices(index);
d->insertSorted(d->endTimes,
AbstractTimelineModelPrivate::RangeEnd(index, startTime + duration));
return index;
}
/*!
Inserts a range start at the time given by \a startTime and returns its index. The range end is
not set. The \a selectionId determines the selection group the new event belongs to.
\sa selectionId()
*/
int AbstractTimelineModel::insertStart(qint64 startTime, int selectionId)
{
Q_D(AbstractTimelineModel);
int index = d->insertSorted(d->ranges,
AbstractTimelineModelPrivate::Range(startTime, 0, selectionId));
if (index < d->ranges.size() - 1)
d->incrementStartIndices(index);
return index;
}
/*!
\fn int AbstractTimelineModel::insertEnd(int index, qint64 duration)
Adds a range end for the given start index.
*/
void AbstractTimelineModel::insertEnd(int index, qint64 duration)
{
Q_D(AbstractTimelineModel);
d->ranges[index].duration = duration;
d->insertSorted(d->endTimes, AbstractTimelineModelPrivate::RangeEnd(index,
d->ranges[index].start + duration));
}
void AbstractTimelineModel::AbstractTimelineModelPrivate::_q_dataChanged()
{
Q_Q(AbstractTimelineModel);
bool wasEmpty = q->isEmpty();
switch (modelManager->state()) {
case QmlProfilerDataState::ProcessingData:
q->loadData();
break;
case QmlProfilerDataState::ClearingData:
q->clear();
break;
default:
break;
}
if (wasEmpty != q->isEmpty())
emit q->emptyChanged();
}
bool AbstractTimelineModel::accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const
{
Q_D(const AbstractTimelineModel);
return (event.rangeType == d->rangeType && event.message == d->message);
}
bool AbstractTimelineModel::expanded() const
{
Q_D(const AbstractTimelineModel);
return d->expanded;
}
void AbstractTimelineModel::setExpanded(bool expanded)
{
Q_D(AbstractTimelineModel);
if (expanded != d->expanded) {
d->expanded = expanded;
emit expandedChanged();
}
}
bool AbstractTimelineModel::hidden() const
{
Q_D(const AbstractTimelineModel);
return d->hidden;
}
void AbstractTimelineModel::setHidden(bool hidden)
{
Q_D(AbstractTimelineModel);
if (hidden != d->hidden) {
d->hidden = hidden;
emit hiddenChanged();
}
}
QString AbstractTimelineModel::displayName() const
{
Q_D(const AbstractTimelineModel);
return d->displayName;
}
int AbstractTimelineModel::rowCount() const
{
Q_D(const AbstractTimelineModel);
if (d->hidden)
return 0;
if (isEmpty())
return d->modelManager->isEmpty() ? 1 : 0;
return d->expanded ? d->expandedRowCount : d->collapsedRowCount;
}
/*!
Returns the ID of the selection group the event with event Id \a index belongs to. Selection
groups are local to the model and the model can arbitrarily assign events to selection groups
when inserting them.
If one event from a selection group is selected, all visible other events from the same
selection group are highlighted. Rows are expected to correspond to selection IDs when the view
is expanded.
*/
int AbstractTimelineModel::selectionId(int index) const
{
Q_D(const AbstractTimelineModel);
return d->ranges[index].selectionId;
}
void AbstractTimelineModel::clear()
{
Q_D(AbstractTimelineModel);
d->collapsedRowCount = d->expandedRowCount = 1;
bool wasExpanded = d->expanded;
bool wasHidden = d->hidden;
bool hadRowHeights = !d->rowOffsets.empty();
d->rowOffsets.clear();
d->expanded = false;
d->hidden = false;
d->ranges.clear();
d->endTimes.clear();
if (hadRowHeights)
emit rowHeightChanged();
if (wasExpanded)
emit expandedChanged();
if (wasHidden)
emit hiddenChanged();
updateProgress(0, 1);
}
}
#include "moc_abstracttimelinemodel.cpp"

View File

@@ -5,7 +5,6 @@ QT += network qml quick
include(../../qtcreatorplugin.pri)
SOURCES += \
abstracttimelinemodel.cpp \
localqmlprofilerrunner.cpp \
qmlprofileranimationsmodel.cpp \
qmlprofilerattachdialog.cpp \
@@ -23,6 +22,7 @@ SOURCES += \
qmlprofilerruncontrolfactory.cpp \
qmlprofilerstatemanager.cpp \
qmlprofilerstatewidget.cpp \
qmlprofilertimelinemodel.cpp \
qmlprofilertimelinemodelfactory.cpp \
qmlprofilertool.cpp \
qmlprofilertracefile.cpp \
@@ -31,14 +31,13 @@ SOURCES += \
qmlprofilerviewmanager.cpp \
qv8profilerdatamodel.cpp \
qv8profilereventview.cpp \
timelinemodel.cpp \
timelinemodelaggregator.cpp \
timelinerenderer.cpp \
timelinezoomcontrol.cpp
HEADERS += \
abstractqmlprofilerrunner.h \
abstracttimelinemodel.h \
abstracttimelinemodel_p.h \
localqmlprofilerrunner.h \
qmlprofiler_global.h \
qmlprofileranimationsmodel.h \
@@ -59,6 +58,7 @@ HEADERS += \
qmlprofilerruncontrolfactory.h \
qmlprofilerstatemanager.h \
qmlprofilerstatewidget.h \
qmlprofilertimelinemodel.h \
qmlprofilertimelinemodelfactory.h \
qmlprofilertool.h \
qmlprofilertracefile.h \
@@ -67,6 +67,8 @@ HEADERS += \
qmlprofilerviewmanager.h \
qv8profilerdatamodel.h \
qv8profilereventview.h \
timelinemodel.h \
timelinemodel_p.h \
timelinemodelaggregator.h \
timelinerenderer.h \
timelinezoomcontrol.h

View File

@@ -21,7 +21,6 @@ QtcPlugin {
name: "General"
files: [
"abstractqmlprofilerrunner.h",
"abstracttimelinemodel.h", "abstracttimelinemodel_p.h", "abstracttimelinemodel.cpp",
"localqmlprofilerrunner.cpp", "localqmlprofilerrunner.h",
"qmlprofiler_global.h",
"qmlprofileranimationsmodel.h", "qmlprofileranimationsmodel.cpp",
@@ -41,6 +40,7 @@ QtcPlugin {
"qmlprofilerstatemanager.cpp", "qmlprofilerstatemanager.h",
"qmlprofilerstatewidget.cpp", "qmlprofilerstatewidget.h",
"qmlprofilerrangemodel.cpp", "qmlprofilerrangemodel.h",
"qmlprofilertimelinemodel.cpp", "qmlprofilertimelinemodel.h",
"qmlprofilertimelinemodelfactory.cpp", "qmlprofilertimelinemodelfactory.h",
"qmlprofilertool.cpp", "qmlprofilertool.h",
"qmlprofilertracefile.cpp", "qmlprofilertracefile.h",
@@ -49,6 +49,7 @@ QtcPlugin {
"qmlprofilerviewmanager.cpp", "qmlprofilerviewmanager.h",
"qv8profilerdatamodel.cpp", "qv8profilerdatamodel.h",
"qv8profilereventview.h", "qv8profilereventview.cpp",
"timelinemodel.cpp", "timelinemodel.h", "timelinemodel_p.h",
"timelinemodelaggregator.cpp", "timelinemodelaggregator.h",
"timelinerenderer.cpp", "timelinerenderer.h",
"timelinezoomcontrol.cpp", "timelinezoomcontrol.h"

View File

@@ -31,7 +31,6 @@
#include "qmlprofileranimationsmodel.h"
#include "qmlprofilermodelmanager.h"
#include "qmlprofilerdatamodel.h"
#include "abstracttimelinemodel_p.h"
#include <utils/qtcassert.h>
#include <QCoreApplication>
@@ -47,10 +46,10 @@ namespace QmlProfiler {
namespace Internal {
QmlProfilerAnimationsModel::QmlProfilerAnimationsModel(QmlProfilerModelManager *manager,
QObject *parent)
: AbstractTimelineModel(manager,
tr(QmlProfilerModelManager::featureName(QmlDebug::ProfileAnimations)),
QmlDebug::Event, QmlDebug::MaximumRangeType, parent)
QObject *parent) :
QmlProfilerTimelineModel(manager,
tr(QmlProfilerModelManager::featureName(QmlDebug::ProfileAnimations)),
QmlDebug::Event, QmlDebug::MaximumRangeType, parent)
{
m_maxGuiThreadAnimations = m_maxRenderThreadAnimations = 0;
announceFeatures(1 << QmlDebug::ProfileAnimations);
@@ -60,12 +59,12 @@ void QmlProfilerAnimationsModel::clear()
{
m_maxGuiThreadAnimations = m_maxRenderThreadAnimations = 0;
m_data.clear();
AbstractTimelineModel::clear();
QmlProfilerTimelineModel::clear();
}
bool QmlProfilerAnimationsModel::accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const
{
return AbstractTimelineModel::accepted(event) &&
return QmlProfilerTimelineModel::accepted(event) &&
event.detailType== QmlDebug::AnimationFrame;
}
@@ -149,7 +148,7 @@ int QmlProfilerAnimationsModel::rowMaxValue(int rowNumber) const
case 2:
return m_maxRenderThreadAnimations;
default:
return AbstractTimelineModel::rowMaxValue(rowNumber);
return QmlProfilerTimelineModel::rowMaxValue(rowNumber);
}
}

View File

@@ -33,7 +33,7 @@
#define QMLPROFILERANIMATIONSMODEL_H
#include <QObject>
#include "abstracttimelinemodel.h"
#include "qmlprofilertimelinemodel.h"
#include <qmldebug/qmlprofilereventtypes.h>
#include <qmldebug/qmlprofilereventlocation.h>
//#include <QHash>
@@ -49,7 +49,7 @@ class QmlProfilerModelManager;
namespace Internal {
class QmlProfilerAnimationsModel : public AbstractTimelineModel
class QmlProfilerAnimationsModel : public QmlProfilerTimelineModel
{
Q_OBJECT
public:

View File

@@ -47,9 +47,9 @@ void QmlProfilerNotesModel::setModelManager(QmlProfilerModelManager *modelManage
m_modelManager = modelManager;
}
void QmlProfilerNotesModel::addTimelineModel(const AbstractTimelineModel *timelineModel)
void QmlProfilerNotesModel::addTimelineModel(const QmlProfilerTimelineModel *timelineModel)
{
connect(timelineModel, &AbstractTimelineModel::destroyed,
connect(timelineModel, &QmlProfilerTimelineModel::destroyed,
this, &QmlProfilerNotesModel::removeTimelineModel);
m_timelineModels.insert(timelineModel->modelId(), timelineModel);
}
@@ -111,7 +111,7 @@ int QmlProfilerNotesModel::get(int timelineModel, int timelineIndex) const
int QmlProfilerNotesModel::add(int timelineModel, int timelineIndex, const QString &text)
{
const AbstractTimelineModel *model = m_timelineModels[timelineModel];
const QmlProfilerTimelineModel *model = m_timelineModels[timelineModel];
int typeId = model->typeId(timelineIndex);
Note note = { text, timelineModel, timelineIndex };
m_data << note;
@@ -162,7 +162,7 @@ int QmlProfilerNotesModel::add(int typeId, qint64 start, qint64 duration, const
int timelineIndex = -1;
const QVector<QmlProfilerDataModel::QmlEventTypeData> &types =
m_modelManager->qmlModel()->getEventTypes();
foreach (const AbstractTimelineModel *model, m_timelineModels) {
foreach (const QmlProfilerTimelineModel *model, m_timelineModels) {
if (model->accepted(types[typeId])) {
for (int i = model->firstIndex(start); i <= model->lastIndex(start + duration); ++i) {
if (i < 0)
@@ -237,7 +237,7 @@ void QmlProfilerNotesModel::saveData()
if (it == m_timelineModels.end())
continue;
const AbstractTimelineModel *model = it.value();
const QmlProfilerTimelineModel *model = it.value();
QmlProfilerDataModel::QmlEventNoteData save = {
model->typeId(note.timelineIndex), model->startTime(note.timelineIndex),
model->duration(note.timelineIndex), note.text

View File

@@ -31,7 +31,7 @@
#ifndef NOTESMODEL_H
#define NOTESMODEL_H
#include "abstracttimelinemodel.h"
#include "qmlprofilertimelinemodel.h"
#include "qmlprofilermodelmanager.h"
#include <QList>
#include <QHash>
@@ -54,7 +54,7 @@ public:
int count() const;
void setModelManager(QmlProfilerModelManager *modelManager);
void addTimelineModel(const AbstractTimelineModel *timelineModel);
void addTimelineModel(const QmlProfilerTimelineModel *timelineModel);
Q_INVOKABLE int typeId(int index) const;
Q_INVOKABLE QString text(int index) const;
@@ -86,7 +86,7 @@ private slots:
protected:
QmlProfilerModelManager *m_modelManager;
QList<Note> m_data;
QHash<int, const AbstractTimelineModel *> m_timelineModels;
QHash<int, const QmlProfilerTimelineModel *> m_timelineModels;
bool m_modified;
int add(int typeId, qint64 startTime, qint64 duration, const QString &text);

View File

@@ -32,7 +32,7 @@
#include "qmlprofilerruncontrolfactory.h"
#include "qmlprofilertool.h"
#include "abstracttimelinemodel.h"
#include "qmlprofilertimelinemodel.h"
#include <analyzerbase/analyzermanager.h>
#include <extensionsystem/pluginmanager.h>
@@ -103,7 +103,7 @@ ExtensionSystem::IPlugin::ShutdownFlag QmlProfilerPlugin::aboutToShutdown()
return SynchronousShutdown;
}
QList<AbstractTimelineModel *> QmlProfilerPlugin::getModels(QmlProfilerModelManager *manager) const
QList<QmlProfilerTimelineModel *> QmlProfilerPlugin::getModels(QmlProfilerModelManager *manager) const
{
return factory->create(manager);
}

View File

@@ -35,7 +35,7 @@
#include "qmlprofilertimelinemodelfactory.h"
#include <extensionsystem/iplugin.h>
#include "abstracttimelinemodel.h"
#include "qmlprofilertimelinemodel.h"
namespace QmlProfiler {
namespace Internal {
@@ -55,7 +55,7 @@ public:
static bool debugOutput;
static QmlProfilerPlugin *instance;
QList<AbstractTimelineModel *> getModels(QmlProfilerModelManager *manager) const;
QList<QmlProfilerTimelineModel *> getModels(QmlProfilerModelManager *manager) const;
private:
QmlProfilerTimelineModelFactory *factory;

View File

@@ -46,8 +46,8 @@ namespace Internal {
QmlProfilerRangeModel::QmlProfilerRangeModel(QmlProfilerModelManager *manager,
QmlDebug::RangeType range, QObject *parent)
: AbstractTimelineModel(manager, categoryLabel(range), QmlDebug::MaximumMessage, range, parent)
QmlDebug::RangeType range, QObject *parent) :
QmlProfilerTimelineModel(manager, categoryLabel(range), QmlDebug::MaximumMessage, range, parent)
{
m_expandedRowTypes << -1;
announceFeatures(1ULL << QmlDebug::featureFromRangeType(rangeType()));
@@ -58,7 +58,7 @@ void QmlProfilerRangeModel::clear()
m_expandedRowTypes.clear();
m_expandedRowTypes << -1;
m_data.clear();
AbstractTimelineModel::clear();
QmlProfilerTimelineModel::clear();
}
void QmlProfilerRangeModel::loadData()

View File

@@ -32,7 +32,7 @@
#ifndef QMLPROFILERRANGEMODEL_H
#define QMLPROFILERRANGEMODEL_H
#include "abstracttimelinemodel.h"
#include "qmlprofilertimelinemodel.h"
#include <qmldebug/qmlprofilereventtypes.h>
#include <qmldebug/qmlprofilereventlocation.h>
#include <QVariantList>
@@ -44,7 +44,7 @@ class QmlProfilerModelManager;
namespace Internal {
class QmlProfilerRangeModel : public AbstractTimelineModel
class QmlProfilerRangeModel : public QmlProfilerTimelineModel
{
Q_OBJECT
public:

View File

@@ -0,0 +1,112 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "qmlprofilertimelinemodel.h"
namespace QmlProfiler {
QmlProfilerTimelineModel::QmlProfilerTimelineModel(QmlProfilerModelManager *modelManager,
const QString &displayName,
QmlDebug::Message message,
QmlDebug::RangeType rangeType, QObject *parent) :
TimelineModel(modelManager->registerModelProxy(), displayName, parent), m_message(message),
m_rangeType(rangeType), m_modelManager(modelManager)
{
connect(modelManager->qmlModel(), &QmlProfilerDataModel::changed,
this, &QmlProfilerTimelineModel::dataChanged);
}
QmlDebug::RangeType QmlProfilerTimelineModel::rangeType() const
{
return m_rangeType;
}
QmlDebug::Message QmlProfilerTimelineModel::message() const
{
return m_message;
}
bool QmlProfilerTimelineModel::accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const
{
return (event.rangeType == m_rangeType && event.message == m_message);
}
bool QmlProfilerTimelineModel::handlesTypeId(int typeIndex) const
{
if (typeIndex < 0)
return false;
return accepted(modelManager()->qmlModel()->getEventTypes().at(typeIndex));
}
void QmlProfilerTimelineModel::clear()
{
TimelineModel::clear();
updateProgress(0, 1);
}
QmlProfilerModelManager *QmlProfilerTimelineModel::modelManager() const
{
return m_modelManager;
}
void QmlProfilerTimelineModel::updateProgress(qint64 count, qint64 max) const
{
m_modelManager->modelProxyCountUpdated(modelId(), count, max);
}
void QmlProfilerTimelineModel::announceFeatures(quint64 features) const
{
m_modelManager->announceFeatures(modelId(), features);
}
void QmlProfilerTimelineModel::dataChanged()
{
switch (m_modelManager->state()) {
case QmlProfilerDataState::ProcessingData:
loadData();
emit emptyChanged();
break;
case QmlProfilerDataState::ClearingData:
clear();
break;
default:
break;
}
}
int QmlProfilerTimelineModel::bindingLoopDest(int index) const
{
Q_UNUSED(index);
return -1;
}
}

View File

@@ -0,0 +1,76 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef QMLPROFILERTIMELINEMODEL_H
#define QMLPROFILERTIMELINEMODEL_H
#include "timelinemodel.h"
namespace QmlProfiler {
class QMLPROFILER_EXPORT QmlProfilerTimelineModel : public TimelineModel {
Q_OBJECT
Q_PROPERTY(QmlDebug::RangeType rangeType READ rangeType CONSTANT)
Q_PROPERTY(QmlDebug::Message message READ message CONSTANT)
Q_PROPERTY(QmlProfilerModelManager *modelManager READ modelManager CONSTANT)
public:
QmlProfilerTimelineModel(QmlProfilerModelManager *modelManager, const QString &displayName,
QmlDebug::Message message, QmlDebug::RangeType rangeType,
QObject *parent);
QmlProfilerModelManager *modelManager() const;
QmlDebug::RangeType rangeType() const;
QmlDebug::Message message() const;
virtual bool accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const;
bool handlesTypeId(int typeId) const;
Q_INVOKABLE virtual int bindingLoopDest(int index) const;
virtual void loadData() = 0;
void clear();
private slots:
void dataChanged();
protected:
void updateProgress(qint64 count, qint64 max) const;
void announceFeatures(quint64 features) const;
private:
const QmlDebug::Message m_message;
const QmlDebug::RangeType m_rangeType;
QmlProfilerModelManager *const m_modelManager;
};
}
#endif // QMLPROFILERTIMELINEMODEL_H

View File

@@ -31,7 +31,7 @@
#ifndef QMLPROFILERTIMELINEMODELFACTORY_H
#define QMLPROFILERTIMELINEMODELFACTORY_H
#include "abstracttimelinemodel.h"
#include "qmlprofilertimelinemodel.h"
#include "qmlprofilermodelmanager.h"
namespace QmlProfiler {
@@ -40,7 +40,7 @@ class QMLPROFILER_EXPORT QmlProfilerTimelineModelFactory : public QObject
{
Q_OBJECT
public:
virtual QList<AbstractTimelineModel *> create(QmlProfilerModelManager *manager) = 0;
virtual QList<QmlProfilerTimelineModel *> create(QmlProfilerModelManager *manager) = 0;
};
}

View File

@@ -0,0 +1,511 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "timelinemodel.h"
#include "timelinemodel_p.h"
#include <QLinkedList>
namespace QmlProfiler {
/*!
\class QmlProfiler::TimelineModel
\brief The TimelineModel class provides a sorted model for timeline data.
The TimelineModel lets you keep range data sorted by both start and end times, so that
visible ranges can easily be computed. The only precondition for that to work is that the ranges
must be perfectly nested. A "parent" range of a range R is defined as a range for which the
start time is earlier than R's start time and the end time is later than R's end time. A set
of ranges is perfectly nested if all parent ranges of any given range have a common parent
range. Mind that you can always make that happen by defining a range that spans the whole
available time span. That, however, will make any code that uses firstIndex() and lastIndex()
for selecting subsets of the model always select all of it.
\note Indices returned from the various methods are only valid until a new range is inserted
before them. Inserting a new range before a given index moves the range pointed to by the
index by one. Incrementing the index by one will make it point to the item again.
*/
/*!
Compute all ranges' parents.
\sa firstIndex()
*/
void TimelineModel::computeNesting()
{
Q_D(TimelineModel);
QLinkedList<int> parents;
for (int range = 0; range != count(); ++range) {
TimelineModelPrivate::Range &current = d->ranges[range];
for (QLinkedList<int>::iterator parentIt = parents.begin();;) {
if (parentIt == parents.end()) {
parents.append(range);
break;
}
TimelineModelPrivate::Range &parent = d->ranges[*parentIt];
qint64 parentEnd = parent.start + parent.duration;
if (parentEnd < current.start) {
if (parent.start == current.start) {
if (parent.parent == -1) {
parent.parent = range;
} else {
TimelineModelPrivate::Range &ancestor = d->ranges[parent.parent];
if (ancestor.start == current.start &&
ancestor.duration < current.duration)
parent.parent = range;
}
// Just switch the old parent range for the new, larger one
*parentIt = range;
break;
} else {
parentIt = parents.erase(parentIt);
}
} else if (parentEnd >= current.start + current.duration) {
// no need to insert
current.parent = *parentIt;
break;
} else {
++parentIt;
}
}
}
}
int TimelineModel::collapsedRowCount() const
{
Q_D(const TimelineModel);
return d->collapsedRowCount;
}
void TimelineModel::setCollapsedRowCount(int rows)
{
Q_D(TimelineModel);
d->collapsedRowCount = rows;
}
int TimelineModel::expandedRowCount() const
{
Q_D(const TimelineModel);
return d->expandedRowCount;
}
void QmlProfiler::TimelineModel::setExpandedRowCount(int rows)
{
Q_D(TimelineModel);
d->expandedRowCount = rows;
}
TimelineModel::TimelineModelPrivate::TimelineModelPrivate(int modelId, const QString &displayName) :
modelId(modelId), displayName(displayName), expanded(false), hidden(false),
expandedRowCount(1), collapsedRowCount(1), q_ptr(0)
{
}
void TimelineModel::TimelineModelPrivate::init(TimelineModel *q)
{
q_ptr = q;
connect(q,SIGNAL(rowHeightChanged()),q,SIGNAL(heightChanged()));
connect(q,SIGNAL(expandedChanged()),q,SIGNAL(heightChanged()));
connect(q,SIGNAL(hiddenChanged()),q,SIGNAL(heightChanged()));
}
TimelineModel::TimelineModel(TimelineModelPrivate &dd, QObject *parent) :
QObject(parent), d_ptr(&dd)
{
d_ptr->init(this);
}
TimelineModel::TimelineModel(int modelId, const QString &displayName, QObject *parent) :
QObject(parent), d_ptr(new TimelineModelPrivate(modelId, displayName))
{
d_ptr->init(this);
}
TimelineModel::~TimelineModel()
{
Q_D(TimelineModel);
delete d;
}
bool TimelineModel::isEmpty() const
{
return count() == 0;
}
int TimelineModel::modelId() const
{
Q_D(const TimelineModel);
return d->modelId;
}
int TimelineModel::rowHeight(int rowNumber) const
{
Q_D(const TimelineModel);
if (!expanded())
return TimelineModelPrivate::DefaultRowHeight;
if (d->rowOffsets.size() > rowNumber)
return d->rowOffsets[rowNumber] - (rowNumber > 0 ? d->rowOffsets[rowNumber - 1] : 0);
return TimelineModelPrivate::DefaultRowHeight;
}
int TimelineModel::rowOffset(int rowNumber) const
{
Q_D(const TimelineModel);
if (rowNumber == 0)
return 0;
if (!expanded())
return TimelineModelPrivate::DefaultRowHeight * rowNumber;
if (d->rowOffsets.size() >= rowNumber)
return d->rowOffsets[rowNumber - 1];
if (!d->rowOffsets.empty())
return d->rowOffsets.last() + (rowNumber - d->rowOffsets.size()) *
TimelineModelPrivate::DefaultRowHeight;
return rowNumber * TimelineModelPrivate::DefaultRowHeight;
}
void TimelineModel::setRowHeight(int rowNumber, int height)
{
Q_D(TimelineModel);
if (d->hidden || !d->expanded)
return;
if (height < TimelineModelPrivate::DefaultRowHeight)
height = TimelineModelPrivate::DefaultRowHeight;
int nextOffset = d->rowOffsets.empty() ? 0 : d->rowOffsets.last();
while (d->rowOffsets.size() <= rowNumber)
d->rowOffsets << (nextOffset += TimelineModelPrivate::DefaultRowHeight);
int difference = height - d->rowOffsets[rowNumber] +
(rowNumber > 0 ? d->rowOffsets[rowNumber - 1] : 0);
if (difference != 0) {
for (; rowNumber < d->rowOffsets.size(); ++rowNumber) {
d->rowOffsets[rowNumber] += difference;
}
emit rowHeightChanged();
}
}
int TimelineModel::height() const
{
Q_D(const TimelineModel);
int depth = rowCount();
if (d->hidden || !d->expanded || d->rowOffsets.empty())
return depth * TimelineModelPrivate::DefaultRowHeight;
return d->rowOffsets.last() + (depth - d->rowOffsets.size()) *
TimelineModelPrivate::DefaultRowHeight;
}
/*!
Returns the number of ranges in the model.
*/
int TimelineModel::count() const
{
Q_D(const TimelineModel);
return d->ranges.count();
}
qint64 TimelineModel::duration(int index) const
{
Q_D(const TimelineModel);
return d->ranges[index].duration;
}
qint64 TimelineModel::startTime(int index) const
{
Q_D(const TimelineModel);
return d->ranges[index].start;
}
qint64 TimelineModel::endTime(int index) const
{
Q_D(const TimelineModel);
return d->ranges[index].start + d->ranges[index].duration;
}
/*!
Returns the type ID of the event with event ID \a index. The type ID is a globally valid ID
which can be used to communicate meta information about events to other parts of the program. By
default it is -1, which means there is no global type information about the event.
*/
int TimelineModel::typeId(int index) const
{
Q_UNUSED(index)
return -1;
}
/*!
Looks up the first range with an end time later than the given time and
returns its parent's index. If no such range is found, it returns -1. If there
is no parent, it returns the found range's index. The parent of a range is the
range with the earliest start time that completely covers the child range.
"Completely covers" means:
parent.startTime <= child.startTime && parent.endTime >= child.endTime
*/
int TimelineModel::firstIndex(qint64 startTime) const
{
Q_D(const TimelineModel);
int index = firstIndexNoParents(startTime);
if (index == -1)
return -1;
int parent = d->ranges[index].parent;
return parent == -1 ? index : parent;
}
/*!
Looks up the first range with an end time later than the specified \a startTime and
returns its index. If no such range is found, it returns -1.
*/
int TimelineModel::firstIndexNoParents(qint64 startTime) const
{
Q_D(const TimelineModel);
// in the "endtime" list, find the first event that ends after startTime
if (d->endTimes.isEmpty())
return -1;
if (d->endTimes.count() == 1 || d->endTimes.first().end > startTime)
return d->endTimes.first().startIndex;
if (d->endTimes.last().end <= startTime)
return -1;
return d->endTimes[d->lowerBound(d->endTimes, startTime) + 1].startIndex;
}
/*!
Looks up the last range with a start time earlier than the specified \a endTime and
returns its index. If no such range is found, it returns -1.
*/
int TimelineModel::lastIndex(qint64 endTime) const
{
Q_D(const TimelineModel);
// in the "starttime" list, find the last event that starts before endtime
if (d->ranges.isEmpty() || d->ranges.first().start >= endTime)
return -1;
if (d->ranges.count() == 1)
return 0;
if (d->ranges.last().start < endTime)
return d->ranges.count() - 1;
return d->lowerBound(d->ranges, endTime);
}
QVariantMap TimelineModel::location(int index) const
{
Q_UNUSED(index);
QVariantMap map;
return map;
}
/*!
Returns \c true if this model can contain events of global type ID \a typeIndex. Otherwise
returns \c false. The base model does not know anything about type IDs and always returns
\c false. You should override this method if you implement \l typeId().
*/
bool TimelineModel::handlesTypeId(int typeIndex) const
{
Q_UNUSED(typeIndex);
return false;
}
int TimelineModel::selectionIdForLocation(const QString &filename, int line, int column) const
{
Q_UNUSED(filename);
Q_UNUSED(line);
Q_UNUSED(column);
return -1;
}
float TimelineModel::relativeHeight(int index) const
{
Q_UNUSED(index);
return 1.0f;
}
int TimelineModel::rowMinValue(int rowNumber) const
{
Q_UNUSED(rowNumber);
return 0;
}
int TimelineModel::rowMaxValue(int rowNumber) const
{
Q_UNUSED(rowNumber);
return 0;
}
int TimelineModel::defaultRowHeight()
{
return TimelineModelPrivate::DefaultRowHeight;
}
QColor TimelineModel::colorBySelectionId(int index) const
{
return colorByHue(selectionId(index) * TimelineModelPrivate::SelectionIdHueMultiplier);
}
QColor TimelineModel::colorByFraction(double fraction) const
{
return colorByHue(fraction * TimelineModelPrivate::FractionHueMultiplier +
TimelineModelPrivate::FractionHueMininimum);
}
QColor TimelineModel::colorByHue(int hue) const
{
return QColor::fromHsl(hue % 360, TimelineModelPrivate::Saturation,
TimelineModelPrivate::Lightness);
}
/*!
Inserts the range defined by \a duration and \a selectionId at the specified \a startTime and
returns its index. The \a selectionId determines the selection group the new event belongs to.
\sa selectionId()
*/
int TimelineModel::insert(qint64 startTime, qint64 duration, int selectionId)
{
Q_D(TimelineModel);
/* Doing insert-sort here is preferable as most of the time the times will actually be
* presorted in the right way. So usually this will just result in appending. */
int index = d->insertSorted(d->ranges,
TimelineModelPrivate::Range(startTime, duration, selectionId));
if (index < d->ranges.size() - 1)
d->incrementStartIndices(index);
d->insertSorted(d->endTimes, TimelineModelPrivate::RangeEnd(index, startTime + duration));
return index;
}
/*!
Inserts the specified \a selectionId as range start at the specified \a startTime and returns
its index. The range end is not set. The \a selectionId determines the selection group the new
event belongs to.
\sa selectionId()
*/
int TimelineModel::insertStart(qint64 startTime, int selectionId)
{
Q_D(TimelineModel);
int index = d->insertSorted(d->ranges, TimelineModelPrivate::Range(startTime, 0, selectionId));
if (index < d->ranges.size() - 1)
d->incrementStartIndices(index);
return index;
}
/*!
Adds the range \a duration at the specified start \a index.
*/
void TimelineModel::insertEnd(int index, qint64 duration)
{
Q_D(TimelineModel);
d->ranges[index].duration = duration;
d->insertSorted(d->endTimes, TimelineModelPrivate::RangeEnd(index,
d->ranges[index].start + duration));
}
bool TimelineModel::expanded() const
{
Q_D(const TimelineModel);
return d->expanded;
}
void TimelineModel::setExpanded(bool expanded)
{
Q_D(TimelineModel);
if (expanded != d->expanded) {
d->expanded = expanded;
emit expandedChanged();
}
}
bool TimelineModel::hidden() const
{
Q_D(const TimelineModel);
return d->hidden;
}
void TimelineModel::setHidden(bool hidden)
{
Q_D(TimelineModel);
if (hidden != d->hidden) {
d->hidden = hidden;
emit hiddenChanged();
}
}
QString TimelineModel::displayName() const
{
Q_D(const TimelineModel);
return d->displayName;
}
int TimelineModel::rowCount() const
{
Q_D(const TimelineModel);
if (d->hidden || isEmpty())
return 0;
return d->expanded ? d->expandedRowCount : d->collapsedRowCount;
}
/*!
Returns the ID of the selection group the event with event ID \a index belongs to. Selection
groups are local to the model and the model can arbitrarily assign events to selection groups
when inserting them.
If one event from a selection group is selected, all visible other events from the same
selection group are highlighted. Rows are expected to correspond to selection IDs when the view
is expanded.
*/
int TimelineModel::selectionId(int index) const
{
Q_D(const TimelineModel);
return d->ranges[index].selectionId;
}
void TimelineModel::clear()
{
Q_D(TimelineModel);
d->collapsedRowCount = d->expandedRowCount = 1;
bool wasExpanded = d->expanded;
bool wasHidden = d->hidden;
bool hadRowHeights = !d->rowOffsets.empty();
d->rowOffsets.clear();
d->expanded = false;
d->hidden = false;
d->ranges.clear();
d->endTimes.clear();
if (hadRowHeights)
emit rowHeightChanged();
if (wasExpanded)
emit expandedChanged();
if (wasHidden)
emit hiddenChanged();
}
}
#include "moc_timelinemodel.cpp"

View File

@@ -28,8 +28,8 @@
**
****************************************************************************/
#ifndef ABSTRACTTIMELINEMODEL_H
#define ABSTRACTTIMELINEMODEL_H
#ifndef TIMELINEMODEL_H
#define TIMELINEMODEL_H
#include "qmlprofiler_global.h"
@@ -40,30 +40,24 @@
namespace QmlProfiler {
class QMLPROFILER_EXPORT AbstractTimelineModel : public QObject
class QMLPROFILER_EXPORT TimelineModel : public QObject
{
Q_OBJECT
Q_PROPERTY(int modelId READ modelId CONSTANT)
Q_PROPERTY(QString displayName READ displayName CONSTANT)
Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged)
Q_PROPERTY(bool hidden READ hidden WRITE setHidden NOTIFY hiddenChanged)
Q_PROPERTY(int height READ height NOTIFY heightChanged)
Q_PROPERTY(QmlProfilerModelManager *modelManager READ modelManager)
public:
class AbstractTimelineModelPrivate;
class TimelineModelPrivate;
AbstractTimelineModel(QmlProfilerModelManager *manager, const QString &displayName,
QmlDebug::Message message, QmlDebug::RangeType rangeType,
QObject *parent);
~AbstractTimelineModel();
// Trivial methods implemented by the abstract model itself
QmlProfilerModelManager *modelManager() const;
TimelineModel(int modelId, const QString &displayName, QObject *parent);
~TimelineModel();
// Methods implemented by the abstract model itself
bool isEmpty() const;
int modelId() const;
// Methods are directly passed on to the private model and relying on its virtual methods.
int rowHeight(int rowNumber) const;
int rowOffset(int rowNumber) const;
void setRowHeight(int rowNumber, int height);
@@ -96,9 +90,7 @@ public:
virtual QVariantMap location(int index) const;
virtual int typeId(int index) const;
virtual bool handlesTypeId(int typeId) const;
virtual bool accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const;
virtual int selectionIdForLocation(const QString &filename, int line, int column) const;
virtual int bindingLoopDest(int index) const;
virtual float relativeHeight(int index) const;
virtual int rowMinValue(int rowNumber) const;
virtual int rowMaxValue(int rowNumber) const;
@@ -128,26 +120,15 @@ protected:
int expandedRowCount() const;
void setExpandedRowCount(int rows);
QmlDebug::RangeType rangeType() const;
QmlDebug::Message message() const;
void updateProgress(qint64 count, qint64 max) const;
void announceFeatures(quint64 features) const;
explicit AbstractTimelineModel(AbstractTimelineModelPrivate *dd,
QmlProfilerModelManager *manager, const QString &displayName,
QmlDebug::Message message, QmlDebug::RangeType rangeType,
QObject *parent);
AbstractTimelineModelPrivate *d_ptr;
virtual void loadData() = 0;
virtual void clear();
explicit TimelineModel(TimelineModelPrivate &dd, QObject *parent);
TimelineModelPrivate *d_ptr;
private:
Q_DECLARE_PRIVATE(AbstractTimelineModel)
Q_PRIVATE_SLOT(d_func(), void _q_dataChanged())
Q_DECLARE_PRIVATE(TimelineModel)
};
}
#endif // ABSTRACTTIMELINEMODEL_H
#endif // TIMELINEMODEL_H

View File

@@ -28,14 +28,14 @@
**
****************************************************************************/
#ifndef ABSTRACTTIMELINEMODEL_P_H
#define ABSTRACTTIMELINEMODEL_P_H
#ifndef TIMELINEMODEL_P_H
#define TIMELINEMODEL_P_H
#include "abstracttimelinemodel.h"
#include "timelinemodel.h"
namespace QmlProfiler {
class QMLPROFILER_EXPORT AbstractTimelineModel::AbstractTimelineModelPrivate {
class QMLPROFILER_EXPORT TimelineModel::TimelineModelPrivate {
public:
static const int DefaultRowHeight = 30;
@@ -67,11 +67,10 @@ public:
inline qint64 timestamp() const {return end;}
};
void init(AbstractTimelineModel *q, QmlProfilerModelManager *manager,
const QString &displayName, QmlDebug::Message message, QmlDebug::RangeType rangeType);
TimelineModelPrivate(int modelId, const QString &displayName);
void init(TimelineModel *q);
inline qint64 lastEndTime() const { return endTimes.last().end; }
inline qint64 firstStartTime() const { return ranges.first().start; }
int firstIndexNoParents(qint64 startTime) const;
void incrementStartIndices(int index)
{
@@ -112,28 +111,24 @@ public:
return fromIndex;
}
void _q_dataChanged();
QVector<Range> ranges;
QVector<RangeEnd> endTimes;
QVector<int> rowOffsets;
QmlProfilerModelManager *modelManager;
int modelId;
const int modelId;
const QString displayName;
bool expanded;
bool hidden;
int expandedRowCount;
int collapsedRowCount;
QString displayName;
QmlDebug::Message message;
QmlDebug::RangeType rangeType;
protected:
AbstractTimelineModel *q_ptr;
TimelineModel *q_ptr;
private:
Q_DECLARE_PUBLIC(AbstractTimelineModel)
Q_DECLARE_PUBLIC(TimelineModel)
};
}
#endif // ABSTRACTTIMELINEMODEL_P_H
#endif // TIMELINEMODEL_P_H

View File

@@ -52,7 +52,7 @@ public:
// mapping of modelId assigned by manager to index in our list
QList <int> modelManagerIndexMapping;
QList <AbstractTimelineModel *> modelList;
QList <QmlProfilerTimelineModel *> modelList;
QmlProfilerModelManager *modelManager;
};
@@ -80,7 +80,7 @@ void TimelineModelAggregator::setModelManager(QmlProfilerModelManager *modelMana
connect(modelManager,SIGNAL(dataAvailable()),this,SIGNAL(dataAvailable()));
// external models pushed on top
foreach (AbstractTimelineModel *timelineModel,
foreach (QmlProfilerTimelineModel *timelineModel,
QmlProfilerPlugin::instance->getModels(modelManager)) {
addModel(timelineModel);
}
@@ -96,7 +96,7 @@ void TimelineModelAggregator::setModelManager(QmlProfilerModelManager *modelMana
this, SIGNAL(notesChanged(int,int,int)));
}
void TimelineModelAggregator::addModel(AbstractTimelineModel *m)
void TimelineModelAggregator::addModel(QmlProfilerTimelineModel *m)
{
while (d->modelManagerIndexMapping.size() <= m->modelId())
d->modelManagerIndexMapping.append(-1);
@@ -110,7 +110,7 @@ void TimelineModelAggregator::addModel(AbstractTimelineModel *m)
emit modelsChanged(d->modelList.length(), d->modelList.length());
}
const AbstractTimelineModel *TimelineModelAggregator::model(int modelIndex) const
const QmlProfilerTimelineModel *TimelineModelAggregator::model(int modelIndex) const
{
return d->modelList[modelIndex];
}
@@ -118,7 +118,7 @@ const AbstractTimelineModel *TimelineModelAggregator::model(int modelIndex) cons
QVariantList TimelineModelAggregator::models() const
{
QVariantList ret;
foreach (AbstractTimelineModel *model, d->modelList)
foreach (QmlProfilerTimelineModel *model, d->modelList)
ret << QVariant::fromValue(model);
return ret;
}
@@ -140,7 +140,7 @@ int TimelineModelAggregator::count(int modelIndex) const
bool TimelineModelAggregator::isEmpty() const
{
foreach (const AbstractTimelineModel *modelProxy, d->modelList)
foreach (const QmlProfilerTimelineModel *modelProxy, d->modelList)
if (!modelProxy->isEmpty())
return false;
return true;
@@ -297,8 +297,8 @@ int TimelineModelAggregator::selectionIdForLocation(int modelIndex, const QStrin
void TimelineModelAggregator::swapModels(int modelIndex1, int modelIndex2)
{
AbstractTimelineModel *&model1 = d->modelList[modelIndex1];
AbstractTimelineModel *&model2 = d->modelList[modelIndex2];
QmlProfilerTimelineModel *&model1 = d->modelList[modelIndex1];
QmlProfilerTimelineModel *&model2 = d->modelList[modelIndex2];
std::swap(d->modelManagerIndexMapping[model1->modelId()],
d->modelManagerIndexMapping[model2->modelId()]);
std::swap(model1, model2);

View File

@@ -31,7 +31,7 @@
#ifndef TIMELINEMODELAGGREGATOR_H
#define TIMELINEMODELAGGREGATOR_H
#include "abstracttimelinemodel.h"
#include "qmlprofilertimelinemodel.h"
#include "qmlprofilermodelmanager.h"
namespace QmlProfiler {
@@ -49,8 +49,8 @@ public:
int height() const;
void setModelManager(QmlProfilerModelManager *modelManager);
void addModel(AbstractTimelineModel *m);
const AbstractTimelineModel *model(int modelIndex) const;
void addModel(QmlProfilerTimelineModel *m);
const QmlProfilerTimelineModel *model(int modelIndex) const;
QVariantList models() const;
int modelIndexFromManagerIndex(int modelManagerIndex) const;

View File

@@ -1,4 +1,4 @@
TEMPLATE = subdirs
SUBDIRS = \
abstracttimelinemodel
timelinemodel

View File

@@ -2,4 +2,4 @@ QTC_PLUGIN_DEPENDS += qmlprofiler
include(../../qttest.pri)
SOURCES += \
tst_abstracttimelinemodel.cpp
tst_timelinemodel.cpp

View File

@@ -29,8 +29,7 @@
****************************************************************************/
#include <QtTest>
#include <qmlprofiler/abstracttimelinemodel.h>
#include <qmlprofiler/abstracttimelinemodel_p.h>
#include <qmlprofiler/timelinemodel.h>
using namespace QmlProfiler;
@@ -40,24 +39,24 @@ static const qint64 ItemDuration = 1 << 19;
static const qint64 ItemSpacing = 1 << 20;
class DummyModelPrivate;
class DummyModel : public AbstractTimelineModel
class DummyModel : public TimelineModel
{
Q_OBJECT
Q_DECLARE_PRIVATE(DummyModel)
friend class tst_AbstractTimelineModel;
friend class tst_TimelineModel;
public:
DummyModel(QString displayName = tr("dummy"), QObject *parent = 0);
int selectionId(int index) const { return index; }
int typeId(int index) const { return index; }
QColor color(int) const { return QColor(); }
QVariantList labels() const { return QVariantList(); }
QVariantMap details(int) const { return QVariantMap(); }
int row(int) const { return 1; }
quint64 features() const { return 0; }
protected:
void loadData();
};
class tst_AbstractTimelineModel : public QObject
class tst_TimelineModel : public QObject
{
Q_OBJECT
@@ -66,7 +65,6 @@ private slots:
void rowHeight();
void rowOffset();
void height();
void accepted();
void expand();
void hide();
void displayName();
@@ -77,20 +75,19 @@ private slots:
};
DummyModel::DummyModel(QString displayName, QObject *parent) :
AbstractTimelineModel(new QmlProfilerModelManager(0, parent), displayName,
QmlDebug::MaximumMessage, QmlDebug::MaximumRangeType, parent)
TimelineModel(0, displayName, parent)
{
}
void DummyModel::loadData()
{
for (int i = 0; i < NumItems; ++i)
insert(i * ItemSpacing, ItemDuration, 0);
insert(i * ItemSpacing, ItemDuration, 5);
setCollapsedRowCount(2);
setExpandedRowCount(2);
}
void tst_AbstractTimelineModel::isEmpty()
void tst_TimelineModel::isEmpty()
{
DummyModel dummy;
QVERIFY(dummy.isEmpty());
@@ -100,7 +97,7 @@ void tst_AbstractTimelineModel::isEmpty()
QVERIFY(dummy.isEmpty());
}
void tst_AbstractTimelineModel::rowHeight()
void tst_TimelineModel::rowHeight()
{
DummyModel dummy;
QCOMPARE(dummy.rowHeight(0), DefaultRowHeight);
@@ -135,7 +132,7 @@ void tst_AbstractTimelineModel::rowHeight()
QCOMPARE(dummy.rowHeight(1), 50);
}
void tst_AbstractTimelineModel::rowOffset()
void tst_TimelineModel::rowOffset()
{
DummyModel dummy;
QCOMPARE(dummy.rowOffset(0), 0);
@@ -164,10 +161,10 @@ void tst_AbstractTimelineModel::rowOffset()
QCOMPARE(dummy.rowOffset(1), 100);
}
void tst_AbstractTimelineModel::height()
void tst_TimelineModel::height()
{
DummyModel dummy;
QCOMPARE(dummy.height(), DefaultRowHeight);
QCOMPARE(dummy.height(), 0);
dummy.loadData();
QCOMPARE(dummy.height(), 2 * DefaultRowHeight);
dummy.setExpanded(true);
@@ -176,22 +173,7 @@ void tst_AbstractTimelineModel::height()
QCOMPARE(dummy.height(), DefaultRowHeight + 80);
}
void tst_AbstractTimelineModel::accepted()
{
DummyModel dummy;
QmlProfilerDataModel::QmlEventTypeData event;
event.message = QmlDebug::MaximumMessage;
event.rangeType = QmlDebug::MaximumRangeType;
QVERIFY(dummy.accepted(event));
event.message = QmlDebug::Event;
QVERIFY(!dummy.accepted(event));
event.rangeType = QmlDebug::Painting;
QVERIFY(!dummy.accepted(event));
event.message = QmlDebug::MaximumMessage;
QVERIFY(!dummy.accepted(event));
}
void tst_AbstractTimelineModel::expand()
void tst_TimelineModel::expand()
{
DummyModel dummy;
QSignalSpy spy(&dummy, SIGNAL(expandedChanged()));
@@ -210,7 +192,7 @@ void tst_AbstractTimelineModel::expand()
QCOMPARE(spy.count(), 2);
}
void tst_AbstractTimelineModel::hide()
void tst_TimelineModel::hide()
{
DummyModel dummy;
QSignalSpy spy(&dummy, SIGNAL(hiddenChanged()));
@@ -229,45 +211,45 @@ void tst_AbstractTimelineModel::hide()
QCOMPARE(spy.count(), 2);
}
void tst_AbstractTimelineModel::displayName()
void tst_TimelineModel::displayName()
{
QLatin1String name("testest");
DummyModel dummy(name);
QCOMPARE(dummy.displayName(), name);
}
void tst_AbstractTimelineModel::defaultValues()
void tst_TimelineModel::defaultValues()
{
DummyModel dummy;
dummy.loadData();
QCOMPARE(dummy.location(0), QVariantMap());
QCOMPARE(dummy.handlesTypeId(0), false);
QCOMPARE(dummy.selectionIdForLocation(QString(), 0, 0), -1);
QCOMPARE(dummy.bindingLoopDest(0), -1);
QCOMPARE(dummy.relativeHeight(0), 1.0);
QCOMPARE(dummy.rowMinValue(0), 0);
QCOMPARE(dummy.rowMaxValue(0), 0);
}
void tst_AbstractTimelineModel::colorByHue()
void tst_TimelineModel::colorByHue()
{
DummyModel dummy;
QCOMPARE(dummy.colorByHue(10), QColor::fromHsl(10, 150, 166));
QCOMPARE(dummy.colorByHue(500), QColor::fromHsl(140, 150, 166));
}
void tst_AbstractTimelineModel::colorBySelectionId()
void tst_TimelineModel::colorBySelectionId()
{
DummyModel dummy;
dummy.loadData();
QCOMPARE(dummy.colorBySelectionId(5), QColor::fromHsl(0, 150, 166));
QCOMPARE(dummy.colorBySelectionId(5), QColor::fromHsl(5 * 25, 150, 166));
}
void tst_AbstractTimelineModel::colorByFraction()
void tst_TimelineModel::colorByFraction()
{
DummyModel dummy;
QCOMPARE(dummy.colorByFraction(0.5), QColor::fromHsl(0.5 * 96 + 10, 150, 166));
}
QTEST_MAIN(tst_AbstractTimelineModel)
QTEST_MAIN(tst_TimelineModel)
#include "tst_abstracttimelinemodel.moc"
#include "tst_timelinemodel.moc"