diff --git a/src/plugins/qmlprofiler/qmlprofilertimelinemodelproxy.cpp b/src/plugins/qmlprofiler/qmlprofilertimelinemodelproxy.cpp
index 3368404de592e18faf3a89ff9b5c7650e3765ec5..11d05081c6f47f073cafa13d67eebc18cb95379b 100644
--- a/src/plugins/qmlprofiler/qmlprofilertimelinemodelproxy.cpp
+++ b/src/plugins/qmlprofiler/qmlprofilertimelinemodelproxy.cpp
@@ -30,6 +30,7 @@
 #include "qmlprofilertimelinemodelproxy.h"
 #include "qmlprofilermodelmanager.h"
 #include "qmlprofilersimplemodel.h"
+#include "sortedtimelinemodel.h"
 
 #include <QCoreApplication>
 #include <QVector>
@@ -51,7 +52,7 @@ struct CategorySpan {
     bool empty;
 };
 
-class BasicTimelineModel::BasicTimelineModelPrivate
+class BasicTimelineModel::BasicTimelineModelPrivate : public SortedTimelineModel<BasicTimelineModel::QmlRangeEventStartInstance>
 {
 public:
     BasicTimelineModelPrivate(BasicTimelineModel *qq) : q(qq) {}
@@ -61,7 +62,6 @@ public:
     void prepare();
     void computeNestingContracted();
     void computeExpandedLevels();
-    void buildEndTimeList();
     void findBindingLoops();
     void computeRowStarts();
 
@@ -69,8 +69,6 @@ public:
 
     QVector <BasicTimelineModel::QmlRangeEventData> eventDict;
     QVector <QString> eventHashes;
-    QVector <BasicTimelineModel::QmlRangeEventStartInstance> startTimeData;
-    QVector <BasicTimelineModel::QmlRangeEventEndInstance> endTimeData;
     QVector <CategorySpan> categorySpan;
 
     BasicTimelineModel *q;
@@ -104,27 +102,11 @@ QString BasicTimelineModel::name() const
     return QLatin1String("BasicTimelineModel");
 }
 
-const QVector<BasicTimelineModel::QmlRangeEventStartInstance> BasicTimelineModel::getData() const
-{
-    return d->startTimeData;
-}
-
-const QVector<BasicTimelineModel::QmlRangeEventStartInstance> BasicTimelineModel::getData(qint64 fromTime, qint64 toTime) const
-{
-    int fromIndex = findFirstIndex(fromTime);
-    int toIndex = findLastIndex(toTime);
-    if (fromIndex != -1 && toIndex > fromIndex)
-        return d->startTimeData.mid(fromIndex, toIndex - fromIndex + 1);
-    else
-        return QVector<BasicTimelineModel::QmlRangeEventStartInstance>();
-}
-
 void BasicTimelineModel::clear()
 {
+    d->SortedTimelineModel::clear();
     d->eventDict.clear();
     d->eventHashes.clear();
-    d->startTimeData.clear();
-    d->endTimeData.clear();
     d->categorySpan.clear();
 
     m_modelManager->modelProxyCountUpdated(m_modelId, 0, 1);
@@ -139,16 +121,6 @@ void BasicTimelineModel::BasicTimelineModelPrivate::prepare()
     }
 }
 
-bool compareStartTimes(const BasicTimelineModel::QmlRangeEventStartInstance&t1, const BasicTimelineModel::QmlRangeEventStartInstance &t2)
-{
-    return t1.startTime < t2.startTime;
-}
-
-bool compareEndTimes(const BasicTimelineModel::QmlRangeEventEndInstance &t1, const BasicTimelineModel::QmlRangeEventEndInstance &t2)
-{
-    return t1.endTime < t2.endTime;
-}
-
 bool BasicTimelineModel::eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const
 {
     // only accept Qt4.x Painting events
@@ -191,42 +163,30 @@ void BasicTimelineModel::loadData()
         }
 
         // store starttime-based instance
