forked from qt-creator/qt-creator
QmlProfiler: drag&drop reordering of models in timeline
Task-number: QTCREATORBUG-12337 Change-Id: I399593f44aa8ff8dd79c623108fecb3c317cb63c Reviewed-by: Kai Koehne <kai.koehne@digia.com>
This commit is contained in:
@@ -33,13 +33,18 @@ import QtQuick.Controls.Styles 1.2
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: labelContainer
|
id: labelContainer
|
||||||
property string text: qmlProfilerModelProxy.displayName(modelIndex)
|
property string text: trigger(1) ? qmlProfilerModelProxy.displayName(modelIndex) : ""
|
||||||
property bool expanded: trigger(qmlProfilerModelProxy.expanded(modelIndex))
|
property bool expanded: trigger(qmlProfilerModelProxy.expanded(modelIndex))
|
||||||
property int modelIndex: index
|
property int modelIndex: index
|
||||||
property int bindingTrigger: 1
|
property int bindingTrigger: 1
|
||||||
property var descriptions: []
|
property var descriptions: []
|
||||||
property var extdescriptions: []
|
property var extdescriptions: []
|
||||||
property var eventIds: []
|
property var eventIds: []
|
||||||
|
property bool dragging
|
||||||
|
property Item draggerParent
|
||||||
|
|
||||||
|
signal dragStarted;
|
||||||
|
signal dragStopped;
|
||||||
|
|
||||||
readonly property int dragHeight: 5
|
readonly property int dragHeight: 5
|
||||||
|
|
||||||
@@ -83,6 +88,32 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
target: qmlProfilerModelProxy
|
target: qmlProfilerModelProxy
|
||||||
onStateChanged: updateDescriptions()
|
onStateChanged: updateDescriptions()
|
||||||
|
onModelsChanged: updateDescriptions()
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: dragArea
|
||||||
|
anchors.fill: txt
|
||||||
|
drag.target: dragger
|
||||||
|
cursorShape: dragging ? Qt.DragMoveCursor : Qt.OpenHandCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
DropArea {
|
||||||
|
id: dropArea
|
||||||
|
|
||||||
|
onPositionChanged: {
|
||||||
|
if ((drag.source.modelIndex > labelContainer.modelIndex &&
|
||||||
|
drag.source.y < labelContainer.y + drag.source.height) ||
|
||||||
|
(drag.source.modelIndex < labelContainer.modelIndex &&
|
||||||
|
drag.source.y > labelContainer.y + labelContainer.height -
|
||||||
|
drag.source.height)) {
|
||||||
|
qmlProfilerModelProxy.swapModels(drag.source.modelIndex,
|
||||||
|
labelContainer.modelIndex);
|
||||||
|
drag.source.modelIndex = labelContainer.modelIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
@@ -178,4 +209,67 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: dragger
|
||||||
|
property int modelIndex
|
||||||
|
width: labelContainer.width
|
||||||
|
height: 0
|
||||||
|
color: "black"
|
||||||
|
opacity: 0.5
|
||||||
|
anchors.left: parent.left
|
||||||
|
|
||||||
|
// anchor to top so that it reliably snaps back after dragging
|
||||||
|
anchors.top: parent.top
|
||||||
|
|
||||||
|
Drag.active: dragArea.drag.active
|
||||||
|
Drag.onActiveChanged: {
|
||||||
|
// We don't want height, text, or modelIndex to be changed when reordering occurs, so we
|
||||||
|
// don't make them properties.
|
||||||
|
draggerText.text = txt.text;
|
||||||
|
modelIndex = labelContainer.modelIndex;
|
||||||
|
if (Drag.active) {
|
||||||
|
height = labelContainer.height;
|
||||||
|
labelContainer.dragStarted();
|
||||||
|
} else {
|
||||||
|
height = 0;
|
||||||
|
labelContainer.dragStopped();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
when: dragger.Drag.active
|
||||||
|
ParentChange {
|
||||||
|
target: dragger
|
||||||
|
parent: draggerParent
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: dragger
|
||||||
|
anchors.top: undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: draggerText
|
||||||
|
visible: parent.Drag.active
|
||||||
|
x: txt.x
|
||||||
|
font.pixelSize: txt.font.pixelSize
|
||||||
|
color: "white"
|
||||||
|
width: txt.width
|
||||||
|
height: txt.height
|
||||||
|
verticalAlignment: txt.verticalAlignment
|
||||||
|
renderType: txt.renderType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.top: dragArea.bottom
|
||||||
|
anchors.bottom: labelContainer.dragging ? labelContainer.bottom : dragArea.bottom
|
||||||
|
anchors.left: labelContainer.left
|
||||||
|
anchors.right: labelContainer.right
|
||||||
|
cursorShape: dragArea.cursorShape
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ Rectangle {
|
|||||||
view.requestPaint();
|
view.requestPaint();
|
||||||
}
|
}
|
||||||
onStateChanged: backgroundMarks.requestPaint()
|
onStateChanged: backgroundMarks.requestPaint()
|
||||||
|
onModelsChanged: backgroundMarks.requestPaint()
|
||||||
onExpandedChanged: backgroundMarks.requestPaint()
|
onExpandedChanged: backgroundMarks.requestPaint()
|
||||||
onRowHeightChanged: backgroundMarks.requestPaint()
|
onRowHeightChanged: backgroundMarks.requestPaint()
|
||||||
}
|
}
|
||||||
@@ -211,10 +212,20 @@ Rectangle {
|
|||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: col
|
id: col
|
||||||
|
|
||||||
|
// Dispatch the cursor shape to all labels. When dragging the DropArea receiving
|
||||||
|
// the drag events is not necessarily related to the MouseArea receiving the mouse
|
||||||
|
// events, so we can't use the drag events to determine the cursor shape.
|
||||||
|
property bool dragging: false
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: labels.rowCount
|
model: labels.rowCount
|
||||||
delegate: CategoryLabel {
|
delegate: CategoryLabel {
|
||||||
|
dragging: col.dragging
|
||||||
reverseSelect: root.shiftPressed
|
reverseSelect: root.shiftPressed
|
||||||
|
onDragStarted: col.dragging = true
|
||||||
|
onDragStopped: col.dragging = false
|
||||||
|
draggerParent: labels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ void TimelineModelAggregator::addModel(AbstractTimelineModel *m)
|
|||||||
d->modelList << m;
|
d->modelList << m;
|
||||||
connect(m,SIGNAL(expandedChanged()),this,SIGNAL(expandedChanged()));
|
connect(m,SIGNAL(expandedChanged()),this,SIGNAL(expandedChanged()));
|
||||||
connect(m,SIGNAL(rowHeightChanged()),this,SIGNAL(rowHeightChanged()));
|
connect(m,SIGNAL(rowHeightChanged()),this,SIGNAL(rowHeightChanged()));
|
||||||
emit modelsChanged();
|
emit modelsChanged(d->modelList.length(), d->modelList.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantList TimelineModelAggregator::models() const
|
QVariantList TimelineModelAggregator::models() const
|
||||||
@@ -255,6 +255,12 @@ int TimelineModelAggregator::eventIdForLocation(int modelIndex, const QString &f
|
|||||||
return d->modelList[modelIndex]->eventIdForLocation(filename, line, column);
|
return d->modelList[modelIndex]->eventIdForLocation(filename, line, column);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimelineModelAggregator::swapModels(int modelIndex1, int modelIndex2)
|
||||||
|
{
|
||||||
|
qSwap(d->modelList[modelIndex1], d->modelList[modelIndex2]);
|
||||||
|
emit modelsChanged(modelIndex1, modelIndex2);
|
||||||
|
}
|
||||||
|
|
||||||
void TimelineModelAggregator::dataChanged()
|
void TimelineModelAggregator::dataChanged()
|
||||||
{
|
{
|
||||||
// this is a slot connected for every modelproxy
|
// this is a slot connected for every modelproxy
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ public:
|
|||||||
Q_INVOKABLE int rowHeight(int modelIndex, int row) const;
|
Q_INVOKABLE int rowHeight(int modelIndex, int row) const;
|
||||||
Q_INVOKABLE void setRowHeight(int modelIndex, int row, int height);
|
Q_INVOKABLE void setRowHeight(int modelIndex, int row, int height);
|
||||||
Q_INVOKABLE int rowOffset(int modelIndex, int row) const;
|
Q_INVOKABLE int rowOffset(int modelIndex, int row) const;
|
||||||
|
|
||||||
Q_INVOKABLE bool expanded(int modelIndex) const;
|
Q_INVOKABLE bool expanded(int modelIndex) const;
|
||||||
Q_INVOKABLE void setExpanded(int modelIndex, bool expanded);
|
Q_INVOKABLE void setExpanded(int modelIndex, bool expanded);
|
||||||
Q_INVOKABLE int rowCount(int modelIndex) const;
|
Q_INVOKABLE int rowCount(int modelIndex) const;
|
||||||
@@ -91,12 +92,14 @@ public:
|
|||||||
Q_INVOKABLE int eventIdForLocation(int modelIndex, const QString &filename, int line,
|
Q_INVOKABLE int eventIdForLocation(int modelIndex, const QString &filename, int line,
|
||||||
int column) const;
|
int column) const;
|
||||||
|
|
||||||
|
Q_INVOKABLE void swapModels(int modelIndex1, int modelIndex2);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void dataAvailable();
|
void dataAvailable();
|
||||||
void stateChanged();
|
void stateChanged();
|
||||||
void expandedChanged();
|
void expandedChanged();
|
||||||
void rowHeightChanged();
|
void rowHeightChanged();
|
||||||
void modelsChanged();
|
void modelsChanged(int modelIndex1, int modelIndex2);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void dataChanged();
|
void dataChanged();
|
||||||
|
|||||||
@@ -56,12 +56,16 @@ void TimelineRenderer::setProfilerModelProxy(QObject *profilerModelProxy)
|
|||||||
if (m_profilerModelProxy) {
|
if (m_profilerModelProxy) {
|
||||||
disconnect(m_profilerModelProxy, SIGNAL(expandedChanged()), this, SLOT(requestPaint()));
|
disconnect(m_profilerModelProxy, SIGNAL(expandedChanged()), this, SLOT(requestPaint()));
|
||||||
disconnect(m_profilerModelProxy, SIGNAL(rowHeightChanged()), this, SLOT(requestPaint()));
|
disconnect(m_profilerModelProxy, SIGNAL(rowHeightChanged()), this, SLOT(requestPaint()));
|
||||||
|
disconnect(m_profilerModelProxy, SIGNAL(modelsChanged(int,int)),
|
||||||
|
this, SLOT(swapSelections(int,int)));
|
||||||
}
|
}
|
||||||
m_profilerModelProxy = qobject_cast<TimelineModelAggregator *>(profilerModelProxy);
|
m_profilerModelProxy = qobject_cast<TimelineModelAggregator *>(profilerModelProxy);
|
||||||
|
|
||||||
if (m_profilerModelProxy) {
|
if (m_profilerModelProxy) {
|
||||||
connect(m_profilerModelProxy, SIGNAL(expandedChanged()), this, SLOT(requestPaint()));
|
connect(m_profilerModelProxy, SIGNAL(expandedChanged()), this, SLOT(requestPaint()));
|
||||||
connect(m_profilerModelProxy, SIGNAL(rowHeightChanged()), this, SLOT(requestPaint()));
|
connect(m_profilerModelProxy, SIGNAL(rowHeightChanged()), this, SLOT(requestPaint()));
|
||||||
|
connect(m_profilerModelProxy, SIGNAL(modelsChanged(int,int)),
|
||||||
|
this, SLOT(swapSelections(int,int)));
|
||||||
}
|
}
|
||||||
emit profilerModelProxyChanged(m_profilerModelProxy);
|
emit profilerModelProxyChanged(m_profilerModelProxy);
|
||||||
}
|
}
|
||||||
@@ -84,6 +88,20 @@ void TimelineRenderer::requestPaint()
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimelineRenderer::swapSelections(int modelIndex1, int modelIndex2)
|
||||||
|
{
|
||||||
|
// Any hovered event is most likely useless now. Reset it.
|
||||||
|
resetCurrentSelection();
|
||||||
|
|
||||||
|
// Explicitly selected events can be tracked in a useful way.
|
||||||
|
if (m_selectedModel == modelIndex1)
|
||||||
|
setSelectedModel(modelIndex2);
|
||||||
|
else if (m_selectedModel == modelIndex2)
|
||||||
|
setSelectedModel(modelIndex1);
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
inline void TimelineRenderer::getItemXExtent(int modelIndex, int i, int ¤tX, int &itemWidth)
|
inline void TimelineRenderer::getItemXExtent(int modelIndex, int i, int ¤tX, int &itemWidth)
|
||||||
{
|
{
|
||||||
qint64 start = m_profilerModelProxy->startTime(modelIndex, i) - m_startTime;
|
qint64 start = m_profilerModelProxy->startTime(modelIndex, i) - m_startTime;
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ signals:
|
|||||||
public slots:
|
public slots:
|
||||||
void clearData();
|
void clearData();
|
||||||
void requestPaint();
|
void requestPaint();
|
||||||
|
void swapSelections(int modelIndex1, int modelIndex2);
|
||||||
|
|
||||||
void setStartTime(qint64 arg)
|
void setStartTime(qint64 arg)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user