From 9c53c1dbea368bd8d65a8f7b16db160b3c25cf7d Mon Sep 17 00:00:00 2001
From: Ulf Hermann <ulf.hermann@theqtcompany.com>
Date: Tue, 9 Dec 2014 14:18:05 +0100
Subject: [PATCH] QmlProfiler: Require only subset of renderer to execute
 render passes

Like that we can easily add different renderers to use the same render
passes, e.g. for the overview.

Change-Id: Ib7dcb77a45e74488971011310f53f7639286768d
Reviewed-by: Kai Koehne <kai.koehne@theqtcompany.com>
---
 src/plugins/qmlprofiler/qmlprofiler.pro       |   7 +-
 src/plugins/qmlprofiler/qmlprofiler.qbs       |   2 +
 .../qmlprofilerbindingloopsrenderpass.cpp     |   2 +-
 .../qmlprofilerbindingloopsrenderpass.h       |   4 +-
 .../qmlprofiler/timelineabstractrenderer.cpp  | 200 ++++++++++++++
 .../qmlprofiler/timelineabstractrenderer.h    |  99 +++++++
 .../qmlprofiler/timelineabstractrenderer_p.h  |  60 ++++
 .../qmlprofiler/timelineitemsrenderpass.cpp   |  11 +-
 .../qmlprofiler/timelineitemsrenderpass.h     |   4 +-
 .../qmlprofiler/timelinenotesrenderpass.cpp   |   2 +-
 .../qmlprofiler/timelinenotesrenderpass.h     |   4 +-
 .../qmlprofiler/timelineoverviewrenderer_p.h  |   5 +
 src/plugins/qmlprofiler/timelinerenderer.cpp  | 261 +-----------------
 src/plugins/qmlprofiler/timelinerenderer.h    |  42 +--
 src/plugins/qmlprofiler/timelinerenderer_p.h  |  16 +-
 src/plugins/qmlprofiler/timelinerenderpass.h  |   5 +-
 .../qmlprofiler/timelinerenderstate.cpp       |  92 ++++++
 src/plugins/qmlprofiler/timelinerenderstate.h |   5 +
 .../timelineselectionrenderpass.cpp           |   6 +-
 .../qmlprofiler/timelineselectionrenderpass.h |   4 +-
 20 files changed, 505 insertions(+), 326 deletions(-)
 create mode 100644 src/plugins/qmlprofiler/timelineabstractrenderer.cpp
 create mode 100644 src/plugins/qmlprofiler/timelineabstractrenderer.h
 create mode 100644 src/plugins/qmlprofiler/timelineabstractrenderer_p.h
 create mode 100644 src/plugins/qmlprofiler/timelineoverviewrenderer_p.h

diff --git a/src/plugins/qmlprofiler/qmlprofiler.pro b/src/plugins/qmlprofiler/qmlprofiler.pro
index a2ab78e8be2..1fa2e2e7b2e 100644
--- a/src/plugins/qmlprofiler/qmlprofiler.pro
+++ b/src/plugins/qmlprofiler/qmlprofiler.pro
@@ -41,7 +41,8 @@ SOURCES += \
     timelinenotesrenderpass.cpp \
     timelinerenderpass.cpp \
     timelinerenderstate.cpp \
-    timelinenotesmodel.cpp
+    timelinenotesmodel.cpp \
+    timelineabstractrenderer.cpp
 
 HEADERS += \
     abstractqmlprofilerrunner.h \
@@ -88,7 +89,9 @@ HEADERS += \
     timelinenotesmodel.h \
     timelinenotesmodel_p.h \
     timelinerenderer_p.h \
-    timelinerenderstate_p.h
+    timelinerenderstate_p.h \
+    timelineabstractrenderer.h \
+    timelineabstractrenderer_p.h
 
 RESOURCES += \
     qml/qmlprofiler.qrc
