Commit 36d8ad4c authored by Ulf Hermann's avatar Ulf Hermann

QmlProfiler: drag&drop reordering of models in timeline

Task-number: QTCREATORBUG-12337
Change-Id: I399593f44aa8ff8dd79c623108fecb3c317cb63c
Reviewed-by: default avatarKai Koehne <kai.koehne@digia.com>
parent 00650c8b
......@@ -33,13 +33,18 @@ import QtQuick.Controls.Styles 1.2
Item {
id: labelContainer
property string text: qmlProfilerModelProxy.displayName(modelIndex)
property string text: trigger(1) ? qmlProfilerModelProxy.displayName(modelIndex) : ""
property bool expanded: trigger(qmlProfilerModelProxy.expanded(modelIndex))
property int modelIndex: index
property int bindingTrigger: 1
property var descriptions: []
property var extdescriptions: []
property var eventIds: []
property bool dragging
property Item draggerParent
signal dragStarted;
signal dragStopped;
readonly property int dragHeight: 5
......@@ -83,6 +88,32 @@ Item {
Connections {
target: qmlProfilerModelProxy
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 {
......@@ -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();
}
onStateChanged: backgroundMarks.requestPaint()
onModelsChanged: backgroundMarks.requestPaint()
onExpandedChanged: backgroundMarks.requestPaint()
onRowHeightChanged: backgroundMarks.requestPaint()
}
......@@ -211,10 +212,20 @@ Rectangle {
Column {
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 {
model: labels.rowCount
delegate: CategoryLabel {
dragging: col.dragging
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;
connect(m,SIGNAL(expandedChanged()),this,SIGNAL(expandedChanged()));
connect(m,SIGNAL(rowHeightChanged()),this,SIGNAL(rowHeightChanged()));
emit modelsChanged();
emit modelsChanged(d->modelList.length(), d->modelList.length());
}
QVariantList TimelineModelAggregator::models() const
......@@ -255,6 +255,12 @@ int TimelineModelAggregator::eventIdForLocation(int modelIndex, const QString &f
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()
{
// this is a slot connected for every modelproxy
......
......@@ -62,6 +62,7 @@ public:
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;
......@@ -91,12 +92,14 @@ public:
Q_INVOKABLE int eventIdForLocation(int modelIndex, const QString &filename, int line,
int column) const;
Q_INVOKABLE void swapModels(int modelIndex1, int modelIndex2);
signals:
void dataAvailable();
void stateChanged();
void expandedChanged();
void rowHeightChanged();
void modelsChanged();
void modelsChanged(int modelIndex1, int modelIndex2);
protected slots:
void dataChanged();
......
......@@ -56,12 +56,16 @@ void TimelineRenderer::setProfilerModelProxy(QObject *profilerModelProxy)
if (m_profilerModelProxy) {
disconnect(m_profilerModelProxy, SIGNAL(expandedChanged()), 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);
if (m_profilerModelProxy) {
connect(m_profilerModelProxy, SIGNAL(expandedChanged()), 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);
}
......@@ -84,6 +88,20 @@ void TimelineRenderer::requestPaint()
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 &currentX, int &itemWidth)
{
qint64 start = m_profilerModelProxy->startTime(modelIndex, i) - m_startTime;
......
......@@ -116,7 +116,7 @@ signals:
public slots:
void clearData();
void requestPaint();
void swapSelections(int modelIndex1, int modelIndex2);
void setStartTime(qint64 arg)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment