Commit 696fd40c authored by Julien Finet's avatar Julien Finet

Merge pull request #4 from finetjul/fix-button-player

Fix button player
parents 02e131e5 1c462c72
......@@ -3,6 +3,7 @@ include(../CMake/qtTestingMacroGenerateMocs.cmake)
set(KIT ${PROJECT_NAME})
set(TEST_SOURCES
pqAbstractButtonEventTranslatorTest.cpp
pqEventPlayerTest.cpp
pqEventRecorderTest.cpp
pqEventTranslatorTest.cpp
......@@ -49,6 +50,7 @@ endmacro()
#
# Add Tests
#
SIMPLE_TEST( pqAbstractButtonEventTranslatorTest )
SIMPLE_TEST( pqEventPlayerTest )
SIMPLE_TEST( pqEventRecorderTest )
SIMPLE_TEST( pqDoubleSpinBoxEventPlayerTest )
......
/*=========================================================================
Program: ParaView
Copyright (c) 2005-2008 Sandia Corporation, Kitware Inc.
All rights reserved.
ParaView is a free software; you can redistribute it and/or modify it
under the terms of the ParaView license version 1.2.
See License_v1.2.txt for the full ParaView license.
A copy of this license can be obtained by contacting
Kitware Inc.
28 Corporate Drive
Clifton Park, NY 12065
USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
// Qt includes
#include <QAction>
#include <QApplication>
#include <QMenu>
#include <QToolButton>
#include <QtTest/QtTest>
// QtTesting includes
#include "pqTestUtility.h"
#include "pqTest.h"
// ----------------------------------------------------------------------------
class pqAbstractButtonEventTranslatorTester: public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void init();
void cleanup();
void cleanupTestCase();
void testToolButton();
void testToolButton_data();
private:
QToolButton* ToolButton;
pqTestUtility* TestUtility;
pqDummyEventObserver* EventObserver;
};
// ----------------------------------------------------------------------------
void pqAbstractButtonEventTranslatorTester::initTestCase()
{
this->TestUtility = new pqTestUtility();
this->TestUtility->setRecordWithDialog(false);
this->EventObserver = new pqDummyEventObserver();
this->TestUtility->addEventObserver("xml", this->EventObserver);
this->TestUtility->addEventSource("xml", new pqDummyEventSource());
this->ToolButton = 0;
}
// ----------------------------------------------------------------------------
void pqAbstractButtonEventTranslatorTester::init()
{
// Init the DoubleSpinBox
this->ToolButton = new QToolButton();
this->ToolButton->setText("toolButton");
this->ToolButton->setObjectName("toolButton");
this->ToolButton->resize(200,200);
this->ToolButton->show();
QTest::qWaitForWindowExposed(this->ToolButton);
// Start to record events
this->TestUtility->recordTestsBySuffix("xml");
// Fire the event "enter" to connect ToolButton signals to the translator slots
QEvent enter(QEvent::Enter);
qApp->notify(this->ToolButton, &enter);
}
// ----------------------------------------------------------------------------
void pqAbstractButtonEventTranslatorTester::cleanup()
{
this->EventObserver->Text = QString();
this->TestUtility->stopRecords(0);
this->ToolButton->deleteLater();
this->ToolButton = 0;
}
// ----------------------------------------------------------------------------
void pqAbstractButtonEventTranslatorTester::cleanupTestCase()
{
this->EventObserver = 0;
delete this->TestUtility;
}
// ----------------------------------------------------------------------------
void pqAbstractButtonEventTranslatorTester::testToolButton()
{
QFETCH(int, popupMode);
this->ToolButton->setPopupMode(static_cast<QToolButton::ToolButtonPopupMode>(popupMode));
QFETCH(bool, withDefaultAction);
QAction* defaultAction = 0;
if (withDefaultAction)
{
defaultAction = new QAction("action", this->ToolButton);
defaultAction->setObjectName("action");
this->ToolButton->setDefaultAction(defaultAction);
}
QFETCH(bool, checkable);
if (defaultAction)
{
defaultAction->setCheckable(checkable);
}
else
{
this->ToolButton->setCheckable(checkable);
}
QFETCH(bool, withMenu);
if (withMenu)
{
QMenu* menu = new QMenu(this->ToolButton);
QAction* menuAction = new QAction("menu action", menu);
menu->addAction(menuAction);
if (defaultAction)
{
defaultAction->setMenu(menu);
}
else
{
this->ToolButton->setMenu(menu);
}
// After opening the menu, the event loop might get blocked.
QTimer::singleShot(1000, menu, SLOT(close()));
}
QTest::mousePress(this->ToolButton, Qt::LeftButton, Qt::NoModifier);
QFETCH(bool, longClick);
QTest::mouseRelease(this->ToolButton, Qt::LeftButton, Qt::NoModifier, QPoint(), longClick ? 800 : -1);
QFETCH(QString, recordEmitted);
bool res = this->EventObserver->Text == recordEmitted;
QCOMPARE(this->EventObserver->Text, recordEmitted);
}
// ----------------------------------------------------------------------------
void pqAbstractButtonEventTranslatorTester::testToolButton_data()
{
QTest::addColumn<int>("popupMode");
QTest::addColumn<bool>("withDefaultAction");
QTest::addColumn<bool>("checkable");
QTest::addColumn<bool>("withMenu");
QTest::addColumn<bool>("longClick");
QTest::addColumn<QString>("recordEmitted");
//QTest::newRow("fail") << 2 << false << false << true << false<< "toolButton, activate, #";
for (int i = 0; i < 0x20; ++i)
{
int popup = i & 0x01 ? QToolButton::ToolButtonPopupMode::DelayedPopup :
QToolButton::ToolButtonPopupMode::InstantPopup;
const bool withDefaultAction = i & 0x02;
const bool checkable = i & 0x04;
const bool withMenu = i & 0x08;
const bool longClick = i & 0x10;
QString testName =
QString("popup=%1 withDefaultAction=%2 checkable=%3 withMenu=%4 longClick=%5")
.arg(popup)
.arg(withDefaultAction)
.arg(checkable)
.arg(withMenu)
.arg(longClick);
bool longActivate = withMenu
&& popup == QToolButton::ToolButtonPopupMode::DelayedPopup
&& longClick;
QString recordEmitted = QString("toolButton%1, %2, %3#")
.arg(withDefaultAction && !longActivate ? "/action" : "")
.arg(longActivate ? "longActivate" : (checkable ? "set_boolean" : "activate"))
.arg(checkable && !longActivate? "true" : "");
QTest::newRow(testName.toLatin1())
<< popup << withDefaultAction
<< checkable << withMenu
<< longClick << recordEmitted;
}
}
// ----------------------------------------------------------------------------
CTK_TEST_MAIN( pqAbstractButtonEventTranslatorTest )
#include "moc_pqAbstractButtonEventTranslatorTest.cpp"
......@@ -45,19 +45,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pqAbstractButtonEventTranslator::pqAbstractButtonEventTranslator(QObject* p)
: pqWidgetEventTranslator(p)
{
this->LastMouseEvent = 0;
this->LastMouseEventType = QEvent::None;
}
bool pqAbstractButtonEventTranslator::translateEvent(QObject* Object, QEvent* Event, bool& /*Error*/)
{
QAbstractButton* const object = qobject_cast<QAbstractButton*>(Object);
if(!object)
{
return false;
}
QPushButton* pushButton = qobject_cast<QPushButton*>(object);
QToolButton* toolButton = qobject_cast<QToolButton*>(object);
bool withMenu = (pushButton && pushButton->menu()) ||
(toolButton && (toolButton->menu() || toolButton->defaultAction() && toolButton->defaultAction()->menu()));
switch(Event->type())
{
case QEvent::KeyPress:
{
QKeyEvent* const e = static_cast<QKeyEvent*>(Event);
QKeyEvent* const e = dynamic_cast<QKeyEvent*>(Event);
if(e->key() == Qt::Key_Space)
{
onActivate(object);
......@@ -66,21 +72,12 @@ bool pqAbstractButtonEventTranslator::translateEvent(QObject* Object, QEvent* Ev
break;
case QEvent::MouseButtonPress:
{
QMouseEvent* const e = static_cast<QMouseEvent*>(Event);
this->LastMouseEvent = e;
QPushButton* pushButton = qobject_cast<QPushButton*>(object);
if(pushButton &&
e->button() == Qt::LeftButton &&
QMouseEvent* const e = dynamic_cast<QMouseEvent*>(Event);
this->LastMouseEventType = Event->type();
// Menus are opened on mouse press
if(e->button() == Qt::LeftButton &&
object->rect().contains(e->pos()) &&
pushButton->menu())
{
onActivate(object);
}
QToolButton* toolButton = qobject_cast<QToolButton*>(object);
if(toolButton &&
e->button() == Qt::LeftButton &&
object->rect().contains(e->pos()) &&
toolButton->menu())
this->hasMenu(object))
{
onActivate(object);
}
......@@ -88,23 +85,30 @@ bool pqAbstractButtonEventTranslator::translateEvent(QObject* Object, QEvent* Ev
break;
case QEvent::Timer:
{
if (this->LastMouseEvent &&
this->LastMouseEvent->type() == QEvent::MouseButtonPress)
if (this->LastMouseEventType == QEvent::MouseButtonPress)
{
QToolButton* tButton = qobject_cast<QToolButton*>(object);
if(tButton &&
tButton->popupMode() == QToolButton::DelayedPopup)
{
emit recordEvent(object, "longActivate", "");
// Tell comming mouse button release to not record activate.
this->LastMouseEventType = QEvent::None;
}
}
}
break;
case QEvent::MouseButtonRelease:
{
QMouseEvent* const e = static_cast<QMouseEvent*>(Event);
this->LastMouseEvent = e;
if(e->button() == Qt::LeftButton && object->rect().contains(e->pos()))
bool lastEventWasMouseButtonPress =
this->LastMouseEventType == QEvent::MouseButtonPress;
QMouseEvent* const e = dynamic_cast<QMouseEvent*>(Event);
this->LastMouseEventType = Event->type();
// Buttons are activated on mouse release. Menus should already be recorded.
if (e->button() == Qt::LeftButton
&& object->rect().contains(e->pos())
&& !this->hasMenu(object)
&& lastEventWasMouseButtonPress)
{
onActivate(object);
}
......@@ -130,15 +134,27 @@ void pqAbstractButtonEventTranslator::onActivate(QAbstractButton* actualObject)
const bool new_value = !actualObject->isChecked();
emit recordEvent(object, "set_boolean", new_value ? "true" : "false");
}
else if(tb)
{
if (!tb->menu())
{
emit recordEvent(tb, "activate", "");
}
}
else
{
emit recordEvent(object, "activate", "");
}
}
bool pqAbstractButtonEventTranslator::hasMenu(QAbstractButton* button) const
{
bool hasMenu = false;
QPushButton* pushButton = qobject_cast<QPushButton*>(button);
if (pushButton)
{
hasMenu = pushButton->menu() != 0;
}
QToolButton* toolButton = qobject_cast<QToolButton*>(button);
if (toolButton)
{
hasMenu = toolButton->menu() != 0
|| (toolButton->defaultAction()
&& toolButton->defaultAction()->menu() != 0);
hasMenu = hasMenu && toolButton->popupMode() != QToolButton::ToolButtonPopupMode::DelayedPopup;
}
return hasMenu;
}
......@@ -56,13 +56,15 @@ public:
virtual bool translateEvent(QObject* Object, QEvent* Event, bool& Error);
protected:
virtual void onActivate(QAbstractButton*);
virtual bool hasMenu(QAbstractButton* actualObject) const;
QEvent::Type LastMouseEventType;
private:
pqAbstractButtonEventTranslator(const pqAbstractButtonEventTranslator&);
pqAbstractButtonEventTranslator& operator=(const pqAbstractButtonEventTranslator&);
void onActivate(QAbstractButton*);
QMouseEvent* LastMouseEvent;
};
#endif // !_pqAbstractButtonEventTranslator_h
......
......@@ -59,6 +59,7 @@ pqTestUtility::pqTestUtility(QObject* p)
: QObject(p)
{
this->PlayingTest = false;
this->RecordWithDialog = true;
this->File = 0;
this->FileSuffix = QString();
......@@ -316,25 +317,28 @@ void pqTestUtility::recordTests()
QObject::connect(&this->Recorder, SIGNAL(stopped()),
this, SLOT(onRecordStopped()), Qt::UniqueConnection);
if (QApplication::activeWindow())
{
pqRecordEventsDialog* dialog = new pqRecordEventsDialog(&this->Recorder,
this,
QApplication::activeWindow());
dialog->setAttribute(Qt::WA_QuitOnClose, false);
QRect rectApp = QApplication::activeWindow()->geometry();
QRect rectDialog(QPoint(rectApp.left(),
rectApp.bottom() - dialog->sizeHint().height()),
QSize(dialog->geometry().width(), dialog->sizeHint().height()));
dialog->setGeometry(rectDialog);
dialog->show();
}
else
{
qWarning() << "No acive windows has been found";
}
if (this->RecordWithDialog)
{
if (QApplication::activeWindow())
{
pqRecordEventsDialog* dialog = new pqRecordEventsDialog(&this->Recorder,
this,
QApplication::activeWindow());
dialog->setAttribute(Qt::WA_QuitOnClose, false);
QRect rectApp = QApplication::activeWindow()->geometry();
QRect rectDialog(QPoint(rectApp.left(),
rectApp.bottom() - dialog->sizeHint().height()),
QSize(dialog->geometry().width(), dialog->sizeHint().height()));
dialog->setGeometry(rectDialog);
dialog->show();
}
else
{
qWarning() << "No active windows has been found";
}
}
this->Recorder.recordEvents(&this->Translator, observer, this->File, true);
}
......@@ -492,3 +496,15 @@ QString pqTestUtility::convertFromDataDirectory(const QString& file)
}
return filename;
}
//-----------------------------------------------------------------------------
bool pqTestUtility::recordWithDialog() const
{
return this->RecordWithDialog;
}
//-----------------------------------------------------------------------------
void pqTestUtility::setRecordWithDialog(bool withDialog)
{
this->RecordWithDialog = withDialog;
}
......@@ -57,7 +57,10 @@ class pqEventSource;
class QTTESTING_EXPORT pqTestUtility : public QObject
{
Q_OBJECT
/// This property controls whether the RecordEventsDialog is opened when
/// recording events.
/// True by default.
Q_PROPERTY(bool recordWithDialog READ recordWithDialog WRITE setRecordWithDialog)
public:
pqTestUtility(QObject* parent = 0);
~pqTestUtility();
......@@ -126,6 +129,10 @@ public:
/// give a filename convert from one of the data directories
QString convertFromDataDirectory(const QString& file);
/// True if a dialog is opened when recording, false otherwise
bool recordWithDialog() const;
/// Set whether a dialog is opened when recording.
void setRecordWithDialog(bool withDialog);
public slots:
bool playTests(const QString& filename);
void openPlayerDialog();
......@@ -152,6 +159,7 @@ protected:
pqEventPlayer Player;
pqEventTranslator Translator;
bool PlayingTest;
bool RecordWithDialog;
QIODevice* File;
QString FileSuffix;
......
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