diff --git a/src/plugins/qmlprofiler/abstracttimelinemodel.cpp b/src/plugins/qmlprofiler/abstracttimelinemodel.cpp index 2f10e17e064..ae5646dfca2 100644 --- a/src/plugins/qmlprofiler/abstracttimelinemodel.cpp +++ b/src/plugins/qmlprofiler/abstracttimelinemodel.cpp @@ -32,6 +32,7 @@ namespace QmlProfiler { +static const int DefaultRowHeight = 30; AbstractTimelineModel::AbstractTimelineModel(AbstractTimelineModelPrivate *dd, const QString &name, const QString &label, QmlDebug::Message message, @@ -122,6 +123,63 @@ bool AbstractTimelineModel::isEmpty() const return count() == 0; } +int AbstractTimelineModel::rowHeight(int rowNumber) const +{ + Q_D(const AbstractTimelineModel); + if (!expanded()) + return DefaultRowHeight; + + if (d->rowOffsets.length() > rowNumber) + return d->rowOffsets[rowNumber] - (rowNumber > 0 ? d->rowOffsets[rowNumber - 1] : 0); + return DefaultRowHeight; +} + +int AbstractTimelineModel::rowOffset(int rowNumber) const +{ + Q_D(const AbstractTimelineModel); + if (rowNumber == 0) + return 0; + if (!expanded()) + return DefaultRowHeight * rowNumber; + + if (d->rowOffsets.length() >= rowNumber) + return d->rowOffsets[rowNumber - 1]; + if (!d->rowOffsets.empty()) + return d->rowOffsets.last() + (rowNumber - 1 - d->rowOffsets.length()) * DefaultRowHeight; + return rowNumber * DefaultRowHeight; +} + +void AbstractTimelineModel::setRowHeight(int rowNumber, int height) +{ + Q_D(AbstractTimelineModel); + if (!expanded()) + return; + if (height < DefaultRowHeight) + height = DefaultRowHeight; + + int nextOffset = d->rowOffsets.empty() ? 0 : d->rowOffsets.last(); + while (d->rowOffsets.length() <= rowNumber) + d->rowOffsets << (nextOffset += DefaultRowHeight); + int difference = height - d->rowOffsets[rowNumber] + + (rowNumber > 0 ? d->rowOffsets[rowNumber - 1] : 0); + if (difference != 0) { + for (; rowNumber < d->rowOffsets.length(); ++rowNumber) { + d->rowOffsets[rowNumber] += difference; + } + emit rowHeightChanged(); + } +} + +int AbstractTimelineModel::height() const +{ + Q_D(const AbstractTimelineModel); + int depth = rowCount(); + if (!expanded() || d->rowOffsets.empty()) + return depth * DefaultRowHeight; + + return d->rowOffsets.last() + (depth - d->rowOffsets.length()) * DefaultRowHeight; +} + qint64 AbstractTimelineModel::traceStartTime() const { Q_D(const AbstractTimelineModel); @@ -192,6 +250,8 @@ void AbstractTimelineModel::dataChanged() default: break; } + + d->rowOffsets.clear(); } bool AbstractTimelineModel::eventAccepted(const QmlProfilerDataModel::QmlEventTypeData &event) const diff --git a/src/plugins/qmlprofiler/abstracttimelinemodel.h b/src/plugins/qmlprofiler/abstracttimelinemodel.h index 813384d989e..ef407afafb9 100644 --- a/src/plugins/qmlprofiler/abstracttimelinemodel.h +++ b/src/plugins/qmlprofiler/abstracttimelinemodel.h @@ -54,6 +54,11 @@ public: bool isEmpty() const; // Methods are directly passed on to the private model and relying on its virtual methods. + int rowHeight(int rowNumber) const; + int rowOffset(int rowNumber) const; + void setRowHeight(int rowNumber, int height); + int height() const; + Q_INVOKABLE qint64 lastTimeMark() const; Q_INVOKABLE qint64 traceStartTime() const; Q_INVOKABLE qint64 traceEndTime() const; @@ -91,6 +96,7 @@ public: signals: void expandedChanged(); + void rowHeightChanged(); protected: enum BoxColorProperties { diff --git a/src/plugins/qmlprofiler/abstracttimelinemodel_p.h b/src/plugins/qmlprofiler/abstracttimelinemodel_p.h index c8a70ada0f5..4cc42cd8eb6 100644 --- a/src/plugins/qmlprofiler/abstracttimelinemodel_p.h +++ b/src/plugins/qmlprofiler/abstracttimelinemodel_p.h @@ -47,6 +47,7 @@ public: virtual int findFirstIndexNoParents(qint64 startTime) const = 0; virtual int findLastIndex(qint64 endTime) const = 0; + QVector rowOffsets; QString name; QmlProfilerModelManager *modelManager; int modelId; diff --git a/src/plugins/qmlprofiler/qml/CategoryLabel.qml b/src/plugins/qmlprofiler/qml/CategoryLabel.qml index c3240352347..cf4588c6b75 100644 --- a/src/plugins/qmlprofiler/qml/CategoryLabel.qml +++ b/src/plugins/qmlprofiler/qml/CategoryLabel.qml @@ -32,30 +32,25 @@ import QtQuick 2.1 Item { id: labelContainer property string text: qmlProfilerModelProxy.title(modelIndex) - property bool expanded: false - property int modelIndex: index; - + property bool expanded: trigger(qmlProfilerModelProxy.expanded(modelIndex)) + property int modelIndex: index + property int bindingTrigger: 1 property var descriptions: [] property var extdescriptions: [] property var eventIds: [] - visible: qmlProfilerModelProxy.rowCount(modelIndex) > 0; + function trigger(i) { + return i * bindingTrigger * bindingTrigger; + } - height: root.singleRowHeight + visible: trigger(qmlProfilerModelProxy.rowCount(modelIndex)) > 0 + + height: trigger(qmlProfilerModelProxy.height(modelIndex)) width: 150 - Component.onCompleted: { - updateHeight(); - } - - function updateHeight() { - height = root.singleRowHeight * qmlProfilerModelProxy.rowCount(modelIndex); - } - function getDescriptions() { - expanded = qmlProfilerModelProxy.expanded(modelIndex); + bindingTrigger = -bindingTrigger; backgroundMarks.requestPaint(); - visible = qmlProfilerModelProxy.rowCount(modelIndex) > 0; if (!visible) return; @@ -71,18 +66,13 @@ Item { descriptions = desc; eventIds = ids; extdescriptions = extdesc; - updateHeight(); } Connections { target: qmlProfilerModelProxy - onExpandedChanged: { - getDescriptions(); - } - - onStateChanged: { - getDescriptions(); - } + onExpandedChanged: getDescriptions(); + onStateChanged: getDescriptions() + onRowHeightChanged: getDescriptions() } Text { @@ -91,7 +81,7 @@ Item { font.pixelSize: 12 text: labelContainer.text color: "#232323" - height: root.singleRowHeight + height: trigger(qmlProfilerModelProxy.rowHeight(modelIndex, 0)) width: 140 verticalAlignment: Text.AlignVCenter } @@ -105,20 +95,21 @@ Item { } Column { - y: root.singleRowHeight + anchors.top: txt.bottom visible: expanded Repeater { model: descriptions.length Rectangle { width: labelContainer.width - height: root.singleRowHeight + height: trigger(qmlProfilerModelProxy.rowHeight(modelIndex, index + 1)) color: "#eaeaea" border.width: 1 border.color:"#c8c8c8" Text { - height: root.singleRowHeight - x: 5 - width: 140 + anchors.fill: parent + anchors.leftMargin: 5 + anchors.rightMargin: 5 + text: descriptions[index] textFormat: Text.PlainText elide: Text.ElideRight @@ -143,7 +134,7 @@ Item { Image { source: expanded ? "arrow_down.png" : "arrow_right.png" x: parent.width - 12 - y: Math.floor((root.singleRowHeight - height) / 2) + y: 9 smooth: false MouseArea { anchors.fill: parent diff --git a/src/plugins/qmlprofiler/qml/MainView.qml b/src/plugins/qmlprofiler/qml/MainView.qml index db38cab72f9..5d54cf5e923 100644 --- a/src/plugins/qmlprofiler/qml/MainView.qml +++ b/src/plugins/qmlprofiler/qml/MainView.qml @@ -36,8 +36,6 @@ Rectangle { // ***** properties - property int singleRowHeight: 30 - property alias selectionLocked : view.selectionLocked property bool lockItemSelection : false diff --git a/src/plugins/qmlprofiler/qml/TimeMarks.qml b/src/plugins/qmlprofiler/qml/TimeMarks.qml index b482023fd59..a2e2d49bc2b 100644 --- a/src/plugins/qmlprofiler/qml/TimeMarks.qml +++ b/src/plugins/qmlprofiler/qml/TimeMarks.qml @@ -102,21 +102,30 @@ Canvas { function drawBackgroundBars( context, region ) { var colorIndex = true; - // row background - var backgroundOffset = y < 0 ? -y : -(y % (2 * root.singleRowHeight)); - for (var currentY= backgroundOffset; currentY < Math.min(height, labels.height - y); currentY += root.singleRowHeight) { - context.fillStyle = colorIndex ? "#f0f0f0" : "white"; - context.strokeStyle = colorIndex ? "#f0f0f0" : "white"; - context.fillRect(0, currentY, width, root.singleRowHeight); - colorIndex = !colorIndex; - } - // separators - var cumulatedHeight = 0; - for (var modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount() && cumulatedHeight < y + height; modelIndex++) { - cumulatedHeight += root.singleRowHeight * qmlProfilerModelProxy.rowCount(modelIndex); - if (cumulatedHeight < y) + var cumulatedHeight = y < 0 ? -y : 0; + for (var modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount(); ++modelIndex) { + var modelHeight = qmlProfilerModelProxy.height(modelIndex); + if (cumulatedHeight + modelHeight < y) { + cumulatedHeight += modelHeight; + if (qmlProfilerModelProxy.rowCount(modelIndex) % 2 !== 0) + colorIndex = !colorIndex; continue; + } + + for (var row = 0; row < qmlProfilerModelProxy.rowCount(modelIndex); ++row) { + // row background + var rowHeight = qmlProfilerModelProxy.rowHeight(modelIndex, row) + cumulatedHeight += rowHeight; + colorIndex = !colorIndex; + if (cumulatedHeight < y - rowHeight) + continue; + context.strokeStyle = context.fillStyle = colorIndex ? "#f0f0f0" : "white"; + context.fillRect(0, cumulatedHeight - rowHeight - y, width, rowHeight); + + if (cumulatedHeight > y + height) + return; + } context.strokeStyle = "#B0B0B0"; context.beginPath(); diff --git a/src/plugins/qmlprofiler/timelinemodelaggregator.cpp b/src/plugins/qmlprofiler/timelinemodelaggregator.cpp index 0d7bb543c2f..cfa33b2af72 100644 --- a/src/plugins/qmlprofiler/timelinemodelaggregator.cpp +++ b/src/plugins/qmlprofiler/timelinemodelaggregator.cpp @@ -91,6 +91,7 @@ void TimelineModelAggregator::addModel(AbstractTimelineModel *m) { d->modelList << m; connect(m,SIGNAL(expandedChanged()),this,SIGNAL(expandedChanged())); + connect(m,SIGNAL(rowHeightChanged()),this,SIGNAL(rowHeightChanged())); } QStringList TimelineModelAggregator::categoryTitles() const @@ -141,6 +142,26 @@ qint64 TimelineModelAggregator::lastTimeMark() const return mark; } +int TimelineModelAggregator::height(int modelIndex) const +{ + return d->modelList[modelIndex]->height(); +} + +int TimelineModelAggregator::rowHeight(int modelIndex, int row) const +{ + return d->modelList[modelIndex]->rowHeight(row); +} + +int TimelineModelAggregator::rowOffset(int modelIndex, int row) const +{ + return d->modelList[modelIndex]->rowOffset(row); +} + +void TimelineModelAggregator::setRowHeight(int modelIndex, int row, int height) +{ + d->modelList[modelIndex]->setRowHeight(row, height); +} + bool TimelineModelAggregator::expanded(int modelIndex) const { return d->modelList[modelIndex]->expanded(); diff --git a/src/plugins/qmlprofiler/timelinemodelaggregator.h b/src/plugins/qmlprofiler/timelinemodelaggregator.h index 8e1a933cb9b..b2690b53626 100644 --- a/src/plugins/qmlprofiler/timelinemodelaggregator.h +++ b/src/plugins/qmlprofiler/timelinemodelaggregator.h @@ -62,6 +62,10 @@ public: Q_INVOKABLE qint64 lastTimeMark() const; + Q_INVOKABLE int height(int modelIndex) const; + Q_INVOKABLE int rowHeight(int modelIndex, int row) const; + Q_INVOKABLE void setRowHeight(int modelIndex, int row, int height); + Q_INVOKABLE int rowOffset(int modelIndex, int row) const; Q_INVOKABLE bool expanded(int modelIndex) const; Q_INVOKABLE void setExpanded(int modelIndex, bool expanded); Q_INVOKABLE int rowCount(int modelIndex) const; @@ -93,6 +97,7 @@ signals: void dataAvailable(); void stateChanged(); void expandedChanged(); + void rowHeightChanged(); protected slots: void dataChanged(); diff --git a/src/plugins/qmlprofiler/timelinerenderer.cpp b/src/plugins/qmlprofiler/timelinerenderer.cpp index 356761a3c2e..518aff5f2b8 100644 --- a/src/plugins/qmlprofiler/timelinerenderer.cpp +++ b/src/plugins/qmlprofiler/timelinerenderer.cpp @@ -41,8 +41,6 @@ using namespace QmlProfiler::Internal; -const int DefaultRowHeight = 30; - TimelineRenderer::TimelineRenderer(QQuickPaintedItem *parent) : QQuickPaintedItem(parent), m_startTime(0), m_endTime(0), m_spacing(0), m_spacedDuration(0), m_lastStartTime(0), m_lastEndTime(0) @@ -130,18 +128,20 @@ void TimelineRenderer::drawItemsToPainter(QPainter *p, int modelIndex, int fromI p->setPen(Qt::transparent); int modelRowStart = 0; for (int mi = 0; mi < modelIndex; mi++) - modelRowStart += m_profilerModelProxy->rowCount(mi); + modelRowStart += m_profilerModelProxy->height(mi); for (int i = fromIndex; i <= toIndex; i++) { int currentX, currentY, itemWidth, itemHeight; int rowNumber = m_profilerModelProxy->getEventRow(modelIndex, i); - currentY = (modelRowStart + rowNumber) * DefaultRowHeight - y(); + currentY = modelRowStart + m_profilerModelProxy->rowOffset(modelIndex, rowNumber) - y(); if (currentY >= height()) continue; - itemHeight = DefaultRowHeight * m_profilerModelProxy->getHeight(modelIndex, i); - currentY += DefaultRowHeight - itemHeight; + itemHeight = m_profilerModelProxy->rowHeight(modelIndex, rowNumber) * + m_profilerModelProxy->getHeight(modelIndex, i); + + currentY += m_profilerModelProxy->rowHeight(modelIndex, rowNumber) - itemHeight; if (currentY + itemHeight < 0) continue; @@ -164,7 +164,7 @@ void TimelineRenderer::drawSelectionBoxes(QPainter *p, int modelIndex, int fromI int modelRowStart = 0; for (int mi = 0; mi < modelIndex; mi++) - modelRowStart += m_profilerModelProxy->rowCount(mi); + modelRowStart += m_profilerModelProxy->height(mi); p->save(); @@ -183,16 +183,19 @@ void TimelineRenderer::drawSelectionBoxes(QPainter *p, int modelIndex, int fromI if (m_profilerModelProxy->getEventId(modelIndex, i) != id) continue; - currentY = (modelRowStart + m_profilerModelProxy->getEventRow(modelIndex, i)) * DefaultRowHeight - y(); - if (currentY + DefaultRowHeight < 0 || height() < currentY) + int row = m_profilerModelProxy->getEventRow(modelIndex, i); + int rowHeight = m_profilerModelProxy->rowHeight(modelIndex, row); + + currentY = modelRowStart + m_profilerModelProxy->rowOffset(modelIndex, row) - y(); + if (currentY + rowHeight < 0 || height() < currentY) continue; getItemXExtent(modelIndex, i, currentX, itemWidth); if (i == m_selectedItem) - selectedItemRect = QRect(currentX, currentY - 1, itemWidth, DefaultRowHeight + 1); + selectedItemRect = QRect(currentX, currentY - 1, itemWidth, rowHeight + 1); else - p->drawRect(currentX, currentY, itemWidth, DefaultRowHeight); + p->drawRect(currentX, currentY, itemWidth, rowHeight); } // draw the selected item rectangle the last, so that it's overlayed @@ -209,7 +212,7 @@ void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int modelIndex, int f int destindex; int xfrom, xto, width; int yfrom, yto; - int radius = DefaultRowHeight / 3; + int radius = 10; QPen shadowPen = QPen(QColor("grey"),2); QPen markerPen = QPen(QColor("orange"),2); QBrush shadowBrush = QBrush(QColor("grey")); @@ -222,12 +225,14 @@ void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int modelIndex, int f // to getItemXExtent(modelIndex, destindex, xto, width); xto += width / 2; - yto = getYPosition(modelIndex, destindex) + DefaultRowHeight / 2 - y(); + yto = getYPosition(modelIndex, destindex) + + m_profilerModelProxy->rowHeight(modelIndex, destindex) / 2 - y(); // from getItemXExtent(modelIndex, i, xfrom, width); xfrom += width / 2; - yfrom = getYPosition(modelIndex, i) + DefaultRowHeight / 2 - y(); + yfrom = getYPosition(modelIndex, i) + + m_profilerModelProxy->rowHeight(modelIndex, i) / 2 - y(); // radius (derived from width of origin event) radius = 5; @@ -260,11 +265,29 @@ void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int modelIndex, int f p->restore(); } +int TimelineRenderer::rowFromPosition(int y) +{ + int ret = 0; + for (int modelIndex = 0; modelIndex < m_profilerModelProxy->modelCount(); modelIndex++) { + int modelHeight = m_profilerModelProxy->height(modelIndex); + if (y < modelHeight) { + for (int row = 0; row < m_profilerModelProxy->rowCount(modelIndex); ++row) { + y -= m_profilerModelProxy->rowHeight(modelIndex, row); + if (y < 0) return ret; + ++ret; + } + } else { + y -= modelHeight; + ret += m_profilerModelProxy->rowCount(modelIndex); + } + } + return ret; +} + int TimelineRenderer::modelFromPosition(int y) { - y = y / DefaultRowHeight; for (int modelIndex = 0; modelIndex < m_profilerModelProxy->modelCount(); modelIndex++) { - y -= m_profilerModelProxy->rowCount(modelIndex); + y -= m_profilerModelProxy->height(modelIndex); if (y < 0) return modelIndex; } @@ -328,7 +351,7 @@ void TimelineRenderer::manageHovered(int mouseX, int mouseY) // Make the "selected" area 3 pixels wide by adding/subtracting 1 to catch very narrow events. qint64 startTime = (mouseX - 1) * (m_endTime - m_startTime) / width() + m_startTime; qint64 endTime = (mouseX + 1) * (m_endTime - m_startTime) / width() + m_startTime; - int row = (mouseY + y()) / DefaultRowHeight; + int row = rowFromPosition(mouseY + y()); int modelIndex = modelFromPosition(mouseY + y()); // already covered? nothing to do @@ -404,10 +427,10 @@ int TimelineRenderer::getYPosition(int modelIndex, int index) const int modelRowStart = 0; for (int mi = 0; mi < modelIndex; mi++) - modelRowStart += m_profilerModelProxy->rowCount(mi); + modelRowStart += m_profilerModelProxy->height(mi); - int y = DefaultRowHeight * (modelRowStart + m_profilerModelProxy->getEventRow(modelIndex, index)); - return y; + return modelRowStart + m_profilerModelProxy->rowOffset(modelIndex, + m_profilerModelProxy->getEventRow(modelIndex, index)); } void TimelineRenderer::selectNext() diff --git a/src/plugins/qmlprofiler/timelinerenderer.h b/src/plugins/qmlprofiler/timelinerenderer.h index db6871462b3..587438f6044 100644 --- a/src/plugins/qmlprofiler/timelinerenderer.h +++ b/src/plugins/qmlprofiler/timelinerenderer.h @@ -172,6 +172,7 @@ private: void drawSelectionBoxes(QPainter *p, int modelIndex, int fromIndex, int toIndex); void drawBindingLoopMarkers(QPainter *p, int modelIndex, int fromIndex, int toIndex); int modelFromPosition(int y); + int rowFromPosition(int y); void manageClicked(); void manageHovered(int mouseX, int mouseY);