diff --git a/src/plugins/qmlprofiler/qml/MainView.qml b/src/plugins/qmlprofiler/qml/MainView.qml index a770d768e7188cf1b4a3af9a88912916f616a0e7..cbdab441c47db24d7608ea6a60b121084c60bf0e 100644 --- a/src/plugins/qmlprofiler/qml/MainView.qml +++ b/src/plugins/qmlprofiler/qml/MainView.qml @@ -154,28 +154,28 @@ Rectangle { } } - function zoomIn() { - updateZoom( 1/1.1 ); - } - - function zoomOut() { - updateZoom( 1.1 ); + function updateWindowLength(absoluteFactor) { + var windowLength = view.endTime - view.startTime; + if (qmlEventList.traceEndTime() <= 0 || windowLength <= 0) + return; + var currentFactor = windowLength / qmlEventList.traceEndTime(); + updateZoom(absoluteFactor / currentFactor); } - function updateZoom(factor) { + function updateZoom(relativeFactor) { var min_length = 1e5; // 0.1 ms var windowLength = view.endTime - view.startTime; if (windowLength < min_length) windowLength = min_length; - var newWindowLength = windowLength * factor; + var newWindowLength = windowLength * relativeFactor; if (newWindowLength > qmlEventList.traceEndTime()) { newWindowLength = qmlEventList.traceEndTime(); - factor = newWindowLength / windowLength; + relativeFactor = newWindowLength / windowLength; } if (newWindowLength < min_length) { newWindowLength = min_length; - factor = newWindowLength / windowLength; + relativeFactor = newWindowLength / windowLength; } var fixedPoint = (view.startTime + view.endTime) / 2; @@ -186,7 +186,29 @@ Rectangle { fixedPoint = newFixedPoint; } - var startTime = fixedPoint - factor*(fixedPoint - view.startTime); + var startTime = fixedPoint - relativeFactor*(fixedPoint - view.startTime); + zoomControl.setRange(startTime, startTime + newWindowLength); + } + + function updateZoomCentered(centerX, relativeFactor) + { + var min_length = 1e5; // 0.1 ms + var windowLength = view.endTime - view.startTime; + if (windowLength < min_length) + windowLength = min_length; + var newWindowLength = windowLength * relativeFactor; + + if (newWindowLength > qmlEventList.traceEndTime()) { + newWindowLength = qmlEventList.traceEndTime(); + relativeFactor = newWindowLength / windowLength; + } + if (newWindowLength < min_length) { + newWindowLength = min_length; + relativeFactor = newWindowLength / windowLength; + } + + var fixedPoint = (centerX - flick.x) * windowLength / flick.width + view.startTime; + var startTime = fixedPoint - relativeFactor*(fixedPoint - view.startTime); zoomControl.setRange(startTime, startTime + newWindowLength); } @@ -200,6 +222,19 @@ Rectangle { zoomControl.setRange(newStart, newStart + windowLength); } + function globalZoom() { + zoomControl.setRange(qmlEventList.traceStartTime(), qmlEventList.traceEndTime()); + } + + function wheelZoom(wheelCenter, wheelDelta) { + if (qmlEventList.traceEndTime()>0 && wheelDelta!=0) { + if (wheelDelta>0) + updateZoomCentered(wheelCenter, 1/1.2); + else + updateZoomCentered(wheelCenter, 1.2); + } + } + function hideRangeDetails() { rangeDetails.visible = false; rangeDetails.duration = ""; @@ -242,7 +277,7 @@ Rectangle { Timer { id: elapsedTimer property date startDate - property bool reset: true + property bool reset: true running: connection.recording repeat: true onRunningChanged: { @@ -482,7 +517,7 @@ Rectangle { selectionRange.isDragging = false; } onDoubleClicked: { - zoomControl.setRange(selectionRange.startTime, selectionRange.startTime+selectionRange.duration); + zoomControl.setRange(selectionRange.startTime, selectionRange.startTime + selectionRange.duration); root.selectionRangeMode = false; root.updateRangeButton(); } diff --git a/src/plugins/qmlprofiler/qml/magnifier-minus.png b/src/plugins/qmlprofiler/qml/magnifier-minus.png deleted file mode 100644 index 3bfcea0ff7603225f0a7f9e9b1ff01bb71cbdbb8..0000000000000000000000000000000000000000 Binary files a/src/plugins/qmlprofiler/qml/magnifier-minus.png and /dev/null differ diff --git a/src/plugins/qmlprofiler/qml/magnifier-plus.png b/src/plugins/qmlprofiler/qml/magnifier-plus.png deleted file mode 100644 index 51bed6844d305c253e12c204befa32a11a0fb2f9..0000000000000000000000000000000000000000 Binary files a/src/plugins/qmlprofiler/qml/magnifier-plus.png and /dev/null differ diff --git a/src/plugins/qmlprofiler/qml/magnifier.png b/src/plugins/qmlprofiler/qml/magnifier.png new file mode 100644 index 0000000000000000000000000000000000000000..0ffafb84f53afddd39bda94070e11cef033d3bc6 Binary files /dev/null and b/src/plugins/qmlprofiler/qml/magnifier.png differ diff --git a/src/plugins/qmlprofiler/qml/qmlprofiler.qrc b/src/plugins/qmlprofiler/qml/qmlprofiler.qrc index 21be444e1a7d8dae807dc5af906f9e381c326c27..0b1ffce54ae995dc8e20a3a49b40f1dbd4cc7b22 100644 --- a/src/plugins/qmlprofiler/qml/qmlprofiler.qrc +++ b/src/plugins/qmlprofiler/qml/qmlprofiler.qrc @@ -11,8 +11,6 @@ <file>clean_pane_small.png</file> <file>prev.png</file> <file>next.png</file> - <file>magnifier-minus.png</file> - <file>magnifier-plus.png</file> <file>recordOff.png</file> <file>recordOn.png</file> <file>StatusDisplay.qml</file> @@ -25,5 +23,6 @@ <file>range_pressed.png</file> <file>SelectionRange.qml</file> <file>SelectionRangeDetails.qml</file> + <file>magnifier.png</file> </qresource> </RCC> diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index d5e954f24197d44d0fab904797919d99a1e50e86..9ba33d195b0db796241f18c57443f922199f1e65 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -176,19 +176,28 @@ IAnalyzerTool::ToolMode QmlProfilerTool::toolMode() const void QmlProfilerTool::showContextMenu(const QPoint &position) { QmlProfilerEventsView *senderView = qobject_cast<QmlProfilerEventsView *>(sender()); + TraceWindow *traceView = qobject_cast<TraceWindow *>(sender()); QMenu menu; QAction *loadAction = menu.addAction(tr("Load QML Trace")); QAction *saveAction = menu.addAction(tr("Save QML Trace")); QAction *copyRowAction = 0; QAction *copyTableAction = 0; + QAction *viewAllAction = 0; if (senderView) { if (senderView->selectedItem().isValid()) copyRowAction = menu.addAction(tr("Copy Row")); copyTableAction = menu.addAction(tr("Copy Table")); } + if (traceView) { + if (traceView->getEventList()->count() > 0) { + menu.addSeparator(); + viewAllAction = menu.addAction(tr("Reset Zoom")); + } + } QAction *selectedAction = menu.exec(position); + if (selectedAction) { if (selectedAction == loadAction) showLoadDialog(); @@ -198,6 +207,8 @@ void QmlProfilerTool::showContextMenu(const QPoint &position) senderView->copyRowToClipboard(); if (selectedAction == copyTableAction) senderView->copyTableToClipboard(); + if (selectedAction == viewAllAction) + traceView->viewAll(); } } diff --git a/src/plugins/qmlprofiler/tracewindow.cpp b/src/plugins/qmlprofiler/tracewindow.cpp index 5d33b9bbed8cbf2f40f0b2f41613efb9fc6c366c..f201ffe069a3e8af13692a2ab64afd19a3806316 100644 --- a/src/plugins/qmlprofiler/tracewindow.cpp +++ b/src/plugins/qmlprofiler/tracewindow.cpp @@ -44,18 +44,36 @@ #include <QtGui/QGraphicsObject> #include <QtGui/QContextMenuEvent> #include <QtGui/QScrollBar> +#include <QtGui/QSlider> #include <QtGui/QWidget> +#include <math.h> + using namespace QmlJsDebugClient; namespace QmlProfiler { namespace Internal { +const int sliderTicks = 10000; +const qreal sliderExp = 3; + +void ZoomControl::setRange(qint64 startTime, qint64 endTime) +{ + if (m_startTime != startTime || m_endTime != endTime) { + m_startTime = startTime; + m_endTime = endTime; + emit rangeChanged(); + } +} + TraceWindow::TraceWindow(QWidget *parent) : QWidget(parent) { setObjectName("QML Profiler"); + m_zoomControl = new ZoomControl(this); + connect(m_zoomControl.data(), SIGNAL(rangeChanged()), this, SLOT(updateRange())); + QVBoxLayout *groupLayout = new QVBoxLayout; groupLayout->setContentsMargins(0, 0, 0, 0); groupLayout->setSpacing(0); @@ -67,6 +85,10 @@ TraceWindow::TraceWindow(QWidget *parent) m_mainView->setAlignment(Qt::AlignLeft | Qt::AlignTop); m_mainView->setFocus(); + MouseWheelResizer *resizer = new MouseWheelResizer(this); + connect(resizer,SIGNAL(mouseWheelMoved(int,int,int)), this, SLOT(mouseWheelMoved(int,int,int))); + m_mainView->viewport()->installEventFilter(resizer); + QHBoxLayout *toolsLayout = new QHBoxLayout; m_timebar = new QDeclarativeView(this); @@ -79,6 +101,10 @@ TraceWindow::TraceWindow(QWidget *parent) m_overview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); m_overview->setMaximumHeight(50); + m_zoomToolbar = createZoomToolbar(); + m_zoomToolbar->move(0, m_timebar->height()); + m_zoomToolbar->setVisible(false); + toolsLayout->addWidget(createToolbar()); toolsLayout->addWidget(m_timebar); @@ -99,15 +125,13 @@ TraceWindow::TraceWindow(QWidget *parent) // Minimum height: 5 rows of 20 pixels + scrollbar of 50 pixels + 20 pixels margin setMinimumHeight(170); - - m_zoomControl = new ZoomControl(); + m_currentZoomLevel = 0; } TraceWindow::~TraceWindow() { delete m_plugin.data(); delete m_v8plugin.data(); - delete m_zoomControl.data(); } QWidget *TraceWindow::createToolbar() @@ -120,26 +144,27 @@ QWidget *TraceWindow::createToolbar() QHBoxLayout *toolBarLayout = new QHBoxLayout(bar); toolBarLayout->setMargin(0); toolBarLayout->setSpacing(0); + QToolButton *buttonPrev= new QToolButton; buttonPrev->setIcon(QIcon(":/qmlprofiler/prev.png")); buttonPrev->setToolTip(tr("Jump to previous event")); connect(buttonPrev, SIGNAL(clicked()), this, SIGNAL(jumpToPrev())); connect(this, SIGNAL(enableToolbar(bool)), buttonPrev, SLOT(setEnabled(bool))); + QToolButton *buttonNext= new QToolButton; buttonNext->setIcon(QIcon(":/qmlprofiler/next.png")); buttonNext->setToolTip(tr("Jump to next event")); connect(buttonNext, SIGNAL(clicked()), this, SIGNAL(jumpToNext())); connect(this, SIGNAL(enableToolbar(bool)), buttonNext, SLOT(setEnabled(bool))); - QToolButton *buttonZoomIn = new QToolButton; - buttonZoomIn->setIcon(QIcon(":/qmlprofiler/magnifier-plus.png")); - buttonZoomIn->setToolTip(tr("Zoom in 10%")); - connect(buttonZoomIn, SIGNAL(clicked()), this, SIGNAL(zoomIn())); - connect(this, SIGNAL(enableToolbar(bool)), buttonZoomIn, SLOT(setEnabled(bool))); - QToolButton *buttonZoomOut = new QToolButton; - buttonZoomOut->setIcon(QIcon(":/qmlprofiler/magnifier-minus.png")); - buttonZoomOut->setToolTip(tr("Zoom out 10%")); - connect(buttonZoomOut, SIGNAL(clicked()), this, SIGNAL(zoomOut())); - connect(this, SIGNAL(enableToolbar(bool)), buttonZoomOut, SLOT(setEnabled(bool))); + + QToolButton *buttonZoomControls = new QToolButton; + buttonZoomControls->setIcon(QIcon(":/qmlprofiler/magnifier.png")); + buttonZoomControls->setToolTip(tr("Show zoom slider")); + buttonZoomControls->setCheckable(true); + buttonZoomControls->setChecked(false); + connect(buttonZoomControls, SIGNAL(toggled(bool)), m_zoomToolbar, SLOT(setVisible(bool))); + connect(this, SIGNAL(enableToolbar(bool)), buttonZoomControls, SLOT(setEnabled(bool))); + m_buttonRange = new QToolButton; m_buttonRange->setIcon(QIcon(":/qmlprofiler/range.png")); m_buttonRange->setToolTip(tr("Select range")); @@ -151,13 +176,57 @@ QWidget *TraceWindow::createToolbar() toolBarLayout->addWidget(buttonPrev); toolBarLayout->addWidget(buttonNext); - toolBarLayout->addWidget(buttonZoomIn); - toolBarLayout->addWidget(buttonZoomOut); + toolBarLayout->addWidget(buttonZoomControls); toolBarLayout->addWidget(m_buttonRange); return bar; } + +QWidget *TraceWindow::createZoomToolbar() +{ + Utils::StyledBar *bar = new Utils::StyledBar(this); + bar->setSingleRow(true); + bar->setFixedWidth(150); + bar->setFixedHeight(24); + + QHBoxLayout *toolBarLayout = new QHBoxLayout(bar); + toolBarLayout->setMargin(0); + toolBarLayout->setSpacing(0); + + QSlider *zoomSlider = new QSlider(Qt::Horizontal); + zoomSlider->setFocusPolicy(Qt::NoFocus); + zoomSlider->setRange(1, sliderTicks); + zoomSlider->setInvertedAppearance(true); + zoomSlider->setPageStep(sliderTicks/100); + connect(this, SIGNAL(enableToolbar(bool)), zoomSlider, SLOT(setEnabled(bool))); + connect(zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(setZoomLevel(int))); + connect(this, SIGNAL(zoomLevelChanged(int)), zoomSlider, SLOT(setValue(int))); + zoomSlider->setStyleSheet("\ + QSlider:horizontal {\ + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #444444, stop: 1 #5a5a5a);\ + border: 1px #313131;\ + height: 20px;\ + margin: 0px 0px 0px 0px;\ + }\ + QSlider::groove:horizontal {\ + position: absolute;\ + }\ + QSlider::add-page:horizontal {\ + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #5a5a5a, stop: 1 #444444);\ + border: 1px #313131;\ + }\ + QSlider::sub-page:horizontal {\ + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #5a5a5a, stop: 1 #444444);\ + border: 1px #313131;\ + }\ + "); + + toolBarLayout->addWidget(zoomSlider); + + return bar; +} + void TraceWindow::reset(QDeclarativeDebugConnection *conn) { if (m_plugin) @@ -198,8 +267,9 @@ void TraceWindow::reset(QDeclarativeDebugConnection *conn) connect(m_eventList, SIGNAL(countChanged()), this, SLOT(updateToolbar())); connect(this, SIGNAL(jumpToPrev()), m_mainView->rootObject(), SLOT(prevEvent())); connect(this, SIGNAL(jumpToNext()), m_mainView->rootObject(), SLOT(nextEvent())); - connect(this, SIGNAL(zoomIn()), m_mainView->rootObject(), SLOT(zoomIn())); - connect(this, SIGNAL(zoomOut()), m_mainView->rootObject(), SLOT(zoomOut())); + connect(this, SIGNAL(updateViewZoom(QVariant)), m_mainView->rootObject(), SLOT(updateWindowLength(QVariant))); + connect(this, SIGNAL(wheelZoom(QVariant,QVariant)), m_mainView->rootObject(), SLOT(wheelZoom(QVariant,QVariant))); + connect(this, SIGNAL(globalZoom()), m_mainView->rootObject(), SLOT(globalZoom())); connect(this, SIGNAL(internalClearDisplay()), m_mainView->rootObject(), SLOT(clearAll())); connect(this,SIGNAL(internalClearDisplay()), m_overview->rootObject(), SLOT(clearDisplay())); @@ -311,5 +381,56 @@ void TraceWindow::resizeEvent(QResizeEvent *event) } } +bool MouseWheelResizer::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::Wheel) { + QWheelEvent *ev = static_cast<QWheelEvent *>(event); + if (ev->modifiers() & Qt::ControlModifier) { + emit mouseWheelMoved(ev->pos().x(), ev->pos().y(), ev->delta()); + return true; + } + } + return QObject::eventFilter(obj, event); +} + +void TraceWindow::mouseWheelMoved(int x, int y, int delta) +{ + Q_UNUSED(y); + if (m_mainView->rootObject()) { + emit wheelZoom(QVariant(x), QVariant(delta)); + } +} + +void TraceWindow::viewAll() +{ + emit globalZoom(); +} + +void TraceWindow::setZoomLevel(int zoomLevel) +{ + if (m_currentZoomLevel != zoomLevel && m_mainView->rootObject()) { + qreal newFactor = pow(qreal(zoomLevel) / qreal(sliderTicks), sliderExp); + m_currentZoomLevel = zoomLevel; + emit updateViewZoom(QVariant(newFactor)); + } +} + +void TraceWindow::updateRange() +{ + if (!m_eventList) + return; + qreal duration = m_zoomControl.data()->endTime() - m_zoomControl.data()->startTime(); + if (duration <= 0) + return; + qreal totalTime = m_eventList->traceEndTime() - m_eventList->traceStartTime(); + if (totalTime <= 0) + return; + int newLevel = pow(duration / totalTime, 1/sliderExp) * sliderTicks; + if (m_currentZoomLevel != newLevel) { + m_currentZoomLevel = newLevel; + emit zoomLevelChanged(newLevel); + } +} + } // namespace Internal } // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/tracewindow.h b/src/plugins/qmlprofiler/tracewindow.h index 7c34f1f2aa88e56d905feffb95577757867ddd2a..a0a9f745464a7f4e3818e89c1ab2533937fe9595 100644 --- a/src/plugins/qmlprofiler/tracewindow.h +++ b/src/plugins/qmlprofiler/tracewindow.h @@ -42,6 +42,8 @@ #include <QtGui/QWidget> #include <QtGui/QToolButton> +#include <QtCore/QEvent> + QT_BEGIN_NAMESPACE class QDeclarativeView; QT_END_NAMESPACE @@ -49,6 +51,16 @@ QT_END_NAMESPACE namespace QmlProfiler { namespace Internal { +class MouseWheelResizer : public QObject { + Q_OBJECT +public: + MouseWheelResizer(QObject *parent=0):QObject(parent){} +protected: + bool eventFilter(QObject *obj, QEvent *event); +signals: + void mouseWheelMoved(int x, int y, int delta); +}; + // centralized zoom control class ZoomControl : public QObject { Q_OBJECT @@ -56,13 +68,7 @@ public: ZoomControl(QObject *parent=0):QObject(parent),m_startTime(0),m_endTime(0) {} ~ZoomControl(){} - Q_INVOKABLE void setRange(qint64 startTime, qint64 endTime) { - if (m_startTime != startTime || m_endTime != endTime) { - m_startTime = startTime; - m_endTime = endTime; - emit rangeChanged(); - } - } + Q_INVOKABLE void setRange(qint64 startTime, qint64 endTime); Q_INVOKABLE qint64 startTime() { return m_startTime; } Q_INVOKABLE qint64 endTime() { return m_endTime; } @@ -88,6 +94,7 @@ public: void setRecording(bool recording); bool isRecording() const; + void viewAll(); public slots: @@ -97,7 +104,9 @@ public slots: void updateToolbar(); void toggleRangeMode(bool); void updateRangeButton(); - + void setZoomLevel(int zoomLevel); + void updateRange(); + void mouseWheelMoved(int x, int y, int delta); void qmlComplete(); void v8Complete(); @@ -114,16 +123,19 @@ signals: void internalClearDisplay(); void jumpToPrev(); void jumpToNext(); - void zoomIn(); - void zoomOut(); void rangeModeChanged(bool); void enableToolbar(bool); + void zoomLevelChanged(int); + void updateViewZoom(QVariant zoomLevel); + void wheelZoom(QVariant wheelCenter, QVariant wheelDelta); + void globalZoom(); void contextMenuRequested(const QPoint& position); private: void contextMenuEvent(QContextMenuEvent *); QWidget *createToolbar(); + QWidget *createZoomToolbar(); protected: virtual void resizeEvent(QResizeEvent *event); @@ -143,6 +155,8 @@ private: QWeakPointer<ZoomControl> m_zoomControl; QToolButton *m_buttonRange; + QWidget *m_zoomToolbar; + int m_currentZoomLevel; }; } // namespace Internal