-        QmlRangeEventStartInstance eventStartInstance = {
-            event.startTime,
-            event.duration,
-            d->eventHashes.indexOf(eventHash), // event id
-            QmlDebug::Constants::QML_MIN_LEVEL, // displayRowExpanded;
-            QmlDebug::Constants::QML_MIN_LEVEL, // displayRowCollapsed;
-            1,
-            -1  // bindingLoopHead
-        };
-        d->startTimeData.append(eventStartInstance);
-
-        m_modelManager->modelProxyCountUpdated(m_modelId, d->startTimeData.count(), eventList.count() * 7);
+        d->insert(event.startTime, event.duration, QmlRangeEventStartInstance(d->eventHashes.indexOf(eventHash)));
+
+        m_modelManager->modelProxyCountUpdated(m_modelId, d->count(), eventList.count() * 6);
     }
 
-    qSort(d->startTimeData.begin(), d->startTimeData.end(), compareStartTimes);
+    m_modelManager->modelProxyCountUpdated(m_modelId, 2, 6);
 
-    m_modelManager->modelProxyCountUpdated(m_modelId, 2, 7);
+    // compute range nesting
+    d->computeNesting();
 
     // compute nestingLevel - nonexpanded
     d->computeNestingContracted();
 
-    m_modelManager->modelProxyCountUpdated(m_modelId, 3, 7);
+    m_modelManager->modelProxyCountUpdated(m_modelId, 3, 6);
 
     // compute nestingLevel - expanded
     d->computeExpandedLevels();
 
-    m_modelManager->modelProxyCountUpdated(m_modelId, 4, 7);
-
-    // populate endtimelist
-    d->buildEndTimeList();
+    m_modelManager->modelProxyCountUpdated(m_modelId, 4, 6);
 
-    m_modelManager->modelProxyCountUpdated(m_modelId, 5, 7);
 
     d->findBindingLoops();
 
-    m_modelManager->modelProxyCountUpdated(m_modelId, 6, 7);
+    m_modelManager->modelProxyCountUpdated(m_modelId, 5, 6);
 
     d->computeRowStarts();
 
