forked from qt-creator/qt-creator
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:
@@ -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 ¤t = 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"
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
112
src/plugins/qmlprofiler/qmlprofilertimelinemodel.cpp
Normal file
112
src/plugins/qmlprofiler/qmlprofilertimelinemodel.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
76
src/plugins/qmlprofiler/qmlprofilertimelinemodel.h
Normal file
76
src/plugins/qmlprofiler/qmlprofilertimelinemodel.h
Normal 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
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
511
src/plugins/qmlprofiler/timelinemodel.cpp
Normal file
511
src/plugins/qmlprofiler/timelinemodel.cpp
Normal 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 ¤t = 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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS = \
|
||||
abstracttimelinemodel
|
||||
timelinemodel
|
||||
|
||||
@@ -2,4 +2,4 @@ QTC_PLUGIN_DEPENDS += qmlprofiler
|
||||
include(../../qttest.pri)
|
||||
|
||||
SOURCES += \
|
||||
tst_abstracttimelinemodel.cpp
|
||||
tst_timelinemodel.cpp
|
||||
@@ -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"
|
||||
Reference in New Issue
Block a user