diff --git a/src/plugins/qmlprofiler/qmlprofiler.qbs b/src/plugins/qmlprofiler/qmlprofiler.qbs
index 16781d605e3..e14395ccc5c 100644
--- a/src/plugins/qmlprofiler/qmlprofiler.qbs
+++ b/src/plugins/qmlprofiler/qmlprofiler.qbs
@@ -50,6 +50,8 @@ QtcPlugin {
             "qmlprofilerviewmanager.cpp", "qmlprofilerviewmanager.h",
             "qv8profilerdatamodel.cpp", "qv8profilerdatamodel.h",
             "qv8profilereventview.h", "qv8profilereventview.cpp",
+            "timelineabstractrenderer.cpp", "timelineabstractrenderer.h",
+            "timelineabstractrenderer_p.h",
             "timelineitemsrenderpass.cpp", "timelineitemsrenderpass.h",
             "timelinemodel.cpp", "timelinemodel.h", "timelinemodel_p.h",
             "timelinemodelaggregator.cpp", "timelinemodelaggregator.h",
diff --git a/src/plugins/qmlprofiler/qmlprofilerbindingloopsrenderpass.cpp b/src/plugins/qmlprofiler/qmlprofilerbindingloopsrenderpass.cpp
index b5ef2651a84..758f1acbcec 100644
--- a/src/plugins/qmlprofiler/qmlprofilerbindingloopsrenderpass.cpp
+++ b/src/plugins/qmlprofiler/qmlprofilerbindingloopsrenderpass.cpp
@@ -149,7 +149,7 @@ void updateNodes(const QmlProfilerRangeModel *model, int from, int to,
 }
 
 Timeline::TimelineRenderPass::State *QmlProfilerBindingLoopsRenderPass::update(
-        const Timeline::TimelineRenderer *renderer,
+        const Timeline::TimelineAbstractRenderer *renderer,
         const Timeline::TimelineRenderState *parentState, State *oldState,
         int indexFrom, int indexTo, bool stateChanged, qreal spacing) const
 {
diff --git a/src/plugins/qmlprofiler/qmlprofilerbindingloopsrenderpass.h b/src/plugins/qmlprofiler/qmlprofilerbindingloopsrenderpass.h
index 21a258433e8..3828a0f7323 100644
--- a/src/plugins/qmlprofiler/qmlprofilerbindingloopsrenderpass.h
+++ b/src/plugins/qmlprofiler/qmlprofilerbindingloopsrenderpass.h
@@ -31,7 +31,7 @@
 #ifndef QMLPROFILERBINDINGLOOPSRENDERPASS_H
 #define QMLPROFILERBINDINGLOOPSRENDERPASS_H
 
-#include "timelinerenderer.h"
+#include "timelineabstractrenderer.h"
 #include "timelinerenderpass.h"
 #include "timelinerenderstate.h"
 #include "qmlprofilerrangemodel.h"
@@ -44,7 +44,7 @@ class QmlProfilerBindingLoopsRenderPass : public Timeline::TimelineRenderPass
 {
 public:
     static const QmlProfilerBindingLoopsRenderPass *instance();
-    State *update(const Timeline::TimelineRenderer *renderer,
+    State *update(const Timeline::TimelineAbstractRenderer *renderer,
                   const Timeline::TimelineRenderState *parentState,
                   State *oldState, int indexFrom, int indexTo, bool stateChanged,
                   qreal spacing) const;
diff --git a/src/plugins/qmlprofiler/timelineabstractrenderer.cpp b/src/plugins/qmlprofiler/timelineabstractrenderer.cpp
new file mode 100644
index 00000000000..720865692d4
--- /dev/null
+++ b/src/plugins/qmlprofiler/timelineabstractrenderer.cpp
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** 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 "timelineabstractrenderer_p.h"
+
+namespace Timeline {
+
+TimelineAbstractRenderer::TimelineAbstractRendererPrivate::TimelineAbstractRendererPrivate() :
+    selectedItem(-1), selectionLocked(true), model(0), notes(0), zoomer(0), modelDirty(false),
+    rowHeightsDirty(false)
+{
+}
+
+TimelineAbstractRenderer::TimelineAbstractRenderer(TimelineAbstractRendererPrivate &dd,
+                                                   QQuickItem *parent) :
+    QQuickItem(parent), d_ptr(&dd)
+{
+}
+
+int TimelineAbstractRenderer::selectedItem() const
+{
+    Q_D(const TimelineAbstractRenderer);
+    return d->selectedItem;
+}
+
+void TimelineAbstractRenderer::setSelectedItem(int itemIndex)
+{
+    Q_D(TimelineAbstractRenderer);
+    if (d->selectedItem != itemIndex) {
+        d->selectedItem = itemIndex;
+        update();
+        emit selectedItemChanged(itemIndex);
+    }
+}
+
+bool TimelineAbstractRenderer::selectionLocked() const
+{
+    Q_D(const TimelineAbstractRenderer);
+    return d->selectionLocked;
+}
+
+void TimelineAbstractRenderer::setSelectionLocked(bool locked)
+{
+    Q_D(TimelineAbstractRenderer);
+    if (d->selectionLocked != locked) {
+        d->selectionLocked = locked;
+        update();
+        emit selectionLockedChanged(locked);
+    }
+}
+
+TimelineModel *TimelineAbstractRenderer::model() const
+{
+    Q_D(const TimelineAbstractRenderer);
+    return d->model;
+}
+
+void TimelineAbstractRenderer::setModel(TimelineModel *model)
+{
+    Q_D(TimelineAbstractRenderer);
+    if (d->model == model)
+        return;
+
+    if (d->model) {
+        disconnect(d->model, &TimelineModel::expandedChanged, this, &QQuickItem::update);
+        disconnect(d->model, &TimelineModel::hiddenChanged, this, &QQuickItem::update);
+        disconnect(d->model, &TimelineModel::expandedRowHeightChanged,
+                   this, &TimelineAbstractRenderer::setRowHeightsDirty);
+        disconnect(d->model, &TimelineModel::emptyChanged,
+                   this, &TimelineAbstractRenderer::setModelDirty);
+    }
+
+    d->model = model;
+    if (d->model) {
+        connect(d->model, &TimelineModel::expandedChanged, this, &QQuickItem::update);
+        connect(d->model, &TimelineModel::hiddenChanged, this, &QQuickItem::update);
+        connect(d->model, &TimelineModel::expandedRowHeightChanged,
+                this, &TimelineAbstractRenderer::setRowHeightsDirty);
+        connect(d->model, &TimelineModel::emptyChanged,
+                this, &TimelineAbstractRenderer::setModelDirty);
+        d->renderPasses = d->model->supportedRenderPasses();
+    }
+
+    setModelDirty();
+    emit modelChanged(d->model);
+}
+
+TimelineNotesModel *TimelineAbstractRenderer::notes() const
+{
+    Q_D(const TimelineAbstractRenderer);
+    return d->notes;
+}
+
+void TimelineAbstractRenderer::setNotes(TimelineNotesModel *notes)
+{
+    Q_D(TimelineAbstractRenderer);
+    if (d->notes == notes)
+        return;
+
+    if (d->notes)
+        disconnect(d->notes, &TimelineNotesModel::changed,
+                   this, &TimelineAbstractRenderer::setNotesDirty);
+
+    d->notes = notes;
+    if (d->notes)
+        connect(d->notes, &TimelineNotesModel::changed,
+                this, &TimelineAbstractRenderer::setNotesDirty);
+
+    emit notesChanged(d->notes);
+    update();
+}
+
+TimelineZoomControl *TimelineAbstractRenderer::zoomer() const
+{
+    Q_D(const TimelineAbstractRenderer);
+    return d->zoomer;
+}
+
+void TimelineAbstractRenderer::setZoomer(TimelineZoomControl *zoomer)
+{
+    Q_D(TimelineAbstractRenderer);
+    if (zoomer != d->zoomer) {
+        if (d->zoomer != 0)
+            disconnect(d->zoomer, SIGNAL(windowChanged(qint64,qint64)), this, SLOT(update()));
+        d->zoomer = zoomer;
+        if (d->zoomer != 0)
+            connect(d->zoomer, SIGNAL(windowChanged(qint64,qint64)), this, SLOT(update()));
+        emit zoomerChanged(zoomer);
+        update();
+    }
+}
+
+bool TimelineAbstractRenderer::modelDirty() const
+{
+    Q_D(const TimelineAbstractRenderer);
+    return d->modelDirty;
+}
+
+bool TimelineAbstractRenderer::notesDirty() const
+{
+    Q_D(const TimelineAbstractRenderer);
+    return d->notesDirty;
+}
+
+bool TimelineAbstractRenderer::rowHeightsDirty() const
+{
+    Q_D(const TimelineAbstractRenderer);
+    return d->rowHeightsDirty;
+}
+
+void TimelineAbstractRenderer::setModelDirty()
+{
+    Q_D(TimelineAbstractRenderer);
+    d->modelDirty = true;
+    update();
+}
+
+void TimelineAbstractRenderer::setRowHeightsDirty()
+{
+    Q_D(TimelineAbstractRenderer);
+    d->rowHeightsDirty = true;
+    update();
+}
+
+void TimelineAbstractRenderer::setNotesDirty()
+{
+    Q_D(TimelineAbstractRenderer);
+    d->notesDirty = true;
+    update();
+}
+
+} // namespace Timeline
+
diff --git a/src/plugins/qmlprofiler/timelineabstractrenderer.h b/src/plugins/qmlprofiler/timelineabstractrenderer.h
new file mode 100644
index 00000000000..ac446ad167e
--- /dev/null
+++ b/src/plugins/qmlprofiler/timelineabstractrenderer.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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 TIMELINEABSTRACTRENDERER_H
+#define TIMELINEABSTRACTRENDERER_H
+
+#include <QQuickItem>
+
+#include <QSGTransformNode>
+#include <QQuickItem>
+#include "timelinezoomcontrol.h"
+#include "timelinemodel.h"
+#include "timelinenotesmodel.h"
+#include "timelinerenderpass.h"
+
+namespace Timeline {
+
+class TimelineRenderPass;
+class TimelineRenderState;
+
+class TimelineAbstractRenderer : public QQuickItem
+{
+    Q_OBJECT
+    Q_PROPERTY(Timeline::TimelineModel *model READ model WRITE setModel NOTIFY modelChanged)
+    Q_PROPERTY(Timeline::TimelineNotesModel *notes READ notes WRITE setNotes NOTIFY notesChanged)
+    Q_PROPERTY(Timeline::TimelineZoomControl *zoomer READ zoomer WRITE setZoomer NOTIFY zoomerChanged)
+    Q_PROPERTY(bool selectionLocked READ selectionLocked WRITE setSelectionLocked NOTIFY selectionLockedChanged)
+    Q_PROPERTY(int selectedItem READ selectedItem WRITE setSelectedItem NOTIFY selectedItemChanged)
+
+public:
+    bool selectionLocked() const;
+    int selectedItem() const;
+
+    TimelineModel *model() const;
+    void setModel(TimelineModel *model);
+
+    TimelineNotesModel *notes() const;
+    void setNotes(TimelineNotesModel *notes);
+
+    TimelineZoomControl *zoomer() const;
+    void setZoomer(TimelineZoomControl *zoomer);
+
+    bool modelDirty() const;
+    bool notesDirty() const;
+    bool rowHeightsDirty() const;
+
+signals:
+    void modelChanged(const TimelineModel *model);
+    void notesChanged(TimelineNotesModel *notes);
+    void zoomerChanged(TimelineZoomControl *zoomer);
+    void selectionLockedChanged(bool locked);
+    void selectedItemChanged(int itemIndex);
+
+public slots:
+    void setSelectedItem(int itemIndex);
+    void setSelectionLocked(bool locked);
+
+    void setModelDirty();
+    void setNotesDirty();
+    void setRowHeightsDirty();
+
+protected:
+    class TimelineAbstractRendererPrivate;
+    TimelineAbstractRenderer(TimelineAbstractRendererPrivate &dd, QQuickItem *parent = 0);
+    TimelineAbstractRendererPrivate *d_ptr;
+    Q_DECLARE_PRIVATE(TimelineAbstractRenderer)
+};
+
+} // namespace Timeline
+
+
+#endif // TIMELINEABSTRACTRENDERER_H
diff --git a/src/plugins/qmlprofiler/timelineabstractrenderer_p.h b/src/plugins/qmlprofiler/timelineabstractrenderer_p.h
new file mode 100644
index 00000000000..dfe881675a2
--- /dev/null
+++ b/src/plugins/qmlprofiler/timelineabstractrenderer_p.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** 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 TIMELINEABSTRACTRENDERER_P_H
+#define TIMELINEABSTRACTRENDERER_P_H
+
+#include "timelineabstractrenderer.h"
+
+namespace Timeline {
+
+class TimelineAbstractRenderer::TimelineAbstractRendererPrivate {
+public:
+    TimelineAbstractRendererPrivate();
+
+    int selectedItem;
+    bool selectionLocked;
+    TimelineModel *model;
+    TimelineNotesModel *notes;
+    TimelineZoomControl *zoomer;
+
+    bool modelDirty;
+    bool rowHeightsDirty;
+    bool notesDirty;
+
+    QList<const TimelineRenderPass *> renderPasses;
+
+
+};
+
+}
+
+#endif // TIMELINEABSTRACTRENDERER_P_H
+
diff --git a/src/plugins/qmlprofiler/timelineitemsrenderpass.cpp b/src/plugins/qmlprofiler/timelineitemsrenderpass.cpp
index e1b6fa3fdee..98d2ef4caf8 100644
--- a/src/plugins/qmlprofiler/timelineitemsrenderpass.cpp
+++ b/src/plugins/qmlprofiler/timelineitemsrenderpass.cpp
@@ -190,10 +190,9 @@ public:
     virtual ~TimelineExpandedRowNode() {}
 };
 
-static void updateNodes(int from, int to, const TimelineRenderer *renderer,
+static void updateNodes(int from, int to, const TimelineModel *model,
                         const TimelineRenderState *parentState, TimelineItemsRenderPassState *state)
 {
-    const TimelineModel *model = renderer->model();
     float defaultRowHeight = TimelineModel::defaultRowHeight();
 
     QVector<TimelineItemsGeometry> expandedPerRow(model->expandedRowCount());
@@ -274,7 +273,7 @@ const TimelineItemsRenderPass *TimelineItemsRenderPass::instance()
     return &pass;
 }
 
-TimelineRenderPass::State *TimelineItemsRenderPass::update(const TimelineRenderer *renderer,
+TimelineRenderPass::State *TimelineItemsRenderPass::update(const TimelineAbstractRenderer *renderer,
                                                            const TimelineRenderState *parentState,
                                                            State *oldState, int indexFrom,
                                                            int indexTo, bool stateChanged,
@@ -315,16 +314,16 @@ TimelineRenderPass::State *TimelineItemsRenderPass::update(const TimelineRendere
             for (int i = indexFrom; i < state->indexFrom;
                  i+= TimelineItemsGeometry::maxEventsPerNode)
                 updateNodes(i, qMin(i + TimelineItemsGeometry::maxEventsPerNode, state->indexFrom),
-                            renderer, parentState, state);
+                            model, parentState, state);
         }
         if (indexTo > state->indexTo) {
             for (int i = state->indexTo; i < indexTo; i+= TimelineItemsGeometry::maxEventsPerNode)
-                updateNodes(i, qMin(i + TimelineItemsGeometry::maxEventsPerNode, indexTo), renderer,
+                updateNodes(i, qMin(i + TimelineItemsGeometry::maxEventsPerNode, indexTo), model,
                             parentState, state);
         }
     } else {
         for (int i = indexFrom; i < indexTo; i+= TimelineItemsGeometry::maxEventsPerNode)
-            updateNodes(i, qMin(i + TimelineItemsGeometry::maxEventsPerNode, indexTo), renderer,
+            updateNodes(i, qMin(i + TimelineItemsGeometry::maxEventsPerNode, indexTo), model,
                         parentState, state);
     }
 
diff --git a/src/plugins/qmlprofiler/timelineitemsrenderpass.h b/src/plugins/qmlprofiler/timelineitemsrenderpass.h
index 09b25b08d6c..06994333c08 100644
--- a/src/plugins/qmlprofiler/timelineitemsrenderpass.h
+++ b/src/plugins/qmlprofiler/timelineitemsrenderpass.h
@@ -31,7 +31,7 @@
 #ifndef TIMELINEITEMSRENDERPASS_H
 #define TIMELINEITEMSRENDERPASS_H
 
-#include "timelinerenderer.h"
+#include "timelineabstractrenderer.h"
 #include "timelinerenderpass.h"
 #include <QSGMaterial>
 
@@ -41,7 +41,7 @@ class TimelineItemsRenderPass : public TimelineRenderPass
 {
 public:
     static const TimelineItemsRenderPass *instance();
-    State *update(const TimelineRenderer *renderer, const TimelineRenderState *parentState,
+    State *update(const TimelineAbstractRenderer *renderer, const TimelineRenderState *parentState,
                   State *state, int firstIndex, int lastIndex, bool stateChanged,
                   qreal spacing) const;
 protected:
diff --git a/src/plugins/qmlprofiler/timelinenotesrenderpass.cpp b/src/plugins/qmlprofiler/timelinenotesrenderpass.cpp
index b6b33217677..0dba68828f1 100644
--- a/src/plugins/qmlprofiler/timelinenotesrenderpass.cpp
+++ b/src/plugins/qmlprofiler/timelinenotesrenderpass.cpp
@@ -96,7 +96,7 @@ TimelineNotesRenderPass::TimelineNotesRenderPass()
 {
 }
 
-TimelineRenderPass::State *TimelineNotesRenderPass::update(const TimelineRenderer *renderer,
+TimelineRenderPass::State *TimelineNotesRenderPass::update(const TimelineAbstractRenderer *renderer,
                                                            const TimelineRenderState *parentState,
                                                            State *oldState, int firstIndex,
                                                            int lastIndex, bool stateChanged,
diff --git a/src/plugins/qmlprofiler/timelinenotesrenderpass.h b/src/plugins/qmlprofiler/timelinenotesrenderpass.h
index e6bf5295cac..0084d899d17 100644
--- a/src/plugins/qmlprofiler/timelinenotesrenderpass.h
+++ b/src/plugins/qmlprofiler/timelinenotesrenderpass.h
@@ -31,7 +31,7 @@
 #ifndef TIMELINENOTESRENDERPASS_H
 #define TIMELINENOTESRENDERPASS_H
 
-#include "timelinerenderer.h"
+#include "timelineabstractrenderer.h"
 #include <QSGMaterial>
 
 namespace Timeline {
@@ -41,7 +41,7 @@ class TimelineNotesRenderPass : public TimelineRenderPass
 public:
     static const TimelineNotesRenderPass *instance();
 
-    State *update(const TimelineRenderer *renderer, const TimelineRenderState *parentState,
+    State *update(const TimelineAbstractRenderer *renderer, const TimelineRenderState *parentState,
                   State *oldState, int firstIndex, int lastIndex, bool stateChanged,
                   qreal spacing) const;
 
diff --git a/src/plugins/qmlprofiler/timelineoverviewrenderer_p.h b/src/plugins/qmlprofiler/timelineoverviewrenderer_p.h
new file mode 100644
index 00000000000..2b62955e709
--- /dev/null
+++ b/src/plugins/qmlprofiler/timelineoverviewrenderer_p.h
@@ -0,0 +1,5 @@
+#ifndef TIMELINEOVERLAYRENDERER_P_H
+#define TIMELINEOVERLAYRENDERER_P_H
+
+#endif // TIMELINEOVERLAYRENDERER_P_H
+
diff --git a/src/plugins/qmlprofiler/timelinerenderer.cpp b/src/plugins/qmlprofiler/timelinerenderer.cpp
index 703c567fa87..69141399c5c 100644
--- a/src/plugins/qmlprofiler/timelinerenderer.cpp
+++ b/src/plugins/qmlprofiler/timelinerenderer.cpp
@@ -51,141 +51,19 @@
 namespace Timeline {
 
 TimelineRenderer::TimelineRendererPrivate::TimelineRendererPrivate(TimelineRenderer *q) :
-    model(0), zoomer(0), notes(0), selectedItem(-1), selectionLocked(true), modelDirty(false),
-    rowHeightsDirty(false), rowCountsDirty(false), lastState(0), q_ptr(q)
+    lastState(0), q_ptr(q)
 {
     resetCurrentSelection();
 }
 
 TimelineRenderer::TimelineRenderer(QQuickItem *parent) :
-    QQuickItem(parent), d_ptr(new TimelineRendererPrivate(this))
+    TimelineAbstractRenderer(*(new TimelineRendererPrivate(this)), parent)
 {
     setFlag(QQuickItem::ItemHasContents);
     setAcceptedMouseButtons(Qt::LeftButton);
     setAcceptHoverEvents(true);
 }
 
-bool TimelineRenderer::selectionLocked() const
-{
-    Q_D(const TimelineRenderer);
-    return d->selectionLocked;
-}
-
-int TimelineRenderer::selectedItem() const
-{
-    Q_D(const TimelineRenderer);
-    return d->selectedItem;
-}
-
-TimelineModel *TimelineRenderer::model() const
-{
-    Q_D(const TimelineRenderer);
-    return d->model;
-}
-
-void TimelineRenderer::setModel(TimelineModel *model)
-{
-    Q_D(TimelineRenderer);
-    if (d->model == model)
-        return;
-
-    if (d->model) {
-        disconnect(d->model, SIGNAL(expandedChanged()), this, SLOT(update()));
-        disconnect(d->model, SIGNAL(hiddenChanged()), this, SLOT(update()));
-        disconnect(d->model, SIGNAL(expandedRowHeightChanged(int,int)),
-                   this, SLOT(setRowHeightsDirty()));
-        disconnect(d->model, SIGNAL(emptyChanged()), this, SLOT(setModelDirty()));
-        disconnect(d->model, SIGNAL(expandedRowCountChanged()), this, SLOT(setRowCountsDirty()));
-        disconnect(d->model, SIGNAL(collapsedRowCountChanged()), this, SLOT(setRowCountsDirty()));
-    }
-
-    d->model = model;
-    if (d->model) {
-        connect(d->model, SIGNAL(expandedChanged()), this, SLOT(update()));
-        connect(d->model, SIGNAL(hiddenChanged()), this, SLOT(update()));
-        connect(d->model, SIGNAL(expandedRowHeightChanged(int,int)),
-                this, SLOT(setRowHeightsDirty()));
-        connect(d->model, SIGNAL(emptyChanged()), this, SLOT(setModelDirty()));
-        connect(d->model, SIGNAL(expandedRowCountChanged()), this, SLOT(setRowCountsDirty()));
-        connect(d->model, SIGNAL(collapsedRowCountChanged()), this, SLOT(setRowCountsDirty()));
-        d->renderPasses = d->model->supportedRenderPasses();
-    }
-
-    setModelDirty();
-    setRowHeightsDirty();
-    setRowCountsDirty();
-    emit modelChanged(d->model);
-}
-
-TimelineZoomControl *TimelineRenderer::zoomer() const
-{
-    Q_D(const TimelineRenderer);
-    return d->zoomer;
-}
-
-void TimelineRenderer::setZoomer(TimelineZoomControl *zoomer)
-{
-    Q_D(TimelineRenderer);
-    if (zoomer != d->zoomer) {
-        if (d->zoomer != 0)
-            disconnect(d->zoomer, SIGNAL(windowChanged(qint64,qint64)), this, SLOT(update()));
-        d->zoomer = zoomer;
-        if (d->zoomer != 0)
-            connect(d->zoomer, SIGNAL(windowChanged(qint64,qint64)), this, SLOT(update()));
-        emit zoomerChanged(zoomer);
-        update();
-    }
-}
-
-TimelineNotesModel *TimelineRenderer::notes() const
-{
-    Q_D(const TimelineRenderer);
-    return d->notes;
-}
-
-void TimelineRenderer::setNotes(TimelineNotesModel *notes)
-{
-    Q_D(TimelineRenderer);
-    if (d->notes == notes)
-        return;
-
-    if (d->notes)
-        disconnect(d->notes, &TimelineNotesModel::changed,
-                   this, &TimelineRenderer::setNotesDirty);
-
-    d->notes = notes;
-    if (d->notes)
-        connect(d->notes, &TimelineNotesModel::changed,
-                this, &TimelineRenderer::setNotesDirty);
-
-    emit notesChanged(d->notes);
-    update();
-}
-
-bool TimelineRenderer::modelDirty() const
-{
-    Q_D(const TimelineRenderer);
-    return d->modelDirty;
-}
-
-bool TimelineRenderer::notesDirty() const
-{
-    Q_D(const TimelineRenderer);
-    return d->notesDirty;
-}
-
-bool TimelineRenderer::rowHeightsDirty() const
-{
-    Q_D(const TimelineRenderer);
-    return d->rowHeightsDirty;
-}
-
-bool TimelineRenderer::rowCountsDirty() const
-{
-    Q_D(const TimelineRenderer);
-    return d->rowCountsDirty;
-}
-
 void TimelineRenderer::TimelineRendererPrivate::resetCurrentSelection()
 {
     currentSelection.startTime = -1;
@@ -241,14 +119,13 @@ QSGNode *TimelineRenderer::updatePaintNode(QSGNode *node, UpdatePaintNodeData *u
             d->zoomer->windowDuration() <= 0) {
         delete node;
         return 0;
-    } else if (node == 0) {
-        node = new QSGTransformNode;
     }
 
     qreal spacing = width() / d->zoomer->windowDuration();
 
-    if (d->modelDirty || d->rowCountsDirty) {
-        node->removeAllChildNodes();
+    if (d->modelDirty) {
+        if (node)
+            node->removeAllChildNodes();
         foreach (QVector<TimelineRenderState *> stateVector, d->renderStates)
             qDeleteAll(stateVector);
         d->renderStates.clear();
@@ -266,91 +143,23 @@ QSGNode *TimelineRenderer::updatePaintNode(QSGNode *node, UpdatePaintNodeData *u
                                                          state != d->lastState, spacing));
 
     if (state->isEmpty()) { // new state
-        for (int pass = 0; pass < d->renderPasses.length(); ++pass) {
-            const TimelineRenderPass::State *passState = state->passState(pass);
-            if (!passState)
-                continue;
-            if (passState->expandedOverlay())
-                state->expandedOverlayRoot()->appendChildNode(passState->expandedOverlay());
-            if (passState->collapsedOverlay())
-                state->collapsedOverlayRoot()->appendChildNode(passState->collapsedOverlay());
-        }
-
-        int row = 0;
-        for (int i = 0; i < d->model->expandedRowCount(); ++i) {
-            QSGTransformNode *rowNode = new QSGTransformNode;
-            for (int pass = 0; pass < d->renderPasses.length(); ++pass) {
-                const TimelineRenderPass::State *passState = state->passState(pass);
-                if (!passState)
-                    continue;
-                const QVector<QSGNode *> &rows = passState->expandedRows();
-                if (rows.length() > row) {
-                    QSGNode *rowChildNode = rows[row];
-                    if (rowChildNode)
-                        rowNode->appendChildNode(rowChildNode);
-                }
-            }
-            state->expandedRowRoot()->appendChildNode(rowNode);
-            ++row;
-        }
-
-        for (int row = 0; row < d->model->collapsedRowCount(); ++row) {
-            QSGTransformNode *rowNode = new QSGTransformNode;
-            QMatrix4x4 matrix;
-            matrix.translate(0, row * TimelineModel::defaultRowHeight(), 0);
-            rowNode->setMatrix(matrix);
-            for (int pass = 0; pass < d->renderPasses.length(); ++pass) {
-                const TimelineRenderPass::State *passState = state->passState(pass);
-                if (!passState)
-                    continue;
-                const QVector<QSGNode *> &rows = passState->collapsedRows();
-                if (rows.length() > row) {
-                    QSGNode *rowChildNode = rows[row];
-                    if (rowChildNode)
-                        rowNode->appendChildNode(rowChildNode);
-                }
-            }
-            state->collapsedRowRoot()->appendChildNode(rowNode);
-        }
-    }
-
-    if (d->rowHeightsDirty || state != d->lastState) {
-        int row = 0;
-        qreal offset = 0;
-        for (QSGNode *rowNode = state->expandedRowRoot()->firstChild(); rowNode != 0;
-             rowNode = rowNode->nextSibling()) {
-            qreal rowHeight = d->model->expandedRowHeight(row++);
-            QMatrix4x4 matrix;
-            matrix.translate(0, offset, 0);
-            matrix.scale(1, rowHeight / TimelineModel::defaultRowHeight(), 1);
-            offset += rowHeight;
-            static_cast<QSGTransformNode *>(rowNode)->setMatrix(matrix);
-        }
+        state->assembleNodeTree(d->model, TimelineModel::defaultRowHeight(),
+                                TimelineModel::defaultRowHeight());
+    } else if (d->rowHeightsDirty || state != d->lastState) {
+        state->updateExpandedRowHeights(d->model, TimelineModel::defaultRowHeight(),
+                                        TimelineModel::defaultRowHeight());
     }
 
     d->modelDirty = false;
     d->notesDirty = false;
-    d->rowCountsDirty = false;
     d->rowHeightsDirty = false;
     d->lastState = state;
 
-    QSGNode *rowNode = d->model->expanded() ? state->expandedRowRoot() : state->collapsedRowRoot();
-    QSGNode *overlayNode = d->model->expanded() ? state->expandedOverlayRoot() :
-                                                 state->collapsedOverlayRoot();
-
     QMatrix4x4 matrix;
     matrix.translate((state->start() - d->zoomer->windowStart()) * spacing, 0, 0);
     matrix.scale(spacing / state->scale(), 1, 1);
 
-    QSGTransformNode *transform = static_cast<QSGTransformNode *>(node);
-    transform->setMatrix(matrix);
-
-    if (node->firstChild() != rowNode || node->lastChild() != overlayNode) {
-        node->removeAllChildNodes();
-        node->appendChildNode(rowNode);
-        node->appendChildNode(overlayNode);
-    }
-    return node;
+    return state->finalize(node, d->model->expanded(), matrix);
 }
 
 void TimelineRenderer::mousePressEvent(QMouseEvent *event)
@@ -481,26 +290,6 @@ void TimelineRenderer::clearData()
     setSelectionLocked(true);
 }
 
-void TimelineRenderer::setSelectedItem(int itemIndex)
-{
-    Q_D(TimelineRenderer);
-    if (d->selectedItem != itemIndex) {
-        d->selectedItem = itemIndex;
-        update();
-        emit selectedItemChanged(itemIndex);
-    }
-}
-
-void TimelineRenderer::setSelectionLocked(bool locked)
-{
-    Q_D(TimelineRenderer);
-    if (d->selectionLocked != locked) {
-        d->selectionLocked = locked;
-        update();
-        emit selectionLockedChanged(locked);
-    }
-}
-
 void TimelineRenderer::selectNextFromSelectionId(int selectionId)
 {
     Q_D(TimelineRenderer);
@@ -515,32 +304,4 @@ void TimelineRenderer::selectPrevFromSelectionId(int selectionId)
                                                    d->selectedItem));
 }
 
-void TimelineRenderer::setModelDirty()
-{
-    Q_D(TimelineRenderer);
-    d->modelDirty = true;
-    update();
-}
-
-void TimelineRenderer::setRowHeightsDirty()
-{
-    Q_D(TimelineRenderer);
-    d->rowHeightsDirty = true;
-    update();
-}
-
-void TimelineRenderer::setNotesDirty()
-{
-    Q_D(TimelineRenderer);
-    d->notesDirty = true;
-    update();
-}
-
-void TimelineRenderer::setRowCountsDirty()
-{
-    Q_D(TimelineRenderer);
-    d->rowCountsDirty = true;
-    update();
-}
-
 } // namespace Timeline
diff --git a/src/plugins/qmlprofiler/timelinerenderer.h b/src/plugins/qmlprofiler/timelinerenderer.h
index b772ac703a9..f996c158d37 100644
--- a/src/plugins/qmlprofiler/timelinerenderer.h
+++ b/src/plugins/qmlprofiler/timelinerenderer.h
@@ -36,43 +36,20 @@
 #include "timelinezoomcontrol.h"
 #include "timelinemodel.h"
 #include "timelinenotesmodel.h"
-#include "timelinerenderpass.h"
+#include "timelineabstractrenderer.h"
 
 namespace Timeline {
 
 class TimelineRenderPass;
 class TimelineRenderState;
 
-class TimelineRenderer : public QQuickItem
+class TimelineRenderer : public TimelineAbstractRenderer
 {
     Q_OBJECT
-    Q_PROPERTY(Timeline::TimelineModel *model READ model WRITE setModel NOTIFY modelChanged)
-    Q_PROPERTY(Timeline::TimelineZoomControl *zoomer READ zoomer WRITE setZoomer NOTIFY zoomerChanged)
-    Q_PROPERTY(Timeline::TimelineNotesModel *notes READ notes WRITE setNotes NOTIFY notesChanged)
-    Q_PROPERTY(bool selectionLocked READ selectionLocked WRITE setSelectionLocked NOTIFY selectionLockedChanged)
-    Q_PROPERTY(int selectedItem READ selectedItem WRITE setSelectedItem NOTIFY selectedItemChanged)
 
 public:
-
     explicit TimelineRenderer(QQuickItem *parent = 0);
 
-    bool selectionLocked() const;
-    int selectedItem() const;
-
-    TimelineModel *model() const;
-    void setModel(TimelineModel *model);
-
-    TimelineZoomControl *zoomer() const;
-    void setZoomer(TimelineZoomControl *zoomer);
-
-    TimelineNotesModel *notes() const;
-    void setNotes(TimelineNotesModel *notes);
-
-    bool modelDirty() const;
-    bool notesDirty() const;
-    bool rowHeightsDirty() const;
-    bool rowCountsDirty() const;
-
     Q_INVOKABLE void selectNextFromSelectionId(int selectionId);
     Q_INVOKABLE void selectPrevFromSelectionId(int selectionId);
 
@@ -80,25 +57,11 @@ public:
     // need arises.
 
 signals:
-    void modelChanged(const TimelineModel *model);
-    void zoomerChanged(TimelineZoomControl *zoomer);
-    void notesChanged(TimelineNotesModel *notes);
-
-    void selectionLockedChanged(bool locked);
-    void selectedItemChanged(int itemIndex);
     void itemPressed(int pressedItem);
 
 public slots:
     void clearData();
 
-    void setSelectedItem(int itemIndex);
-    void setSelectionLocked(bool locked);
-
-    void setModelDirty();
-    void setRowHeightsDirty();
-    void setNotesDirty();
-    void setRowCountsDirty();
-
 protected:
     virtual QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData);
     virtual void mousePressEvent(QMouseEvent *event);
@@ -108,7 +71,6 @@ protected:
 
 private:
     class TimelineRendererPrivate;
-    TimelineRendererPrivate *d_ptr;
     Q_DECLARE_PRIVATE(TimelineRenderer)
 };
 
diff --git a/src/plugins/qmlprofiler/timelinerenderer_p.h b/src/plugins/qmlprofiler/timelinerenderer_p.h
index 82de1d84a0b..3d4a2678aa0 100644
--- a/src/plugins/qmlprofiler/timelinerenderer_p.h
+++ b/src/plugins/qmlprofiler/timelinerenderer_p.h
@@ -32,10 +32,12 @@
 #define TIMELINERENDERER_P_H
 
 #include "timelinerenderer.h"
+#include "timelineabstractrenderer_p.h"
 
 namespace Timeline {
 
-class TimelineRenderer::TimelineRendererPrivate {
+class TimelineRenderer::TimelineRendererPrivate :
+        TimelineAbstractRenderer::TimelineAbstractRendererPrivate {
 public:
     TimelineRendererPrivate(TimelineRenderer *q);
 
@@ -50,10 +52,6 @@ public:
 
     TimelineRenderState *findRenderState();
 
-    TimelineModel *model;
-    TimelineZoomControl *zoomer;
-    TimelineNotesModel *notes;
-
     struct {
         qint64 startTime;
         qint64 endTime;
@@ -61,14 +59,6 @@ public:
         int eventIndex;
     } currentSelection;
 
-    int selectedItem;
-    bool selectionLocked;
-    bool modelDirty;
-    bool rowHeightsDirty;
-    bool notesDirty;
-    bool rowCountsDirty;
-
-    QList<const TimelineRenderPass *> renderPasses;
     QVector<QVector<TimelineRenderState *> > renderStates;
     TimelineRenderState *lastState;
 
diff --git a/src/plugins/qmlprofiler/timelinerenderpass.h b/src/plugins/qmlprofiler/timelinerenderpass.h
index 89c1171c3cf..9068c2de85b 100644
--- a/src/plugins/qmlprofiler/timelinerenderpass.h
+++ b/src/plugins/qmlprofiler/timelinerenderpass.h
@@ -36,7 +36,7 @@
 QT_FORWARD_DECLARE_CLASS(QSGNode)
 namespace Timeline {
 
-class TimelineRenderer;
+class TimelineAbstractRenderer;
 class TimelineRenderState;
 
 class TimelineRenderPass {
@@ -50,7 +50,8 @@ public:
     };
 
     virtual ~TimelineRenderPass();
-    virtual State *update(const TimelineRenderer *renderer, const TimelineRenderState *parentState,
+    virtual State *update(const TimelineAbstractRenderer *renderer,
+                          const TimelineRenderState *parentState,
                           State *state, int indexFrom, int indexTo, bool stateChanged,
                           qreal spacing) const = 0;
 };
diff --git a/src/plugins/qmlprofiler/timelinerenderstate.cpp b/src/plugins/qmlprofiler/timelinerenderstate.cpp
index 4e6014cb387..e014f910487 100644
--- a/src/plugins/qmlprofiler/timelinerenderstate.cpp
+++ b/src/plugins/qmlprofiler/timelinerenderstate.cpp
@@ -134,6 +134,98 @@ bool TimelineRenderState::isEmpty() const
             d->collapsedOverlayRoot->childCount() == 0 && d->expandedOverlayRoot->childCount() == 0;
 }
 
+void TimelineRenderState::assembleNodeTree(const TimelineModel *model, int defaultRowHeight,
+                                           int defaultRowOffset)
+{
+    Q_D(TimelineRenderState);
+    for (int pass = 0; pass < d->passes.length(); ++pass) {
+        const TimelineRenderPass::State *passState = d->passes[pass];
+        if (!passState)
+            continue;
+        if (passState->expandedOverlay())
+            d->expandedOverlayRoot->appendChildNode(passState->expandedOverlay());
+        if (passState->collapsedOverlay())
+            d->collapsedOverlayRoot->appendChildNode(passState->collapsedOverlay());
+    }
+
+    int row = 0;
+    for (int i = 0; i < model->expandedRowCount(); ++i) {
+        QSGTransformNode *rowNode = new QSGTransformNode;
+        for (int pass = 0; pass < d->passes.length(); ++pass) {
+            const TimelineRenderPass::State *passState = d->passes[pass];
+            if (!passState)
+                continue;
+            const QVector<QSGNode *> &rows = passState->expandedRows();
+            if (rows.length() > row) {
+                QSGNode *rowChildNode = rows[row];
+                if (rowChildNode)
+                    rowNode->appendChildNode(rowChildNode);
+            }
+        }
+        d->expandedRowRoot->appendChildNode(rowNode);
+        ++row;
+    }
+
+    for (int row = 0; row < model->collapsedRowCount(); ++row) {
+        QSGTransformNode *rowNode = new QSGTransformNode;
+        QMatrix4x4 matrix;
+        matrix.translate(0, row * defaultRowOffset, 0);
+        matrix.scale(1.0, static_cast<float>(defaultRowHeight) /
+                     static_cast<float>(TimelineModel::defaultRowHeight()), 1.0);
+        rowNode->setMatrix(matrix);
+        for (int pass = 0; pass < d->passes.length(); ++pass) {
+            const TimelineRenderPass::State *passState = d->passes[pass];
+            if (!passState)
+                continue;
+            const QVector<QSGNode *> &rows = passState->collapsedRows();
+            if (rows.length() > row) {
+                QSGNode *rowChildNode = rows[row];
+                if (rowChildNode)
+                    rowNode->appendChildNode(rowChildNode);
+            }
+        }
+        d->collapsedRowRoot->appendChildNode(rowNode);
+    }
+
+    updateExpandedRowHeights(model, defaultRowHeight, defaultRowOffset);
+}
+
+void TimelineRenderState::updateExpandedRowHeights(const TimelineModel *model, int defaultRowHeight,
+                                                   int defaultRowOffset)
+{
+    Q_D(TimelineRenderState);
+    int row = 0;
+    qreal offset = 0;
+    for (QSGNode *rowNode = d->expandedRowRoot->firstChild(); rowNode != 0;
+         rowNode = rowNode->nextSibling()) {
+        qreal rowHeight = model->expandedRowHeight(row++);
+        QMatrix4x4 matrix;
+        matrix.translate(0, offset, 0);
+        matrix.scale(1, rowHeight / defaultRowHeight, 1);
+        offset += defaultRowOffset * rowHeight / defaultRowHeight;
+        static_cast<QSGTransformNode *>(rowNode)->setMatrix(matrix);
+    }
+}
+
+QSGTransformNode *TimelineRenderState::finalize(QSGNode *oldNode, bool expanded,
+                                                const QMatrix4x4 &transform)
+{
+    Q_D(TimelineRenderState);
+    QSGNode *rowNode = expanded ? d->expandedRowRoot : d->collapsedRowRoot;
+    QSGNode *overlayNode = expanded ?d->expandedOverlayRoot : d->collapsedOverlayRoot;
+
+    QSGTransformNode *node = oldNode ? static_cast<QSGTransformNode *>(oldNode) :
+                                            new QSGTransformNode;
+    node->setMatrix(transform);
+
+    if (node->firstChild() != rowNode || node->lastChild() != overlayNode) {
+        node->removeAllChildNodes();
+        node->appendChildNode(rowNode);
+        node->appendChildNode(overlayNode);
+    }
+    return node;
+}
+
 TimelineRenderPass::State *TimelineRenderState::passState(int i)
 {
     Q_D(TimelineRenderState);
diff --git a/src/plugins/qmlprofiler/timelinerenderstate.h b/src/plugins/qmlprofiler/timelinerenderstate.h
index 9d28d349e83..2333e836fb3 100644
--- a/src/plugins/qmlprofiler/timelinerenderstate.h
+++ b/src/plugins/qmlprofiler/timelinerenderstate.h
@@ -33,6 +33,7 @@
 
 #include <QSGNode>
 #include "timelinerenderpass.h"
+#include "timelinemodel.h"
 
 namespace Timeline {
 
@@ -60,6 +61,10 @@ public:
     QSGNode *collapsedOverlayRoot();
 
     bool isEmpty() const;
+    void assembleNodeTree(const TimelineModel *model, int defaultRowHeight, int defaultRowOffset);
+    void updateExpandedRowHeights(const TimelineModel *model, int defaultRowHeight,
+                                  int defaultRowOffset);
+    QSGTransformNode *finalize(QSGNode *oldNode, bool expanded, const QMatrix4x4 &transform);
 
 private:
     class TimelineRenderStatePrivate;
diff --git a/src/plugins/qmlprofiler/timelineselectionrenderpass.cpp b/src/plugins/qmlprofiler/timelineselectionrenderpass.cpp
index 10b674fccea..eb5cdb5b040 100644
--- a/src/plugins/qmlprofiler/timelineselectionrenderpass.cpp
+++ b/src/plugins/qmlprofiler/timelineselectionrenderpass.cpp
@@ -55,9 +55,9 @@ struct TimelineSelectionRenderPassState : public TimelineRenderPass::State {
     QSGNode *collapsedOverlay() const { return m_collapsedOverlay; }
 };
 
-TimelineRenderPass::State *TimelineSelectionRenderPass::update(const TimelineRenderer *renderer,
-        const TimelineRenderState *parentState, State *oldState, int firstIndex, int lastIndex,
-        bool stateChanged, qreal spacing) const
+TimelineRenderPass::State *TimelineSelectionRenderPass::update(
+        const TimelineAbstractRenderer *renderer, const TimelineRenderState *parentState,
+        State *oldState, int firstIndex, int lastIndex, bool stateChanged, qreal spacing) const
 {
     Q_UNUSED(stateChanged);
 
diff --git a/src/plugins/qmlprofiler/timelineselectionrenderpass.h b/src/plugins/qmlprofiler/timelineselectionrenderpass.h
index 83046465fa4..f7445ac661d 100644
--- a/src/plugins/qmlprofiler/timelineselectionrenderpass.h
+++ b/src/plugins/qmlprofiler/timelineselectionrenderpass.h
@@ -31,7 +31,7 @@
 #ifndef TIMELINESELECTIONRENDERPASS_H
 #define TIMELINESELECTIONRENDERPASS_H
 
-#include "timelinerenderer.h"
+#include "timelineabstractrenderer.h"
 #include "timelinerenderpass.h"
 #include "timelinerenderstate.h"
 
@@ -42,7 +42,7 @@ class TimelineSelectionRenderPass : public TimelineRenderPass
 public:
     static const TimelineSelectionRenderPass *instance();
 
-    State *update(const TimelineRenderer *renderer, const TimelineRenderState *parentState,
+    State *update(const TimelineAbstractRenderer *renderer, const TimelineRenderState *parentState,
                   State *state, int firstIndex, int lastIndex, bool stateChanged,
                   qreal spacing) const;
 
-- 
GitLab