@@ -238,15 +198,10 @@ void BasicTimelineModel::loadData()
 void BasicTimelineModel::BasicTimelineModelPrivate::computeNestingContracted()
 {
     int i;
-    int eventCount = startTimeData.count();
+    int eventCount = count();
 
-    QHash<int, qint64> endtimesPerLevel;
     QList<int> nestingLevels;
     QList< QHash<int, qint64> > endtimesPerNestingLevel;
-    int level = QmlDebug::Constants::QML_MIN_LEVEL;
-    endtimesPerLevel[QmlDebug::Constants::QML_MIN_LEVEL] = 0;
-    int lastBaseEventIndex = 0;
-    qint64 lastBaseEventEndTime = q->m_modelManager->traceTime()->startTime();
 
     for (i = 0; i < QmlDebug::MaximumQmlEventType; i++) {
         nestingLevels << QmlDebug::Constants::QML_MIN_LEVEL;
@@ -256,18 +211,9 @@ void BasicTimelineModel::BasicTimelineModelPrivate::computeNestingContracted()
     }
 
     for (i = 0; i < eventCount; i++) {
-        qint64 st = startTimeData[i].startTime;
+        qint64 st = ranges[i].start;
         int type = q->getEventType(i);
 
-        // general level
-        if (endtimesPerLevel[level] > st) {
-            level++;
-        } else {
-            while (level > QmlDebug::Constants::QML_MIN_LEVEL && endtimesPerLevel[level-1] <= st)
-                level--;
-        }
-        endtimesPerLevel[level] = st + startTimeData[i].duration;
-
         // per type
         if (endtimesPerNestingLevel[type][nestingLevels[type]] > st) {
             nestingLevels[type]++;
@@ -277,67 +223,42 @@ void BasicTimelineModel::BasicTimelineModelPrivate::computeNestingContracted()
                 nestingLevels[type]--;
         }
         endtimesPerNestingLevel[type][nestingLevels[type]] =
-                st + startTimeData[i].duration;
+                st + ranges[i].duration;
 
-        startTimeData[i].displayRowCollapsed = nestingLevels[type];
-
-        if (level == QmlDebug::Constants::QML_MIN_LEVEL) {
-            if (lastBaseEventEndTime < startTimeData[i].startTime) {
-                lastBaseEventIndex = i;
-                lastBaseEventEndTime = startTimeData[i].startTime + startTimeData[i].duration;
-            }
-        }
-        startTimeData[i].baseEventIndex = lastBaseEventIndex;
+        ranges[i].displayRowCollapsed = nestingLevels[type];
     }
 
     // nestingdepth
     for (i = 0; i < eventCount; i++) {
         int eventType = q->getEventType(i);
         categorySpan[eventType].empty = false;
-        if (categorySpan[eventType].contractedRows <= startTimeData[i].displayRowCollapsed)
-            categorySpan[eventType].contractedRows = startTimeData[i].displayRowCollapsed + 1;
+        if (categorySpan[eventType].contractedRows <= ranges[i].displayRowCollapsed)
+            categorySpan[eventType].contractedRows = ranges[i].displayRowCollapsed + 1;
     }
 }
 
 void BasicTimelineModel::BasicTimelineModelPrivate::computeExpandedLevels()
 {
     QHash<int, int> eventRow;
-    int eventCount = startTimeData.count();
+    int eventCount = count();
     for (int i = 0; i < eventCount; i++) {
-        int eventId = startTimeData[i].eventId;
+        int eventId = ranges[i].eventId;
         int eventType = eventDict[eventId].eventType;
         if (!eventRow.contains(eventId)) {
             categorySpan[eventType].empty = false;
             eventRow[eventId] = categorySpan[eventType].expandedRows++;
         }
-        startTimeData[i].displayRowExpanded = eventRow[eventId];
+        ranges[i].displayRowExpanded = eventRow[eventId];
     }
 }
 
