From b7742f79b621ed6424fc5f9a3097208a0ba64768 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 27 Oct 2014 18:42:39 +0100 Subject: [PATCH] QmlProfiler: Merge SortedTimelineModel into AbstractTimelineModel In order to provide a stable interface we need most of SortedTimelineModel to be private. There is no real benefit in keeping a distinction between AbstractTimelineModel and SortedTimelineModel as SortedTimelineModel isn't very useful on its own. Change-Id: Ibc6945e2740320f430f2634f95c7807d6b460123 Reviewed-by: Kai Koehne --- .../qmlprofiler/abstracttimelinemodel.cpp | 268 ++++++++++++++++-- .../qmlprofiler/abstracttimelinemodel.h | 20 +- .../qmlprofiler/abstracttimelinemodel_p.h | 68 +++++ src/plugins/qmlprofiler/qmlprofiler.pro | 2 - src/plugins/qmlprofiler/qmlprofiler.qbs | 1 - .../qmlprofileranimationsmodel.cpp | 2 +- .../qmlprofiler/qmlprofilernotesmodel.cpp | 12 +- .../qmlprofiler/qmlprofilerrangemodel.cpp | 20 +- .../qmlprofiler/sortedtimelinemodel.cpp | 165 ----------- src/plugins/qmlprofiler/sortedtimelinemodel.h | 190 ------------- 10 files changed, 353 insertions(+), 395 deletions(-) delete mode 100644 src/plugins/qmlprofiler/sortedtimelinemodel.cpp delete mode 100644 src/plugins/qmlprofiler/sortedtimelinemodel.h diff --git a/src/plugins/qmlprofiler/abstracttimelinemodel.cpp b/src/plugins/qmlprofiler/abstracttimelinemodel.cpp index bb107b7e89a..5545d371ff5 100644 --- a/src/plugins/qmlprofiler/abstracttimelinemodel.cpp +++ b/src/plugins/qmlprofiler/abstracttimelinemodel.cpp @@ -31,28 +31,124 @@ #include "abstracttimelinemodel.h" #include "abstracttimelinemodel_p.h" +#include + 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 parents; + for (int range = 0; range != count(); ++range) { + AbstractTimelineModelPrivate::Range ¤t = d->ranges[range]; + for (QLinkedList::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; + } + } + } +} + +void AbstractTimelineModel::AbstractTimelineModelPrivate::init(AbstractTimelineModel *q, + const QString &newDisplayName, + QmlDebug::Message newMessage, + QmlDebug::RangeType newRangeType) +{ + q_ptr = q; + modelId = 0; + modelManager = 0; + expanded = false; + hidden = false; + displayName = newDisplayName; + message = newMessage; + rangeType = newRangeType; + expandedRowCount = 1; + collapsedRowCount = 1; + 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, const QString &displayName, QmlDebug::Message message, QmlDebug::RangeType rangeType, QObject *parent) : - SortedTimelineModel(parent), d_ptr(dd) + QObject(parent), d_ptr(dd) { - Q_D(AbstractTimelineModel); - connect(this,SIGNAL(rowHeightChanged()),this,SIGNAL(heightChanged())); - connect(this,SIGNAL(expandedChanged()),this,SIGNAL(heightChanged())); - connect(this,SIGNAL(hiddenChanged()),this,SIGNAL(heightChanged())); + dd->init(this, displayName, message, rangeType); +} - d->q_ptr = this; - d->modelId = 0; - d->modelManager = 0; - d->expanded = false; - d->hidden = false; - d->displayName = displayName; - d->message = message; - d->rangeType = rangeType; - d->expandedRowCount = 1; - d->collapsedRowCount = 1; +AbstractTimelineModel::AbstractTimelineModel(const QString &displayName, QmlDebug::Message message, + QmlDebug::RangeType rangeType, QObject *parent) : + QObject(parent), d_ptr(new AbstractTimelineModelPrivate) +{ + d_ptr->init(this, displayName, message, rangeType); } AbstractTimelineModel::~AbstractTimelineModel() @@ -138,6 +234,97 @@ int AbstractTimelineModel::height() const return d->rowOffsets.last() + (depth - d->rowOffsets.size()) * 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; +} + +int AbstractTimelineModel::typeId(int index) const +{ + Q_D(const AbstractTimelineModel); + return d->ranges[index].typeId; +} + +/*! + \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); @@ -183,6 +370,51 @@ int AbstractTimelineModel::rowMaxValue(int rowNumber) const return 0; } +/*! + \fn int AbstractTimelineModel::insert(qint64 startTime, qint64 duration) + Inserts a range at the given time position and returns its index. +*/ +int AbstractTimelineModel::insert(qint64 startTime, qint64 duration, int typeId) +{ + 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, typeId)); + if (index < d->ranges.size() - 1) + d->incrementStartIndices(index); + d->insertSorted(d->endTimes, + AbstractTimelineModelPrivate::RangeEnd(index, startTime + duration)); + return index; +} + +/*! + \fn int AbstractTimelineModel::insertStart(qint64 startTime, int typeId) + Inserts the given data as range start at the given time position and + returns its index. The range end is not set. +*/ +int AbstractTimelineModel::insertStart(qint64 startTime, int typeId) +{ + Q_D(AbstractTimelineModel); + int index = d->insertSorted(d->ranges, + AbstractTimelineModelPrivate::Range(startTime, 0, typeId)); + 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::dataChanged() { Q_D(AbstractTimelineModel); @@ -255,7 +487,8 @@ int AbstractTimelineModel::rowCount() const int AbstractTimelineModel::selectionId(int index) const { - return range(index).typeId; + Q_D(const AbstractTimelineModel); + return d->ranges[index].typeId; } void AbstractTimelineModel::clear() @@ -268,7 +501,8 @@ void AbstractTimelineModel::clear() d->rowOffsets.clear(); d->expanded = false; d->hidden = false; - SortedTimelineModel::clear(); + d->ranges.clear(); + d->endTimes.clear(); if (hadRowHeights) emit rowHeightChanged(); if (wasExpanded) diff --git a/src/plugins/qmlprofiler/abstracttimelinemodel.h b/src/plugins/qmlprofiler/abstracttimelinemodel.h index 5aff5e91d14..54758e04d09 100644 --- a/src/plugins/qmlprofiler/abstracttimelinemodel.h +++ b/src/plugins/qmlprofiler/abstracttimelinemodel.h @@ -35,13 +35,12 @@ #include "qmlprofiler_global.h" #include "qmlprofilermodelmanager.h" #include "qmlprofilerdatamodel.h" -#include "sortedtimelinemodel.h" #include #include namespace QmlProfiler { -class QMLPROFILER_EXPORT AbstractTimelineModel : public SortedTimelineModel +class QMLPROFILER_EXPORT AbstractTimelineModel : public QObject { Q_OBJECT Q_PROPERTY(QString displayName READ displayName CONSTANT) @@ -51,6 +50,9 @@ class QMLPROFILER_EXPORT AbstractTimelineModel : public SortedTimelineModel public: class AbstractTimelineModelPrivate; + + AbstractTimelineModel(const QString &displayName, QmlDebug::Message message, + QmlDebug::RangeType rangeType, QObject *parent); ~AbstractTimelineModel(); // Trivial methods implemented by the abstract model itself @@ -63,6 +65,15 @@ public: int rowOffset(int rowNumber) const; void setRowHeight(int rowNumber, int height); int height() const; + int count() const; + qint64 duration(int index) const; + qint64 startTime(int index) const; + qint64 endTime(int index) const; + int typeId(int index) const; + + int firstIndex(qint64 startTime) const; + int firstIndexNoParents(qint64 startTime) const; + int lastIndex(qint64 endTime) const; bool accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const; bool expanded() const; @@ -123,6 +134,11 @@ protected: return QColor::fromHsl(hue % 360, Saturation, Lightness); } + int insert(qint64 startTime, qint64 duration, int typeId); + int insertStart(qint64 startTime, int typeId); + void insertEnd(int index, qint64 duration); + void computeNesting(); + explicit AbstractTimelineModel(AbstractTimelineModelPrivate *dd, const QString &displayName, QmlDebug::Message message, QmlDebug::RangeType rangeType, QObject *parent); diff --git a/src/plugins/qmlprofiler/abstracttimelinemodel_p.h b/src/plugins/qmlprofiler/abstracttimelinemodel_p.h index c487b791167..c415dcff04a 100644 --- a/src/plugins/qmlprofiler/abstracttimelinemodel_p.h +++ b/src/plugins/qmlprofiler/abstracttimelinemodel_p.h @@ -37,6 +37,74 @@ namespace QmlProfiler { class QMLPROFILER_EXPORT AbstractTimelineModel::AbstractTimelineModelPrivate { public: + struct Range { + Range() : start(-1), duration(-1), typeId(-1), parent(-1) {} + Range(qint64 start, qint64 duration, int typeId) : + start(start), duration(duration), typeId(typeId), parent(-1) {} + qint64 start; + qint64 duration; + int typeId; + int parent; + inline qint64 timestamp() const {return start;} + }; + + struct RangeEnd { + RangeEnd() : startIndex(-1), end(-1) {} + RangeEnd(int startIndex, qint64 end) : + startIndex(startIndex), end(end) {} + int startIndex; + qint64 end; + inline qint64 timestamp() const {return end;} + }; + + void init(AbstractTimelineModel *q, const QString &displayName, QmlDebug::Message message, + QmlDebug::RangeType rangeType); + + inline qint64 lastEndTime() const { return endTimes.last().end; } + inline qint64 firstStartTime() const { return ranges.first().start; } + + void incrementStartIndices(int index) + { + for (int i = 0; i < endTimes.size(); ++i) { + if (endTimes[i].startIndex >= index) + endTimes[i].startIndex++; + } + } + + template + static inline int insertSorted(QVector &container, const RangeDelimiter &item) + { + for (int i = container.count();;) { + if (i == 0) { + container.prepend(item); + return 0; + } + if (container[--i].timestamp() <= item.timestamp()) { + container.insert(++i, item); + return i; + } + } + } + + template + static inline int lowerBound(const QVector &container, qint64 time) + { + int fromIndex = 0; + int toIndex = container.count() - 1; + while (toIndex - fromIndex > 1) { + int midIndex = (fromIndex + toIndex)/2; + if (container[midIndex].timestamp() < time) + fromIndex = midIndex; + else + toIndex = midIndex; + } + + return fromIndex; + } + + QVector ranges; + QVector endTimes; + QVector rowOffsets; QmlProfilerModelManager *modelManager; int modelId; diff --git a/src/plugins/qmlprofiler/qmlprofiler.pro b/src/plugins/qmlprofiler/qmlprofiler.pro index 8b2ec8aef51..6b35ed75a23 100644 --- a/src/plugins/qmlprofiler/qmlprofiler.pro +++ b/src/plugins/qmlprofiler/qmlprofiler.pro @@ -30,7 +30,6 @@ SOURCES += \ qmlprofilerviewmanager.cpp \ qv8profilerdatamodel.cpp \ qv8profilereventview.cpp \ - sortedtimelinemodel.cpp \ timelinemodelaggregator.cpp \ timelinerenderer.cpp \ timelinezoomcontrol.cpp @@ -66,7 +65,6 @@ HEADERS += \ qmlprofilerviewmanager.h \ qv8profilerdatamodel.h \ qv8profilereventview.h \ - sortedtimelinemodel.h \ timelinemodelaggregator.h \ timelinerenderer.h \ timelinezoomcontrol.h diff --git a/src/plugins/qmlprofiler/qmlprofiler.qbs b/src/plugins/qmlprofiler/qmlprofiler.qbs index 67f01cb424b..39a4f1948fe 100644 --- a/src/plugins/qmlprofiler/qmlprofiler.qbs +++ b/src/plugins/qmlprofiler/qmlprofiler.qbs @@ -48,7 +48,6 @@ QtcPlugin { "qmlprofilerviewmanager.cpp", "qmlprofilerviewmanager.h", "qv8profilerdatamodel.cpp", "qv8profilerdatamodel.h", "qv8profilereventview.h", "qv8profilereventview.cpp", - "sortedtimelinemodel.h", "sortedtimelinemodel.cpp", "timelinemodelaggregator.cpp", "timelinemodelaggregator.h", "timelinerenderer.cpp", "timelinerenderer.h", "timelinezoomcontrol.cpp", "timelinezoomcontrol.h" diff --git a/src/plugins/qmlprofiler/qmlprofileranimationsmodel.cpp b/src/plugins/qmlprofiler/qmlprofileranimationsmodel.cpp index 147cb21f3d5..177dcc3ea82 100644 --- a/src/plugins/qmlprofiler/qmlprofileranimationsmodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofileranimationsmodel.cpp @@ -237,7 +237,7 @@ QVariantMap QmlProfilerAnimationsModel::details(int index) const QVariantMap result; result.insert(QStringLiteral("displayName"), displayName()); - result.insert(tr("Duration"), QmlProfilerBaseModel::formatTime(range(index).duration)); + result.insert(tr("Duration"), QmlProfilerBaseModel::formatTime(duration(index))); result.insert(tr("Framerate"), QString::fromLatin1("%1 FPS").arg(d->data[index].framerate)); result.insert(tr("Animations"), QString::fromLatin1("%1").arg(d->data[index].animationcount)); result.insert(tr("Context"), tr(d->data[index].threadId == QmlDebug::GuiThread ? diff --git a/src/plugins/qmlprofiler/qmlprofilernotesmodel.cpp b/src/plugins/qmlprofiler/qmlprofilernotesmodel.cpp index 96641ff2b19..81feb8d2778 100644 --- a/src/plugins/qmlprofiler/qmlprofilernotesmodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilernotesmodel.cpp @@ -112,7 +112,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]; - int typeId = model->range(timelineIndex).typeId; + int typeId = model->typeId(timelineIndex); Note note = { text, timelineModel, timelineIndex }; m_data << note; m_modified = true; @@ -167,9 +167,8 @@ int QmlProfilerNotesModel::add(int typeId, qint64 start, qint64 duration, const for (int i = model->firstIndex(start); i <= model->lastIndex(start + duration); ++i) { if (i < 0) continue; - const SortedTimelineModel::Range &timelineRange = model->range(i); - if (timelineRange.typeId == typeId && timelineRange.start == start && - timelineRange.duration == duration) { + if (model->typeId(i) == typeId && model->startTime(i) == start && + model->duration(i) == duration) { timelineModel = model->modelId(); timelineIndex = i; break; @@ -218,9 +217,10 @@ void QmlProfilerNotesModel::saveData() if (it == m_timelineModels.end()) continue; - const SortedTimelineModel::Range ¬eRange = it.value()->range(note.timelineIndex); + const AbstractTimelineModel *model = it.value(); QmlProfilerDataModel::QmlEventNoteData save = { - noteRange.typeId, noteRange.start, noteRange.duration, note.text + model->typeId(note.timelineIndex), model->startTime(note.timelineIndex), + model->duration(note.timelineIndex), note.text }; notes.append(save); } diff --git a/src/plugins/qmlprofiler/qmlprofilerrangemodel.cpp b/src/plugins/qmlprofiler/qmlprofilerrangemodel.cpp index 552c17c86a6..114b2a991af 100644 --- a/src/plugins/qmlprofiler/qmlprofilerrangemodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerrangemodel.cpp @@ -138,7 +138,7 @@ void QmlProfilerRangeModel::QmlProfilerRangeModelPrivate::computeNestingContract nestingEndTimes.fill(0, nestingLevels + 1); for (i = 0; i < eventCount; i++) { - qint64 st = q->ranges[i].start; + qint64 st = ranges[i].start; // per type if (nestingEndTimes[nestingLevels] > st) { @@ -151,7 +151,7 @@ void QmlProfilerRangeModel::QmlProfilerRangeModelPrivate::computeNestingContract nestingEndTimes[nestingLevels-1] <= st) nestingLevels--; } - nestingEndTimes[nestingLevels] = st + q->ranges[i].duration; + nestingEndTimes[nestingLevels] = st + ranges[i].duration; data[i].displayRowCollapsed = nestingLevels; } @@ -163,7 +163,7 @@ void QmlProfilerRangeModel::QmlProfilerRangeModelPrivate::computeExpandedLevels( QHash eventRow; int eventCount = q->count(); for (int i = 0; i < eventCount; i++) { - int typeId = q->range(i).typeId; + int typeId = ranges[i].typeId; if (!eventRow.contains(typeId)) { eventRow[typeId] = expandedRowTypes.size(); expandedRowTypes << typeId; @@ -184,25 +184,23 @@ void QmlProfilerRangeModel::QmlProfilerRangeModelPrivate::findBindingLoops() for (int i = 0; i < q->count(); ++i) { const Range *potentialParent = callStack.isEmpty() - ? 0 : &q->ranges[callStack.top().second]; + ? 0 : &ranges[callStack.top().second]; while (potentialParent - && !(potentialParent->start + potentialParent->duration > q->ranges[i].start)) { + && !(potentialParent->start + potentialParent->duration > ranges[i].start)) { callStack.pop(); - potentialParent = callStack.isEmpty() ? 0 - : &q->ranges[callStack.top().second]; + potentialParent = callStack.isEmpty() ? 0 : &ranges[callStack.top().second]; } // check whether event is already in stack for (int ii = 0; ii < callStack.size(); ++ii) { - if (callStack.at(ii).first == q->range(i).typeId) { + if (callStack.at(ii).first == ranges[i].typeId) { data[i].bindingLoopHead = callStack.at(ii).second; break; } } - - CallStackEntry newEntry(q->range(i).typeId, i); + CallStackEntry newEntry(ranges[i].typeId, i); callStack.push(newEntry); } @@ -266,7 +264,7 @@ QVariantMap QmlProfilerRangeModel::details(int index) const d->modelManager->qmlModel()->getEventTypes(); result.insert(QStringLiteral("displayName"), categoryLabel(d->rangeType)); - result.insert(tr("Duration"), QmlProfilerBaseModel::formatTime(range(index).duration)); + result.insert(tr("Duration"), QmlProfilerBaseModel::formatTime(duration(index))); result.insert(tr("Details"), types[id].data); result.insert(tr("Location"), types[id].displayName); diff --git a/src/plugins/qmlprofiler/sortedtimelinemodel.cpp b/src/plugins/qmlprofiler/sortedtimelinemodel.cpp deleted file mode 100644 index 96da2d47641..00000000000 --- a/src/plugins/qmlprofiler/sortedtimelinemodel.cpp +++ /dev/null @@ -1,165 +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 "sortedtimelinemodel.h" -namespace QmlProfiler { - -/*! - \class QmlProfiler::SortedTimelineModel - \brief The SortedTimelineModel class provides a sorted model for timeline data. - - The SortedTimelineModel 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 SortedTimelineModel::clear() - Clears the ranges and their end times. -*/ -void SortedTimelineModel::clear() -{ - ranges.clear(); - endTimes.clear(); -} - -/*! - \fn int SortedTimelineModel::count() const - Returns the number of ranges in the model. -*/ - -/*! - \fn qint64 SortedTimelineModel::firstStartTime() const - Returns the begin of the first range in the model. -*/ - -/*! - \fn qint64 SortedTimelineModel::lastEndTime() const - Returns the end of the last range in the model. -*/ - -/*! - \fn const SortedTimelineModel::Range &SortedTimelineModel::range(int index) const - Returns the range data at the specified index. -*/ - -/*! - \fn int SortedTimelineModel::insert(qint64 startTime, qint64 duration) - Inserts a range at the given time position and returns its index. -*/ - -/*! - \fn int SortedTimelineModel::insertStart(qint64 startTime, const Data &item) - Inserts the given data as range start at the given time position and - returns its index. The range end is not set. -*/ - -/*! - \fn int SortedTimelineModel::insertEnd(int index, qint64 duration) - Adds a range end for the given start index. -*/ - -/*! - \fn int SortedTimelineModel::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. -*/ - -/*! - \fn int SortedTimelineModel::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 -*/ - -/*! - \fn int SortedTimelineModel::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. -*/ - -/*! - \fn void SortedTimelineModel::computeNesting() - Compute all ranges' parents. - \sa findFirstIndex -*/ -void SortedTimelineModel::computeNesting() -{ - QLinkedList parents; - for (int range = 0; range != count(); ++range) { - Range ¤t = ranges[range]; - for (QLinkedList::iterator parentIt = parents.begin();;) { - if (parentIt == parents.end()) { - parents.append(range); - break; - } - - Range &parent = 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 { - Range &ancestor = 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; - } - } - } -} - -} diff --git a/src/plugins/qmlprofiler/sortedtimelinemodel.h b/src/plugins/qmlprofiler/sortedtimelinemodel.h deleted file mode 100644 index ef2b54873cc..00000000000 --- a/src/plugins/qmlprofiler/sortedtimelinemodel.h +++ /dev/null @@ -1,190 +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. -** -****************************************************************************/ - -#ifndef SORTEDTIMELINEMODEL_H -#define SORTEDTIMELINEMODEL_H - -#include "qmlprofiler_global.h" -#include -#include -#include - -namespace QmlProfiler { - -class QMLPROFILER_EXPORT SortedTimelineModel : public QObject { - Q_OBJECT - -public: - struct Range { - Range() : start(-1), duration(-1), typeId(-1), parent(-1) {} - Range(qint64 start, qint64 duration, int typeId) : - start(start), duration(duration), typeId(typeId), parent(-1) {} - qint64 start; - qint64 duration; - int typeId; - int parent; - inline qint64 timestamp() const {return start;} - }; - - struct RangeEnd { - RangeEnd() : startIndex(-1), end(-1) {} - RangeEnd(int startIndex, qint64 end) : - startIndex(startIndex), end(end) {} - int startIndex; - qint64 end; - inline qint64 timestamp() const {return end;} - }; - - inline int count() const { return ranges.count(); } - - qint64 duration(int index) const { return ranges[index].duration; } - qint64 startTime(int index) const { return ranges[index].start; } - qint64 endTime(int index) const { return ranges[index].start + ranges[index].duration; } - int typeId(int index) const { return ranges[index].typeId; } - - inline qint64 lastEndTime() const { return endTimes.last().end; } - inline qint64 firstStartTime() const { return ranges.first().start; } - - inline const Range &range(int index) const { return ranges[index]; } - - inline int firstIndex(qint64 startTime) const - { - int index = firstIndexNoParents(startTime); - if (index == -1) - return -1; - int parent = ranges[index].parent; - return parent == -1 ? index : parent; - } - - inline int firstIndexNoParents(qint64 startTime) const - { - // in the "endtime" list, find the first event that ends after startTime - if (endTimes.isEmpty()) - return -1; - if (endTimes.count() == 1 || endTimes.first().end > startTime) - return endTimes.first().startIndex; - if (endTimes.last().end <= startTime) - return -1; - - return endTimes[lowerBound(endTimes, startTime) + 1].startIndex; - } - - inline int lastIndex(qint64 endTime) const - { - // in the "starttime" list, find the last event that starts before endtime - if (ranges.isEmpty() || ranges.first().start >= endTime) - return -1; - if (ranges.count() == 1) - return 0; - if (ranges.last().start < endTime) - return ranges.count() - 1; - - return lowerBound(ranges, endTime); - } - -protected: - - SortedTimelineModel(QObject *parent = 0) : QObject(parent) {} - - void clear(); - - inline int insert(qint64 startTime, qint64 duration, int typeId) - { - /* 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 = insertSorted(ranges, Range(startTime, duration, typeId)); - if (index < ranges.size() - 1) - incrementStartIndices(index); - insertSorted(endTimes, RangeEnd(index, startTime + duration)); - return index; - } - - inline int insertStart(qint64 startTime, int typeId) - { - int index = insertSorted(ranges, Range(startTime, 0, typeId)); - if (index < ranges.size() - 1) - incrementStartIndices(index); - return index; - } - - inline void insertEnd(int index, qint64 duration) - { - ranges[index].duration = duration; - insertSorted(endTimes, RangeEnd(index, ranges[index].start + duration)); - } - - void computeNesting(); - - void incrementStartIndices(int index) - { - for (int i = 0; i < endTimes.size(); ++i) { - if (endTimes[i].startIndex >= index) - endTimes[i].startIndex++; - } - } - - template - static inline int insertSorted(QVector &container, const RangeDelimiter &item) - { - for (int i = container.count();;) { - if (i == 0) { - container.prepend(item); - return 0; - } - if (container[--i].timestamp() <= item.timestamp()) { - container.insert(++i, item); - return i; - } - } - } - - template - static inline int lowerBound(const QVector &container, qint64 time) - { - int fromIndex = 0; - int toIndex = container.count() - 1; - while (toIndex - fromIndex > 1) { - int midIndex = (fromIndex + toIndex)/2; - if (container[midIndex].timestamp() < time) - fromIndex = midIndex; - else - toIndex = midIndex; - } - - return fromIndex; - } - - QVector ranges; - QVector endTimes; -}; - -} - -#endif