aboutsummaryrefslogtreecommitdiffstats
path: root/tests/manual/quickcontrols2/gifs/eventcapturer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/manual/quickcontrols2/gifs/eventcapturer.cpp')
-rw-r--r--tests/manual/quickcontrols2/gifs/eventcapturer.cpp236
1 files changed, 236 insertions, 0 deletions
diff --git a/tests/manual/quickcontrols2/gifs/eventcapturer.cpp b/tests/manual/quickcontrols2/gifs/eventcapturer.cpp
new file mode 100644
index 0000000000..ad88b1dbf9
--- /dev/null
+++ b/tests/manual/quickcontrols2/gifs/eventcapturer.cpp
@@ -0,0 +1,236 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. 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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "eventcapturer.h"
+
+#include <QDebug>
+#include <QMetaEnum>
+#include <QMouseEvent>
+#include <QTimer>
+
+/*!
+ Installs an event filter on a particular object to record specific events
+ that can be retrieved as C++ source code.
+
+ For example:
+
+ \code
+ EventCapturer eventCapturer;
+
+ view.show();
+
+ eventCapturer.startCapturing(&view, 5000);
+
+ // interact with the view here, in order for the events to be captured
+
+ qDebug() << "\n";
+ const auto capturedEvents = eventCapturer.capturedEvents();
+ for (CapturedEvent event : capturedEvents)
+ qDebug().noquote() << event.cppCommand();
+ \endcode
+
+ It is recommended to set the \c Qt::FramelessWindowHint flag on the view
+ (this code has not been tested under other usage):
+
+ view.setFlags(view.flags() | Qt::FramelessWindowHint);
+*/
+
+EventCapturer::EventCapturer(QObject *parent) :
+ QObject(parent),
+ mEventSource(nullptr),
+ mStopCaptureKey(Qt::Key_Escape),
+ mMoveEventTrimFlags(TrimNone),
+ mDuration(0),
+ mLastCaptureTime(0)
+{
+ mCapturedEventTypes << QEvent::MouseButtonPress << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick << QEvent::MouseMove;
+}
+
+void EventCapturer::startCapturing(QObject *eventSource, int duration)
+{
+ mEventSource = eventSource;
+
+ if (!mEventSource)
+ return;
+
+ mEventSource->installEventFilter(this);
+ mDelayTimer.start();
+ mDuration = duration;
+ mLastCaptureTime = 0;
+
+ QTimer::singleShot(mDuration, this, SLOT(stopCapturing()));
+}
+
+void EventCapturer::setStopCaptureKey(Qt::Key stopCaptureKey)
+{
+ mStopCaptureKey = stopCaptureKey;
+}
+
+/*!
+ Move events generate a lot of clutter, and for most cases they're not
+ necessary. Here's a list of scenarios where various trim flags make sense:
+
+ Scenario Flags
+
+ Record the mouse cursor TrimNone
+ Record mouseover/hover effects TrimNone
+ Dragging/flicking TrimAll
+*/
+void EventCapturer::setMoveEventTrimFlags(MoveEventTrimFlags trimFlags)
+{
+ mMoveEventTrimFlags = trimFlags;
+}
+
+QSet<QEvent::Type> EventCapturer::capturedEventTypes()
+{
+ return mCapturedEventTypes;
+}
+
+void EventCapturer::setCapturedEventTypes(QSet<QEvent::Type> types)
+{
+ mCapturedEventTypes = types;
+}
+
+QList<CapturedEvent> EventCapturer::capturedEvents() const
+{
+ if (mMoveEventTrimFlags == TrimNone || mEvents.isEmpty())
+ return mEvents;
+
+ // We can't easily trim "trailing" move events as they come in without
+ // storing them in some form, so we just do it all here.
+
+ int firstEventIndex = 0;
+ int lastEventIndex = mEvents.size() - 1;
+ // The accumulated delay of all of the move events that we remove.
+ // We keep this in order to maintain the correct timing between events.
+ int accumulatedDelay = 0;
+
+ bool encounteredNonMoveEvent = false;
+ if (mMoveEventTrimFlags.testFlag(TrimLeading)) {
+ for (int eventIndex = 0; !encounteredNonMoveEvent && eventIndex < mEvents.size(); ++eventIndex) {
+ const CapturedEvent event = mEvents.at(eventIndex);
+ if (event.type() != QEvent::MouseMove) {
+ encounteredNonMoveEvent = true;
+ firstEventIndex = eventIndex;
+ } else {
+ accumulatedDelay += event.delay();
+ }
+ }
+ }
+
+ if (mMoveEventTrimFlags.testFlag(TrimTrailing)) {
+ encounteredNonMoveEvent = false;
+ for (int eventIndex = mEvents.size() - 1; !encounteredNonMoveEvent && eventIndex >= 0; --eventIndex) {
+ const CapturedEvent event = mEvents.at(eventIndex);
+ if (event.type() != QEvent::MouseMove) {
+ encounteredNonMoveEvent = true;
+ lastEventIndex = eventIndex;
+ // Don't need to bother with delays for trailing mouse moves, as there is nothing after them.
+ }
+ }
+ }
+
+ // Before we go any further, we need to copy the subset of commands while
+ // the indices are still valid - we could be removing from the middle of
+ // the commands next. Also, the function is const, so we can't remove from
+ // mEvents anyway. :)
+ QList<CapturedEvent> events = mEvents.mid(firstEventIndex, (lastEventIndex - firstEventIndex) + 1);
+
+ if (mMoveEventTrimFlags.testFlag(TrimAfterReleases)) {
+ bool lastNonMoveEventWasRelease = false;
+ for (int eventIndex = 0; eventIndex < events.size(); ) {
+ CapturedEvent &event = events[eventIndex];
+ if (event.type() == QEvent::MouseMove && lastNonMoveEventWasRelease) {
+ accumulatedDelay += event.delay();
+ events.remove(eventIndex);
+ } else {
+ lastNonMoveEventWasRelease = event.type() == QEvent::MouseButtonRelease;
+ if (event.type() == QEvent::MouseButtonPress) {
+ event.setDelay(event.delay() + accumulatedDelay);
+ accumulatedDelay = 0;
+ }
+ ++eventIndex;
+ }
+ }
+ }
+
+ return events;
+}
+
+bool EventCapturer::eventFilter(QObject *object, QEvent *event)
+{
+ if (event->type() == QEvent::KeyPress && static_cast<QKeyEvent*>(event)->key() == mStopCaptureKey) {
+ stopCapturing();
+ return true;
+ }
+
+ if (object != mEventSource)
+ return false;
+
+ if (!mCapturedEventTypes.contains(event->type()))
+ return false;
+
+ if (event->type() == QEvent::MouseButtonPress) {
+ captureEvent(event);
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ captureEvent(event);
+ } else if (event->type() == QEvent::MouseButtonDblClick) {
+ captureEvent(event);
+ } else if (event->type() == QEvent::MouseMove) {
+ captureEvent(event);
+ } else {
+ qWarning() << "No support for event type" << QMetaEnum::fromType<QEvent::Type>().valueToKey(event->type());
+ }
+ return false;
+}
+
+void EventCapturer::stopCapturing()
+{
+ if (mEventSource) {
+ mEventSource->removeEventFilter(this);
+ mEventSource = 0;
+ mDuration = 0;
+ mLastCaptureTime = 0;
+ }
+}
+
+void EventCapturer::captureEvent(const QEvent *event)
+{
+ qDebug() << "captured" << event->type();
+ CapturedEvent capturedEvent(*event, mDelayTimer.elapsed() - mLastCaptureTime);
+ mEvents.append(capturedEvent);
+ mLastCaptureTime = mDelayTimer.elapsed();
+}