-void BasicTimelineModel::BasicTimelineModelPrivate::buildEndTimeList()
-{
-    endTimeData.clear();
-
-    int eventCount = startTimeData.count();
-    for (int i = 0; i < eventCount; i++) {
-        BasicTimelineModel::QmlRangeEventEndInstance endInstance = {
-            i,
-            startTimeData[i].startTime + startTimeData[i].duration
-        };
-
-        endTimeData << endInstance;
-    }
-
-    qSort(endTimeData.begin(), endTimeData.end(), compareEndTimes);
-}
-
 void BasicTimelineModel::BasicTimelineModelPrivate::findBindingLoops()
 {
     typedef QPair<QString, int> CallStackEntry;
     QStack<CallStackEntry> callStack;
 
-    for (int i = 0; i < startTimeData.size(); ++i) {
-        QmlRangeEventStartInstance *event = &startTimeData[i];
+    for (int i = 0; i < count(); ++i) {
+        Range *event = &ranges[i];
 
         BasicTimelineModel::QmlRangeEventData data = eventDict.at(event->eventId);
 
@@ -349,14 +270,14 @@ void BasicTimelineModel::BasicTimelineModelPrivate::findBindingLoops()
             continue;
 
         const QString eventHash = eventHashes.at(event->eventId);
-        const QmlRangeEventStartInstance *potentialParent = callStack.isEmpty()
-                ? 0 : &startTimeData[callStack.top().second];
+        const Range *potentialParent = callStack.isEmpty()
+                ? 0 : &ranges[callStack.top().second];
 
         while (potentialParent
-               && !(potentialParent->startTime + potentialParent->duration > event->startTime)) {
+               && !(potentialParent->start + potentialParent->duration > event->start)) {
             callStack.pop();
             potentialParent = callStack.isEmpty() ? 0
-                                                  : &startTimeData[callStack.top().second];
+                                                  : &ranges[callStack.top().second];
         }
 
         // check whether event is already in stack
@@ -392,12 +313,12 @@ bool BasicTimelineModel::isEmpty() const
 
 int BasicTimelineModel::count() const
 {
-    return d->startTimeData.count();
+    return d->count();
 }
 
 qint64 BasicTimelineModel::lastTimeMark() const
 {
-    return d->startTimeData.last().startTime + d->startTimeData.last().duration;
+    return d->lastEndTime();
 }
 
 bool BasicTimelineModel::expanded(int category) const
@@ -450,95 +371,22 @@ const QString BasicTimelineModel::categoryLabel(int categoryIndex) const
 
 int BasicTimelineModel::findFirstIndex(qint64 startTime) const
 {
-    int candidate = -1;
-    // in the "endtime" list, find the first event that ends after startTime
-    if (d->endTimeData.isEmpty())
-        return -1;
-    if (d->endTimeData.count() == 1 || d->endTimeData.first().endTime >= startTime)
-        candidate = 0;
-    else
-        if (d->endTimeData.last().endTime <= startTime)
-            return -1;
-
-    if (candidate == -1)
-    {
-        int fromIndex = 0;
-        int toIndex = d->endTimeData.count()-1;
-        while (toIndex - fromIndex > 1) {
-            int midIndex = (fromIndex + toIndex)/2;
-            if (d->endTimeData[midIndex].endTime < startTime)
-                fromIndex = midIndex;
-            else
-                toIndex = midIndex;
-        }
-
-        candidate = toIndex;
-    }
-
-    int eventIndex = d->endTimeData[candidate].startTimeIndex;
-    return d->startTimeData[eventIndex].baseEventIndex;
-
+    return d->findFirstIndex(startTime);
 }
 
 int BasicTimelineModel::findFirstIndexNoParents(qint64 startTime) const
 {
-    int candidate = -1;
-    // in the "endtime" list, find the first event that ends after startTime
-    if (d->endTimeData.isEmpty())
-        return -1;
-    if (d->endTimeData.count() == 1 || d->endTimeData.first().endTime >= startTime)
-        candidate = 0;
-    else
-        if (d->endTimeData.last().endTime <= startTime)
-            return -1;
-
-    if (candidate == -1) {
-        int fromIndex = 0;
-        int toIndex = d->endTimeData.count()-1;
-        while (toIndex - fromIndex > 1) {
-            int midIndex = (fromIndex + toIndex)/2;
-            if (d->endTimeData[midIndex].endTime < startTime)
-                fromIndex = midIndex;
-            else
-                toIndex = midIndex;
-        }
-
-        candidate = toIndex;
-    }
-
-    int ndx = d->endTimeData[candidate].startTimeIndex;
-
-    return ndx;
+    return d->findFirstIndexNoParents(startTime);
 }
 
 int BasicTimelineModel::findLastIndex(qint64 endTime) const
 {
-        // in the "starttime" list, find the last event that starts before endtime
-        if (d->startTimeData.isEmpty())
-            return -1;
-        if (d->startTimeData.first().startTime >= endTime)
-            return -1;
-        if (d->startTimeData.count() == 1)
-            return 0;
-        if (d->startTimeData.last().startTime <= endTime)
-            return d->startTimeData.count()-1;
-
-        int fromIndex = 0;
-        int toIndex = d->startTimeData.count()-1;
-        while (toIndex - fromIndex > 1) {
-            int midIndex = (fromIndex + toIndex)/2;
-            if (d->startTimeData[midIndex].startTime < endTime)
-                fromIndex = midIndex;
-            else
-                toIndex = midIndex;
-        }
-
-        return fromIndex;
+    return d->findLastIndex(endTime);
 }
 
 int BasicTimelineModel::getEventType(int index) const
 {
-    return d->eventDict[d->startTimeData[index].eventId].eventType;
+    return d->eventDict[d->range(index).eventId].eventType;
 }
 
 int BasicTimelineModel::getEventCategory(int index) const
@@ -553,34 +401,34 @@ int BasicTimelineModel::getEventCategory(int index) const
 int BasicTimelineModel::getEventRow(int index) const
 {
     if (d->categorySpan[getEventType(index)].expanded)
-        return d->startTimeData[index].displayRowExpanded + d->categorySpan[getEventType(index)].rowStart;
+        return d->range(index).displayRowExpanded + d->categorySpan[getEventType(index)].rowStart;
     else
-        return d->startTimeData[index].displayRowCollapsed  + d->categorySpan[getEventType(index)].rowStart;
+        return d->range(index).displayRowCollapsed  + d->categorySpan[getEventType(index)].rowStart;
 }
 
 qint64 BasicTimelineModel::getDuration(int index) const
 {
-    return d->startTimeData[index].duration;
+    return d->range(index).duration;
 }
 
 qint64 BasicTimelineModel::getStartTime(int index) const
 {
-    return d->startTimeData[index].startTime;
+    return d->range(index).start;
 }
 
 qint64 BasicTimelineModel::getEndTime(int index) const
 {
-    return d->startTimeData[index].startTime + d->startTimeData[index].duration;
+    return d->range(index).start + d->range(index).duration;
 }
 
 int BasicTimelineModel::getEventId(int index) const
 {
-    return d->startTimeData[index].eventId;
+    return d->range(index).eventId;
 }
 
 int BasicTimelineModel::getBindingLoopDest(int index) const
 {
-    return d->startTimeData[index].bindingLoopHead;
+    return d->range(index).bindingLoopHead;
 }
 
 QColor BasicTimelineModel::getColor(int index) const
@@ -641,7 +489,7 @@ const QVariantList BasicTimelineModel::getEventDetails(int index) const
     // duration
     {
         QVariantMap valuePair;
-        valuePair.insert(QCoreApplication::translate(trContext, "Duration:"), QVariant(d->displayTime(d->startTimeData[index].duration)));
+        valuePair.insert(QCoreApplication::translate(trContext, "Duration:"), QVariant(d->displayTime(d->range(index).duration)));
         result << valuePair;
     }
 
diff --git a/src/plugins/qmlprofiler/qmlprofilertimelinemodelproxy.h b/src/plugins/qmlprofiler/qmlprofilertimelinemodelproxy.h
index ace89143fd426692df5538bb2c03e2bfc5c9ae10..bdb5bf57459896bd914fe63295c8af2d280e79d7 100644
--- a/src/plugins/qmlprofiler/qmlprofilertimelinemodelproxy.h
+++ b/src/plugins/qmlprofiler/qmlprofilertimelinemodelproxy.h
@@ -65,22 +65,20 @@ public:
     };
 
     struct QmlRangeEventStartInstance {
-        qint64 startTime;
-        qint64 duration;
+        QmlRangeEventStartInstance(int eventId = -1) :
+                eventId(eventId),
+                displayRowExpanded(QmlDebug::Constants::QML_MIN_LEVEL),
+                displayRowCollapsed(QmlDebug::Constants::QML_MIN_LEVEL),
+                bindingLoopHead(-1) {}
+
         int eventId;
 
         // not-expanded, per type
         int displayRowExpanded;
         int displayRowCollapsed;
-        int baseEventIndex; // used by findfirstindex
         int bindingLoopHead;
     };
 
-    struct QmlRangeEventEndInstance {
-        int startTimeIndex;
-        qint64 endTime;
-    };
-
     BasicTimelineModel(QObject *parent = 0);
     ~BasicTimelineModel();
 
@@ -89,8 +87,6 @@ public:
     QStringList categoryTitles() const;
     QString name() const;
 
-    const QVector<QmlRangeEventStartInstance> getData() const;
-    const QVector<QmlRangeEventStartInstance> getData(qint64 fromTime, qint64 toTime) const;
     void loadData();
     Q_INVOKABLE int count() const;
     void clear();