pax_global_header00006660000000000000000000000064152607050000014505gustar00rootroot0000000000000052 comment=c7bb5d372133e94c75cbdc70b04e039b864ea379 qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/000077500000000000000000000000001526070500000213535ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/.clang-format000066400000000000000000000010601526070500000237230ustar00rootroot00000000000000# Note: if you change any of the settings here, please reformat the entire # codebase as part of the same commit, that will prevent subsequent commits # from being flagged as being improperly formatted. --- # This configuration requires clang-format 8.0 or higher. BasedOnStyle: Mozilla AlignAfterOpenBracket: DontAlign AlignOperands: false AlwaysBreakAfterReturnType: None AlwaysBreakAfterDefinitionReturnType: None BreakBeforeBraces: Allman BinPackArguments: true BinPackParameters: true ColumnLimit: 100 SpaceAfterTemplateKeyword: true Standard: Cpp11 ... qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/CMakeLists.txt000066400000000000000000000254051526070500000241210ustar00rootroot00000000000000CMAKE_MINIMUM_REQUIRED(VERSION 3.12) PROJECT(QtTesting VERSION 1.0.1) IF(NOT DEFINED QtTesting_QT_VERSION) SET(QtTesting_QT_VERSION "6" CACHE STRING "Expected Qt version") MARK_AS_ADVANCED(QtTesting_QT_VERSION) SET_PROPERTY(CACHE QtTesting_QT_VERSION PROPERTY STRINGS 5 6) ENDIF() IF(NOT (QtTesting_QT_VERSION VERSION_EQUAL "5" OR QtTesting_QT_VERSION VERSION_EQUAL "6")) message(FATAL_ERROR "Expected value for QtTesting_QT_VERSION is either '5' or '6'") ENDIF() set(qt_imported_targets) FIND_PACKAGE(Qt${QtTesting_QT_VERSION} REQUIRED COMPONENTS Core Widgets Gui) SET(qt_imported_targets Qt${QtTesting_QT_VERSION}::Core Qt${QtTesting_QT_VERSION}::Widgets Qt${QtTesting_QT_VERSION}::Gui) IF(NOT DEFINED QT_TESTING_WITH_PYTHON) OPTION(QT_TESTING_WITH_PYTHON "Enable Qt Testing with Python" OFF) ENDIF() IF(NOT DEFINED QtTesting_INSTALL_BIN_DIR) SET(QtTesting_INSTALL_BIN_DIR bin) ENDIF() IF(NOT DEFINED QtTesting_INSTALL_INCLUDE_DIR) SET(QtTesting_INSTALL_INCLUDE_DIR include/QtTesting) ENDIF() IF(NOT DEFINED QtTesting_INSTALL_LIB_DIR) SET(QtTesting_INSTALL_LIB_DIR lib) ENDIF() IF(NOT DEFINED QtTesting_INSTALL_CMAKE_DIR) SET(QtTesting_INSTALL_CMAKE_DIR lib/cmake/qttesting) ENDIF() IF(NOT DEFINED QT_TESTING_EVENT_PLAYBACK_DELAY) SET(QT_TESTING_EVENT_PLAYBACK_DELAY "100" CACHE STRING "Delay between invocation of each testing event." FORCE) MARK_AS_ADVANCED(QT_TESTING_EVENT_PLAYBACK_DELAY) ENDIF() IF(NOT DEFINED QT_TESTING_INSTALL_EXPORT_NAME) SET(QT_TESTING_INSTALL_EXPORT_NAME QtTestingTargets) ENDIF() # One can define QT_TESTING_CUSTOM_LIBRARY_PREFIX and/or # QT_TESTING_CUSTOM_LIBRARY_SUFFIX to add prefix/suffix to libraries # generated by thus project. Default is empty. if(NOT DEFINED QT_TESTING_CUSTOM_LIBRARY_SUFFIX) set(QT_TESTING_CUSTOM_LIBRARY_SUFFIX) endif() if(NOT DEFINED QT_TESTING_CUSTOM_LIBRARY_PREFIX) set(QT_TESTING_CUSTOM_LIBRARY_PREFIX) endif() IF(QT_TESTING_WITH_PYTHON) IF(NOT PythonLibs_FOUND) FIND_PACKAGE(PythonLibs REQUIRED) ENDIF() IF(UNIX) FIND_LIBRARY(PYTHON_UTIL_LIBRARY NAMES util PATHS /usr/lib DOC "Utility library needed for vtkpython" ) MARK_AS_ADVANCED(PYTHON_UTIL_LIBRARY) IF(PYTHON_UTIL_LIBRARY) SET(PYTHON_UTIL_LIBRARY_LIB ${PYTHON_UTIL_LIBRARY}) ENDIF() ENDIF() INCLUDE_DIRECTORIES( ${PYTHON_INCLUDE_PATH} ) SET(PYTHON_SRCS pqPythonEventObserver.cxx pqPythonEventObserver.h pqPythonEventSource.cxx pqPythonEventSource.h ) ENDIF(QT_TESTING_WITH_PYTHON) set(ui_files pqPlayBackEventsDialog.ui pqRecordEventsDialog.ui) set(rc_files Resources/QtTesting.qrc) set(CMAKE_AUTOMOC 1) set(CMAKE_AUTOUIC 1) set(CMAKE_AUTORCC 1) SET(QtTesting_SOURCES pq3DViewEventPlayer.cxx pq3DViewEventTranslator.cxx pqAbstractActivateEventPlayer.cxx pqAbstractBooleanEventPlayer.cxx pqAbstractButtonEventTranslator.cxx pqAbstractDoubleEventPlayer.cxx pqAbstractIntEventPlayer.cxx pqAbstractItemViewEventPlayer.cxx pqAbstractItemViewEventPlayerBase.cxx pqAbstractItemViewEventTranslator.cxx pqAbstractItemViewEventTranslatorBase.cxx pqAbstractMiscellaneousEventPlayer.cxx pqAbstractSliderEventTranslator.cxx pqAbstractStringEventPlayer.cxx pqBasicWidgetEventPlayer.cxx pqBasicWidgetEventTranslator.cxx pqCheckEventOverlay.cxx pqComboBoxEventTranslator.cxx pqComboBoxEventPlayer.cxx pqCommentEventPlayer.cxx pqDoubleSpinBoxEventTranslator.cxx pqEventComment.cxx pqEventDispatcher.cxx pqEventObserver.cxx pqEventPlayer.cxx pqEventRecorder.cxx pqEventTranslator.cxx pqLineEditEventTranslator.cxx pqListViewEventPlayer.cxx pqListViewEventTranslator.cxx pqMenuEventTranslator.cxx pqNativeFileDialogEventPlayer.cxx pqNativeFileDialogEventTranslator.cxx pqObjectNaming.cxx pqObjectPlayer.cxx pqPlayBackEventsDialog.cxx pqRecordEventsDialog.cxx pqSpinBoxEventTranslator.cxx pqStdoutEventObserver.cxx pqTabBarEventPlayer.cxx pqTabBarEventTranslator.cxx pqTableViewEventPlayer.cxx pqTableViewEventTranslator.cxx pqTestUtility.cxx pqThreadedEventSource.cxx pqTimer.cxx pqTreeViewEventPlayer.cxx pqTreeViewEventTranslator.cxx pqWidgetEventPlayer.cxx pqWidgetEventTranslator.cxx ) SET(QtTesting_DEVEL_HEADERS QtTestingExport.h pq3DViewEventPlayer.h pq3DViewEventTranslator.h pqAbstractActivateEventPlayer.h pqAbstractBooleanEventPlayer.h pqAbstractButtonEventTranslator.h pqAbstractDoubleEventPlayer.h pqAbstractIntEventPlayer.h pqAbstractItemViewEventPlayer.h pqAbstractItemViewEventPlayerBase.h pqAbstractItemViewEventTranslator.h pqAbstractItemViewEventTranslatorBase.h pqAbstractMiscellaneousEventPlayer.h pqAbstractSliderEventTranslator.h pqAbstractStringEventPlayer.h pqBasicWidgetEventPlayer.h pqBasicWidgetEventTranslator.h pqCheckEventOverlay.h pqComboBoxEventTranslator.h pqComboBoxEventPlayer.h pqCommentEventPlayer.h pqDoubleSpinBoxEventTranslator.h pqEventComment.h pqEventDispatcher.h pqEventObserver.h pqEventPlayer.h pqEventRecorder.h pqEventSource.h pqEventTranslator.h pqEventTypes.h pqLineEditEventTranslator.h pqListViewEventPlayer.h pqListViewEventTranslator.h pqMenuEventTranslator.h pqNativeFileDialogEventPlayer.h pqNativeFileDialogEventTranslator.h pqObjectNaming.h pqObjectPlayer.h pqPlayBackEventsDialog.h pqRecordEventsDialog.h pqSpinBoxEventTranslator.h pqStdoutEventObserver.h pqTabBarEventPlayer.h pqTabBarEventTranslator.h pqTableViewEventPlayer.h pqTableViewEventTranslator.h pqTestUtility.h pqThreadedEventSource.h pqTimer.h pqTreeViewEventPlayer.h pqTreeViewEventTranslator.h pqWidgetEventPlayer.h pqWidgetEventTranslator.h ${QtTesting_BINARY_DIR}/QtTestingConfigure.h ) if(NOT DEFINED QTTESTING_BUILD_AS_VTK_MODULE) option(QTTESTING_BUILD_AS_VTK_MODULE "Build QtTesting as a VTK module" OFF) ENDIF() if (QTTESTING_BUILD_AS_VTK_MODULE) # When building as a ThirdParty in ParaView # or in any vtk module based software # it can be useful to build qttesting as a VTK Module. # This macro is defined in VTK cmake macros vtk_module_add_module(ParaView::qttesting SOURCES ${QtTesting_SOURCES} ${ui_files} ${rc_files} ${PYTHON_SRCS} HEADERS ${QtTesting_DEVEL_HEADERS} HEADERS_SUBDIR "vtkqttesting" ) vtk_module_set_property(ParaView::qttesting PROPERTY DEFINE_SYMBOL VALUE QtTesting_EXPORTS) vtk_module_include(ParaView::qttesting PUBLIC "$" "$" "$") vtk_module_definitions(ParaView::qttesting PRIVATE QT_NO_KEYWORDS) # Set library name to include custom prefixes/suffixes. vtk_module_set_property(ParaView::qttesting PROPERTY OUTPUT_NAME VALUE ${QT_TESTING_CUSTOM_LIBRARY_PREFIX}qttesting${QT_TESTING_CUSTOM_LIBRARY_SUFFIX}) vtk_module_link(ParaView::qttesting PRIVATE ${qt_imported_targets} ) IF(QT_TESTING_WITH_PYTHON) vtk_module_link(ParaView::qttesting VTK::Python ) ENDIF() else () add_library(qttesting ${QtTesting_SOURCES} ${ui_files} ${rc_files} ${PYTHON_SRCS} ${QtTesting_DEVEL_HEADERS}) add_library(QtTesting ALIAS qttesting) target_include_directories( qttesting PUBLIC $ $ "$") target_compile_definitions(qttesting PRIVATE QT_NO_KEYWORDS) # Version matters when building standalone set_target_properties(qttesting PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR} ) # Set library name to include custom prefixes/suffixes. set_property(TARGET qttesting PROPERTY OUTPUT_NAME ${QT_TESTING_CUSTOM_LIBRARY_PREFIX}qttesting${QT_TESTING_CUSTOM_LIBRARY_SUFFIX}) TARGET_LINK_LIBRARIES(qttesting PRIVATE ${qt_imported_targets} ) IF(QT_TESTING_WITH_PYTHON) TARGET_LINK_LIBRARIES(qttesting VTK::Python ) ENDIF() endif () SET(QTTESTING_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}) CONFIGURE_FILE(${QtTesting_SOURCE_DIR}/QtTestingConfigure.h.in ${QtTesting_BINARY_DIR}/QtTestingConfigure.h) if (NOT QTTESTING_BUILD_AS_VTK_MODULE) INSTALL(TARGETS qttesting EXPORT ${QT_TESTING_INSTALL_EXPORT_NAME} RUNTIME DESTINATION ${QtTesting_INSTALL_BIN_DIR} COMPONENT Runtime LIBRARY DESTINATION ${QtTesting_INSTALL_LIB_DIR} COMPONENT Runtime ARCHIVE DESTINATION ${QtTesting_INSTALL_LIB_DIR} COMPONENT Development) endif () if (NOT DEFINED BUILD_EXAMPLES) option(BUILD_EXAMPLES "Build examples" OFF) endif () if (BUILD_EXAMPLES) add_subdirectory(Examples) endif () include(CTest) IF(BUILD_TESTING) add_subdirectory(Testing) ENDIF() IF(NOT QtTesting_INSTALL_NO_DEVELOPMENT) export(TARGETS qttesting FILE ${QtTesting_BINARY_DIR}/QtTestingExports.cmake) # Set up the build export configuration set(QtTesting_EXPORT_FILE "${QtTesting_BINARY_DIR}/QtTestingConfig.cmake") configure_file( "${QtTesting_SOURCE_DIR}/QtTestingConfig.cmake.in" "${QtTesting_EXPORT_FILE}" @ONLY ) # Set up the install export IF(IS_ABSOLUTE QtTesting_INSTALL_INCLUDE_DIR) set(QtTesting_INSTALL_INCLUDE_FULL_DIR "${QtTesting_INSTALL_INCLUDE_DIR}") ELSE() set(QtTesting_INSTALL_INCLUDE_FULL_DIR "${CMAKE_INSTALL_PREFIX}/${QtTesting_INSTALL_INCLUDE_DIR}") get_filename_component(QtTesting_INSTALL_INCLUDE_FULL_DIR "${QtTesting_INSTALL_INCLUDE_FULL_DIR}" ABSOLUTE) ENDIF() IF(IS_ABSOLUTE QtTesting_INSTALL_LIB_DIR) set(QtTesting_INSTALL_LIB_FULL_DIR "${QtTesting_INSTALL_LIB_DIR}") ELSE() set(QtTesting_INSTALL_LIB_FULL_DIR "${CMAKE_INSTALL_PREFIX}/${QtTesting_INSTALL_LIB_DIR}") get_filename_component(QtTesting_INSTALL_LIB_FULL_DIR "${QtTesting_INSTALL_LIB_FULL_DIR}" ABSOLUTE) ENDIF() set(QtTesting_EXPORT_INSTALL_FILE "${QtTesting_BINARY_DIR}/CMakeFiles/QtTestingConfig.cmake") configure_file( "${QtTesting_SOURCE_DIR}/QtTestingConfig-install.cmake.in" "${QtTesting_EXPORT_INSTALL_FILE}" @ONLY ) include(CMakePackageConfigHelpers) # Configure 'Config.cmake' # Use variables: # * targets_export_name # * PROJECT_NAME configure_package_config_file( "${PROJECT_NAME}Config-install.cmake.in" "${QtTesting_EXPORT_INSTALL_FILE}" INSTALL_DESTINATION "${QtTesting_INSTALL_CMAKE_DIR}" NO_CHECK_REQUIRED_COMPONENTS_MACRO ) install( FILES ${QtTesting_DEVEL_HEADERS} DESTINATION ${QtTesting_INSTALL_INCLUDE_DIR} ) # Configure the CMake EXPORT file during installation install( FILES ${QtTesting_BINARY_DIR}/CMakeFiles/QtTestingConfig.cmake DESTINATION ${QtTesting_INSTALL_CMAKE_DIR} ) install( EXPORT ${QT_TESTING_INSTALL_EXPORT_NAME} DESTINATION ${QtTesting_INSTALL_CMAKE_DIR} ) ENDIF() qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Copyright.txt000066400000000000000000000026461526070500000240740ustar00rootroot00000000000000Copyright (c) 2000 Kitware Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Kitware nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 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. qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Examples/000077500000000000000000000000001526070500000231315ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Examples/CMakeLists.txt000066400000000000000000000013421526070500000256710ustar00rootroot00000000000000 SET (UI_FILES TestingDemo.ui ) SET (SOURCE_FILES TestingDemo.cxx TestingDemo.h ) SET (MOC_FILES TestingDemo.h ) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) IF(QtTesting_QT_VERSION VERSION_GREATER "5") QT6_WRAP_UI (EXAMPLE_UI_BUILT_SOURCES ${UI_FILES}) QT6_WRAP_CPP(EXAMPLE_MOC_BUILT_SOURCES ${MOC_FILES}) ELSE() QT5_WRAP_UI (EXAMPLE_UI_BUILT_SOURCES ${UI_FILES}) QT5_WRAP_CPP(EXAMPLE_MOC_BUILT_SOURCES ${MOC_FILES}) ENDIF() add_executable (TestingDemo ${SOURCE_FILES} ${EXAMPLE_UI_BUILT_SOURCES} ${EXAMPLE_MOC_BUILT_SOURCES} ) target_link_libraries(TestingDemo qttesting ${qt_imported_targets}) set_target_properties(TestingDemo PROPERTIES COMPILE_FLAGS "${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Examples/TestingDemo.cxx000066400000000000000000000136441526070500000261070ustar00rootroot00000000000000 #include "TestingDemo.h" #include "ui_TestingDemo.h" #include "pqEventObserver.h" #include "pqEventSource.h" #include "pqTestUtility.h" #include #include #include #include #include #include #include #include #include class XMLEventObserver : public pqEventObserver { QXmlStreamWriter* XMLStream; QString XMLString; public: XMLEventObserver(QObject* p) : pqEventObserver(p) { this->XMLStream = NULL; } ~XMLEventObserver() override { delete this->XMLStream; } protected: void setStream(QTextStream* stream) override { if (this->XMLStream) { this->XMLStream->writeEndElement(); this->XMLStream->writeEndDocument(); delete this->XMLStream; this->XMLStream = NULL; } if (this->Stream) { *this->Stream << this->XMLString; } this->XMLString = QString(); pqEventObserver::setStream(stream); if (this->Stream) { this->XMLStream = new QXmlStreamWriter(&this->XMLString); this->XMLStream->setAutoFormatting(true); this->XMLStream->writeStartDocument(); this->XMLStream->writeStartElement("events"); } } void onRecordEvent(const QString& widget, const QString& command, const QString& arguments, const int& eventType) override { if (this->XMLStream) { this->XMLStream->writeStartElement("event"); this->XMLStream->writeAttribute("widget", widget); if (eventType == pqEventTypes::ACTION_EVENT) { this->XMLStream->writeAttribute("command", command); } else // if(eventType == pqEventTypes::CHECK_EVENT) { this->XMLStream->writeAttribute("property", command); } this->XMLStream->writeAttribute("arguments", arguments); this->XMLStream->writeEndElement(); } } }; class XMLEventSource : public pqEventSource { typedef pqEventSource Superclass; QXmlStreamReader* XMLStream; public: XMLEventSource(QObject* p) : Superclass(p) { this->XMLStream = NULL; } ~XMLEventSource() override { delete this->XMLStream; } protected: void setContent(const QString& xmlfilename) override { delete this->XMLStream; this->XMLStream = NULL; QFile xml(xmlfilename); if (!xml.open(QIODevice::ReadOnly)) { qDebug() << "Failed to load " << xmlfilename; return; } QByteArray data = xml.readAll(); this->XMLStream = new QXmlStreamReader(data); /* This checked for valid event objects, but also caused the first event * to get dropped. Commenting this out in the example. If you wish to report * empty XML test files a flag indicating whether valid events were found is * probably the best way to go. while (!this->XMLStream->atEnd()) { QXmlStreamReader::TokenType token = this->XMLStream->readNext(); if (token == QXmlStreamReader::StartElement) { if (this->XMLStream->name() == "event") { break; } } } */ if (this->XMLStream->atEnd()) { qDebug() << "Invalid xml" << Qt::endl; } return; } int getNextEvent(QString& widget, QString& command, QString& arguments, int& eventType) override { if (this->XMLStream->atEnd()) { return DONE; } while (!this->XMLStream->atEnd()) { QXmlStreamReader::TokenType token = this->XMLStream->readNext(); if (token == QXmlStreamReader::StartElement) { if (this->XMLStream->name() == QStringLiteral("event")) { break; } } } if (this->XMLStream->atEnd()) { return DONE; } eventType = pqEventTypes::ACTION_EVENT; widget = this->XMLStream->attributes().value("widget").toString(); command = this->XMLStream->attributes().value("command").toString(); arguments = this->XMLStream->attributes().value("arguments").toString(); return SUCCESS; } }; //----------------------------------------------------------------------------- TestingDemo::TestingDemo() { Ui::TestingDemo ui; ui.setupUi(this); QObject::connect(ui.actionRecord, SIGNAL(triggered()), this, SLOT(record())); QObject::connect(ui.actionPlay, SIGNAL(triggered()), this, SLOT(play())); QObject::connect(ui.actionOpen_Dialog, SIGNAL(triggered()), this, SLOT(popup())); this->TestUtility = new pqTestUtility(this); this->TestUtility->addEventObserver("xml", new XMLEventObserver(this)); this->TestUtility->addEventSource("xml", new XMLEventSource(this)); } //----------------------------------------------------------------------------- TestingDemo::~TestingDemo() { delete this->TestUtility; } //----------------------------------------------------------------------------- void TestingDemo::record() { QString filename = QFileDialog::getSaveFileName(this, "Test File Name", QString(), "XML Files (*.xml)"); if (!filename.isEmpty()) { #if QT_VERSION < QT_VERSION_CHECK(6, 5, 0) QApplication::setActiveWindow(this); #else QWidget::activateWindow(); #endif this->TestUtility->recordTests(filename); } } //----------------------------------------------------------------------------- void TestingDemo::play() { QString filename = QFileDialog::getOpenFileName(this, "Test File Name", QString(), "XML Files (*.xml)"); if (!filename.isEmpty()) { this->TestUtility->playTests(filename); } } //----------------------------------------------------------------------------- void TestingDemo::popup() { QDialog dialog; QHBoxLayout* hbox = new QHBoxLayout(&dialog); QPushButton button("Click to Close", &dialog); hbox->addWidget(&button); QObject::connect(&button, SIGNAL(clicked()), &dialog, SLOT(accept())); dialog.exec(); } //----------------------------------------------------------------------------- int main(int argc, char* argv[]) { QApplication app(argc, argv); TestingDemo mainWindow; mainWindow.show(); return app.exec(); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Examples/TestingDemo.h000066400000000000000000000004431526070500000255250ustar00rootroot00000000000000 #include class pqTestUtility; class TestingDemo : public QMainWindow { Q_OBJECT public: TestingDemo(); ~TestingDemo() override; protected slots: void record(); void play(); void popup(); private: Q_DISABLE_COPY(TestingDemo) pqTestUtility* TestUtility; }; qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Examples/TestingDemo.ui000066400000000000000000000056641526070500000257250ustar00rootroot00000000000000 TestingDemo 0 0 483 392 MainWindow Items Item0 Item1 Item2 Qt::Horizontal 0 0 483 22 &File Testing Popup Dialog E&xit Record Play actionE_xit triggered() TestingDemo close() -1 -1 241 195 qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/QtTestingConfig-install.cmake.in000066400000000000000000000014231526070500000274760ustar00rootroot00000000000000# # QtTestingConfig.cmake - QtTesting CMake configuration file for external projects. # @PACKAGE_INIT@ if(IS_ABSOLUTE "@QtTesting_INSTALL_INCLUDE_DIR@") set(QtTesting_INCLUDE_DIRS "@QtTesting_INSTALL_INCLUDE_DIR@") else() set(QtTesting_INCLUDE_DIRS "${PACKAGE_PREFIX_DIR}/@QtTesting_INSTALL_INCLUDE_DIR@") get_filename_component(QtTesting_INCLUDE_DIRS "${QtTesting_INCLUDE_DIRS}" ABSOLUTE) endif() if(IS_ABSOLUTE "@QtTesting_INSTALL_LIB_DIR@") set(QtTesting_LIBRARY_DIR "@QtTesting_INSTALL_LIB_DIR@") else() set(QtTesting_LIBRARY_DIR "${PACKAGE_PREFIX_DIR}/@QtTesting_INSTALL_LIB_DIR@") get_filename_component(QtTesting_LIBRARY_DIR "${QtTesting_LIBRARY_DIR}" ABSOLUTE) endif() set(QtTesting_LIBRARIES QtTesting) include("${CMAKE_CURRENT_LIST_DIR}/QtTestingTargets.cmake") qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/QtTestingConfig.cmake.in000066400000000000000000000005531526070500000260350ustar00rootroot00000000000000 if(NOT QtTesting_EXPORTS_INCLUDED) include("@QtTesting_BINARY_DIR@/QtTestingExports.cmake") set(QtTesting_EXPORTS_INCLUDED 1) endif() set(QtTesting_INCLUDE_DIRS "@QtTesting_SOURCE_DIR@;@QtTesting_BINARY_DIR@") set(QtTesting_LIBRARY_DIR "@QtTesting_BINARY_DIR@") set(QtTesting_LIBRARIES QtTesting) include("${CMAKE_CURRENT_LIST_DIR}/QtTestingExports.cmake") qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/QtTestingConfigure.h.in000066400000000000000000000012771526070500000257240ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _QtTestingConfigure_h #define _QtTestingConfigure_h #cmakedefine QTTESTING_BUILD_SHARED_LIBS #cmakedefine QT_TESTING_WITH_PYTHON #define QT_TESTING_EVENT_PLAYBACK_DELAY @QT_TESTING_EVENT_PLAYBACK_DELAY@ // // This macro is used to quiet compiler warnings about unused parameters // to methods. Only use it when the parameter really shouldn't be used. // Don't use it as a way to shut up the compiler while you take your // sweet time getting around to implementing the method. // #define pqNotUsed(x) #endif // _QtTestingConfigure_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/QtTestingExport.h000066400000000000000000000012461526070500000246530ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _QtTestingExport_h #define _QtTestingExport_h #include "QtTestingConfigure.h" #if defined(QTTESTING_BUILD_SHARED_LIBS) #if defined(QtTesting_EXPORTS) #if defined(_WIN32) #define QTTESTING_EXPORT __declspec(dllexport) #elif defined(__GNUC__) && __GNUC__ >= 4 #define QTTESTING_EXPORT __attribute__((visibility("default"))) #endif #else #if defined(_WIN32) #define QTTESTING_EXPORT __declspec(dllimport) #endif #endif #endif #ifndef QTTESTING_EXPORT #define QTTESTING_EXPORT #endif #endif // !_QtTestingExport_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/ReadMe.rst000066400000000000000000000435641526070500000232560ustar00rootroot00000000000000*********** ReadMe *********** .. sectnum:: .. contents:: Table of Contents Overview ~~~~~~~~~~~~~~~~~~~~~~~~~ The VTK and ParaView projects have a long history of regression testing using the tools (ctest, dashboards, etc) provided by CMake. With Qt as the user interface toolkit in ParaView, QtTesting library has been created for automatic testing of UI components in ParaView application. This document is intended to describe the new framework in sufficient detail to allow outside contribution. Requirements ~~~~~~~~~~~~~~~~~~~~~~~~~ - The framework must have an open source license consistent with the ParaView / VTK license. Rationale: to allow all ParaView users to contribute and run test cases. - The framework should support easy test case creation to encourage user-contributed tests and bug reporting. - The framework should allow for multiple forms of validation whether a test passes or fails, including-but-not-limited to image-based validation. - The framework should support test cases that can be recorded as scripts. Rationale: a test case recorded as a script can apply complex logic for quantitative verification and validation of results. For example, a scripted test case could check the values of internal data structures during playback, instead of relying on image-based validation. - The framework should support test cases that can be recorded as low-level "metafiles". Rationale: simplicity, reduce dependencies on any given script engine for testing. - Where possible, test-cases should continue to play-back correctly despite modifications to the user interface. - To reduce developer burden, the framework should be as unintrusive as possible. In particular, it should be possible to use the framework with existing code and interfaces built using Qt Designer, and the framework should not require that the developer use "special" widgets, multiple inheritance, or the like. Design Challenges ~~~~~~~~~~~~~~~~~~~~~~~~~ Low-Level vs. High-Level Events ******************************************** In theory, all user interaction with a graphical user interface can be broken-down into a handful of low-level "events": mouse button press, mouse button release, mouse movement, key press, and key release. Recording the low-level events and their parameters as they happen for recording, then synthesizing the same events in order for playback, will put the application into the same state. In practice, this approach does not work well due to differences in user interface "skins", platform, hardware, and operating environment: - Differences in window manager between platforms (or even on the same platform, due to user choices) may cause the sizes and arrangement of windows to vary between test case recording and playback. - Due to user interface skinning or platform specific look-and-feel, the sizes of widgets may very, even if the top-level window is consistently sized. As an example, the width of a splitter bar may vary by a few pixels between two platforms. During playback of a test case where the user resizes a splitter, this could cause the mouse to "miss" the splitter, sending the subsequent mouse movement events into adjacent controls instead of to the splitter where they belong. Differences in font size will affect the size of a menu. Internationalization can radically change the size and layout of widgets. - When recording typical user interaction with a file dialog, the test case would include some combination of scrollbar movement and double-clicks as the user navigated through their filesystem. Unfortunately, this recording would be heavily dependent on the contents of the filesystem - nearly any change in filesystem contents between recording and playback will cause the test to fail, since filenames would be in different locations relative to the mouse. - A recording of user interaction with a spin button would fail during playback if the spin button is replaced with a slider, despite the fact that both represent an integer quantity. For these and many other similar issues, it isn't enough that a test case record what the user did - a test case should record what the user intended. Thus, test case recording and playback becomes a case of mapping between low level user interface events and high-level events - rather than recording a button activation as a mouse press event followed by a mouse release event at such-and-such coordinates, a single high-level "button activation" event can be recorded, so that the correct button can be activated during playback, regardless of its screen coordinates. Similarly, all of the mouse clicks and scrolling within a file dialog can be replaced by a single "file selected" event that includes the file name as a parameter - during playback, the correct file can be selected regardless of any changes to the underlying filesystem. When recording interaction with a spin button, the series of mouse-clicks and keyboard input can be replaced with a single "set integer" event that includes the final value as a parameter - during playback, the "set integer" event can be interpreted by any widget that represents integers (spin buttons, sliders, dials, etc), not just the type of widget used to record the test. Widget Naming ******************************************** While the notion of mapping between low-level and high-level events is straightforward, one problem remains - how to provide a serializable name for widgets so that high-level events can be directed to the correct widget during playback. It is typical to use pointers or references to access Qt widgets at runtime, but these are obviously inadequate as serializable identifiers. The main problem is with generating globally-unique names, while allowing for reasonable changes to the user interface without breaking test cases. As an example, a test recorded on one system may be played-back on another, with a different configuration of docked / floating toolbars. Several alternatives have been discussed: - Flat - Assign a globally-unique name to every widget. Pros: test cases work no matter how the UI is rearranged. Cons: Developers must explicitly name everything, names quickly become unwieldy, QtDesigner limits widget names (e.g. can't contain slashes), and QtDesigner-generated intance variables will share the long, unwieldy names. - The MS Way - Same as "Flat", only use 128-bit UUIDs as identifiers. Insert Homer Simpson-like shudder here ... - Widget Hierarchy - Use the Qt widget hierarchy to generate unique names. Pros: developers can use straightforward names for widgets in Qt designer, and only have to explicitly name top-level objects like dialogs. Cons: rearranging the widget hierarchy breaks test cases, e.g. floating/docking windows. - The K-3D Way - Use a hierarchical naming scheme, but make it orthogonal to the Qt widget hierachy. Pros: same as "Widget Hierarchy", plus floating and docking windows no longer break test cases. Cons: since this is a separate hierarchy, it has to be maintained at runtime, e.g. by explicitly registering widgets with some central manager, implying a highly-intrusive mechanism of custom widgets or the like. After considering these options it was decided that the framework would use the "Widget Hierarchy" method, generating widget names by walking the Qt widget hierarchy, concatenating object names (separated by slashes) into a hierarchical "path" string. Although this method is especially brittle in the face of UI modifications, it requires the least developer effort and integrates well with custom user interfaces and interfaces created with Qt designer. Design ~~~~~~~~~~~~~~~~~~~~~~~~~ Recording ******************************************** Test case recording centers around the pqWidgetEventTranslator abstract interface class. Derivatives of this class are responsible for converting low-level Qt events ("mouse move", "button down", "button up", etc) into the high-level events (e.g: "button activated") that can be serialized and played back. pqWidgetEventTranslator derivatives may be particular to a specific widget type, such as pqComboBoxEventTranslator, or may represent a class of related widgets, such as pqAbstractSliderEventTranslator, which can translate events for any widget that derives from QAbstractSlider, including QDial, QScrollBar, and QSlider. pqWidgetEventTranslator derivatives implement the translateEvent() method, where they determine whether they can handle a Qt event, and if they can, convert it into a high-level event which consists of two strings: a command, and the corresponding command arguments (which may be empty). The translator then emits the recordEvent() signal one-or-more times to pass the high-level event(s) to its container. It is intended that the test framework eventually include pqEventWidgetTranslator derivatives for all "stock" Qt widgets. Some events are generic for every kind of widgets ( eg. contextMenu ) and are handled by pqWidgetEventTranslator, so any derivatives should call the superclass::translateEvent method when an event cannot be treated. A collection of pqWidgetEventTranslator objects is maintained at runtime by an instance of pqEventTranslator. pqEventTranslator hooks itself into the Qt event loop as a top-level event filter, so it receives every Qt event that occurs at runtime for the entire application. pqEventTranslator passes the Qt event to each of its pqWidgetEventTranslator instances in-turn, until one of the instances signals that the event has been "consumed". When a pqWidgetEventTranslator emits a high-level event, the event is "caught" by the pqEventTranslator instance and combined with the serializable address of the widget to which the high-level event applies. The three strings (address, command, and arguments) of the complete high-level event are emitted from the pqEventTranslator as a Qt signal. The high-level event emitted from pqEventTranslator may be caught by any observer with the correct Qt slot. It is up to the observer(s) to serialize the high-level event for later playback. At this time the framework includes two observers, pqEventObserverStdout and pqEventObserverXML, which serialize the high-level events to stdout and an XML file respectively. Developers can create their own observers to implement custom functionality, such as serializing events to a logfile, a Python script, etc. It is also possible to record check event, ( by using the check button on the recordDialog ). When checking, an overlay is drawned over the widget hovered by the mouse. If the overlay is green, then it means that the widget can be checked, if it's red, that it cannot. When clicking on the widget to check, a check event is recorded, associated with a QString value representing the widget "value". Translator managing check event should handle only two types QEvent, MouseMove to see if widget is checkable, and MouseButtonRelease, to record check events. Playback ******************************************** Test case playback is basically a mirror-image of recording. The pqEventSource provides an abstract interface for objects capable of providing a "stream" of high-level events. The pqXMLEventSource provides a concrete implementation of pqEventSource, and is capable of reading the XML files generated by pqEventObserverXML. The pqEventPlayer class maintains a collection of pqWidgetEventPlayer objects that handle translation from high-level events to low-level events. An instance of pqEventDispatcher retrieves events from a pqEventSource, handing them off to an instance of pqEventPlayer for playback. Derivatives of the pqWidgetEventPlayer abstract interface class are responsible for mapping high-level events back into low-level Qt events (or direct widget manipulation). Note that there is not a one-to-one correspondence between pqWidgetEventTranslator and pqWidgetEventPlayer classes - a single pqAbstractIntEventPlayer object is capable of handling events generated by both pqSpinBoxEventTranslator and pqAbstractSliderEventTranslator, because the two translators map dissimilar Qt events into a single, abstract "set_int" event. pqEventPlayer maintains a collection of pqWidgetEventPlayer objects, and as with pqEventTranslator, the set of pqWidgetEventPlayer objects can be instantiated by the developer or by pqEventTranslator, or both. Each high-level event is encoded as three strings(address, command, and arguments), which are fed to pqEventPlayer::playEvent(). pqEventPlayer decodes the address string and uses it to lookup the corresponding widget. The high-level event and widget are then passed to each pqWidgetEventPlayer in-turn, until one of them signals that the event has been handled. Extensions ******************************************** The test framework can be extended through the creation of custom components. To store high-level events to a custom format or device, the developer creates an observer class with a correctly-prototyped slot to receive events from pqEventTranslator. To play the data back, a corresponding pqEventSource derivative is created that can read the data. Support for test case recording and playback of custom widgets is handled by creating custom derivatives of pqWidgetEventTranslator and pqWidgetEventPlayer, then adding instances of those custom derivatives to pqEventTranslator and pqEventPlayer, respectively. pqEventTranslator and pqEventPlayer also have methods that instantiate all of the "built in" translators and players that are part of the framework. Because translators and players are executed in-order until a given event has been handled, the developer can "override" builtin translators/players by adding their custom components first. Outstanding Issues ~~~~~~~~~~~~~~~~~~~~~~~~~ A significant issue with the design of the framework is the problem of modality - in general, dispatchers cannot assume that a call to pqEventPlayer::playEvent() will return immediately, since the event playback may cause a modal dialog or a widget-generated context menu to be shown. In these cases playEvent() will not return until the dialog is closed or the context menu is hidden, yet the test framework must continue dispatching events or there will never be any simulated user input to close the dialog or choose an item from the menu! For this reason pqEventDispatcher relies on the QAbstractEventDispatcher::aboutToBlock() signal to force asynchronous dispatching of events. Other methods of handling event dispatching have been tried, e.g pqThreadedEventDispatcher, and we consider this to be an area for further development. A second tricky problem has been the mapping of high-level events to low-level Qt events for playback. In a nutshell, receiving useful events for recording is easy, because the API of a user interface toolkit such as Qt is fundamentally there to enable a client application to receive information about user interaction. Playback is more difficult because the synthesis of simulated user input is a highly specialized use case that is generally not supported or encouraged by the public API. This can lead to complex code, and generally requires an understanding of the internal implementation details of Qt widgets: on one hand, playing-back a button activation is simple, because the QAbstractButton::click() method is part of the API, while playing-back a menu activation is complex, because there is no comparable method for menu items. In the latter case, the implementation must synthesize low-level Qt events to simulate the corresponding user interaction. Developer's Guide ~~~~~~~~~~~~~~~~~~~~~~~~~ Download and Build with CMake ******************************** - `QtTesting `_ - `CMake `_ Add the testing framework into your application ************************************************************ Checkout the application example in the "Examples" directory, and follow these steps to add the testing framework to your application: - Create a variable myQtTestingUtiliy - can be added to your mainWindow class (You can have your own EventObserver and EventSource), and initialize this variable as following:: this->TestUtility = new myQtTestingUtility(this); this->TestUtility->addEventObserver("xml", new myXMLEventObserver(this)); this->TestUtility->addEventSource("xml", new myXMLEventSource(this)); - Link UI buttons to the myQtTestUtility "record" and "play" slots:: QObject::connect(Ui.RecordButton, SIGNAL(clicked(bool)), this, SLOT(record())); QObject::connect(Ui.PlayBackButton, SIGNAL(clicked(bool)), this, SLOT(play())); Writing new Translators/Player ************************************************************ A new translator must at least reimplement the translateEvent(QObject object, QEvent event, int eventType, bool& error) method. For starters, it must check that the object is of correct class Then it should handle the pqEventTypes::ACTION_EVENT case, recording meaningfull events with identifiable command and associated arguments And it should also handle the pqEventTypes::CHECK_EVENT case, only for two different QEvent For QEvent::MouseMove it should return true only if a check event can be recorded For QEvent::MouseButtonRelease , it should record a check event, associated to the value you want to check and an existing qt property or an identified command A new player, symmetrically, should at least reimplement the playEvent(QObject* object, const QString& command, const QString& arguments, int eventType, bool& error) method First it should handle the pqEventTypes::ACTION_EVENT, converting provided command and arguments into qt instructions, returning true for event that it can handle. Then, if the the translator can record check command, it should hendle the pqEventTypes::CHECK_EVENT, checking the current value of qt object using provided command and arguments, positionning error to false when a value differ, but returning true for all handled check event, even failed one. Property to check are handled by pqBasicWidgetEventPlayer See the pqLineEditEventTranslator and pqLineEditEventPlayer for a simple example and pqAbstractItemViewEventTranslatorBase/pqAbstractItemViewEventPlayerBase for a advanced example. qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/000077500000000000000000000000001526070500000233255ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/Icons/000077500000000000000000000000001526070500000244005ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/Icons/check.png000066400000000000000000000015571526070500000261730ustar00rootroot00000000000000‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs  šœtIMEß  (/RÏüIDATHÇÕ•MhSYÇ÷¥MÒF_Õ6Qñ ¦Š383)µ(¢¢ 7"¨H»j@fP60‹Q¤à.‹I7.¤]¨EŠø‰ˆ"ZüD-��¢¨Ùi±(‚­I^žy÷Ì¢í3µIZfÆ…ÎâÝûçÿ»çœ{ßU"·ßx|?€h´¥è¼úº¥„‰DmmÍ¥$�ŸQ…ÅTs—ÌgKd«ûÝwë ÉÛO&hÂVÒ°q%�í'h=ü;�þ’g W‰F'BŠ–Hlmck›ÏÚF‹3IãˆCgû ZE8}ñ¸¼ix À³H7Ñh‹”hÑØŽ…íX䋼ä'iþîécÇ�fÎ_é”á—˜'A*Šg ±%W°ÛÉ€åë~äæõËbý:äšó“ úš/SEé ²Eã þ`‰ýË;Ð`RÇ0ï1 2'¹ŒX¤{ªhrÚrcÐÖÖL"ÑEpÕlÑá�T3Ç2¨#ôt±Ön5å=Ðâ`ë ¶Î’ÓòòÙ=¦±®?ÄÛ8 ô{.dÖÀd{E}íU²DVA‰^ßÀѳ…ð',=jn9iüžF²†ì ­¦{“Eã�Ór:Co¢ŸàªÙÔ¯]*þÆÑÓç7nF²†Ðê9JãLý«ˆF[¤~ß1颷ÝÄãgTê^Ê5÷~¼ž*–®[6fêw!gIÝ}¥òbc9i7Êâ‘‹ª¿§×5÷*^O• zøžý»Ž(€¼ØdõY=BF�0­&ÇZ»UÏ�k_Ì ƒÞ²gçA÷(J_ÝBw„�޼õNï=h?õ›lÚ¼ÍÝÕ‹;ÏÙ½ýOõ¯^")GNí•;C—ä乘”ÒL'Ê.þWs)^¢ÿsüÆ+õ×L€u5IEND®B`‚qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/Icons/clear.svg000066400000000000000000000164601526070500000262160ustar00rootroot00000000000000 image/svg+xml round error warning button Lumen Design Studio Lumen Design Studio error warning icon error icon button red stop no warning negative delete cancel qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/Icons/frameForward.png000066400000000000000000000011541526070500000275260ustar00rootroot00000000000000‰PNG  IHDRàw=øgAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<þIDATxÚìUOKQŸÕH*&j(ViAbÁÃì­Ø@OÁK…BƒzL>�Z¿€› ‚ê¡û ÔC= þ¡Ð[iŽ ¶Ùf7û/û^g6É{”M¶ ¥àÀ�÷fßðûÍÌÛ�U8çp—Öwlÿ¿@ªµ)•Vþxåò¾Bk±øj—Mô+Ý’Óý¦Ú¼^_Þoí´»Ä ‘Hù¯Zä®Ùæ ‹Ã™á¬Ž"‡ˆ‰äÌ Û˜úÞ.ÃÌœ–G÷;Šl$àŽÙÖèã0ýü)äW_BöÑà&Šœ!^t%à¶Ù\憕¹Ü†#ixöf&óªÖ›î=B‘mÄPG€l=gMq'¨‡ëC-S+*ô?I—0ä\®&%fX�í'eN—ïG•´À|]„Ÿ_ õ׉GÕDo�‘L3ö$r�*bv¸òœJ†ÿ¡h®".*;ÎèÜ�ˆÝ6rDZ¡vê�û…¢úNÞÑN×?ˆ-r˜_VØ$·oÉÍo˜' `&Q[ä/]ªÀêP�u›¹mÔ¡ú÷^�ˆ?Å΢&�)÷ ž�D^½´À<õ�{ GóÉè8ìB& äϼ®ÁÍ¡�~Nó‰�»ž¦Í kÒ¡(põѤvè­KL4®Cgo<.ö ʺ’ä Üÿ“ÿ¹ÀoˆwP#IËQ¨IEND®B`‚qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/Icons/info.png000066400000000000000000000006351526070500000260450ustar00rootroot00000000000000‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe</IDAT8Ëcøÿÿ?%˜�jD´ïâ¥@üˆÿãÁ»€X›W¼õÿ÷Ÿ¿ÿñ�-'ïƒ ¹ Älp€ þó÷ß¿ÿ¾ýûÿòÓ¿ÿÏ>þûÿäý¿ÿßýûïÍ¿ÿ·_ýýçÄðêÇA†˜! —3õXòPã³ÿþ?j~ðößÿ»PÍ×_üýõÄ€ÎUgAxc5à)Pó£wPͯÿý¿õ¢ù PóÅ'¸ €{äüû@[ï¼þûÿ&Póµçÿ_j¾ðdÀ°µ‹N€ °Äˆ C�È5ÿŒˆœ¸¢ñ,Êæî¸ 7èýç`>Pü2ÖhĆ� ï<÷¦ñ;×��Š{gn»Òøˆ IJÊ@ J@|ˆSè—Ì÷‹"¾âj IEND®B`‚qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/Icons/minus.png000066400000000000000000000004501526070500000262400ustar00rootroot00000000000000‰PNG  IHDR(-SŠPLTEÿÿÿË#!Ó62Ó52ÿ½½½/-ÿ¸¸ÿŸŸ¿65¾1.¿63¶ Â;8À:7ÿèèÀ85¿52ÿÄÄÿÀÀ¾2/ÿººÿË˾0-ÿ¯¯ÿ§§»*(¼20ÿÚÚÿ¬¬ÿ¤¤¿41ÿœœÿ££ÿ´´ÿªªÿ••ÿŠŠ¹%"ÿÒÒ»,*º*)¹)'¹'%¸%#ÿ¾¾· j�˜tRNSàààä§®IIDAT•c` `âáåç�ædeec p𩉠±ˆ°è°‰KH¤¤edÙåØ•Ø•UT�ŒêšZÚÜ` ËH'wA_„tÆHIEND®B`‚qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/Icons/pause.png000066400000000000000000000007171526070500000262300ustar00rootroot00000000000000‰PNG  IHDRàw=øgAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<aIDATxÚì•¿NÃ0Æ/üéÒ… ÄÄ#€ÔhGvØxƒö €7hß ì,ŒíT*�ÀÌ�Äumw›¸n©BH\ä$>}ÎÏß]”$ˆ›Œ-Øpü}ÀÎÏÄ`pÑ¥Ë$ ½�înø¦ß?¿ây@Óo§QÇÁÑ!œ^žóùd�Ó™§9îvà¤×)æã{x}z^ï€é�FÚû„†A]Òhʹ^S©D`h@jQ̪@y^S€@\x+oBy^SÓA(ë oî`aDÀ9WSÓ70³íãæ)\KOz¢%n‰L ('š–È€&û™Sï€r®†×Ôs`RøzµW„N›;:+Ú§P’6‘9-Öõš,ô»So\ÑÕÐ�äÎnY¶[vàZtÞ®^¢Ü¼}š§�í @›ô[{ÕðÒ3Þ�~çqÞ¶c]$ÿÿä_|0YײK‚¼áIEND®B`‚qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/Icons/playback-stop.png000066400000000000000000000003421526070500000276560ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<_IDAT8�cüÿÿ?-ML’³  ¸D›“è{–ždÄk0CÛäF’ ­Ê­ÇÃjð�¿_I2Àjð÷42˜f.z�†1í za|µûÅ3ŽÖ 47Næ/§kìWÀIEND®B`‚qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/Icons/plus.png000066400000000000000000000005771526070500000261020ustar00rootroot00000000000000‰PNG  IHDR(-S·PLTEÿÿÿ½½´³ÞÔé ¶ Çõ·‚ñe¶´¦ï�Èô¹ ©÷”róS‘ºö©”ïy°õ�ÖöÊÂô±¶ô£­õ™¦÷‘µµÙ÷Ï]ð[@æ@&Ú&Ì ¶ ¸ ¹¶µ¸Åó¶¡îˆ�îu€ðcpòR\ö?0ÿ!ô†÷m_÷?˜ø‹ Ì ‡ XôXô{GîG<å<1Û1&Ð&ÉѸCtRNSààÕJtIDATx^uÍEÃ@ÐNÿ„™™SfÆûŸ«Šš,þTõòI¶GB”„ ˜dúƒ¤1à¸ROVϱ6L˦@¡[ný Œâýá˜eÌËÕz³Ý ‚¡r¾\oßJz(z�ž<¯7ýÞo>®ý©|àrIEND®B`‚qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/Icons/record.png000066400000000000000000000030011526070500000263560ustar00rootroot00000000000000‰PNG  IHDR*'y]Ú…sRGB®ÎébKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÜ04õ©Ð»�IDATXÃí˜[lUÆ¿sÎÌÎvvYºui V[@’jÐ&€/(ñ‰6©‰`Hc"1únBÄðhQcÔ%ƘøàÞ䢉>‰ „r)”¶¶¥—ín»—™9gfŽ;³Ù]öÖ­ =ÉæœÝ™Íþò}ÿï¿ç °4–ƃ=Èb¾ü:³�]vJ @;rómwHn>N|¤ï;è`½ŽH`7%äF8àAU¥¥ÍAEql)Ó®ãdæ8O¥,«Ý‘ò1 |à½ã9ø{ zÀQ{ô@`&ªi�£ !`”‚…ÒüšQ Kˆ[ñøhFˆ |Ú: Ø÷ô5 ÃN1JÛjjj[ÕÝ�‡7nÄòŽh¡Ô@Rðùy˜ÓÓÈŒŒ`np°¬8!H qåüؘêJ9,�¾ã@ò?íºp^S剞žhÏÞ½ˆvvÂ容™sHo-mæô4ÆOŸ†›Jå!™3CC— Û^.�gê…%õØm‚ŠÒñì¾}ú†Þ^HÇ© )9„€ÖÔîœ9“/O]ûÔàà_Y!’�ÀŽzÊ€ÖºÁ¾a”®Ü¾¿¾±¯¯.HéAB–--¨_o­¼°nÝãŒÒ®ÛÀ‘z¥5,ß*�]›¶m[ödoo¬&¤¯¨mœçk4:B )JhÇÚµÞìºJ ù8ÒÔĶô÷/’ØvNQÎÛ.†ô:‚BV†Ã�¬Ðõ+Þm´è–R>ݽu+Õ£Q8• =¸» …§i™©LfGÌ4A…€ �JY éÍn2Y¬¤÷>išøa`À•R¾ô'0µ¨�óÛš6VÕÖMíí`”¢)�¢i¹À8¨ã€8˜ãÔT¯ððù… Öp*õýW®ûê¢7ÎÑPh{Ü0ì[‰!p38‰œD2•L´`+WZ�•Òÿãµkîx:=pÝ·êÙ8³Z7œ3Œé]‘ÈÀÐÜ\!„´‡Bem,U¯h³\à§7ðÇøø¼íº[¾¨Q›uƒÀY˺Ò‹]½�H¼8gYtU8Œü1¹P9û³BàÛK—äµx|Ìpœ-_#÷ä\ÿ~kë†Étúlšó–§ÚÚ°>C@Qj**¿��áÜð°VÕ³¦iî^è““†ž”|‹K§ßIs\�bus3ZuMCDÓ`�¬˜Êfq=ÇÕÙY¹\ÓnÚR8fš¿Þ÷gOµµíÉñF<›Ý”µí&˶󥤫ªÐU5¡«ê©”mû0“ùû�yâvPê9Q.�¥±4þÇñ/y® ÃG_߀IEND®B`‚qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/Icons/repeat.png000066400000000000000000000014331526070500000263670ustar00rootroot00000000000000‰PNG  IHDRàw=øgAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<­IDATxÚ´VÍkSAŸÝ¼}¯Š©-j¥ØPô$%Ñ(©6J/*AüÛ¿ õèÉü éQ/FATŠ/úB=ô` •Ú*’-5¨´¶Æä}:»y¯Ä�—�†. ³;™ýýfggö…ض »:8�+ÍŒ‰‰«ïQzëaÒb ¡d�d¨–S+püBØÏ¦"É]/RžšÉÉkïšÀ�Dï\†ÍÜÌ(®šPøf€¥ÙåÑVëØ(F=ÎÁ©LT,•u×j­¨¿¦‹œÆ]¯;‘ñï(wDðWÛUÔ%A×¥= YÈÝ×¼S„›†+ò|KRXÂ(ê;N#­ñ˜=Àg 1xã\K�©Tx/O•ÿ@GhèæyÀsí^ψ¿a ò|÷�B#a  ÃÒ`àúÔzÄ´ 0l]Ø„vÄb<…FC'ˆËŠ89:Xb3�‡;AGP]kâ2Këh6ŵ�óÆ¢¶ûë{/ƯD }»0.¥Á²M0QJÚØÖ&¸kCü^“€?µ¨Æ1U™·�Þă#' §¿>¥—Ài¨¦ÇÏ5!¤ü>Dý÷�:âÿ2û™““f>ÃuËÔyƒBži¥Lk~2‘d™¹øåìöß– t+={ÙjÜIEND®B`‚qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/Icons/timePlay.png000066400000000000000000000010421526070500000266670ustar00rootroot00000000000000‰PNG  IHDRàw=øgAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<´IDATxÚìU»JA=1& fQ,,4Z"ø¬L"bm%*HÄ0`>Áü�vZ+Kµ±ôÙ6,-Œnv&›�]ïÌ®�&&Ù ‚wwg8gî�™³ÇqÐÊhC‹ãï ´7�ɬ¦)½ærûG?%ûj?«U0HÈom­b-iÑèìF—è±@"ißÂa$–0¿¾¨uÆ:wIä„÷M@8¦àÐú5Ìm¦ŸŠ'éó‰lû$`¡ls;da(5„Éõq-ÒÉ’È%a¢)K 0”2vëè™éšü¬¦Ú!¨QAŰ B \eL”�¡w-‚ö>'ë %ê¯À¶¼ÕJŠœ �²3X¢¶œªyǺÞU©‚ý —üýŽ¡x€uÌKrº�{uÝd·E¦j‹©ÚÄ(s°gý\@<µhÊŸ5d2*ªÝ=IœA¿)ƒ]È‘€ìû‘ö"wL0[Àxäx;µ@Ý9•6EÄ×M›�ª lâ娆ùà¼Òk–ˆs¾¹© ãVÈ´ë­ºè«]Kƒ#$kmb­üÿ“]àC€ƒ¼ñ +‡IEND®B`‚qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Resources/QtTesting.qrc000066400000000000000000000007421526070500000257610ustar00rootroot00000000000000 Icons/check.png Icons/frameForward.png Icons/pause.png Icons/repeat.png Icons/timePlay.png Icons/clear.svg Icons/minus.png Icons/plus.png Icons/info.png Icons/playback-stop.png Icons/record.png qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/000077500000000000000000000000001526070500000227705ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/CMake/000077500000000000000000000000001526070500000237505ustar00rootroot00000000000000qtTestingMacroGenerateMocs.cmake000066400000000000000000000015141526070500000321350ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/CMake # QT4_GENERATE_MOCS(inputfile1 [inputfile2 ...]) macro(QT4_GENERATE_MOCS) foreach(file ${ARGN}) set(moc_file moc_${file}) QT4_GENERATE_MOC(${file} ${moc_file}) macro_add_file_dependencies(${file} ${CMAKE_CURRENT_BINARY_DIR}/${moc_file}) endforeach() endmacro() # QT5_GENERATE_MOCS(inputfile1 [inputfile2 ...]) macro(QT5_GENERATE_MOCS) foreach(file ${ARGN}) set(moc_file moc_${file}) QT5_GENERATE_MOC(${file} ${moc_file}) set_property(SOURCE ${file} APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${moc_file}) endforeach() endmacro() macro(QT6_GENERATE_MOCS) foreach(file ${ARGN}) set(moc_file moc_${file}) QT_GENERATE_MOC(${file} ${moc_file}) set_property(SOURCE ${file} APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${moc_file}) endforeach() endmacro() qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/CMakeLists.txt000066400000000000000000000002631526070500000255310ustar00rootroot00000000000000if(NOT CMAKE_Cxx_Fortran_COMPILER_ID STREQUAL "Intel") # QtTest fails to compile on ICC. Hence we don't add these tests on # Intel compilers. add_subdirectory(Cpp) endif() qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/Cpp/000077500000000000000000000000001526070500000235125ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/Cpp/CMakeLists.txt000066400000000000000000000036551526070500000262630ustar00rootroot00000000000000include(../CMake/qtTestingMacroGenerateMocs.cmake) IF(QtTesting_QT_VERSION VERSION_GREATER "5") FIND_PACKAGE(Qt6 REQUIRED QUIET COMPONENTS Core Test Widgets Gui) SET(TEST_LIBRARIES Qt6::Test Qt6::Core Qt6::Widgets Qt6::Gui) ELSE() FIND_PACKAGE(Qt5 REQUIRED QUIET COMPONENTS Core Test Widgets Gui) SET(TEST_LIBRARIES Qt5::Test Qt5::Core Qt5::Widgets Qt5::Gui) ENDIF() set(KIT ${PROJECT_NAME}) set(TEST_SOURCES pqAbstractButtonEventTranslatorTest.cpp pqEventPlayerTest.cpp pqEventRecorderTest.cpp pqEventTranslatorTest.cpp pqDoubleSpinBoxEventPlayerTest.cpp pqDoubleSpinBoxEventTranslatorTest.cpp pqSpinBoxEventPlayerTest.cpp pqSpinBoxEventTranslatorTest.cpp pqTestUtilityTest.cpp ) set(TEST_MOC_HEADERS pqTest.h ) create_test_sourcelist(Tests ${KIT}CppTests.cxx ${TEST_SOURCES} ) set(TestsToRun ${Tests}) remove(TestsToRun ${KIT}CppTests.cxx) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ) if(QtTesting_QT_VERSION VERSION_GREATER "5") QT6_GENERATE_MOCS(${TEST_SOURCES}) QT6_WRAP_CPP( TEST_MOC_SRCS ${TEST_MOC_HEADERS} ) else() QT5_GENERATE_MOCS(${TEST_SOURCES}) QT5_WRAP_CPP( TEST_MOC_SRCS ${TEST_MOC_HEADERS} ) endif() add_executable(${KIT}CppTests ${Tests} ${TEST_MOC_SRCS}) target_link_libraries(${KIT}CppTests ${PROJECT_NAME} ${TEST_LIBRARIES} qttesting) set_target_properties(${KIT}CppTests PROPERTIES COMPILE_FLAGS "${Qt5Test_EXECUTABLE_COMPILE_FLAGS}") macro(SIMPLE_TEST testname) add_test(NAME ${testname} COMMAND $ ${testname} ${ARGN}) endmacro() # # Add Tests # SIMPLE_TEST( pqAbstractButtonEventTranslatorTest ) SIMPLE_TEST( pqEventPlayerTest ) SIMPLE_TEST( pqEventRecorderTest ) SIMPLE_TEST( pqDoubleSpinBoxEventPlayerTest ) SIMPLE_TEST( pqDoubleSpinBoxEventTranslatorTest ) SIMPLE_TEST( pqSpinBoxEventPlayerTest ) SIMPLE_TEST( pqSpinBoxEventTranslatorTest ) SIMPLE_TEST( pqEventTranslatorTest ) SIMPLE_TEST( pqTestUtilityTest ) pqAbstractButtonEventTranslatorTest.cpp000066400000000000000000000131151526070500000333540ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/Cpp// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include #include #include #include #include // 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(); #if QT_VERSION < QT_VERSION_CHECK(5, 3, 0) QTest::qWaitForWindowShown(this->ToolButton); #else std::ignore = QTest::qWaitForWindowExposed(this->ToolButton); #endif // 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); delete this->ToolButton; this->ToolButton = 0; } // ---------------------------------------------------------------------------- void pqAbstractButtonEventTranslatorTester::cleanupTestCase() { this->EventObserver = 0; delete this->TestUtility; } // ---------------------------------------------------------------------------- void pqAbstractButtonEventTranslatorTester::testToolButton() { QFETCH(int, popupMode); this->ToolButton->setPopupMode(static_cast(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("popupMode"); QTest::addColumn("withDefaultAction"); QTest::addColumn("checkable"); QTest::addColumn("withMenu"); QTest::addColumn("longClick"); QTest::addColumn("recordEmitted"); // QTest::newRow("fail") << 2 << false << false << true << false<< "toolButton, activate, #"; for (int i = 0; i < 0x20; ++i) { int popup = i & 0x01 ? QToolButton::DelayedPopup : QToolButton::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); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) bool longActivate = withMenu && popup == QToolButton::DelayedPopup && longClick; #else bool longActivate = false; #endif 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.toUtf8()) << popup << withDefaultAction << checkable << withMenu << longClick << recordEmitted; } } // ---------------------------------------------------------------------------- CTK_TEST_MAIN(pqAbstractButtonEventTranslatorTest) #include "moc_pqAbstractButtonEventTranslatorTest.cpp" pqDoubleSpinBoxEventPlayerTest.cpp000066400000000000000000000064101526070500000322350ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/Cpp// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include #include #include #include // QtTesting includes #include "pqEventTypes.h" #include "pqTestUtility.h" #include "pqTest.h" // ---------------------------------------------------------------------------- class pqDoubleSpinBoxEventPlayerTester : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void init(); void cleanup(); void cleanupTestCase(); void testPlayBackCommandSetDouble(); void testPlayBackCommandSetDouble_data(); private: QDoubleSpinBox* DoubleSpinBox; pqTestUtility* TestUtility; }; // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventPlayerTester::initTestCase() { this->TestUtility = new pqTestUtility(); this->TestUtility->addEventObserver("xml", new pqDummyEventObserver); this->TestUtility->addEventSource("xml", new pqDummyEventSource()); this->DoubleSpinBox = 0; } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventPlayerTester::init() { // Init the QSpinBox this->DoubleSpinBox = new QDoubleSpinBox(); this->DoubleSpinBox->setObjectName("doubleSpinBoxTest"); this->DoubleSpinBox->setMinimum(-99.99); this->DoubleSpinBox->setValue(0); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventPlayerTester::cleanup() { delete this->DoubleSpinBox; } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventPlayerTester::cleanupTestCase() { delete this->TestUtility; } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventPlayerTester::testPlayBackCommandSetDouble() { QFETCH(double, value); QFETCH(double, result); QFETCH(int, count); QSignalSpy spy(this->DoubleSpinBox, SIGNAL(valueChanged(double))); bool error; this->TestUtility->eventPlayer()->playEvent( QString("doubleSpinBoxTest"), QString("set_double"), QString::number(value), error); QCOMPARE(error, false); QCOMPARE(this->DoubleSpinBox->value(), result); this->TestUtility->eventPlayer()->playEvent(QString("doubleSpinBoxTest"), QString("value"), QString::number(result), pqEventTypes::CHECK_EVENT, error); QCOMPARE(error, false); QCOMPARE(spy.count(), count); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventPlayerTester::testPlayBackCommandSetDouble_data() { QTest::addColumn("value"); QTest::addColumn("result"); QTest::addColumn("count"); QTest::newRow("negative") << -10.5 << -10.5 << 1; QTest::newRow("positive") << 33.25 << 33.25 << 1; QTest::newRow("negativeoutside") << -200.00 << -99.99 << 1; QTest::newRow("positiveoutside") << 200.00 << 99.99 << 1; QTest::newRow("negativeboundary") << -99.99 << -99.99 << 1; QTest::newRow("positiveboundary") << 99.99 << 99.99 << 1; } // ---------------------------------------------------------------------------- CTK_TEST_MAIN(pqDoubleSpinBoxEventPlayerTest) #include "moc_pqDoubleSpinBoxEventPlayerTest.cpp" pqDoubleSpinBoxEventTranslatorTest.cpp000066400000000000000000000267371526070500000331500ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/Cpp// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include #include #include #include // QtTesting includes #include "pqTestUtility.h" #include "pqTest.h" // ---------------------------------------------------------------------------- class pqDoubleSpinBoxEventTranslatorTester : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void init(); void cleanup(); void cleanupTestCase(); void testRecordLeftMouseClick(); void testRecordLeftMouseClick_data(); void testRecordRightMouseClick(); void testRecordRightMouseClick_data(); void testRecordMiddleMouseClick(); void testRecordMiddleMouseClick_data(); void testRecordKeyBoardClick(); void testRecordKeyBoardClick_data(); void testRecordComplexClick(); void testRecordCheckMouseClick(); void testRecordCheckMouseClick_data(); private: QDoubleSpinBox* DoubleSpinBox; pqTestUtility* TestUtility; pqDummyEventObserver* EventObserver; }; // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::initTestCase() { this->TestUtility = new pqTestUtility(); this->EventObserver = new pqDummyEventObserver(); this->TestUtility->addEventObserver("xml", this->EventObserver); this->TestUtility->addEventSource("xml", new pqDummyEventSource()); this->DoubleSpinBox = 0; } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::init() { // Init the DoubleSpinBox this->DoubleSpinBox = new QDoubleSpinBox(); this->DoubleSpinBox->setObjectName("doubleSpinBoxTest"); this->DoubleSpinBox->setMinimum(-100); this->DoubleSpinBox->setSingleStep(0.25); // Start to record events this->TestUtility->recordTestsBySuffix("xml"); // Fire the event "enter" to connect DoubleSpinBox signals to the translator slots QEvent enter(QEvent::Enter); qApp->notify(this->DoubleSpinBox, &enter); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::cleanup() { this->TestUtility->stopRecords(0); delete this->DoubleSpinBox; } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::cleanupTestCase() { this->EventObserver = 0; delete this->TestUtility; } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::testRecordLeftMouseClick() { QFETCH(int, X); QFETCH(int, Y); QFETCH(QString, recordEmitted); QTest::mouseClick(this->DoubleSpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(X, Y)); QCOMPARE(this->EventObserver->Text, recordEmitted); this->EventObserver->Text = QString(); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::testRecordLeftMouseClick_data() { QDoubleSpinBox doubleSpinBox; QTest::addColumn("X"); QTest::addColumn("Y"); QTest::addColumn("recordEmitted"); QSize size = doubleSpinBox.size(); int frameWidth = doubleSpinBox.style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth) + 1; QTest::newRow("0,0") << 0 << 0 << QString(); QTest::newRow("invalid") << -size.rwidth() << 0 << QString(); QTest::newRow("middle") << size.rwidth() / 2 << size.rheight() / 2 << QString(); QTest::newRow("arrow up") << size.rwidth() - frameWidth << frameWidth << QString("doubleSpinBoxTest, set_double, 0.25#"); QTest::newRow("arrow down") << size.rwidth() - frameWidth << size.rheight() - frameWidth << QString("doubleSpinBoxTest, set_double, -0.25#"); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::testRecordRightMouseClick() { QFETCH(int, X); QFETCH(int, Y); QFETCH(QString, recordEmitted); QTest::mouseClick(this->DoubleSpinBox, Qt::RightButton, Qt::NoModifier, QPoint(X, Y)); QCOMPARE(this->EventObserver->Text, recordEmitted); this->EventObserver->Text = QString(); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::testRecordRightMouseClick_data() { QDoubleSpinBox doubleSpinBox; QTest::addColumn("X"); QTest::addColumn("Y"); QTest::addColumn("recordEmitted"); QSize size = doubleSpinBox.size(); int frameWidth = doubleSpinBox.style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth) + 1; QTest::newRow("0,0") << 0 << 0 << QString(); QTest::newRow("invalid") << -size.rwidth() << 0 << QString(); QTest::newRow("middle") << size.rwidth() / 2 << size.rheight() / 2 << QString(); QTest::newRow("arrow up") << size.rwidth() - frameWidth << frameWidth << QString(); QTest::newRow("arrow down") << size.rwidth() - frameWidth << size.rheight() - frameWidth << QString(); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::testRecordMiddleMouseClick() { QFETCH(int, X); QFETCH(int, Y); QFETCH(QString, recordEmitted); QTest::mouseClick(this->DoubleSpinBox, Qt::MiddleButton, Qt::NoModifier, QPoint(X, Y)); QCOMPARE(this->EventObserver->Text, recordEmitted); this->EventObserver->Text = QString(); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::testRecordMiddleMouseClick_data() { this->testRecordRightMouseClick_data(); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::testRecordKeyBoardClick() { QFETCH(QString, number); QFETCH(QString, recordEmitted); this->DoubleSpinBox->clear(); QTest::keyClicks(this->DoubleSpinBox, number); QCOMPARE(this->EventObserver->Text, recordEmitted); this->EventObserver->Text = QString(); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::testRecordKeyBoardClick_data() { QTest::addColumn("number"); QTest::addColumn("recordEmitted"); QTest::newRow("33.5") << QString::number(33.5) << QString("%1#%2#%3#%4#%5#%6#%7#") .arg(QString("doubleSpinBoxTest, set_double, 3"), QString("doubleSpinBoxTest, set_double, 3"), QString("doubleSpinBoxTest, set_double, 33"), QString("doubleSpinBoxTest, set_double, 33"), QString("doubleSpinBoxTest, set_double, 33"), // corresponds to "." QString("doubleSpinBoxTest, set_double, 33.5"), QString("doubleSpinBoxTest, set_double, 33.5")); QTest::newRow("-5.23") << QString::number(-5.23) << QString("%1#%2#%3#%4#%5#%6#%7#%8#") .arg( QString("doubleSpinBoxTest, set_double, 0"), // corresponds to "-" QString("doubleSpinBoxTest, set_double, -5"), QString("doubleSpinBoxTest, set_double, -5"), QString("doubleSpinBoxTest, set_double, -5"), // corresponds to "." QString("doubleSpinBoxTest, set_double, -5.2"), QString("doubleSpinBoxTest, set_double, -5.2"), QString("doubleSpinBoxTest, set_double, -5.23"), QString("doubleSpinBoxTest, set_double, -5.23")); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::testRecordComplexClick() { QSize size = this->DoubleSpinBox->size(); int frameWidth = this->DoubleSpinBox->style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth) + 1; QString recordExpected; this->DoubleSpinBox->clear(); QTest::keyClicks(this->DoubleSpinBox, QString::number(-5.25)); recordExpected.append(QString("doubleSpinBoxTest, set_double, 0#")); // corresponds to "-" recordExpected.append(QString("doubleSpinBoxTest, set_double, -5#")); recordExpected.append(QString("doubleSpinBoxTest, set_double, -5#")); recordExpected.append(QString("doubleSpinBoxTest, set_double, -5#")); // corresponds to "." recordExpected.append(QString("doubleSpinBoxTest, set_double, -5.2#")); recordExpected.append(QString("doubleSpinBoxTest, set_double, -5.2#")); recordExpected.append(QString("doubleSpinBoxTest, set_double, -5.25#")); recordExpected.append(QString("doubleSpinBoxTest, set_double, -5.25#")); QTest::mouseClick(this->DoubleSpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, size.rheight() - frameWidth)); recordExpected.append(QString("doubleSpinBoxTest, set_double, -5.5#")); QTest::mouseClick(this->DoubleSpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, size.rheight() - frameWidth)); recordExpected.append(QString("doubleSpinBoxTest, set_double, -5.75#")); QTest::mouseClick(this->DoubleSpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, frameWidth)); recordExpected.append(QString("doubleSpinBoxTest, set_double, -5.5#")); QTest::mouseClick(this->DoubleSpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, frameWidth)); recordExpected.append(QString("doubleSpinBoxTest, set_double, -5.25#")); QTest::mouseClick(this->DoubleSpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, frameWidth)); recordExpected.append(QString("doubleSpinBoxTest, set_double, -5#")); QTest::mouseClick(this->DoubleSpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, frameWidth)); recordExpected.append(QString("doubleSpinBoxTest, set_double, -4.75#")); QTest::mouseClick(this->DoubleSpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, frameWidth)); recordExpected.append(QString("doubleSpinBoxTest, set_double, -4.5#")); QTest::keyClicks(this->DoubleSpinBox, QString::number(0)); recordExpected.append(QString("doubleSpinBoxTest, set_double, 0#")); recordExpected.append(QString("doubleSpinBoxTest, set_double, 0#")); QCOMPARE(this->EventObserver->Text, recordExpected); this->EventObserver->Text = QString(); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::testRecordCheckMouseClick() { this->EventObserver->Text = QString(); this->DoubleSpinBox->clear(); this->DoubleSpinBox->setValue(17.17); this->TestUtility->recorder()->check(true); QFETCH(QString, recordEmitted); QTest::mouseClick(this->DoubleSpinBox, Qt::LeftButton); QCOMPARE(this->EventObserver->Text, recordEmitted); this->EventObserver->Text = QString(); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslatorTester::testRecordCheckMouseClick_data() { QTest::addColumn("recordEmitted"); QTest::newRow("Click") << QString("%1#%2#").arg(QString("doubleSpinBoxTest, set_double, 17.17"), QString("Check, doubleSpinBoxTest, value, 17.17")); } // ---------------------------------------------------------------------------- CTK_TEST_MAIN(pqDoubleSpinBoxEventTranslatorTest) #include "moc_pqDoubleSpinBoxEventTranslatorTest.cpp" qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/Cpp/pqEventPlayerTest.cpp000066400000000000000000000154471526070500000276700ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include // QtTesting includes #include "pqCommentEventPlayer.h" #include "pqEventPlayer.h" #include "pqTestUtility.h" #include "pqTreeViewEventPlayer.h" #include "pqTest.h" // ---------------------------------------------------------------------------- class pqEventPlayerTester : public QObject { Q_OBJECT private Q_SLOTS: void testDefaults(); void testAddWidgetEventPlayer(); void testAddWidgetEventPlayer_data(); void testRemoveWidgetEventPlayer(); void testRemoveWidgetEventPlayer_data(); void testGetWidgetEventPlayer(); void testAddDefaultWidgetEventPlayers(); void testAddDefaultWidgetEventPlayers_data(); }; // ---------------------------------------------------------------------------- void pqEventPlayerTester::testDefaults() { pqEventPlayer eventPlayer; QCOMPARE(eventPlayer.players().count(), 0); } // ---------------------------------------------------------------------------- void pqEventPlayerTester::testAddWidgetEventPlayer() { pqEventPlayer eventPlayer; QFETCH(QObject*, widget1); QFETCH(int, newCount1); QFETCH(QObject*, widget2); QFETCH(int, newCount2); // When we add the widgetEventPlayer into the eventPlayer, it is automaticaly // reparented to the eventPlayer. So its deletion would be automatic. eventPlayer.addWidgetEventPlayer(qobject_cast(widget1)); QCOMPARE(eventPlayer.players().count(), newCount1); eventPlayer.addWidgetEventPlayer(qobject_cast(widget2)); QCOMPARE(eventPlayer.players().count(), newCount2); } // ---------------------------------------------------------------------------- void pqEventPlayerTester::testAddWidgetEventPlayer_data() { QTest::addColumn("widget1"); QTest::addColumn("newCount1"); QTest::addColumn("widget2"); QTest::addColumn("newCount2"); pqWidgetEventPlayer* nullWidget = NULL; QTest::newRow("empty_empty") << qobject_cast(nullWidget) << 0 << qobject_cast(nullWidget) << 0; QTest::newRow("empty_pqComment") << qobject_cast(nullWidget) << 0 << qobject_cast(new pqCommentEventPlayer(0)) << 1; QTest::newRow("pqComment_pqComment") << qobject_cast(new pqCommentEventPlayer(0)) << 1 << qobject_cast(new pqCommentEventPlayer(0)) << 1; QTest::newRow("pqComment_pqTreeView") << qobject_cast(new pqCommentEventPlayer(0)) << 1 << qobject_cast(new pqTreeViewEventPlayer()) << 2; } // ---------------------------------------------------------------------------- void pqEventPlayerTester::testRemoveWidgetEventPlayer() { pqEventPlayer eventPlayer; QFETCH(QString, nameToRemove); QFETCH(bool, firstResult); QFETCH(bool, secondResult); QFETCH(int, newCount); QFETCH(bool, thirdResult); QCOMPARE(eventPlayer.removeWidgetEventPlayer(nameToRemove), firstResult); // When we add the widgetEventPlayer into the eventPlayer, it is automaticaly // reparented to the eventPlayer. So its deletion would be automatic. pqCommentEventPlayer* commentPlayer = new pqCommentEventPlayer(0); eventPlayer.addWidgetEventPlayer(commentPlayer); QCOMPARE(eventPlayer.players().count(), 1); QCOMPARE(eventPlayer.removeWidgetEventPlayer(nameToRemove), secondResult); QCOMPARE(eventPlayer.players().count(), newCount); QCOMPARE(eventPlayer.removeWidgetEventPlayer(nameToRemove), thirdResult); } // ---------------------------------------------------------------------------- void pqEventPlayerTester::testRemoveWidgetEventPlayer_data() { QTest::addColumn("nameToRemove"); QTest::addColumn("firstResult"); QTest::addColumn("secondResult"); QTest::addColumn("newCount"); QTest::addColumn("thirdResult"); QTest::newRow("empty") << "" << false << false << 1 << false; QTest::newRow("wrong") << "pqTreeViewEventPlayer" << false << false << 1 << false; QTest::newRow("right") << "pqCommentEventPlayer" << false << true << 0 << false; } // ---------------------------------------------------------------------------- void pqEventPlayerTester::testGetWidgetEventPlayer() { pqEventPlayer eventPlayer; pqWidgetEventPlayer* nullWidget = NULL; QCOMPARE(eventPlayer.getWidgetEventPlayer(0), nullWidget); QCOMPARE(eventPlayer.getWidgetEventPlayer("pqCommentEventPlayer"), nullWidget); // When we add the widgetEventPlayer into the eventPlayer, it is automaticaly // reparented to the eventPlayer. So its deletion would be automatic. pqCommentEventPlayer* comment = new pqCommentEventPlayer(0); eventPlayer.addWidgetEventPlayer(comment); QCOMPARE(eventPlayer.getWidgetEventPlayer(0), nullWidget); QCOMPARE(eventPlayer.getWidgetEventPlayer("pqTreeViewEventPlayer"), nullWidget); QCOMPARE(eventPlayer.getWidgetEventPlayer("pqCommentEventPlayer"), comment); } // ---------------------------------------------------------------------------- void pqEventPlayerTester::testAddDefaultWidgetEventPlayers() { pqEventPlayer eventPlayer; pqTestUtility testUtility; eventPlayer.addDefaultWidgetEventPlayers(&testUtility); QList players = eventPlayer.players(); QFETCH(QString, widgetEventPlayerName); QFETCH(int, index); QCOMPARE(QString(players.at(index)->metaObject()->className()), widgetEventPlayerName); } // ---------------------------------------------------------------------------- void pqEventPlayerTester::testAddDefaultWidgetEventPlayers_data() { QTest::addColumn("index"); QTest::addColumn("widgetEventPlayerName"); QTest::newRow("0") << 0 << "pqNativeFileDialogEventPlayer"; QTest::newRow("1") << 1 << "pq3DViewEventPlayer"; QTest::newRow("2") << 2 << "pqAbstractMiscellaneousEventPlayer"; QTest::newRow("3") << 3 << "pqListViewEventPlayer"; QTest::newRow("4") << 4 << "pqTableViewEventPlayer"; QTest::newRow("5") << 5 << "pqTreeViewEventPlayer"; QTest::newRow("6") << 6 << "pqComboBoxEventPlayer"; QTest::newRow("7") << 7 << "pqTabBarEventPlayer"; QTest::newRow("8") << 8 << "pqAbstractStringEventPlayer"; QTest::newRow("9") << 9 << "pqAbstractItemViewEventPlayer"; QTest::newRow("10") << 10 << "pqAbstractIntEventPlayer"; QTest::newRow("11") << 11 << "pqAbstractDoubleEventPlayer"; QTest::newRow("12") << 12 << "pqAbstractBooleanEventPlayer"; QTest::newRow("13") << 13 << "pqAbstractActivateEventPlayer"; QTest::newRow("14") << 14 << "pqBasicWidgetEventPlayer"; QTest::newRow("15") << 15 << "pqCommentEventPlayer"; } // ---------------------------------------------------------------------------- CTK_TEST_MAIN(pqEventPlayerTest) #include "moc_pqEventPlayerTest.cpp" qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/Cpp/pqEventRecorderTest.cpp000066400000000000000000000131441526070500000301710ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include // QtTesting includes #include "pqEventObserver.h" #include "pqEventRecorder.h" #include "pqTestUtility.h" #include "pqTest.h" // ---------------------------------------------------------------------------- class pqEventRecorderTester : public QObject { Q_OBJECT private Q_SLOTS: void testDefaults(); void testSetFile(); void testSetObserver(); void testSetTranslator(); void testSetContiniousFlush(); void testSetContiniousFlush_data(); void testRecordEvents(); void testRecordEvents_data(); }; // ---------------------------------------------------------------------------- void pqEventRecorderTester::testDefaults() { pqEventRecorder eventRecorder; QIODevice* nullDevice = 0; pqEventObserver* nullObserver = 0; pqEventTranslator* nullTranslator = 0; QCOMPARE(eventRecorder.isRecording(), false); QCOMPARE(eventRecorder.file(), nullDevice); QCOMPARE(eventRecorder.observer(), nullObserver); QCOMPARE(eventRecorder.translator(), nullTranslator); } // ---------------------------------------------------------------------------- void pqEventRecorderTester::testSetFile() { pqEventRecorder recorder; QFile file; recorder.setFile(&file); QCOMPARE(recorder.file(), &file); } // ---------------------------------------------------------------------------- void pqEventRecorderTester::testSetObserver() { pqEventRecorder recorder; pqDummyEventObserver observer; recorder.setObserver(&observer); QCOMPARE(recorder.observer(), &observer); } // ---------------------------------------------------------------------------- void pqEventRecorderTester::testSetTranslator() { pqEventRecorder recorder; pqEventTranslator translator; recorder.setTranslator(&translator); QCOMPARE(recorder.translator(), &translator); } // ---------------------------------------------------------------------------- void pqEventRecorderTester::testSetContiniousFlush() { pqEventRecorder recorder; QFETCH(bool, activeObserver); QFETCH(bool, first); QFETCH(bool, firstResult); QFETCH(bool, second); QFETCH(bool, secondResult); recorder.setObserver(activeObserver ? new pqDummyEventObserver() : 0); recorder.setContinuousFlush(first); QCOMPARE(recorder.continuousFlush(), firstResult); recorder.setContinuousFlush(second); QCOMPARE(recorder.continuousFlush(), secondResult); } // ---------------------------------------------------------------------------- void pqEventRecorderTester::testSetContiniousFlush_data() { QTest::addColumn("activeObserver"); QTest::addColumn("first"); QTest::addColumn("firstResult"); QTest::addColumn("second"); QTest::addColumn("secondResult"); QTest::newRow("1") << false << false << false << false << false; QTest::newRow("2") << false << false << false << true << false; QTest::newRow("3") << false << true << false << false << false; QTest::newRow("4") << false << true << false << true << false; QTest::newRow("5") << true << false << false << false << false; QTest::newRow("6") << true << false << false << true << true; QTest::newRow("7") << true << true << true << false << false; QTest::newRow("8") << true << true << true << true << true; } // ---------------------------------------------------------------------------- void pqEventRecorderTester::testRecordEvents() { pqEventRecorder recorder; QFETCH(QObject*, ioDevice); QFETCH(QObject*, activeObserver); QFETCH(QObject*, activeTranslator); QFETCH(bool, continuousFlush); QFETCH(bool, started); QFETCH(bool, flushing); recorder.recordEvents(qobject_cast(activeTranslator), qobject_cast(activeObserver), qobject_cast(ioDevice), continuousFlush); QCOMPARE(recorder.isRecording(), started); QCOMPARE(recorder.continuousFlush(), flushing); } // ---------------------------------------------------------------------------- void pqEventRecorderTester::testRecordEvents_data() { QTest::addColumn("ioDevice"); QTest::addColumn("activeObserver"); QTest::addColumn("activeTranslator"); QTest::addColumn("continuousFlush"); QTest::addColumn("started"); QTest::addColumn("flushing"); QFile* nullFile = 0; QFile* file = new QFile; pqEventObserver* nullObserver = 0; pqDummyEventObserver* observer = new pqDummyEventObserver; pqEventTranslator* nullTranslator = 0; pqEventTranslator* translator = new pqEventTranslator; QTest::newRow("1") << qobject_cast(nullFile) << qobject_cast(nullObserver) << qobject_cast(nullTranslator) << false << false << false; QTest::newRow("2") << qobject_cast(nullFile) << qobject_cast(nullObserver) << qobject_cast(translator) << false << false << false; QTest::newRow("3") << qobject_cast(nullFile) << qobject_cast(observer) << qobject_cast(translator) << false << false << false; QTest::newRow("4") << qobject_cast(file) << qobject_cast(observer) << qobject_cast(translator) << false << true << false; QTest::newRow("5") << qobject_cast(file) << qobject_cast(observer) << qobject_cast(translator) << true << true << true; } // ---------------------------------------------------------------------------- CTK_TEST_MAIN(pqEventRecorderTest) #include "moc_pqEventRecorderTest.cpp" qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/Cpp/pqEventTranslatorTest.cpp000066400000000000000000000161171526070500000305600ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include // QtTesting includes #include "pqEventTranslator.h" #include "pqSpinBoxEventTranslator.h" #include "pqTestUtility.h" #include "pqTreeViewEventTranslator.h" #include "pqTest.h" // ---------------------------------------------------------------------------- class pqEventTranslatorTester : public QObject { Q_OBJECT private Q_SLOTS: void testDefaults(); void testAddWidgetEventTranslator(); void testAddWidgetEventTranslator_data(); void testRemoveWidgetEventTranslator(); void testRemoveWidgetEventTranslator_data(); void testGetWidgetEventTranslator(); void testAddDefaultWidgetEventTranslators(); void testAddDefaultWidgetEventTranslators_data(); }; // ---------------------------------------------------------------------------- void pqEventTranslatorTester::testDefaults() { pqEventTranslator eventTranslator; QCOMPARE(eventTranslator.translators().count(), 0); } // ---------------------------------------------------------------------------- void pqEventTranslatorTester::testAddWidgetEventTranslator() { pqEventTranslator eventTranslator; QFETCH(QObject*, widget1); QFETCH(int, newCount1); QFETCH(QObject*, widget2); QFETCH(int, newCount2); // When we add the widgetEventPlayer into the eventPlayer, it is automaticaly // reparented to the eventPlayer. So its deletion would be automatic. eventTranslator.addWidgetEventTranslator(dynamic_cast(widget1)); QCOMPARE(eventTranslator.translators().count(), newCount1); eventTranslator.addWidgetEventTranslator(dynamic_cast(widget2)); QCOMPARE(eventTranslator.translators().count(), newCount2); } // ---------------------------------------------------------------------------- void pqEventTranslatorTester::testAddWidgetEventTranslator_data() { QTest::addColumn("widget1"); QTest::addColumn("newCount1"); QTest::addColumn("widget2"); QTest::addColumn("newCount2"); pqWidgetEventTranslator* nullWidget = NULL; QTest::newRow("empty_empty") << qobject_cast(nullWidget) << 0 << qobject_cast(nullWidget) << 0; QTest::newRow("empty_pqSpinBox") << qobject_cast(nullWidget) << 0 << qobject_cast(new pqSpinBoxEventTranslator()) << 1; QTest::newRow("pqSpinBox_pqSpinBox") << qobject_cast(new pqSpinBoxEventTranslator()) << 1 << qobject_cast(new pqSpinBoxEventTranslator()) << 1; QTest::newRow("pqSpinBox_pqTreeView") << qobject_cast(new pqSpinBoxEventTranslator()) << 1 << qobject_cast(new pqTreeViewEventTranslator()) << 2; } // ---------------------------------------------------------------------------- void pqEventTranslatorTester::testRemoveWidgetEventTranslator() { pqEventTranslator eventTranslator; QFETCH(QString, nameToRemove); QFETCH(bool, firstResult); QFETCH(bool, secondResult); QFETCH(int, newCount); QFETCH(bool, thirdResult); QCOMPARE(eventTranslator.removeWidgetEventTranslator(nameToRemove), firstResult); // When we add the widgetEventPlayer into the eventPlayer, it is automaticaly // reparented to the eventPlayer. So its deletion would be automatic. pqTreeViewEventTranslator* treeView = new pqTreeViewEventTranslator(); eventTranslator.addWidgetEventTranslator(treeView); QCOMPARE(eventTranslator.translators().count(), 1); QCOMPARE(eventTranslator.removeWidgetEventTranslator(nameToRemove), secondResult); QCOMPARE(eventTranslator.translators().count(), newCount); QCOMPARE(eventTranslator.removeWidgetEventTranslator(nameToRemove), thirdResult); } // ---------------------------------------------------------------------------- void pqEventTranslatorTester::testRemoveWidgetEventTranslator_data() { QTest::addColumn("nameToRemove"); QTest::addColumn("firstResult"); QTest::addColumn("secondResult"); QTest::addColumn("newCount"); QTest::addColumn("thirdResult"); QTest::newRow("empty") << "" << false << false << 1 << false; QTest::newRow("wrong") << "pqSpinBoxEventTranslator" << false << false << 1 << false; QTest::newRow("right") << "pqTreeViewEventTranslator" << false << true << 0 << false; } // ---------------------------------------------------------------------------- void pqEventTranslatorTester::testGetWidgetEventTranslator() { pqEventTranslator eventTranslator; pqSpinBoxEventTranslator* nullWidget = NULL; QCOMPARE(eventTranslator.getWidgetEventTranslator(0), nullWidget); QCOMPARE(eventTranslator.getWidgetEventTranslator("pqSpinBoxEventTranslator"), nullWidget); // When we add the widgetEventPlayer into the eventPlayer, it is automaticaly // reparented to the eventPlayer. So its deletion would be automatic. pqSpinBoxEventTranslator* spinBox = new pqSpinBoxEventTranslator(); eventTranslator.addWidgetEventTranslator(spinBox); QCOMPARE(eventTranslator.getWidgetEventTranslator(0), nullWidget); QCOMPARE(eventTranslator.getWidgetEventTranslator("pqTreeViewEventTranslator"), nullWidget); QCOMPARE(eventTranslator.getWidgetEventTranslator("pqSpinBoxEventTranslator"), spinBox); } // ---------------------------------------------------------------------------- void pqEventTranslatorTester::testAddDefaultWidgetEventTranslators() { pqEventTranslator eventTranslator; pqTestUtility testUtility; eventTranslator.addDefaultWidgetEventTranslators(&testUtility); QList translators = eventTranslator.translators(); QFETCH(int, index); QFETCH(QString, widgetEventTranslatorName); QCOMPARE(QString(translators.at(index)->metaObject()->className()), widgetEventTranslatorName); } // ---------------------------------------------------------------------------- void pqEventTranslatorTester::testAddDefaultWidgetEventTranslators_data() { QTest::addColumn("index"); QTest::addColumn("widgetEventTranslatorName"); QTest::newRow("0") << 0 << "pqNativeFileDialogEventTranslator"; QTest::newRow("1") << 1 << "pq3DViewEventTranslator"; QTest::newRow("2") << 2 << "pqListViewEventTranslator"; QTest::newRow("3") << 3 << "pqTableViewEventTranslator"; QTest::newRow("4") << 4 << "pqTreeViewEventTranslator"; QTest::newRow("5") << 5 << "pqTabBarEventTranslator"; QTest::newRow("6") << 6 << "pqSpinBoxEventTranslator"; QTest::newRow("7") << 7 << "pqMenuEventTranslator"; QTest::newRow("8") << 8 << "pqLineEditEventTranslator"; QTest::newRow("9") << 9 << "pqDoubleSpinBoxEventTranslator"; QTest::newRow("10") << 10 << "pqComboBoxEventTranslator"; QTest::newRow("11") << 11 << "pqAbstractSliderEventTranslator"; QTest::newRow("12") << 12 << "pqAbstractItemViewEventTranslator"; QTest::newRow("13") << 13 << "pqAbstractButtonEventTranslator"; QTest::newRow("14") << 14 << "pqBasicWidgetEventTranslator"; } // ---------------------------------------------------------------------------- CTK_TEST_MAIN(pqEventTranslatorTest) #include "moc_pqEventTranslatorTest.cpp" qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/Cpp/pqSpinBoxEventPlayerTest.cpp000066400000000000000000000060041526070500000311600ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include #include #include // QtTesting includes #include "pqEventTypes.h" #include "pqTestUtility.h" #include "pqTest.h" // ---------------------------------------------------------------------------- class pqSpinBoxEventPlayerTester : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void init(); void cleanup(); void cleanupTestCase(); void testPlayBackCommandSetInt(); void testPlayBackCommandSetInt_data(); private: QSpinBox* SpinBox; pqTestUtility* TestUtility; }; // ---------------------------------------------------------------------------- void pqSpinBoxEventPlayerTester::initTestCase() { this->TestUtility = new pqTestUtility(); this->TestUtility->addEventObserver("xml", new pqDummyEventObserver); this->TestUtility->addEventSource("xml", new pqDummyEventSource()); this->SpinBox = 0; } // ---------------------------------------------------------------------------- void pqSpinBoxEventPlayerTester::init() { // Init the QSpinBox this->SpinBox = new QSpinBox(); this->SpinBox->setObjectName("spinBoxTest"); this->SpinBox->setMinimum(-99); } // ---------------------------------------------------------------------------- void pqSpinBoxEventPlayerTester::cleanup() { delete this->SpinBox; } // ---------------------------------------------------------------------------- void pqSpinBoxEventPlayerTester::cleanupTestCase() { delete this->TestUtility; } // ---------------------------------------------------------------------------- void pqSpinBoxEventPlayerTester::testPlayBackCommandSetInt() { QFETCH(int, value); QFETCH(int, result); QFETCH(int, count); QSignalSpy spy(this->SpinBox, SIGNAL(valueChanged(int))); bool error; this->TestUtility->eventPlayer()->playEvent( QString("spinBoxTest"), QString("set_int"), QString::number(value), error); QCOMPARE(this->SpinBox->value(), result); QCOMPARE(error, false); this->TestUtility->eventPlayer()->playEvent(QString("spinBoxTest"), QString("value"), QString::number(result), pqEventTypes::CHECK_EVENT, error); QCOMPARE(error, false); QCOMPARE(spy.count(), count); } // ---------------------------------------------------------------------------- void pqSpinBoxEventPlayerTester::testPlayBackCommandSetInt_data() { QTest::addColumn("value"); QTest::addColumn("result"); QTest::addColumn("count"); QTest::newRow("positive") << 10 << 10 << 1; QTest::newRow("negative") << -33 << -33 << 1; QTest::newRow("negativeoutside") << -200 << -99 << 1; QTest::newRow("positiveoutside") << 200 << 99 << 1; QTest::newRow("negativeboundary") << -99 << -99 << 1; QTest::newRow("positiveboundary") << 99 << 99 << 1; } // ---------------------------------------------------------------------------- CTK_TEST_MAIN(pqSpinBoxEventPlayerTest) #include "moc_pqSpinBoxEventPlayerTest.cpp" pqSpinBoxEventTranslatorTest.cpp000066400000000000000000000233341526070500000320030ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/Cpp// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include #include #include #include // QtTesting includes #include "pqTestUtility.h" #include "pqTest.h" // ---------------------------------------------------------------------------- class pqSpinBoxEventTranslatorTester : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void init(); void cleanup(); void cleanupTestCase(); void testRecordLeftMouseClick(); void testRecordLeftMouseClick_data(); void testRecordRightMouseClick(); void testRecordRightMouseClick_data(); void testRecordMiddleMouseClick(); void testRecordMiddleMouseClick_data(); void testRecordKeyBoardClick(); void testRecordKeyBoardClick_data(); void testRecordComplexClick(); void testRecordCheckMouseClick(); void testRecordCheckMouseClick_data(); private: QSpinBox* SpinBox; pqTestUtility* TestUtility; pqDummyEventObserver* EventObserver; }; // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::initTestCase() { this->TestUtility = new pqTestUtility(); this->EventObserver = new pqDummyEventObserver(); this->TestUtility->addEventObserver("xml", this->EventObserver); this->TestUtility->addEventSource("xml", new pqDummyEventSource()); this->SpinBox = 0; } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::init() { // Init SpinBox this->SpinBox = new QSpinBox(); this->SpinBox->setObjectName("spinBoxTest"); this->SpinBox->setMinimum(-100); // Start to record events this->TestUtility->recordTestsBySuffix("xml"); // Fire the event "enter" to connect spinbox signals to the translator slots QEvent enter(QEvent::Enter); qApp->notify(this->SpinBox, &enter); } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::cleanup() { this->TestUtility->stopRecords(0); delete this->SpinBox; } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::cleanupTestCase() { this->EventObserver = 0; delete this->TestUtility; } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::testRecordLeftMouseClick() { QFETCH(int, X); QFETCH(int, Y); QFETCH(QString, recordEmitted); QTest::mouseClick(this->SpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(X, Y)); QCOMPARE(this->EventObserver->Text, recordEmitted); this->EventObserver->Text = QString(); } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::testRecordLeftMouseClick_data() { QSpinBox spinBox; QTest::addColumn("X"); QTest::addColumn("Y"); QTest::addColumn("recordEmitted"); QSize size = spinBox.size(); int frameWidth = spinBox.style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth) + 1; QTest::newRow("0,0") << 0 << 0 << QString(); QTest::newRow("invalid") << -size.rwidth() << frameWidth << QString(); QTest::newRow("middle") << size.rwidth() / 2 << size.rheight() / 2 << QString(); QTest::newRow("arrow up") << size.rwidth() - frameWidth << frameWidth << QString("spinBoxTest, set_int, 1#"); QTest::newRow("arrow down") << size.rwidth() - frameWidth << size.rheight() - frameWidth << QString("spinBoxTest, set_int, -1#"); } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::testRecordRightMouseClick() { QFETCH(int, X); QFETCH(int, Y); QFETCH(QString, recordEmitted); QTest::mouseClick(this->SpinBox, Qt::RightButton, Qt::NoModifier, QPoint(X, Y)); QCOMPARE(this->EventObserver->Text, recordEmitted); this->EventObserver->Text = QString(); } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::testRecordRightMouseClick_data() { QSpinBox spinBox; QTest::addColumn("X"); QTest::addColumn("Y"); QTest::addColumn("recordEmitted"); QSize size = spinBox.size(); int frameWidth = spinBox.style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth) + 1; QTest::newRow("0,0") << 0 << 0 << QString(); QTest::newRow("invalid") << -size.rwidth() << frameWidth << QString(); QTest::newRow("middle") << size.rwidth() / 2 << size.rheight() / 2 << QString(); QTest::newRow("arrow down") << size.rwidth() - frameWidth << size.rheight() - frameWidth << QString(); QTest::newRow("arrow up") << size.rwidth() - frameWidth << frameWidth << QString(); } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::testRecordMiddleMouseClick() { QFETCH(int, X); QFETCH(int, Y); QFETCH(QString, recordEmitted); QTest::mouseClick(this->SpinBox, Qt::MiddleButton, Qt::NoModifier, QPoint(X, Y)); QCOMPARE(this->EventObserver->Text, recordEmitted); this->EventObserver->Text = QString(); } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::testRecordMiddleMouseClick_data() { this->testRecordRightMouseClick_data(); } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::testRecordKeyBoardClick() { QFETCH(QString, number); QFETCH(QString, recordEmitted); this->SpinBox->clear(); QTest::keyClicks(this->SpinBox, number); QCOMPARE(this->EventObserver->Text, recordEmitted); this->EventObserver->Text = QString(); } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::testRecordKeyBoardClick_data() { QTest::addColumn("number"); QTest::addColumn("recordEmitted"); QTest::newRow("33") << QString::number(33) << QString("%1#%2#%3#%4#") .arg(QString("spinBoxTest, set_int, 3"), QString("spinBoxTest, set_int, 3"), QString("spinBoxTest, set_int, 33"), QString("spinBoxTest, set_int, 33")); QTest::newRow("-5") << QString::number(-5) << QString("%1#%2#%3#") .arg(QString("spinBoxTest, set_int, 0"), // corresponds to "-" QString("spinBoxTest, set_int, -5"), QString("spinBoxTest, set_int, -5")); } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::testRecordComplexClick() { QSize size = this->SpinBox->size(); int frameWidth = this->SpinBox->style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth) + 1; QString recordExpected; QTest::keyClicks(this->SpinBox, "10"); recordExpected.append(QString("spinBoxTest, set_int, 1#")); recordExpected.append(QString("spinBoxTest, set_int, 1#")); recordExpected.append(QString("spinBoxTest, set_int, 10#")); recordExpected.append(QString("spinBoxTest, set_int, 10#")); QTest::mouseClick(this->SpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, size.rheight() - frameWidth)); recordExpected.append(QString("spinBoxTest, set_int, 9#")); QTest::mouseClick(this->SpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, size.rheight() - frameWidth)); recordExpected.append(QString("spinBoxTest, set_int, 8#")); QTest::mouseClick( this->SpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, frameWidth)); recordExpected.append(QString("spinBoxTest, set_int, 9#")); QTest::mouseClick( this->SpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, frameWidth)); recordExpected.append(QString("spinBoxTest, set_int, 10#")); QTest::mouseClick( this->SpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, frameWidth)); recordExpected.append(QString("spinBoxTest, set_int, 11#")); QTest::mouseClick( this->SpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, frameWidth)); recordExpected.append(QString("spinBoxTest, set_int, 12#")); QTest::mouseClick( this->SpinBox, Qt::LeftButton, Qt::NoModifier, QPoint(size.rwidth() - frameWidth, frameWidth)); recordExpected.append(QString("spinBoxTest, set_int, 13#")); QTest::keyClicks(this->SpinBox, "0"); recordExpected.append(QString("spinBoxTest, set_int, 0#")); recordExpected.append(QString("spinBoxTest, set_int, 0#")); QCOMPARE(this->EventObserver->Text, recordExpected); this->EventObserver->Text = QString(); } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::testRecordCheckMouseClick() { this->EventObserver->Text = QString(); this->SpinBox->clear(); this->SpinBox->setValue(17); this->TestUtility->recorder()->check(true); QFETCH(QString, recordEmitted); QTest::mouseClick(this->SpinBox, Qt::LeftButton); QCOMPARE(this->EventObserver->Text, recordEmitted); this->EventObserver->Text = QString(); } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslatorTester::testRecordCheckMouseClick_data() { QTest::addColumn("recordEmitted"); QTest::newRow("Click") << QString("%1#%2#").arg( QString("spinBoxTest, set_int, 17"), QString("Check, spinBoxTest, value, 17")); } // ---------------------------------------------------------------------------- CTK_TEST_MAIN(pqSpinBoxEventTranslatorTest) #include "moc_pqSpinBoxEventTranslatorTest.cpp" qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/Cpp/pqTest.h000066400000000000000000000122201526070500000251400ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause AND Apache-2.0 // Qt includes #include // QtTesting includes #include "pqEventObserver.h" #include "pqEventSource.h" // ---------------------------------------------------------------------------- // Dumy pqEventObserver class pqDummyEventObserver : public pqEventObserver { Q_OBJECT public: pqDummyEventObserver(QObject* p = 0) : pqEventObserver(p) { } ~pqDummyEventObserver() {} virtual void setStream(QTextStream* /*stream*/) {} QString Text; public Q_SLOTS: virtual void onRecordEvent( const QString& widget, const QString& command, const QString& arguments, const int& eventType) { if (eventType == pqEventTypes::CHECK_EVENT) { this->Text.append(QString("Check, %1, %2, %3#").arg(widget, command, arguments)); } else { this->Text.append(QString("%1, %2, %3#").arg(widget, command, arguments)); } } }; // ---------------------------------------------------------------------------- // Dumy eventSource class pqDummyEventSource : public pqEventSource { typedef pqEventSource Superclass; public: pqDummyEventSource(QObject* p = 0) : Superclass(p) { } ~pqDummyEventSource() {} protected: virtual void setContent(const QString& /*xmlfilename*/) { return; } int getNextEvent( QString& /*widget*/, QString& /*command*/, QString& /*arguments*/, int& /*eventType*/) { return 0; } }; // ---------------------------------------------------------------------------- // MACRO #define CTK_TEST_NOOP_MAIN(TestObject) \ int TestObject(int argc, char* argv[]) \ { \ QObject tc; \ return QTest::qExec(&tc, argc, argv); \ } #ifdef QT_GUI_LIB //----------------------------------------------------------------------------- #define CTK_TEST_MAIN(TestObject) \ int TestObject(int argc, char* argv[]) \ { \ QApplication app(argc, argv); \ TestObject##er tc; \ return QTest::qExec(&tc, argc, argv); \ } #else //----------------------------------------------------------------------------- #define CTK_TEST_MAIN(TestObject) \ int TestObject(int argc, char* argv[]) \ { \ QCoreApplication app(argc, argv); \ QTEST_DISABLE_KEYPAD_NAVIGATION \ TestObject##er tc; \ return QTest::qExec(&tc, argc, argv); \ } #endif // QT_GUI_LIB namespace ctkTest { static void mouseEvent(QTest::MouseAction action, QWidget* widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey, QPoint pos, int delay = -1) { if (action != QTest::MouseMove) { QTest::mouseEvent(action, widget, button, stateKey, pos, delay); return; } QTEST_ASSERT(widget); // extern int Q_TESTLIB_EXPORT defaultMouseDelay(); // if (delay == -1 || delay < defaultMouseDelay()) // delay = defaultMouseDelay(); if (delay > 0) QTest::qWait(delay); if (pos.isNull()) pos = widget->rect().center(); QTEST_ASSERT(button == Qt::NoButton || button & Qt::MouseButtonMask); QTEST_ASSERT(stateKey == 0 || stateKey & Qt::KeyboardModifierMask); stateKey &= static_cast(Qt::KeyboardModifierMask); QMouseEvent me(QEvent::MouseMove, pos, widget->mapToGlobal(pos), button, button, stateKey); QSpontaneKeyEvent::setSpontaneous(&me); if (!qApp->notify(widget, &me)) { static const char* mouseActionNames[] = { "MousePress", "MouseRelease", "MouseClick", "MouseDClick", "MouseMove" }; QString warning = QString::fromLatin1("Mouse event \"%1\" not accepted by receiving widget"); qWarning() << warning.arg(QString::fromLatin1(mouseActionNames[static_cast(action)])) .toLatin1() .data(); } } inline void mouseMove(QWidget* widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = Qt::NoModifier, QPoint pos = QPoint(), int delay = -1) { ctkTest::mouseEvent(QTest::MouseMove, widget, button, stateKey, pos, delay); } } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Testing/Cpp/pqTestUtilityTest.cpp000066400000000000000000000360761526070500000277360ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include #include #include // QtTesting includes #include "pqEventObserver.h" #include "pqEventSource.h" #include "pqTestUtility.h" #include "pqTest.h" // ---------------------------------------------------------------------------- class pqTestUtilityTester : public QObject { Q_OBJECT private Q_SLOTS: void testDefaults(); void testAddEventSource(); void testAddEventSource_data(); void testAddEventObserver(); void testAddEventObserver_data(); void testAddObjectStateProperty(); void testAddObjectStateProperty_data(); // void testRemoveObjectStateProperty(); // void testRemoveObjectStateProperty_data(); void testAddDataDirectory(); void testAddDataDirectory_data(); void testRemoveDataDirectory(); void testRemoveDataDirectory_data(); void testConvertToDataDirectory(); void testConvertToDataDirectory_data(); void testConvertFromDataDirectory(); void testConvertFromDataDirectory_data(); }; // ---------------------------------------------------------------------------- void pqTestUtilityTester::testDefaults() { pqTestUtility testUtility; QCOMPARE(testUtility.playingTest(), false); QCOMPARE(testUtility.eventSources().count(), 0); QCOMPARE(testUtility.eventObservers().count(), 0); } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testAddEventSource() { pqTestUtility testUtility; QFETCH(QString, extension1); QFETCH(QObject*, source1); QFETCH(int, newCount1); QFETCH(QString, extension2); QFETCH(QObject*, source2); QFETCH(int, newCount2); testUtility.addEventSource(extension1, dynamic_cast(source1)); QCOMPARE(testUtility.eventSources().count(), newCount1); testUtility.addEventSource(extension2, dynamic_cast(source2)); QCOMPARE(testUtility.eventSources().count(), newCount2); } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testAddEventSource_data() { QTest::addColumn("extension1"); QTest::addColumn("source1"); QTest::addColumn("newCount1"); QTest::addColumn("extension2"); QTest::addColumn("source2"); QTest::addColumn("newCount2"); pqDummyEventSource* nullSource = NULL; pqDummyEventSource* dummySource1 = new pqDummyEventSource(); pqDummyEventSource* dummySource2 = new pqDummyEventSource(); pqDummyEventSource* dummySource3 = new pqDummyEventSource(); pqDummyEventSource* dummySource4 = new pqDummyEventSource(); pqDummyEventSource* dummySource5 = new pqDummyEventSource(); QTest::newRow("null") << QString("") << qobject_cast(nullSource) << 0 << QString("null") << qobject_cast(nullSource) << 0; QTest::newRow("same") << QString("py") << qobject_cast(dummySource1) << 1 << QString("py") << qobject_cast(dummySource1) << 1; QTest::newRow("same2") << QString("py") << qobject_cast(dummySource2) << 1 << QString("py") << qobject_cast(dummySource3) << 1; QTest::newRow("diff") << QString("py") << qobject_cast(dummySource4) << 1 << QString("xml") << qobject_cast(dummySource5) << 2; } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testAddEventObserver() { pqTestUtility testUtility; QFETCH(QString, extension1); QFETCH(QObject*, observer1); QFETCH(int, newCount1); QFETCH(QString, extension2); QFETCH(QObject*, observer2); QFETCH(int, newCount2); testUtility.addEventObserver(extension1, dynamic_cast(observer1)); QCOMPARE(testUtility.eventObservers().count(), newCount1); testUtility.addEventObserver(extension2, dynamic_cast(observer2)); QCOMPARE(testUtility.eventObservers().count(), newCount2); } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testAddEventObserver_data() { QTest::addColumn("extension1"); QTest::addColumn("observer1"); QTest::addColumn("newCount1"); QTest::addColumn("extension2"); QTest::addColumn("observer2"); QTest::addColumn("newCount2"); pqDummyEventObserver* nullObserver = NULL; pqDummyEventObserver* dummyObserver1 = new pqDummyEventObserver(); pqDummyEventObserver* dummyObserver2 = new pqDummyEventObserver(); pqDummyEventObserver* dummyObserver3 = new pqDummyEventObserver(); pqDummyEventObserver* dummyObserver4 = new pqDummyEventObserver(); pqDummyEventObserver* dummyObserver5 = new pqDummyEventObserver(); QTest::newRow("null") << QString("") << qobject_cast(nullObserver) << 0 << QString("null") << qobject_cast(nullObserver) << 0; QTest::newRow("all_same") << QString("py") << qobject_cast(dummyObserver1) << 1 << QString("py") << qobject_cast(dummyObserver1) << 1; QTest::newRow("only_same_key") << QString("py") << qobject_cast(dummyObserver2) << 1 << QString("py") << qobject_cast(dummyObserver3) << 1; QTest::newRow("diff") << QString("py") << qobject_cast(dummyObserver4) << 1 << QString("xml") << qobject_cast(dummyObserver5) << 2; } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testAddObjectStateProperty() { pqTestUtility testUtility; QFETCH(QObject*, object1); QFETCH(QString, property1); QFETCH(int, objectCount1); QFETCH(int, propertyCount1); QFETCH(QObject*, object2); QFETCH(QString, property2); QFETCH(int, objectCount2); QFETCH(int, propertyCount2); testUtility.addObjectStateProperty(object1, property1); int nbObject = testUtility.objectStateProperty().count(); QCOMPARE(nbObject, objectCount1); if (nbObject > 0) { int nbProperty1 = 0; foreach (QStringList list, testUtility.objectStateProperty().values()) { nbProperty1 += list.count(); } QCOMPARE(nbProperty1, propertyCount1); } testUtility.addObjectStateProperty(object2, property2); nbObject = testUtility.objectStateProperty().count(); QCOMPARE(nbObject, objectCount2); if (nbObject > 0) { int nbProperty2 = 0; foreach (QStringList list, testUtility.objectStateProperty().values()) { nbProperty2 += list.count(); } QCOMPARE(nbProperty2, propertyCount2); } } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testAddObjectStateProperty_data() { QTest::addColumn("object1"); QTest::addColumn("property1"); QTest::addColumn("objectCount1"); QTest::addColumn("propertyCount1"); QTest::addColumn("object2"); QTest::addColumn("property2"); QTest::addColumn("objectCount2"); QTest::addColumn("propertyCount2"); QObject* nullObject = NULL; QLineEdit* lineEdit1 = new QLineEdit(); QLineEdit* lineEdit2 = new QLineEdit(); QLineEdit* lineEdit3 = new QLineEdit(); QLineEdit* lineEdit4 = new QLineEdit(); QLineEdit* lineEdit5 = new QLineEdit(); QTest::newRow("objectNull") << nullObject << QString("") << 0 << 0 << nullObject << QString("maxLength") << 0 << 0; QTest::newRow("wrongProperty") << qobject_cast(lineEdit1) << QString("") << 0 << 0 << qobject_cast(lineEdit1) << QString("wrongProperty") << 0 << 0; QTest::newRow("sameProperty") << qobject_cast(lineEdit2) << QString("maxLength") << 1 << 1 << qobject_cast(lineEdit2) << QString("maxLength") << 1 << 1; QTest::newRow("diffProperty") << qobject_cast(lineEdit3) << QString("maxLength") << 1 << 1 << qobject_cast(lineEdit3) << QString("readOnly") << 1 << 2; QTest::newRow("diffObject") << qobject_cast(lineEdit4) << QString("maxLength") << 1 << 1 << qobject_cast(lineEdit5) << QString("maxLength") << 2 << 2; } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testAddDataDirectory() { pqTestUtility testUtility; QFETCH(QString, label1); QFETCH(QString, path1); QFETCH(int, result1); QFETCH(QString, label2); QFETCH(QString, path2); QFETCH(int, result2); testUtility.addDataDirectory(label1, QDir(path1)); QCOMPARE(testUtility.dataDirectory().count(), result1); testUtility.addDataDirectory(label2, QDir(path2)); QCOMPARE(testUtility.dataDirectory().count(), result2); } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testAddDataDirectory_data() { QTest::addColumn("label1"); QTest::addColumn("path1"); QTest::addColumn("result1"); QTest::addColumn("label2"); QTest::addColumn("path2"); QTest::addColumn("result2"); QTest::newRow("empty") << QString() << QString() << 0 << QString("label") << QString("") << 0; QTest::newRow("allSame") << QString("TEMPLATE") << QString("/home/") << 1 << QString("TEMPLATE") << QString("/home/") << 1; QTest::newRow("sameLabel") << QString("TEMPLATE") << QString("/home/") << 1 << QString("TEMPLATE") << QString("/home/BenLg") << 1; QTest::newRow("samePath") << QString("TEMPLATE") << QString("/home/") << 1 << QString("TEMP") << QString("/home/") << 2; QTest::newRow("diff") << QString("TEMPLATE") << QString("/home/") << 1 << QString("TEMP") << QString("/home/BenLg") << 2; } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testRemoveDataDirectory() { pqTestUtility testUtility; QFETCH(QString, label); QFETCH(bool, result); testUtility.addDataDirectory(QString("TEMPLATE"), QDir("/home")); QCOMPARE(testUtility.removeDataDirectory(label), result); } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testRemoveDataDirectory_data() { QTest::addColumn("label"); QTest::addColumn("result"); QTest::newRow("empty") << QString() << false; QTest::newRow("wrong") << QString("TEMP") << false; QTest::newRow("right") << QString("TEMPLATE") << true; } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testConvertToDataDirectory() { pqTestUtility testUtility; QFETCH(QString, label1); QFETCH(QString, dir1); QFETCH(QString, label2); QFETCH(QString, dir2); testUtility.addDataDirectory(QString(label1), QDir(dir1)); testUtility.addDataDirectory(QString(label2), QDir(dir2)); QFETCH(QString, path); QFETCH(QString, result); const QString convertPath = testUtility.convertToDataDirectory(path); QCOMPARE(QDir::cleanPath(convertPath), QDir::cleanPath(result)); } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testConvertToDataDirectory_data() { QTest::addColumn("label1"); QTest::addColumn("dir1"); QTest::addColumn("label2"); QTest::addColumn("dir2"); QTest::addColumn("path"); QTest::addColumn("result"); QTest::newRow("0") << "ROOT" << "/home/BenLg" << "ROOTDATA" << "/home/BenLg/data" << QString() << QString(); QTest::newRow("1") << "ROOT" << "/home/BenLg" << "ROOTDATA" << "/home/BenLg/data" << QString("/home") << QString("/home"); QTest::newRow("2") << "ROOT" << "/home/BenLg" << "ROOTDATA" << "/home/BenLg/data" << QString("/home/toto/") << QString("/home/toto/"); QTest::newRow("3") << "ROOT" << "/home/BenLg" << "ROOTDATA" << "/home/BenLg/data" << QString("/home/BenLg") << QString("${ROOT}/"); QTest::newRow("4") << "ROOT" << "/home/BenLg" << "ROOTDATA" << "/home/BenLg/data" << QString("/home/BenLg/toto") << QString("${ROOT}/toto"); QTest::newRow("5") << "ROOT" << "/home/BenLg" << "ROOTDATA" << "/home/BenLg/data" << QString("/home/BenLg/data/toto") << QString("${ROOTDATA}/toto"); // Same test as the previous one but we inverse the two dataDirectories // to be sure that our function chosse the right one. QTest::newRow("6") << "ROOTDATA" << "/home/BenLg/data" << "ROOT" << "/home/BenLg" << QString("/home/BenLg/data/toto") << QString("${ROOTDATA}/toto"); QTest::newRow("7") << "ROOT" << "/home/BenLg" << "ROOTDATA" << "/home/BenLg/data" << QString("/usr/toto/home/BenLg/toto") << QString("/usr/toto/home/BenLg/toto"); QTest::newRow("8") << "ROOT" << "/home/BenLg" << "ROOTDATA" << "/home/BenLg/data" << QString("/usr/home/BenLg/data/toto") << QString("/usr/home/BenLg/data/toto"); } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testConvertFromDataDirectory() { pqTestUtility testUtility; testUtility.addDataDirectory(QString("ROOT"), QDir("/home/BenLg")); testUtility.addDataDirectory(QString("ROOTDATA"), QDir("/home/BenLg/data")); QFETCH(QString, path); QFETCH(QString, result); QString convertPath = testUtility.convertFromDataDirectory(path); QCOMPARE(convertPath, result); } // ---------------------------------------------------------------------------- void pqTestUtilityTester::testConvertFromDataDirectory_data() { QTest::addColumn("path"); QTest::addColumn("result"); QTest::newRow("0") << QString("") << QString(); QTest::newRow("1") << QString("/home/guest/data") << QString("/home/guest/data"); QTest::newRow("2") << QString("${WRONG}/home") << QString("${WRONG}/home"); QTest::newRow("3") << QString("${ROOT}") << QString("/home/BenLg"); QTest::newRow("4") << QString("${ROOT}/Doc/bin") << QString("/home/BenLg/Doc/bin"); QTest::newRow("5") << QString("${ROOTDATA}") << QString("/home/BenLg/data"); QTest::newRow("6") << QString("${ROOTDATA}/Ex1/Patient0") << QString("/home/BenLg/data/Ex1/Patient0"); } // ---------------------------------------------------------------------------- CTK_TEST_MAIN(pqTestUtilityTest) #include "moc_pqTestUtilityTest.cpp" qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/000077500000000000000000000000001526070500000233265ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/Scripts/000077500000000000000000000000001526070500000247555ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/Scripts/PlayerTestWizard.py000077500000000000000000000056121526070500000306130ustar00rootroot00000000000000#!/usr/bin/env python import sys import os import fnmatch def findSource(dir): fileList = [] for root, subFolders, files in os.walk(dir): for file in files: if fnmatch.fnmatch(file, "*.h") or \ fnmatch.fnmatch(file, "*.cxx") or \ fnmatch.fnmatch(file, "*.cpp") or \ fnmatch.fnmatch(file, "CMakeLists.txt") or \ fnmatch.fnmatch(file, "*.ui") or \ fnmatch.fnmatch(file, "*.qrc") or \ fnmatch.fnmatch(file, "*.py") or \ fnmatch.fnmatch(file, "*.png"): file = os.path.join(root,file) file = file[len(dir):] # strip common dir fileList.append(file) return fileList def copyAndReplace(inFile, template, target, key, moduleName): newFile = os.path.join( target, inFile.replace(key, moduleName) ) #newFile = os.path.join(target + "EventTranslatorPlayerTest1.cxx") print "creating %s" % newFile path = os.path.dirname(newFile) if not os.path.exists(path): os.makedirs(path) fp = open(os.path.join(template,inFile)) contents = fp.read() fp.close() contents = contents.replace(key, moduleName) contents = contents.replace(key.upper(), moduleName.upper()) fp = open(newFile, "w") fp.write(contents) fp.close() def usage(): print "" print "Usage:" print "ModuleWizard [--template ] [--templateKey ] [--target ] " print " --template default ../TemplateTranslatorPlayer/" print " --templateKey default is Template" print " --target default ..//" def main(argv): template = "" templateKey = "" target = "" moduleName = "" while argv != []: arg = argv.pop(0) if arg == "--template": template = argv.pop(0) continue if arg == "--templateKey": templateKey = argv.pop(0) continue if arg == "--target": target = argv.pop(0) continue if arg == "--help": usage() exit() moduleName = arg if moduleName == "": print "Please specify module name" usage() exit() if template == "": template = "../TemplatePlayerTest/" if template[-1] != '/': template += '/' if templateKey == "": templateKey = "Template" #templateKey = os.path.split(template[:-1])[-1] if target == "": target = "../" + moduleName if os.path.exists(target): print target, "exists - delete it first" exit() if not os.path.exists(template): print template, "does not exist - run from source dir or specify with --template" usage() exit() print "\nWill copy \n\t%s \nto \n\t%s \nreplacing \"%s\" with \"%s\"\n" % (template, target, templateKey, moduleName) sources = findSource( template ) print sources for file in sources: copyAndReplace(file, template, target, templateKey, moduleName) print '\nModule %s created!' % moduleName if __name__ == "__main__": main(sys.argv[1:]) TranslatorPlayerWizard.py000077500000000000000000000056201526070500000317450ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/Scripts#!/usr/bin/env python import sys import os import fnmatch def findSource(dir): fileList = [] for root, subFolders, files in os.walk(dir): for file in files: if fnmatch.fnmatch(file, "*.h") or \ fnmatch.fnmatch(file, "*.cxx") or \ fnmatch.fnmatch(file, "*.cpp") or \ fnmatch.fnmatch(file, "CMakeLists.txt") or \ fnmatch.fnmatch(file, "*.ui") or \ fnmatch.fnmatch(file, "*.qrc") or \ fnmatch.fnmatch(file, "*.py") or \ fnmatch.fnmatch(file, "*.png"): file = os.path.join(root,file) file = file[len(dir):] # strip common dir fileList.append(file) return fileList def copyAndReplace(inFile, template, target, key, moduleName): newFile = os.path.join( target, inFile.replace(key, moduleName) ) #newFile = os.path.join(target + "EventTranslatorPlayerTest1.cxx") print "creating %s" % newFile path = os.path.dirname(newFile) if not os.path.exists(path): os.makedirs(path) fp = open(os.path.join(template,inFile)) contents = fp.read() fp.close() contents = contents.replace(key, moduleName) contents = contents.replace(key.upper(), moduleName.upper()) fp = open(newFile, "w") fp.write(contents) fp.close() def usage(): print "" print "Usage:" print "ModuleWizard [--template ] [--templateKey ] [--target ] " print " --template default ../TemplateTranslatorPlayer/" print " --templateKey default is Template" print " --target default ..//" def main(argv): template = "" templateKey = "" target = "" moduleName = "" while argv != []: arg = argv.pop(0) if arg == "--template": template = argv.pop(0) continue if arg == "--templateKey": templateKey = argv.pop(0) continue if arg == "--target": target = argv.pop(0) continue if arg == "--help": usage() exit() moduleName = arg if moduleName == "": print "Please specify module name" usage() exit() if template == "": template = "../TemplateTranslatorPlayer/" if template[-1] != '/': template += '/' if templateKey == "": templateKey = "Template" #templateKey = os.path.split(template[:-1])[-1] if target == "": target = "../" + moduleName if os.path.exists(target): print target, "exists - delete it first" exit() if not os.path.exists(template): print template, "does not exist - run from source dir or specify with --template" usage() exit() print "\nWill copy \n\t%s \nto \n\t%s \nreplacing \"%s\" with \"%s\"\n" % (template, target, templateKey, moduleName) sources = findSource( template ) print sources for file in sources: copyAndReplace(file, template, target, templateKey, moduleName) print '\nModule %s created!' % moduleName if __name__ == "__main__": main(sys.argv[1:]) qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/Scripts/TranslatorTestWizard.py000077500000000000000000000056161526070500000315140ustar00rootroot00000000000000#!/usr/bin/env python import sys import os import fnmatch def findSource(dir): fileList = [] for root, subFolders, files in os.walk(dir): for file in files: if fnmatch.fnmatch(file, "*.h") or \ fnmatch.fnmatch(file, "*.cxx") or \ fnmatch.fnmatch(file, "*.cpp") or \ fnmatch.fnmatch(file, "CMakeLists.txt") or \ fnmatch.fnmatch(file, "*.ui") or \ fnmatch.fnmatch(file, "*.qrc") or \ fnmatch.fnmatch(file, "*.py") or \ fnmatch.fnmatch(file, "*.png"): file = os.path.join(root,file) file = file[len(dir):] # strip common dir fileList.append(file) return fileList def copyAndReplace(inFile, template, target, key, moduleName): newFile = os.path.join( target, inFile.replace(key, moduleName) ) #newFile = os.path.join(target + "EventTranslatorPlayerTest1.cxx") print "creating %s" % newFile path = os.path.dirname(newFile) if not os.path.exists(path): os.makedirs(path) fp = open(os.path.join(template,inFile)) contents = fp.read() fp.close() contents = contents.replace(key, moduleName) contents = contents.replace(key.upper(), moduleName.upper()) fp = open(newFile, "w") fp.write(contents) fp.close() def usage(): print "" print "Usage:" print "ModuleWizard [--template ] [--templateKey ] [--target ] " print " --template default ../TemplateTranslatorPlayer/" print " --templateKey default is Template" print " --target default ..//" def main(argv): template = "" templateKey = "" target = "" moduleName = "" while argv != []: arg = argv.pop(0) if arg == "--template": template = argv.pop(0) continue if arg == "--templateKey": templateKey = argv.pop(0) continue if arg == "--target": target = argv.pop(0) continue if arg == "--help": usage() exit() moduleName = arg if moduleName == "": print "Please specify module name" usage() exit() if template == "": template = "../TemplateTranslatorTest/" if template[-1] != '/': template += '/' if templateKey == "": templateKey = "Template" #templateKey = os.path.split(template[:-1])[-1] if target == "": target = "../" + moduleName if os.path.exists(target): print target, "exists - delete it first" exit() if not os.path.exists(template): print template, "does not exist - run from source dir or specify with --template" usage() exit() print "\nWill copy \n\t%s \nto \n\t%s \nreplacing \"%s\" with \"%s\"\n" % (template, target, templateKey, moduleName) sources = findSource( template ) print sources for file in sources: copyAndReplace(file, template, target, templateKey, moduleName) print '\nModule %s created!' % moduleName if __name__ == "__main__": main(sys.argv[1:]) qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/TemplatePlayerTest/000077500000000000000000000000001526070500000271165ustar00rootroot00000000000000pqTemplateEventPlayerTest.cpp000066400000000000000000000032741526070500000347040ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/TemplatePlayerTest// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include #include #include // QtTesting includes #include "pqTestUtility.h" #include "pqTest.h" // ---------------------------------------------------------------------------- class pqTemplateEventPlayerTester : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void init(); void cleanup(); void cleanupTestCase(); private: QTemplate* Template; pqTestUtility* TestUtility; }; // ---------------------------------------------------------------------------- void pqTemplateEventPlayerTester::initTestCase() { this->TestUtility = new pqTestUtility(); this->TestUtility->addEventObserver("xml", new pqDummyEventObserver); this->TestUtility->addEventSource("xml", new pqDummyEventSource()); this->Template = 0; } // ---------------------------------------------------------------------------- void pqTemplateEventPlayerTester::init() { // Init the QTemplate this->Template = new QTemplate(); this->Template->setObjectName("TemplateTest"); this->Template->setMinimum(-99); } // ---------------------------------------------------------------------------- void pqTemplateEventPlayerTester::cleanup() { delete this->Template; } // ---------------------------------------------------------------------------- void pqTemplateEventPlayerTester::cleanupTestCase() { delete this->TestUtility; } // ---------------------------------------------------------------------------- CTK_TEST_MAIN(pqTemplateEventPlayerTest) #include "moc_pqTemplateEventPlayerTest.cpp" qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/TemplateTranslatorPlayer/000077500000000000000000000000001526070500000303305ustar00rootroot00000000000000TemplateEventPlayer.cpp000066400000000000000000000015041526070500000347070ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/TemplateTranslatorPlayer// Qt includes #include #include "Template.h" #include "TemplateEventPlayer.h" // ---------------------------------------------------------------------------- TemplateEventPlayer::TemplateEventPlayer(QObject* parent) : pqWidgetEventPlayer(parent) { } // ---------------------------------------------------------------------------- bool TemplateEventPlayer::playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) { if (Command != "") { return false; } if (Template* const object = qobject_cast(Object)) { if (Command == "") { // Edit what the widget "object" should do with this command and argument return true; } } qCritical() << "calling ....'your commands'..... on unhandled type " << Object; Error = true; return true; } TemplateEventPlayer.h000066400000000000000000000013111526070500000343500ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/TemplateTranslatorPlayer#ifndef __TemplateEventPlayer_h #define __TemplateEventPlayer_h // QtTesting includes #include /// Concrete implementation of pqWidgetEventPlayer that translates /// high-level events into low-level Qt events. class TemplateEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: TemplateEventPlayer(QObject* parent = 0); using Superclass::playEvent; bool playEvent(QObject* Object, const QString& Command, const QString& Arguments, bool& Error); private: TemplateEventPlayer(const TemplateEventPlayer&); // NOT implemented TemplateEventPlayer& operator=(const TemplateEventPlayer&); // NOT implemented }; #endif TemplateEventTranslator.cpp000066400000000000000000000022661526070500000356120ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/TemplateTranslatorPlayer// Qt includes #include #include "Template.h" #include "TemplateEventTranslator.h" // ---------------------------------------------------------------------------- TemplateEventTranslator::TemplateEventTranslator(QObject* parent) : pqWidgetEventTranslator(parent) { this->CurrentObject = 0; } // ---------------------------------------------------------------------------- bool TemplateEventTranslator::translateEvent(QObject* Object, QEvent* Event, bool& Error) { Q_UNUSED(Error); Template* object = qobject_cast(Object); if (!object) { return false; } if (Event->type() == QEvent::Enter && Object == object) { if (this->CurrentObject != Object) { if (this->CurrentObject) { disconnect(this->CurrentObject, 0, this, 0); } this->CurrentObject = Object; connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(onDestroyed())); // Add your connect and edit the slots functions associated } } return true; } // ---------------------------------------------------------------------------- void TemplateEventTranslator::onDestroyed() { if (this->CurrentObject) { this->CurrentObject = 0; } } TemplateEventTranslator.h000066400000000000000000000012051526070500000352470ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/TemplateTranslatorPlayer#ifndef __TemplateEventTranslator_h #define __TemplateEventTranslator_h // QtTesting inlcudes #include class TemplateEventTranslator : public pqWidgetEventTranslator { Q_OBJECT public: TemplateEventTranslator(QObject* parent = 0); using Superclass::translateEvent; virtual bool translateEvent(QObject* Object, QEvent* Event, bool& Error); private Q_SLOTS: void onDestroyed(); private: TemplateEventTranslator(const TemplateEventTranslator&); // NOT implemented TemplateEventTranslator& operator=(const TemplateEventTranslator&); // NOT implemented QObject* CurrentObject; }; #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/TemplateTranslatorTest/000077500000000000000000000000001526070500000300135ustar00rootroot00000000000000pqTemplateEventTranslatorTest.cpp000066400000000000000000000041031526070500000364660ustar00rootroot00000000000000qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/Utilities/TemplateTranslatorTest// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include #include #include #include // QtTesting includes #include "pqTestUtility.h" #include "pqTest.h" // ---------------------------------------------------------------------------- class pqTemplateEventTranslatorTester : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void init(); void cleanup(); void cleanupTestCase(); private: QTemplate* Template; pqTestUtility* TestUtility; pqDummyEventObserver* EventObserver; }; // ---------------------------------------------------------------------------- void pqTemplateEventTranslatorTester::initTestCase() { this->TestUtility = new pqTestUtility(); this->EventObserver = new pqDummyEventObserver(); this->TestUtility->addEventObserver("xml", this->EventObserver); this->TestUtility->addEventSource("xml", new pqDummyEventSource()); this->Template = 0; } // ---------------------------------------------------------------------------- void pqTemplateEventTranslatorTester::init() { // Init the Template this->Template = new QTemplate(); this->Template->setObjectName("TemplateTest"); // Start to record events this->TestUtility->recordTestsBySuffix("xml"); // Fire the event "enter" to connect Template signals to the translator slots QEvent enter(QEvent::Enter); qApp->notify(this->Template, &enter); } // ---------------------------------------------------------------------------- void pqTemplateEventTranslatorTester::cleanup() { this->TestUtility->stopRecords(0); delete this->Template; } // ---------------------------------------------------------------------------- void pqTemplateEventTranslatorTester::cleanupTestCase() { this->EventObserver = 0; delete this->TestUtility; } // ---------------------------------------------------------------------------- CTK_TEST_MAIN(pqTemplateEventTranslatorTest) #include "moc_pqTemplateEventTranslatorTest.cpp" qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pq3DViewEventPlayer.cxx000066400000000000000000000036461526070500000257310ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pq3DViewEventPlayer.h" #include #include #include #include #include #include pq3DViewEventPlayer::pq3DViewEventPlayer(const QByteArray& classname, QObject* p) : pqWidgetEventPlayer(p) , mClassType(classname) { } bool pq3DViewEventPlayer::playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) { QWidget* widget = qobject_cast(Object); if (widget && Object->inherits(mClassType.data())) { if (Command == "mousePress" || Command == "mouseRelease" || Command == "mouseMove") { QRegularExpression mouseRegExp("\\(([^,]*),([^,]*),([^,]),([^,]),([^,]*)\\)"); QRegularExpressionMatch match = mouseRegExp.match(Arguments); if (match.hasMatch()) { QVariant v = match.captured(1); int x = static_cast(v.toDouble() * widget->size().width()); v = match.captured(2); int y = static_cast(v.toDouble() * widget->size().height()); v = match.captured(3); Qt::MouseButton button = static_cast(v.toInt()); v = match.captured(4); Qt::MouseButtons buttons = static_cast(v.toInt()); v = match.captured(5); Qt::KeyboardModifiers keym = static_cast(v.toInt()); QEvent::Type type = (Command == "mousePress") ? QEvent::MouseButtonPress : ((Command == "mouseMove") ? QEvent::MouseMove : QEvent::MouseButtonRelease); QPoint pos(x, y); QMouseEvent e(type, pos, widget->mapToGlobal(pos), button, buttons, keym); qApp->notify(Object, &e); } return true; } } return this->Superclass::playEvent(Object, Command, Arguments, Error); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pq3DViewEventPlayer.h000066400000000000000000000017641526070500000253550ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pq3DViewEventPlayer_h #define _pq3DViewEventPlayer_h #include "pqWidgetEventPlayer.h" /** Concrete implementation of pqWidgetEventPlayer that handles playback of "activate" events for 3d views. It is not registered by default, and user can register with their own 3d view type. \sa pqEventPlayer */ class QTTESTING_EXPORT pq3DViewEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pq3DViewEventPlayer(const QByteArray& classname, QObject* p = 0); using Superclass::playEvent; bool playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) override; protected: QByteArray mClassType; private: pq3DViewEventPlayer(const pq3DViewEventPlayer&); pq3DViewEventPlayer& operator=(const pq3DViewEventPlayer&); }; #endif // !_pq3DViewEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pq3DViewEventTranslator.cxx000066400000000000000000000117221526070500000266200ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pq3DViewEventTranslator.h" #include #include #include #include pq3DViewEventTranslator::pq3DViewEventTranslator(const QByteArray& classname, QObject* p) : pqWidgetEventTranslator(p) , mClassType(classname) , lastMoveEvent(QEvent::MouseButtonPress, QPoint(), QPoint(), Qt::MouseButton(), Qt::MouseButtons(), Qt::KeyboardModifiers()) { } pq3DViewEventTranslator::~pq3DViewEventTranslator() {} bool pq3DViewEventTranslator::translateEvent(QObject* Object, QEvent* Event, bool& Error) { QWidget* widget = qobject_cast(Object); if (!widget || !Object->inherits(mClassType.data())) { return false; } switch (Event->type()) { case QEvent::ContextMenu: { return true; break; } case QEvent::MouseButtonPress: { QMouseEvent* mouseEvent = dynamic_cast(Event); if (mouseEvent) { QSize size = widget->size(); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) auto pos = mouseEvent->pos(); #else auto pos = mouseEvent->position().toPoint(); #endif double normalized_x = pos.x() / static_cast(size.width()); double normalized_y = pos.y() / static_cast(size.height()); int button = mouseEvent->button(); int buttons = mouseEvent->buttons(); int modifiers = mouseEvent->modifiers(); Q_EMIT recordEvent(Object, "mousePress", QString("(%1,%2,%3,%4,%5)") .arg(normalized_x) .arg(normalized_y) .arg(button) .arg(buttons) .arg(modifiers)); } // reset lastMoveEvent QMouseEvent e(QEvent::MouseButtonPress, QPoint(), QPoint(), Qt::MouseButton(), Qt::MouseButtons(), Qt::KeyboardModifiers()); #if QT_VERSION < 0x060000 // FIXME: QMouseEvent copy ctor is private in Qt6 lastMoveEvent = e; #endif return true; break; } case QEvent::MouseMove: { QMouseEvent* mouseEvent = dynamic_cast(Event); if (mouseEvent) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) auto pos = mouseEvent->pos(); #else auto pos = mouseEvent->position().toPoint(); #endif QMouseEvent e(QEvent::MouseMove, pos, widget->mapToGlobal(pos), mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers()); #if QT_VERSION < 0x060000 // FIXME: QMouseEvent copy ctor is private in Qt6 lastMoveEvent = e; #endif } return true; break; } case QEvent::MouseButtonRelease: { QMouseEvent* mouseEvent = dynamic_cast(Event); if (mouseEvent) { QSize size = widget->size(); // record last move event if it is valid if (lastMoveEvent.type() == QEvent::MouseMove) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) auto pos = lastMoveEvent.pos(); #else auto pos = lastMoveEvent.position().toPoint(); #endif double normalized_x = pos.x() / static_cast(size.width()); double normalized_y = pos.y() / static_cast(size.height()); int button = lastMoveEvent.button(); int buttons = lastMoveEvent.buttons(); int modifiers = lastMoveEvent.modifiers(); Q_EMIT recordEvent(Object, "mouseMove", QString("(%1,%2,%3,%4,%5)") .arg(normalized_x) .arg(normalized_y) .arg(button) .arg(buttons) .arg(modifiers)); } #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) auto pos = mouseEvent->pos(); #else auto pos = mouseEvent->position().toPoint(); #endif double normalized_x = pos.x() / static_cast(size.width()); double normalized_y = pos.y() / static_cast(size.height()); int button = mouseEvent->button(); int buttons = mouseEvent->buttons(); int modifiers = mouseEvent->modifiers(); Q_EMIT recordEvent(Object, "mouseRelease", QString("(%1,%2,%3,%4,%5)") .arg(normalized_x) .arg(normalized_y) .arg(button) .arg(buttons) .arg(modifiers)); } return true; break; } case QEvent::KeyPress: case QEvent::KeyRelease: { QKeyEvent* ke = static_cast(Event); QString data = QString("%1:%2:%3:%4:%5:%6") .arg(ke->type()) .arg(ke->key()) .arg(static_cast(ke->modifiers())) .arg(ke->text()) .arg(ke->isAutoRepeat()) .arg(ke->count()); Q_EMIT recordEvent(Object, "keyEvent", data); return true; break; } default: { break; } } return this->Superclass::translateEvent(Object, Event, Error); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pq3DViewEventTranslator.h000066400000000000000000000020151526070500000262400ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pq3DViewEventTranslator_h #define _pq3DViewEventTranslator_h #include "pqWidgetEventTranslator.h" #include /** Translates low-level Qt events into high-level ParaView events that can be recorded as test cases. \sa pqEventTranslator */ class QTTESTING_EXPORT pq3DViewEventTranslator : public pqWidgetEventTranslator { Q_OBJECT typedef pqWidgetEventTranslator Superclass; public: pq3DViewEventTranslator(const QByteArray& classname, QObject* p = 0); ~pq3DViewEventTranslator() override; using Superclass::translateEvent; bool translateEvent(QObject* Object, QEvent* Event, bool& Error) override; protected: QByteArray mClassType; QMouseEvent lastMoveEvent; private: pq3DViewEventTranslator(const pq3DViewEventTranslator&); pq3DViewEventTranslator& operator=(const pq3DViewEventTranslator&); }; #endif // !_pq3DViewEventTranslator_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractActivateEventPlayer.cxx000066400000000000000000000107001526070500000300410ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqAbstractActivateEventPlayer.h" #include #include #include #include #include #include #include #include #include "pqEventDispatcher.h" pqAbstractActivateEventPlayer::pqAbstractActivateEventPlayer(QObject* p) : pqWidgetEventPlayer(p) { } bool pqAbstractActivateEventPlayer::playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) { if (Command != "activate" && Command != "longActivate") return false; if (QMenuBar* const menu_bar = qobject_cast(Object)) { QAction* action = findAction(menu_bar, Arguments); if (action) { menu_bar->setActiveAction(action); return true; } qCritical() << "couldn't find action " << Arguments; Error = true; return true; } if (QMenu* qmenu = qobject_cast(Object)) { QAction* action = findAction(qmenu, Arguments); if (!action) { Error = true; return true; } // get a list of menus that must be navigated to // click on the action QObjectList menus; for (QObject* p = qmenu; qobject_cast(p) || qobject_cast(p); p = p->parent()) { menus.push_front(p); } // unfold menus to make action visible int i; int numMenus = menus.size() - 1; for (i = 0; i < numMenus; ++i) { QObject* p = menus[i]; QMenu* next = qobject_cast(menus[i + 1]); if (QMenuBar* menu_bar = qobject_cast(p)) { menu_bar->setActiveAction(next->menuAction()); int max_wait = 0; while (!next->isVisible() && (++max_wait) <= 2) { pqEventDispatcher::processEventsAndWait(100); } } else if (QMenu* menu = qobject_cast(p)) { menu->setActiveAction(next->menuAction()); int max_wait = 0; while (!next->isVisible() && (++max_wait) <= 2) { pqEventDispatcher::processEventsAndWait(100); } } } // set active action, will cause scrollable menus to scroll // to make action visible qmenu->setActiveAction(action); // activate the action item QKeyEvent keyDown(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); QKeyEvent keyUp(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier); qApp->notify(qmenu, &keyDown); qApp->notify(qmenu, &keyUp); // QApplication::processEvents(); return true; } if (QAbstractButton* const object = qobject_cast(Object)) { if (Command == "activate") { object->click(); // QApplication::processEvents(); return true; } if (Command == "longActivate") { QToolButton* tButton = qobject_cast(Object); if (tButton) { tButton->showMenu(); return true; } } } if (QAction* const action = qobject_cast(Object)) { action->activate(QAction::Trigger); // QApplication::processEvents(); return true; } qCritical() << "calling activate on unhandled type " << Object; Error = true; return true; } QAction* pqAbstractActivateEventPlayer::findAction(QMenuBar* p, const QString& name) { QList actions = p->actions(); QAction* action = NULL; Q_FOREACH (QAction* a, actions) { if (a->menu()->objectName() == name) { action = a; break; } } if (!action) { Q_FOREACH (QAction* a, actions) { if (a->text() == name) { action = a; break; } } } return action; } QAction* pqAbstractActivateEventPlayer::findAction(QMenu* p, const QString& name) { QStringList checked; QList actions = p->actions(); QAction* action = NULL; Q_FOREACH (QAction* a, actions) { checked.append(a->objectName()); if (checked.back() == name) { action = a; break; } } if (!action) { Q_FOREACH (QAction* a, actions) { checked.append(a->text()); if (checked.back() == name) { action = a; break; } } } if (!action) { checked.removeDuplicates(); qCritical() << "Unable to find action " << name << " in " << p->objectName() << ". Available actions: " << checked.join(", "); } return action; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractActivateEventPlayer.h000066400000000000000000000021361526070500000274720ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqAbstractActivateEventPlayer_h #define _pqAbstractActivateEventPlayer_h #include "pqWidgetEventPlayer.h" class QAction; class QMenuBar; class QMenu; /** Concrete implementation of pqWidgetEventPlayer that handles playback of "activate" events for buttons and menus. \sa pqEventPlayer */ class QTTESTING_EXPORT pqAbstractActivateEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pqAbstractActivateEventPlayer(QObject* p = 0); using Superclass::playEvent; bool playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) override; private: QAction* findAction(QMenu* p, const QString& name); QAction* findAction(QMenuBar* p, const QString& name); pqAbstractActivateEventPlayer(const pqAbstractActivateEventPlayer&); pqAbstractActivateEventPlayer& operator=(const pqAbstractActivateEventPlayer&); }; #endif // !_pqAbstractActivateEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractBooleanEventPlayer.cxx000066400000000000000000000023201526070500000276570ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqAbstractBooleanEventPlayer.h" #include #include #include #include pqAbstractBooleanEventPlayer::pqAbstractBooleanEventPlayer(QObject* p) : pqWidgetEventPlayer(p) { } bool pqAbstractBooleanEventPlayer::playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) { if (Command != "set_boolean") return false; const bool value = Arguments == "true" ? true : false; if (QAbstractButton* const object = qobject_cast(Object)) { if (value != object->isChecked()) object->click(); return true; } if (QAction* const action = qobject_cast(Object)) { if (action->isChecked() != value) { action->trigger(); } return true; } if (QGroupBox* const object = qobject_cast(Object)) { if (value != object->isChecked()) { object->setChecked(value); } return true; } qCritical() << "calling set_boolean on unhandled type " << Object; Error = true; return true; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractBooleanEventPlayer.h000066400000000000000000000016741526070500000273170ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqAbstractBooleanEventPlayer_h #define _pqAbstractBooleanEventPlayer_h #include "pqWidgetEventPlayer.h" /** Concrete implementation of pqWidgetEventPlayer that translates high-level ParaView events into low-level Qt events. \sa pqEventPlayer */ class QTTESTING_EXPORT pqAbstractBooleanEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pqAbstractBooleanEventPlayer(QObject* p = 0); using Superclass::playEvent; bool playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) override; private: pqAbstractBooleanEventPlayer(const pqAbstractBooleanEventPlayer&); pqAbstractBooleanEventPlayer& operator=(const pqAbstractBooleanEventPlayer&); }; #endif // !_pqAbstractBooleanEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractButtonEventTranslator.cxx000066400000000000000000000067371526070500000304700ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqAbstractButtonEventTranslator.h" #include #include #include #include #include #include #include #include pqAbstractButtonEventTranslator::pqAbstractButtonEventTranslator(QObject* p) : pqWidgetEventTranslator(p) { this->LastMouseEventType = QEvent::None; } bool pqAbstractButtonEventTranslator::translateEvent(QObject* Object, QEvent* Event, bool& Error) { QAbstractButton* const object = qobject_cast(Object); if (!object) { return false; } switch (Event->type()) { case QEvent::KeyPress: { QKeyEvent* const e = dynamic_cast(Event); if (e->key() == Qt::Key_Space) { onActivate(object); } return true; break; } case QEvent::MouseButtonPress: { QMouseEvent* const e = dynamic_cast(Event); this->LastMouseEventType = Event->type(); // Menus are opened on mouse press if (e->button() == Qt::LeftButton && object->rect().contains(e->pos()) && this->hasMenu(object)) { onActivate(object); } return true; break; } case QEvent::Timer: { if (this->LastMouseEventType == QEvent::MouseButtonPress) { QToolButton* tButton = qobject_cast(object); if (tButton && tButton->popupMode() == QToolButton::DelayedPopup) { Q_EMIT recordEvent(object, "longActivate", ""); // Tell comming mouse button release to not record activate. this->LastMouseEventType = QEvent::None; } } return true; break; } case QEvent::MouseButtonRelease: { bool lastEventWasMouseButtonPress = this->LastMouseEventType == QEvent::MouseButtonPress; QMouseEvent* const e = dynamic_cast(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); } return true; break; } default: break; } return this->Superclass::translateEvent(Object, Event, Error); } void pqAbstractButtonEventTranslator::onActivate(QAbstractButton* actualObject) { QObject* object = actualObject; QToolButton* tb = qobject_cast(object); if (tb && tb->defaultAction()) { object = tb->defaultAction(); } if (actualObject->isCheckable()) { const bool new_value = !actualObject->isChecked(); Q_EMIT recordEvent(object, "set_boolean", new_value ? "true" : "false"); } else { Q_EMIT recordEvent(object, "activate", ""); } } bool pqAbstractButtonEventTranslator::hasMenu(QAbstractButton* button) const { bool hasMenu = false; QPushButton* pushButton = qobject_cast(button); if (pushButton) { hasMenu = pushButton->menu() != 0; } QToolButton* toolButton = qobject_cast(button); if (toolButton) { hasMenu = toolButton->menu() != 0 || (toolButton->defaultAction() && toolButton->defaultAction()->menu() != 0); hasMenu = hasMenu && toolButton->popupMode() != QToolButton::DelayedPopup; } return hasMenu; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractButtonEventTranslator.h000066400000000000000000000022221526070500000300760ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqAbstractButtonEventTranslator_h #define _pqAbstractButtonEventTranslator_h // Qt includes #include #include "pqWidgetEventTranslator.h" class QAbstractButton; /** Translates low-level Qt events into high-level ParaView events that can be recorded as test cases. \sa pqEventTranslator */ class QTTESTING_EXPORT pqAbstractButtonEventTranslator : public pqWidgetEventTranslator { Q_OBJECT typedef pqWidgetEventTranslator Superclass; public: pqAbstractButtonEventTranslator(QObject* p = 0); using Superclass::translateEvent; bool translateEvent(QObject* Object, QEvent* Event, bool& Error) override; protected: virtual void onActivate(QAbstractButton*); virtual bool hasMenu(QAbstractButton* actualObject) const; QEvent::Type LastMouseEventType; private: pqAbstractButtonEventTranslator(const pqAbstractButtonEventTranslator&); pqAbstractButtonEventTranslator& operator=(const pqAbstractButtonEventTranslator&); }; #endif // !_pqAbstractButtonEventTranslator_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractDoubleEventPlayer.cxx000066400000000000000000000021041526070500000275120ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqAbstractDoubleEventPlayer.h" #include #include pqAbstractDoubleEventPlayer::pqAbstractDoubleEventPlayer(QObject* p) : pqWidgetEventPlayer(p) { } bool pqAbstractDoubleEventPlayer::playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) { if (Command != "set_double" && Command != "spin") return false; const double value = Arguments.toDouble(); if (QDoubleSpinBox* const object = qobject_cast(Object)) { if (Command == "set_double") { object->setValue(value); return true; } else if (Command == "spin" && Arguments == "up") { object->stepUp(); return true; } else if (Command == "spin" && Arguments == "down") { object->stepDown(); return true; } } qCritical() << "calling set_double on unhandled type " << Object; Error = true; return true; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractDoubleEventPlayer.h000066400000000000000000000016641526070500000271510ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqAbstractDoubleEventPlayer_h #define _pqAbstractDoubleEventPlayer_h #include "pqWidgetEventPlayer.h" /** Concrete implementation of pqWidgetEventPlayer that translates high-level ParaView events into low-level Qt events. \sa pqEventPlayer */ class QTTESTING_EXPORT pqAbstractDoubleEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pqAbstractDoubleEventPlayer(QObject* p = 0); using Superclass::playEvent; bool playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) override; private: pqAbstractDoubleEventPlayer(const pqAbstractDoubleEventPlayer&); pqAbstractDoubleEventPlayer& operator=(const pqAbstractDoubleEventPlayer&); }; #endif // !_pqAbstractDoubleEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractIntEventPlayer.cxx000066400000000000000000000024431526070500000270400ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqAbstractIntEventPlayer.h" #include #include #include pqAbstractIntEventPlayer::pqAbstractIntEventPlayer(QObject* p) : pqWidgetEventPlayer(p) { } bool pqAbstractIntEventPlayer::playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) { if (Command != "set_int" && Command != "spin") return false; const int value = Arguments.toInt(); if (QAbstractSlider* const object = qobject_cast(Object)) { object->setValue(value); return true; } if (QSpinBox* const object = qobject_cast(Object)) { if (Command == "set_int") { object->setValue(value); return true; } else if (Command == "spin" && Arguments == "up") { object->stepUp(); return true; } else if (Command == "spin" && Arguments == "down") { object->stepDown(); return true; } } if (Command == "spin") { // let pqAbstractEventPlayer handle it if possible. return false; } qCritical() << "calling set_int on unhandled type " << Object; Error = true; return true; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractIntEventPlayer.h000066400000000000000000000016311526070500000264630ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqAbstractIntEventPlayer_h #define _pqAbstractIntEventPlayer_h #include "pqWidgetEventPlayer.h" /** Concrete implementation of pqWidgetEventPlayer that translates high-level ParaView events into low-level Qt events. \sa pqEventPlayer */ class QTTESTING_EXPORT pqAbstractIntEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pqAbstractIntEventPlayer(QObject* p = 0); using Superclass::playEvent; bool playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) override; private: pqAbstractIntEventPlayer(const pqAbstractIntEventPlayer&); pqAbstractIntEventPlayer& operator=(const pqAbstractIntEventPlayer&); }; #endif // !_pqAbstractIntEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractItemViewEventPlayer.cxx000066400000000000000000000135261526070500000300430ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqAbstractItemViewEventPlayer.h" #include #include #include #include #include #include #include #include #include #include #include "pqEventDispatcher.h" /// Converts a string representation of a model index into the real thing static QModelIndex OldGetIndex(QAbstractItemView& View, const QString& Name) { #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) QStringList rows = Name.split('/', Qt::SkipEmptyParts); #else QStringList rows = Name.split('/', QString::SkipEmptyParts); #endif QString column; if (rows.size()) { column = rows.back().split('|').at(1); rows.back() = rows.back().split('|').at(0); } QModelIndex index; for (int i = 0; i != rows.size(); ++i) { index = View.model()->index(rows[i].toInt(), column.toInt(), index); } return index; } static QModelIndex GetIndexByItemName(QAbstractItemView& View, const QString& Name) { QListWidget* const listWidget = qobject_cast(&View); QModelIndex index; if (!listWidget) { return index; } QList findResult = listWidget->findItems(Name, Qt::MatchExactly); if (findResult.count() > 0) { // in theory more than one item could match? Only return the index for // the first instance. index = View.model()->index(listWidget->row(findResult.first()), 0, index); } return index; } static QModelIndex GetIndex(QAbstractItemView* View, const QString& Name) { #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) QStringList idxs = Name.split('/', Qt::SkipEmptyParts); #else QStringList idxs = Name.split('/', QString::SkipEmptyParts); #endif QModelIndex index; for (int i = 0; i != idxs.size(); ++i) { QStringList rowCol = idxs[i].split(':'); index = View->model()->index(rowCol[0].toInt(), rowCol[1].toInt(), index); } return index; } /////////////////////////////////////////////////////////////////////////////// // pqAbstractItemViewEventPlayer pqAbstractItemViewEventPlayer::pqAbstractItemViewEventPlayer(QObject* p) : pqWidgetEventPlayer(p) { } bool pqAbstractItemViewEventPlayer::playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) { QAbstractItemView* object = qobject_cast(Object); QMenu* contextMenu = qobject_cast(Object); // if this a QMenu (potentially a context menu of the view), // we should not move onto parent if (!object && !contextMenu) { // mouse events go to the viewport widget object = qobject_cast(Object->parent()); } if (!object) { return false; } if (Command == "key" || Command == "editCancel" || Command == "editAccepted") { // We let the pqBasicWidgetEventPlayer do it ... return false; } if (Command == "currentChanged") // left to support old recordings { const QModelIndex index = OldGetIndex(*object, Arguments); if (!index.isValid()) return false; object->setCurrentIndex(index); return true; } else if (Command == "currentChangedbyItemName") { const QModelIndex index = GetIndexByItemName(*object, Arguments); if (!index.isValid()) return false; object->setCurrentIndex(index); return true; } else if (Command == "keyEvent") { QStringList data = Arguments.split(','); if (data.size() == 6) { QKeyEvent ke(static_cast(data[0].toInt()), data[1].toInt(), static_cast(data[2].toInt()), data[3], !!data[4].toInt(), data[5].toInt()); qApp->notify(object, &ke); return true; } } else if (Command.startsWith("mouse")) { QStringList args = Arguments.split(','); if (args.size() == 5) { // Sometime, mouseWheel event does not contain the index, in that case, // they should be played by the basic widget event player return false; } if (args.size() == 6) { Qt::MouseButtons buttons = static_cast(args[1].toInt()); Qt::KeyboardModifiers keym = static_cast(args[2].toInt()); int x = args[3].toInt(); int y = args[4].toInt(); QPoint pt; QHeaderView* header = qobject_cast(object); if (header) { int idx = args[5].toInt(); if (header->orientation() == Qt::Horizontal) { pt = QPoint(header->sectionPosition(idx) + 4, 4); } else { pt = QPoint(4, header->sectionPosition(idx) + 4); } } else { QModelIndex idx = GetIndex(object, args[5]); object->scrollTo(idx); QRect r = object->visualRect(idx); pt = r.topLeft() + QPoint(x, y); } if (Command == "mouseWheel") { int delta = args[0].toInt(); QWheelEvent we(QPointF(x, y), QPointF(x, y), QPoint(0, 0), QPoint(0, delta), buttons, keym, Qt::NoScrollPhase, false); QCoreApplication::sendEvent(Object, &we); return true; } Qt::MouseButton button = static_cast(args[0].toInt()); QEvent::Type type = QEvent::MouseButtonPress; type = Command == "mouseMove" ? QEvent::MouseMove : type; type = Command == "mouseRelease" ? QEvent::MouseButtonRelease : type; type = Command == "mouseDblClick" ? QEvent::MouseButtonDblClick : type; QMouseEvent e(type, pt, object->mapToGlobal(pt), button, buttons, keym); qApp->notify(object->viewport(), &e); return true; } } if (!this->Superclass::playEvent(Object, Command, Arguments, Error)) { qCritical() << "Unknown abstract item command: " << Command << "\n"; Error = true; } return true; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractItemViewEventPlayer.h000066400000000000000000000017061526070500000274650ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqAbstractItemViewEventPlayer_h #define _pqAbstractItemViewEventPlayer_h #include "pqWidgetEventPlayer.h" /** Concrete implementation of pqWidgetEventPlayer that translates high-level ParaView events into low-level Qt events. \sa pqEventPlayer */ class QTTESTING_EXPORT pqAbstractItemViewEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pqAbstractItemViewEventPlayer(QObject* p = 0); using Superclass::playEvent; bool playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) override; private: pqAbstractItemViewEventPlayer(const pqAbstractItemViewEventPlayer&); pqAbstractItemViewEventPlayer& operator=(const pqAbstractItemViewEventPlayer&); }; #endif // !_pqAbstractItemViewEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractItemViewEventPlayerBase.cxx000066400000000000000000000273161526070500000306400ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqAbstractItemViewEventPlayerBase.h" #include "pqEventTypes.h" #include #include #include #include #include #include namespace { int findSection(QAbstractItemModel* model, const QString& label, Qt::Orientation orientation, int role = Qt::DisplayRole) { QStringList currentHeaders; const int max = orientation == Qt::Horizontal ? model->columnCount() : model->rowCount(); for (int section = 0; section < max; ++section) { auto data = model->headerData(section, orientation, role).toString(); currentHeaders.push_back(data); if (data == label) { return section; } } qCritical() << "No header labeled '" << label << "' was found. " << "Available values are " << currentHeaders; return -1; } } // end of namespace //----------------------------------------------------------------------------- pqAbstractItemViewEventPlayerBase::pqAbstractItemViewEventPlayerBase(QObject* parentObject) : Superclass(parentObject) { } //----------------------------------------------------------------------------- pqAbstractItemViewEventPlayerBase::~pqAbstractItemViewEventPlayerBase() {} //----------------------------------------------------------------------------- QModelIndex pqAbstractItemViewEventPlayerBase::GetIndex( const QString& itemStr, QAbstractItemView* abstractItemView, bool& error) { // Get only the "index" part of the string int sep = itemStr.indexOf(","); QString strIndex = itemStr.left(sep); // Recover model index #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) const QStringList indices = strIndex.split(".", Qt::SkipEmptyParts); #else const QStringList indices = strIndex.split(".", QString::SkipEmptyParts); #endif if (indices.isEmpty() || (indices.size() % 2 != 0)) // indices are in pairs (row, column). { error = true; qCritical() << "ERROR: Incorrect number of values in index! Cannot playback."; return QModelIndex(); } QList iIndices; auto model = abstractItemView->model(); // indices may be simply ints or strings. If not ints, then assume strings that // represent row or column name. for (int cc = 0; cc < indices.size(); ++cc) { bool ok; int index = indices[cc].toInt(&ok); if (!ok) { // must be a string that represents the row/column name. determine the index. index = ::findSection(model, indices[cc], (cc % 2 == 0) ? Qt::Vertical : Qt::Horizontal); if (index == -1) { error = true; return QModelIndex(); } } iIndices.push_back(index); } QModelIndex index; for (int cc = 0; (cc + 1) < iIndices.size(); cc += 2) { index = abstractItemView->model()->index(iIndices[cc], iIndices[cc + 1], /*parent=*/index); if (!index.isValid()) { error = true; qCritical() << "ERROR: Abstract Item view must have changed. " << "Indices recorded in the test are no longer valid. Cannot playback."; break; } } return index; } //----------------------------------------------------------------------------- QString pqAbstractItemViewEventPlayerBase::GetDataString(const QString& itemStr, bool& error) { Q_UNUSED(error); // Get only the "data" part of the string int sep = itemStr.indexOf(","); return itemStr.mid(sep + 1); } //----------------------------------------------------------------------------- bool pqAbstractItemViewEventPlayerBase::playEvent( QObject* object, const QString& command, const QString& arguments, int eventType, bool& error) { QAbstractItemView* abstractItemView = qobject_cast(object); QMenu* contextMenu = qobject_cast(object); // if this a QMenu (potentially a context menu of the view), // we should not move onto parent if (!abstractItemView && !contextMenu) { // mouse events go to the viewport widget abstractItemView = qobject_cast(object->parent()); } if (!abstractItemView) { return false; } if (eventType == pqEventTypes::ACTION_EVENT) { if (command == "key") { return false; } QRegularExpression regExp1("^([\\d\\.]+),(\\d+)$"); QRegularExpressionMatch match = regExp1.match(arguments); if (command == "setCheckState" && match.hasMatch()) { QString strIndex = match.captured(1); int check_state = match.captured(2).toInt(); QModelIndex index = pqAbstractItemViewEventPlayerBase::GetIndex(strIndex, abstractItemView, error); if (error) { return true; } if (abstractItemView->model()->data(index, Qt::CheckStateRole).toInt() != check_state) { abstractItemView->model()->setData( index, static_cast(check_state), Qt::CheckStateRole); } return true; } else if (command == "edit") { QString strIndex = arguments; QModelIndex index = pqAbstractItemViewEventPlayerBase::GetIndex(strIndex, abstractItemView, error); if (error) { return true; } abstractItemView->edit(index); return true; } else if (command == "doubleClick") { QString strIndex = arguments; QModelIndex index = pqAbstractItemViewEventPlayerBase::GetIndex(strIndex, abstractItemView, error); if (error) { return true; } abstractItemView->doubleClicked(index); return true; } else if (command == "editCancel") { QString strIndex = arguments; QModelIndex index = pqAbstractItemViewEventPlayerBase::GetIndex(strIndex, abstractItemView, error); abstractItemView->closePersistentEditor(index); return true; } else if (command == "editAccepted") { QStringList list = arguments.split(','); QModelIndex index = pqAbstractItemViewEventPlayerBase::GetIndex(list.at(0), abstractItemView, error); QVariant value = QVariant(list.at(1)); abstractItemView->model()->setData(index, value); abstractItemView->closePersistentEditor(index); return true; } else if (command == "setCurrent" || command == "activate") { QString strIndex = arguments; QModelIndex index = pqAbstractItemViewEventPlayerBase::GetIndex(strIndex, abstractItemView, error); if (error) { return true; } abstractItemView->setFocus(); abstractItemView->setCurrentIndex(index); // The following code will cause a modal dialog to close, // such as the pqColorPresetDialog, if the abstractItemView widget is not handling the key // event, // the key event will bevpropogated to the abstractItemView's parent, in this case the dialog, // and the dialog be default has OK/Cancel button in focus, and will process the key event, // close itself. This is causing a few a paraview's tests using pqColorPresetDialog to fail. // The fix here (above) is to add "abstractItemView->setFocus();" so that the // "abstractItemView->setCurrentIndex(index);" will trigger selection changed event in // abstractItemView, // which is the purpose of the following code. /* QKeyEvent kd(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); QKeyEvent ku(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier); QCoreApplication::sendEvent(abstractItemView, &kd); QCoreApplication::sendEvent(abstractItemView, &ku); */ return true; } else if (command == "setSelection") { QString strIndexList = arguments; QStringList indexList = strIndexList.split(','); QItemSelectionModel* selModel = abstractItemView->selectionModel(); // selection doesn't work as expected if we don't respect row/col selection. QItemSelectionModel::SelectionFlags selFlag = QItemSelectionModel::SelectCurrent; if (abstractItemView->selectionBehavior() == QAbstractItemView::SelectRows) { selFlag |= QItemSelectionModel::Rows; } else if (abstractItemView->selectionBehavior() == QAbstractItemView::SelectColumns) { selFlag |= QItemSelectionModel::Columns; } // shouldn't have to check selectionMode - single or multi enforced when recorded. auto selMode = abstractItemView->selectionMode(); if (QAbstractItemView::NoSelection == selMode) { qCritical() << "ERROR: Multi-select on ItemView with no-select mode :" << selMode; return true; } if (strIndexList.isEmpty()) { abstractItemView->clearSelection(); return true; } QModelIndex topLeft, bottomRight; QItemSelection selection; // don't reset the selection - setCurrent does that, and is always recorded first. for (int i = 0; i < indexList.size(); i += 2) { // ranges are recorded in pairs, topLeft -> bottomRight, but to a flat list for // simplicity. topLeft = pqAbstractItemViewEventPlayerBase::GetIndex(indexList.at(i), abstractItemView, error); bottomRight = pqAbstractItemViewEventPlayerBase::GetIndex(indexList.at(i + 1), abstractItemView, error); if (error) { return true; } QItemSelection itemSel(topLeft, bottomRight); // merge allows a single selection to contain multiple ranges. selection.merge(itemSel, QItemSelectionModel::Select); } selModel->select(selection, selFlag); return true; } else if (command == "openContextMenu") { const QModelIndex index = pqAbstractItemViewEventPlayerBase::GetIndex(arguments, abstractItemView, error); if (error) { return true; } const QRect itemRect = abstractItemView->visualRect(index); const QPoint centerOfItem = itemRect.topLeft(); const QPoint globalCenterOfItem = abstractItemView->viewport()->mapToGlobal(centerOfItem); QContextMenuEvent contextMenuEvent( QContextMenuEvent::Other, centerOfItem, globalCenterOfItem); if (!qApp->notify(abstractItemView->viewport(), &contextMenuEvent)) { qCritical() << "The " << abstractItemView->objectName() << " rejected the context menu event"; error = true; } return true; } } else if (eventType == pqEventTypes::CHECK_EVENT) { if (command == "modelItemData") { // Recover index to check QString itemString = arguments; QModelIndex index = pqAbstractItemViewEventPlayerBase::GetIndex(itemString, abstractItemView, error); if (error) { return true; } // Recover Data to check QString testDataString = pqAbstractItemViewEventPlayerBase::GetDataString(itemString, error); if (error) { return true; } // Recover current data, replacing tab by space as they are not existing in xml QString currentDataString = index.data().toString(); currentDataString.replace("\t", " "); // Compare strings if (currentDataString != testDataString) { qCritical() << "ERROR: Checked item contain :" << index.data().toString() << ".Expecting :" << testDataString; error = true; } return true; } else if (command == "modelRowCount") { if (abstractItemView->model()->rowCount() != arguments.toInt()) { qCritical() << "ERROR: Checked abstract item view has " << abstractItemView->model()->rowCount() << " rows. Expecting :" << arguments; error = true; } return true; } } return this->Superclass::playEvent(object, command, arguments, eventType, error); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractItemViewEventPlayerBase.h000066400000000000000000000027021526070500000302550ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef __pqAbstractItemViewEventPlayerBase_h #define __pqAbstractItemViewEventPlayerBase_h #include "pqWidgetEventPlayer.h" #include class QAbstractItemView; /// pqAbstractItemViewEventPlayerBase is a player for QAbstractItemViewWidget. Plays back the state /// recorded using pQAbstractItemViewEventTranslatorBase. class QTTESTING_EXPORT pqAbstractItemViewEventPlayerBase : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pqAbstractItemViewEventPlayerBase(QObject* parent = 0); ~pqAbstractItemViewEventPlayerBase() override = 0; /// Play an event on a QAbstractViewItem using Superclass::playEvent; bool playEvent(QObject* object, const QString& command, const QString& arguments, int eventType, bool& error) override; protected: /// Get index using a previously recorded string static QModelIndex GetIndex( const QString& str_index, QAbstractItemView* abstractItemView, bool& error); /// Get data string using a previously recorded string static QString GetDataString(const QString& str_index, bool& error); private: pqAbstractItemViewEventPlayerBase(const pqAbstractItemViewEventPlayerBase&); // Not implemented. void operator=(const pqAbstractItemViewEventPlayerBase&); // Not implemented. }; #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractItemViewEventTranslator.cxx000066400000000000000000000111161526070500000307310ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqAbstractItemViewEventTranslator.h" #include #include #include #include static QString toIndexStr(QModelIndex index) { QString result; for (QModelIndex i = index; i.isValid(); i = i.parent()) { result = "/" + QString("%1:%2").arg(i.row()).arg(i.column()) + result; } return result; } pqAbstractItemViewEventTranslator::pqAbstractItemViewEventTranslator(QObject* p) : pqWidgetEventTranslator(p) { } bool pqAbstractItemViewEventTranslator::translateEvent(QObject* Object, QEvent* Event, bool& Error) { QAbstractItemView* object = qobject_cast(Object); if (!object) { // mouse events go to the viewport widget object = qobject_cast(Object->parent()); } if (!object) { return false; } // Don't try to record events for QComboBox implementation details if (object->inherits("QComboBoxListView")) { return false; } switch (Event->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: { QKeyEvent* ke = static_cast(Event); QString data = QString("%1,%2,%3,%4,%5,%6") .arg(ke->type()) .arg(ke->key()) .arg(static_cast(ke->modifiers())) .arg(ke->text()) .arg(ke->isAutoRepeat()) .arg(ke->count()); Q_EMIT recordEvent(object, "keyEvent", data); return true; } case QEvent::MouseButtonPress: case QEvent::MouseButtonDblClick: case QEvent::MouseButtonRelease: { if (Object == object) { return false; } QMouseEvent* mouseEvent = static_cast(Event); if (Event->type() != QEvent::MouseButtonRelease) { this->LastPos = mouseEvent->pos(); } QString idxStr; QPoint relPt = QPoint(0, 0); QHeaderView* header = qobject_cast(object); if (header) { int idx = header->logicalIndexAt(mouseEvent->pos()); idxStr = QString("%1").arg(idx); } else { QModelIndex idx = object->indexAt(mouseEvent->pos()); idxStr = toIndexStr(idx); QRect r = object->visualRect(idx); relPt = mouseEvent->pos() - r.topLeft(); } QString info = QString("%1,%2,%3,%4,%5,%6") .arg(mouseEvent->button()) .arg(static_cast(mouseEvent->buttons())) .arg(static_cast(mouseEvent->modifiers())) .arg(relPt.x()) .arg(relPt.y()) .arg(idxStr); if (Event->type() == QEvent::MouseButtonPress) { Q_EMIT recordEvent(object, "mousePress", info); } else if (Event->type() == QEvent::MouseButtonDblClick) { Q_EMIT recordEvent(object, "mouseDblClick", info); } else if (Event->type() == QEvent::MouseButtonRelease) { if (this->LastPos != mouseEvent->pos()) { Q_EMIT recordEvent(object, "mouseMove", info); } Q_EMIT recordEvent(object, "mouseRelease", info); } return true; break; } case QEvent::Wheel: { if (Object == object) { return false; } QPoint relPt = QPoint(0, 0); QWheelEvent* wheelEvent = dynamic_cast(Event); if (wheelEvent) { QString idxStr; #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QModelIndex idx = object->indexAt(wheelEvent->position().toPoint()); #else QModelIndex idx = object->indexAt(wheelEvent->pos()); #endif idxStr = toIndexStr(idx); QRect r = object->visualRect(idx); #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) relPt = wheelEvent->position().toPoint() - r.topLeft(); #else relPt = wheelEvent->pos() - r.topLeft(); #endif int numStep = wheelEvent->angleDelta().y() > 0 ? 120 : -120; int buttons = wheelEvent->buttons(); int modifiers = wheelEvent->modifiers(); Q_EMIT recordEvent(Object, "mouseWheel", QString("%1,%2,%3,%4,%5") .arg(numStep) .arg(buttons) .arg(modifiers) .arg(relPt.x()) .arg(relPt.y()) .arg(idxStr)); } return true; break; } default: { break; } } return this->Superclass::translateEvent(Object, Event, Error); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractItemViewEventTranslator.h000066400000000000000000000017731526070500000303660ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqAbstractItemViewEventTranslator_h #define _pqAbstractItemViewEventTranslator_h #include "pqWidgetEventTranslator.h" #include /** Translates low-level Qt events into high-level ParaView events that can be recorded as test cases. \sa pqEventTranslator */ class QTTESTING_EXPORT pqAbstractItemViewEventTranslator : public pqWidgetEventTranslator { Q_OBJECT typedef pqWidgetEventTranslator Superclass; public: pqAbstractItemViewEventTranslator(QObject* p = 0); using Superclass::translateEvent; bool translateEvent(QObject* Object, QEvent* Event, bool& Error) override; protected: QPoint LastPos; private: pqAbstractItemViewEventTranslator(const pqAbstractItemViewEventTranslator&); pqAbstractItemViewEventTranslator& operator=(const pqAbstractItemViewEventTranslator&); }; #endif // !_pqAbstractItemViewEventTranslator_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractItemViewEventTranslatorBase.cxx000066400000000000000000000267401526070500000315350ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqAbstractItemViewEventTranslatorBase.h" #include "pqEventTypes.h" #include #include #include #include #include #include //----------------------------------------------------------------------------- pqAbstractItemViewEventTranslatorBase::pqAbstractItemViewEventTranslatorBase(QObject* parentObject) : Superclass(parentObject) { this->Editing = false; this->AbstractItemView = NULL; this->AbstractItemViewMouseTracking = false; this->Checking = false; } //----------------------------------------------------------------------------- pqAbstractItemViewEventTranslatorBase::~pqAbstractItemViewEventTranslatorBase() { if (this->AbstractItemView != NULL) { this->AbstractItemView->setMouseTracking(this->AbstractItemViewMouseTracking); } } //----------------------------------------------------------------------------- bool pqAbstractItemViewEventTranslatorBase::translateEvent( QObject* object, QEvent* event, int eventType, bool& error) { // Recover corrected abstract item view QAbstractItemView* abstractItemView = this->findCorrectedAbstractItemView(object); if (!abstractItemView) { return false; } // Don't try to record events for QComboBox implementation details if (abstractItemView->inherits("QComboBoxListView")) { return false; } if (eventType == pqEventTypes::ACTION_EVENT) { switch (event->type()) { case QEvent::KeyRelease: { QKeyEvent* ke = static_cast(event); QModelIndex index = abstractItemView->currentIndex(); QString indexString = this->getIndexAsString(index); if (this->Editing) { if (ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return) { QVariant value = abstractItemView->model()->data(index); this->Editing = false; Q_EMIT this->recordEvent(abstractItemView, "editAccepted", QString("%1,%2").arg(indexString, value.toString())); return true; break; } if (ke->key() == Qt::Key_Escape) { this->Editing = false; Q_EMIT this->recordEvent(abstractItemView, "editCancel", indexString); return true; break; } } else if (ke->key() == Qt::Key_F2) { this->Editing = true; Q_EMIT this->recordEvent(abstractItemView, "edit", indexString); return true; break; } break; } case QEvent::Enter: { if (this->Checking) { // If we entered before in check mode, then we need to reset cached view pointer. this->Checking = false; this->AbstractItemView = nullptr; } this->monitorSignals(abstractItemView); return true; break; } case QEvent::ContextMenu: { auto contextMenuEvent = dynamic_cast(event); Q_EMIT this->recordEvent(abstractItemView, "openContextMenu", this->getIndexAsString(abstractItemView->indexAt(contextMenuEvent->pos()))); return true; } default: { break; } } } else if (eventType == pqEventTypes::CHECK_EVENT) { if (event->type() == QEvent::MouseMove) { // Entering while checking if (this->AbstractItemView != abstractItemView || !this->Checking) { // Checking flag this->Checking = true; // Disconnect precedently check item view if (this->AbstractItemView != NULL) { this->AbstractItemView->setMouseTracking(this->AbstractItemViewMouseTracking); QObject::disconnect(this->AbstractItemView, SIGNAL(entered(const QModelIndex&)), this, SLOT(onEnteredCheck(const QModelIndex&))); QObject::disconnect(this->AbstractItemView, SIGNAL(viewportEntered()), this, SLOT(onViewportEnteredCheck())); } // Keep track of checked item view this->AbstractItemView = abstractItemView; // Set mouse tracking so entered item signal are emitted this->AbstractItemViewMouseTracking = this->AbstractItemView->hasMouseTracking(); this->AbstractItemView->setMouseTracking(true); // Connect item entered event to the entered check slot QObject::connect(this->AbstractItemView, SIGNAL(entered(const QModelIndex&)), this, SLOT(onEnteredCheck(const QModelIndex&))); QObject::connect( this->AbstractItemView, SIGNAL(viewportEntered()), this, SLOT(onViewportEnteredCheck())); } return true; } // Clicking while checking, actual check event if (event->type() == QEvent::MouseButtonRelease) { // Item Check if (this->ModelItemCheck.isValid()) { QString indexString = this->getIndexAsString(this->ModelItemCheck); Q_EMIT this->recordEvent(abstractItemView, "modelItemData", QString("%1,%2") .arg(indexString) .arg( // Replacing tab by space, as they are not valid in xml this->ModelItemCheck.data().toString().replace("\t", " ")), pqEventTypes::CHECK_EVENT); } // Abstract Item View nb row check else { Q_EMIT this->recordEvent(abstractItemView, "modelRowCount", QString::number(abstractItemView->model()->rowCount()), pqEventTypes::CHECK_EVENT); } return true; } } return this->Superclass::translateEvent(object, event, eventType, error); } //----------------------------------------------------------------------------- void pqAbstractItemViewEventTranslatorBase::monitorSignals(QAbstractItemView* abstractItemView) { if (abstractItemView != this->AbstractItemView) { if (this->AbstractItemView) { this->AbstractItemView->disconnect(this); } QObject::connect(abstractItemView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(onClicked(const QModelIndex&))); QObject::connect(abstractItemView, SIGNAL(activated(const QModelIndex&)), this, SLOT(onActivated(const QModelIndex&))); QObject::connect(abstractItemView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(onDoubleClicked(const QModelIndex&))); monitorSignalsInternal(abstractItemView); this->AbstractItemView = abstractItemView; } // If no model has been set yet, there will be no selectionModel auto selectionModel = abstractItemView->selectionModel(); if (selectionModel) { if (selectionModel != this->ItemSelectionModel) { if (this->ItemSelectionModel) { this->ItemSelectionModel->disconnect(this); } this->ItemSelectionModel = selectionModel; QObject::connect(selectionModel, SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(onCurrentChanged(const QModelIndex&))); QObject::connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(onSelectionChanged(const QItemSelection&))); } } } //----------------------------------------------------------------------------- void pqAbstractItemViewEventTranslatorBase::onClicked(const QModelIndex& index) { static QModelIndex oldIndex; QAbstractItemView* abstractItemView = qobject_cast(this->sender()); QString indexString = this->getIndexAsString(index); if ((index.model()->flags(index) & Qt::ItemIsUserCheckable) != 0) { // record the check state change if the item is user-checkable. Q_EMIT this->recordEvent(abstractItemView, "setCheckState", QString("%1,%3") .arg(indexString) .arg(index.model()->data(index, Qt::CheckStateRole).toInt())); } if ((abstractItemView->editTriggers() & QAbstractItemView::SelectedClicked) == QAbstractItemView::SelectedClicked && index == oldIndex) { this->Editing = true; Q_EMIT this->recordEvent(abstractItemView, "edit", indexString); } oldIndex = index; } //----------------------------------------------------------------------------- void pqAbstractItemViewEventTranslatorBase::onActivated(const QModelIndex& index) { QAbstractItemView* abstractItemView = qobject_cast(this->sender()); QString indexString = this->getIndexAsString(index); Q_EMIT this->recordEvent(abstractItemView, "activate", indexString); } //----------------------------------------------------------------------------- void pqAbstractItemViewEventTranslatorBase::onDoubleClicked(const QModelIndex& index) { QAbstractItemView* abstractItemView = qobject_cast(this->sender()); QString indexString = this->getIndexAsString(index); if ((abstractItemView->editTriggers() & QAbstractItemView::DoubleClicked) == QAbstractItemView::DoubleClicked) { this->Editing = true; Q_EMIT this->recordEvent(abstractItemView, "doubleClick", indexString); Q_EMIT this->recordEvent(abstractItemView, "edit", indexString); } } //----------------------------------------------------------------------------- QString pqAbstractItemViewEventTranslatorBase::getIndexAsString(const QModelIndex& index) { QString indexString; for (QModelIndex curIndex = index; curIndex.isValid(); curIndex = curIndex.parent()) { indexString.prepend(QString("%1.%2.").arg(curIndex.row()).arg(curIndex.column())); } // remove the last ".". indexString.chop(1); return indexString; } QString pqAbstractItemViewEventTranslatorBase::getIndicesAsString( const QModelIndexList& selectedIndices) { QString listString; for (QModelIndex idx : selectedIndices) { listString.append(QString("%1,").arg(this->getIndexAsString(idx))); } // remove the last ",". listString.chop(1); return listString; } //----------------------------------------------------------------------------- void pqAbstractItemViewEventTranslatorBase::onCurrentChanged(const QModelIndex& index) { Q_EMIT this->recordEvent(this->AbstractItemView, "setCurrent", this->getIndexAsString(index)); } //----------------------------------------------------------------------------- void pqAbstractItemViewEventTranslatorBase::onSelectionChanged(const QItemSelection& selected) { Q_UNUSED(selected); // see if the view supports multi-select auto selMode = this->AbstractItemView->selectionMode(); if (!(QAbstractItemView::SingleSelection == selMode || QAbstractItemView::NoSelection == selMode)) { // selected and deselected args build on current selection. Retrieve the total selection instead QItemSelectionModel* selModel = qobject_cast(this->sender()); QModelIndexList selectedIndices; QItemSelection selection = selModel->selection(); // selections are a list of disjoint ranges, record the bounds of each. // this works better for playback than recording all the selected indexes. for (QItemSelectionRange selRange : selection) { selectedIndices.push_back(selRange.topLeft()); selectedIndices.push_back(selRange.bottomRight()); } Q_EMIT this->recordEvent( this->AbstractItemView, "setSelection", this->getIndicesAsString(selectedIndices)); } } //----------------------------------------------------------------------------- void pqAbstractItemViewEventTranslatorBase::onViewportEnteredCheck() { this->ModelItemCheck = QPersistentModelIndex(); Q_EMIT this->specificOverlay(this->AbstractItemView->rect()); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractItemViewEventTranslatorBase.h000066400000000000000000000052301526070500000311510ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef __pqAbstractItemViewEventTranslatorBase_h #define __pqAbstractItemViewEventTranslatorBase_h #include "pqWidgetEventTranslator.h" #include // for QModelIndexList #include #include class QModelIndex; class QAbstractItemView; class QItemSelection; class QItemSelectionModel; /// Event recorder for QAbstractItemView. Records the toggling of the check states for /// tree widget items. The recorded state can be played back using /// pqTreeViewEventPlayer. class QTTESTING_EXPORT pqAbstractItemViewEventTranslatorBase : public pqWidgetEventTranslator { Q_OBJECT typedef pqWidgetEventTranslator Superclass; public: pqAbstractItemViewEventTranslatorBase(QObject* parent = 0); ~pqAbstractItemViewEventTranslatorBase() override; /// Overridden to handle events on QAbstractItemView using pqWidgetEventTranslator::translateEvent; bool translateEvent(QObject* object, QEvent* event, int eventType, bool& error) override; /// find and set the corrected abstract item view virtual QAbstractItemView* findCorrectedAbstractItemView(QObject* object) const = 0; protected Q_SLOTS: virtual void onClicked(const QModelIndex&); virtual void onActivated(const QModelIndex&); virtual void onDoubleClicked(const QModelIndex&); virtual void onCurrentChanged(const QModelIndex&); virtual void onSelectionChanged(const QItemSelection&); /// Compute a visual rectangle for the item and signal it virtual void onEnteredCheck(const QModelIndex&) = 0; virtual void onViewportEnteredCheck(); protected: QString getIndexAsString(const QModelIndex& item); QString getIndicesAsString(const QModelIndexList& selectedIndices); /// Record events from @a abstractItemView when signals are fired. /// @sa monitorSignalsInternal() void monitorSignals(QAbstractItemView* abstractItemView); /// Subclasses (pqTreeViewEventTranslator, possibly others) override this to monitor /// additional view specific signals virtual void monitorSignalsInternal(QAbstractItemView* abstractItemView) { Q_UNUSED(abstractItemView); } QPointer AbstractItemView; QPointer ItemSelectionModel; QPersistentModelIndex ModelItemCheck; bool Editing; bool AbstractItemViewMouseTracking; bool Checking; QPoint LastPos; private: pqAbstractItemViewEventTranslatorBase( const pqAbstractItemViewEventTranslatorBase&); // Not implemented. void operator=(const pqAbstractItemViewEventTranslatorBase&); // Not implemented. }; #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractMiscellaneousEventPlayer.cxx000066400000000000000000000031621526070500000311100ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqAbstractMiscellaneousEventPlayer.h" #include #include #include #include #include "pqEventDispatcher.h" #include "pqTestUtility.h" // Class that encapsulates the protected function QThread::msleep class SleeperThread : public QThread { public: // Allows for cross platform sleep function static bool msleep(unsigned long msecs) { QThread::msleep(msecs); return true; } }; pqAbstractMiscellaneousEventPlayer::pqAbstractMiscellaneousEventPlayer( pqTestUtility* util, QObject* p) : pqWidgetEventPlayer(p) , TestUtility(util) { } // Allows for execution of testing commands that don't merit their own class bool pqAbstractMiscellaneousEventPlayer::playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) { if (Command == "pause") { const int value = Arguments.toInt(); if (SleeperThread::msleep(value)) { return true; } Error = true; qCritical() << "calling pause on unhandled type " << Object; } if (Command == "process_events") { bool valid = false; const int ms = Arguments.toInt(&valid); if (valid) { pqEventDispatcher::processEventsAndWait(ms); } else { pqEventDispatcher::processEvents(); } return true; } if (Command == "dashboard_mode") { bool toggle = QVariant(Arguments).toBool(); this->TestUtility->setDashboardMode(toggle); return true; } return false; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractMiscellaneousEventPlayer.h000066400000000000000000000036011526070500000305330ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqAbstractMiscellaneousEventPlayer_h #define _pqAbstractMiscellaneousEventPlayer_h #include "pqWidgetEventPlayer.h" class pqTestUtility; /// Event playback handler for a collection of miscellaneous commands. /// For these events, the "object" on which the event is triggered is generally /// immaterial. /// /// Supported commands are: /// \li \c pause : pause the application for a fixed time. Time is specified as /// the arguments in milliseconds to pause the application for. /// This is a sleep i.e. no events will be processed and the /// application will appear frozen. /// \li \c process_events: process pending events (including timers, etc.). /// Optional time (in milliseconds) may be specified to also pause /// the test playback. Unlike "pause" however, this will continue /// to process all events arising in the application e.g. /// responding to timer events. /// \li \c dashboard_mode: trigger a call to pqTestUtility::setDashboardMode with the /// provided argument. class QTTESTING_EXPORT pqAbstractMiscellaneousEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pqAbstractMiscellaneousEventPlayer(pqTestUtility* util, QObject* p = 0); using Superclass::playEvent; bool playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) override; private: pqAbstractMiscellaneousEventPlayer(const pqAbstractMiscellaneousEventPlayer&); pqAbstractMiscellaneousEventPlayer& operator=(const pqAbstractMiscellaneousEventPlayer&); pqTestUtility* TestUtility = nullptr; }; #endif // !_pqAbstractMiscellaneousEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractSliderEventTranslator.cxx000066400000000000000000000023071526070500000304240ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqAbstractSliderEventTranslator.h" #include #include #include pqAbstractSliderEventTranslator::pqAbstractSliderEventTranslator(QObject* p) : pqWidgetEventTranslator(p) , CurrentObject(0) { } bool pqAbstractSliderEventTranslator::translateEvent(QObject* Object, QEvent* Event, bool& Error) { QAbstractSlider* const object = qobject_cast(Object); if (!object || qobject_cast(object)) return false; switch (Event->type()) { case QEvent::Enter: this->CurrentObject = Object; connect(object, SIGNAL(valueChanged(int)), this, SLOT(onValueChanged(int))); return true; break; case QEvent::Leave: disconnect(Object, 0, this, 0); this->CurrentObject = 0; return true; break; default: break; } return this->Superclass::translateEvent(Object, Event, Error); } void pqAbstractSliderEventTranslator::onValueChanged(int Value) { Q_EMIT recordEvent(this->CurrentObject, "set_int", QString().setNum(Value)); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractSliderEventTranslator.h000066400000000000000000000020021526070500000300410ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqAbstractSliderEventTranslator_h #define _pqAbstractSliderEventTranslator_h #include "pqWidgetEventTranslator.h" /** Translates low-level Qt events into high-level ParaView events that can be recorded as test cases. \sa pqEventTranslator */ class QTTESTING_EXPORT pqAbstractSliderEventTranslator : public pqWidgetEventTranslator { Q_OBJECT typedef pqWidgetEventTranslator Superclass; public: pqAbstractSliderEventTranslator(QObject* p = 0); using Superclass::translateEvent; bool translateEvent(QObject* Object, QEvent* Event, bool& Error) override; private: pqAbstractSliderEventTranslator(const pqAbstractSliderEventTranslator&); pqAbstractSliderEventTranslator& operator=(const pqAbstractSliderEventTranslator&); QObject* CurrentObject; private Q_SLOTS: void onValueChanged(int); }; #endif // !_pqAbstractSliderEventTranslator_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractStringEventPlayer.cxx000066400000000000000000000037001526070500000275510ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqAbstractStringEventPlayer.h" #include #include #include #include #include #include #include "pqObjectNaming.h" pqAbstractStringEventPlayer::pqAbstractStringEventPlayer(QObject* p) : pqWidgetEventPlayer(p) { } bool pqAbstractStringEventPlayer::playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) { if (Command != "set_string") return false; const QString value = Arguments; if (QComboBox* const comboBox = qobject_cast(Object)) { int index = comboBox->findText(value); if (index != -1) { comboBox->setCurrentIndex(index); } else { QString possibles; for (int i = 0; i < comboBox->count(); i++) { possibles += QString("\t") + comboBox->itemText(i) + QString("\n"); } qCritical() << "Unable to find " << value << " in combo box: " << pqObjectNaming::GetName(*Object) << "\nPossible values are:\n" << possibles; Error = true; } return true; } if (QLineEdit* const lineEdit = qobject_cast(Object)) { lineEdit->setText(value); return true; } if (QTextEdit* const textEdit = qobject_cast(Object)) { textEdit->setFocus(Qt::OtherFocusReason); textEdit->document()->setPlainText(value); textEdit->clearFocus(); return true; } if (QPlainTextEdit* const plainTextEdit = qobject_cast(Object)) { plainTextEdit->setFocus(Qt::OtherFocusReason); plainTextEdit->document()->setPlainText(value); plainTextEdit->clearFocus(); return true; } qCritical() << "calling set_string on unhandled type " << Object; Error = true; return true; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqAbstractStringEventPlayer.h000066400000000000000000000017211526070500000271770ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqAbstractStringEventPlayer_h #define _pqAbstractStringEventPlayer_h #include "QtTestingExport.h" #include "pqWidgetEventPlayer.h" /** Concrete implementation of pqWidgetEventPlayer that translates high-level ParaView events into low-level Qt events. \sa pqEventPlayer */ class QTTESTING_EXPORT pqAbstractStringEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pqAbstractStringEventPlayer(QObject* p = 0); using Superclass::playEvent; bool playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) override; private: pqAbstractStringEventPlayer(const pqAbstractStringEventPlayer&); pqAbstractStringEventPlayer& operator=(const pqAbstractStringEventPlayer&); }; #endif // !_pqAbstractStringEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqBasicWidgetEventPlayer.cxx000066400000000000000000000056601526070500000270130ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqBasicWidgetEventPlayer.h" #include #include #include // ---------------------------------------------------------------------------- pqBasicWidgetEventPlayer::pqBasicWidgetEventPlayer(QObject* parent) : pqWidgetEventPlayer(parent) { } // ---------------------------------------------------------------------------- bool pqBasicWidgetEventPlayer::playEvent( QObject* object, const QString& command, const QString& arguments, bool& error) { QWidget* widget = qobject_cast(object); if (widget) { if (command == "key") { QKeyEvent kd(QEvent::KeyPress, arguments.toInt(), Qt::NoModifier); QKeyEvent ku(QEvent::KeyRelease, arguments.toInt(), Qt::NoModifier); qApp->notify(widget, &kd); qApp->notify(widget, &ku); return true; } else if (command == "keyEvent") { // The double split is for retrocompatibility QStringList data = arguments.split(','); if (data.size() != 6) { data = arguments.split(':'); } if (data.size() == 6) { QKeyEvent ke(static_cast(data[0].toInt()), data[1].toInt(), static_cast(data[2].toInt()), data[3], !!data[4].toInt(), data[5].toInt()); qApp->notify(widget, &ke); return true; } } else if (command.startsWith("mouse")) { QStringList args = arguments.split(','); if (args.size() == 5) { Qt::MouseButtons buttons = static_cast(args[1].toInt()); Qt::KeyboardModifiers keym = static_cast(args[2].toInt()); int x = args[3].toInt(); int y = args[4].toInt(); QPoint pt(x, y); if (command == "mouseWheel") { int delta = args[0].toInt(); QWheelEvent we(QPoint(x, y), QPoint(x, y), QPoint(0, 0), QPoint(0, delta), buttons, keym, Qt::NoScrollPhase, false); QCoreApplication::sendEvent(object, &we); return true; } Qt::MouseButton button = static_cast(args[0].toInt()); QEvent::Type type = QEvent::MouseButtonPress; type = command == "mouseMove" ? QEvent::MouseMove : type; type = command == "mouseRelease" ? QEvent::MouseButtonRelease : type; type = command == "mouseDblClick" ? QEvent::MouseButtonDblClick : type; if (type == QEvent::MouseMove) { // We have not been setting mouse move correctly. buttons = button; button = Qt::NoButton; } QMouseEvent e(type, pt, widget->mapToGlobal(pt), button, buttons, keym); qApp->notify(widget, &e); return true; } } } return this->Superclass::playEvent(object, command, arguments, error); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqBasicWidgetEventPlayer.h000066400000000000000000000015161526070500000264340ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqBasicWidgetEventPlayer_h #define _pqBasicWidgetEventPlayer_h #include "pqWidgetEventPlayer.h" /** * EventPlayer for QWidget to handles mouse and keyboard inputs. */ class pqBasicWidgetEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pqBasicWidgetEventPlayer(QObject* parent = nullptr); using Superclass::playEvent; bool playEvent( QObject* object, const QString& command, const QString& arguments, bool& error) override; private: pqBasicWidgetEventPlayer(const pqBasicWidgetEventPlayer&); pqBasicWidgetEventPlayer& operator=(const pqBasicWidgetEventPlayer&); }; #endif // !_pqBasicWidgetEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqBasicWidgetEventTranslator.cxx000066400000000000000000000113001526070500000276740ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqBasicWidgetEventTranslator.h" #include #include #include #include #include #include #include "pqEventTypes.h" pqBasicWidgetEventTranslator::pqBasicWidgetEventTranslator(QObject* p) : pqWidgetEventTranslator(p) { } pqBasicWidgetEventTranslator::~pqBasicWidgetEventTranslator() {} bool pqBasicWidgetEventTranslator::translateEvent( QObject* object, QEvent* event, int eventType, bool& error) { QWidget* widget = qobject_cast(object); if (!widget) return false; if (eventType == pqEventTypes::ACTION_EVENT) { switch (event->type()) { case QEvent::KeyPress: { QKeyEvent* keyEvent = static_cast(event); if (qobject_cast(object)) { Q_EMIT recordEvent(widget, "key", QString::number(keyEvent->key())); } return true; break; } case QEvent::MouseButtonPress: case QEvent::MouseButtonDblClick: case QEvent::MouseButtonRelease: { QMouseEvent* mouseEvent = static_cast(event); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) auto pos = mouseEvent->pos(); #else auto pos = mouseEvent->position().toPoint(); #endif QString info = QString("%1,%2,%3,%4,%5") .arg(mouseEvent->button()) .arg(static_cast(mouseEvent->buttons())) .arg(static_cast(mouseEvent->modifiers())) .arg(pos.x()) .arg(pos.y()); if (event->type() != QEvent::MouseButtonRelease) { this->LastPos = mouseEvent->pos(); } if (event->type() == QEvent::MouseButtonPress) { Q_EMIT recordEvent(widget, "mousePress", info); } if (event->type() == QEvent::MouseButtonDblClick) { Q_EMIT recordEvent(widget, "mouseDblClick", info); } else if (event->type() == QEvent::MouseButtonRelease) { if (this->LastPos != mouseEvent->pos()) { Q_EMIT recordEvent(widget, "mouseMove", info); } Q_EMIT recordEvent(widget, "mouseRelease", info); } return true; break; } case QEvent::Wheel: { if (qobject_cast(object)) { QWheelEvent* wheelEvent = dynamic_cast(event); if (wheelEvent) { int buttons = wheelEvent->buttons(); int modifiers = wheelEvent->modifiers(); int numStep = wheelEvent->angleDelta().y(); Q_EMIT recordEvent(object, "mouseWheel", QString("%1,%2,%3,%4,%5") .arg(numStep) .arg(buttons) .arg(modifiers) #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) .arg(wheelEvent->position().x()) .arg(wheelEvent->position().y())); #else .arg(wheelEvent->x()) .arg(wheelEvent->y())); #endif } } return true; break; } default: break; } } else if (eventType == pqEventTypes::CHECK_EVENT) { if (event->type() == QEvent::MouseMove) { // Check for available meta prop QMetaProperty metaProp = widget->metaObject()->userProperty(); if (!metaProp.isValid() && qobject_cast(widget->parent()) != NULL) { // MouseEvent can be received by the viewport metaProp = widget->parent()->metaObject()->userProperty(); } if (metaProp.isValid()) { return true; } } // Clicking while checking, actual check event if (event->type() == QEvent::MouseButtonRelease) { // Generic Meta prop check QMetaProperty metaProp = widget->metaObject()->userProperty(); if (!metaProp.isValid() && widget->parent() != NULL) { // MouseEvent can be received by the viewport, so try the parent widget metaProp = widget->parent()->metaObject()->userProperty(); widget = qobject_cast(widget->parent()); } if (metaProp.isValid() && widget) { // Recover meto prop name QString propName = metaProp.name(); // Record check event Q_EMIT recordEvent(widget, propName, widget->property(propName.toUtf8().data()).toString().replace("\t", " "), pqEventTypes::CHECK_EVENT); return true; } } } return this->Superclass::translateEvent(object, event, eventType, error); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqBasicWidgetEventTranslator.h000066400000000000000000000020361526070500000273270ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqBasicWidgetEventTranslator_h #define _pqBasicWidgetEventTranslator_h #include "pqWidgetEventTranslator.h" #include #include /** Translates low-level Qt events into high-level ParaView events that can be recorded as test cases. \sa pqEventTranslator */ class QTTESTING_EXPORT pqBasicWidgetEventTranslator : public pqWidgetEventTranslator { Q_OBJECT typedef pqWidgetEventTranslator Superclass; public: pqBasicWidgetEventTranslator(QObject* p = 0); ~pqBasicWidgetEventTranslator() override; using Superclass::translateEvent; bool translateEvent(QObject* object, QEvent* event, int eventType, bool& error) override; protected: QPoint LastPos; private: pqBasicWidgetEventTranslator(const pqBasicWidgetEventTranslator&); pqBasicWidgetEventTranslator& operator=(const pqBasicWidgetEventTranslator&); }; #endif // !_pqBasicWidgetEventTranslator_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqCheckEventOverlay.cxx000066400000000000000000000016331526070500000260240ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqCheckEventOverlay.h" #include pqCheckEventOverlay::pqCheckEventOverlay(QWidget* parent) : QWidget(parent) { setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_TransparentForMouseEvents); this->Valid = false; this->GlWidget = false; this->Specific = false; this->setObjectName("Overlay"); } void pqCheckEventOverlay::paintEvent(QPaintEvent*) { QPainter p(this); // Draw red on invalid widget QPen pen(Qt::red, pqCheckEventOverlay::OVERLAY_PEN_WIDTH); if (this->Valid) { // Draw green on valid widget pen.setColor(Qt::green); } p.setPen(pen); // Remove the margins to draw p.drawRect(0, 0, width() - pqCheckEventOverlay::OVERLAY_MARGIN, height() - pqCheckEventOverlay::OVERLAY_MARGIN); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqCheckEventOverlay.h000066400000000000000000000017041526070500000254500ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqCheckEventOverlay_h #define _pqCheckEventOverlay_h #include /** Display a green or red overlay rectangle on top of parent widget \sa pqEventTranslator */ class pqCheckEventOverlay : public QWidget { Q_OBJECT typedef QWidget Superclass; public: pqCheckEventOverlay(QWidget* parent = 0); // true if the overlayed widget can be checked, false otherwise bool Valid; // true if the overlayed widget in an opengl widget, false otherwise bool GlWidget; // true if the size of the overlay is specifically defined // via resize slot, false otherwise bool Specific; // Static overlauy margin static const int OVERLAY_MARGIN = 2; // Static overlay pen width static const int OVERLAY_PEN_WIDTH = 5; protected: void paintEvent(QPaintEvent*) override; }; #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqComboBoxEventPlayer.cxx000066400000000000000000000036471526070500000263410ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqComboBoxEventPlayer.h" #include "pqEventTypes.h" #include "pqObjectNaming.h" #include #include //----------------------------------------------------------------------------- pqComboBoxEventPlayer::pqComboBoxEventPlayer(QObject* parentObject) : Superclass(parentObject) { } //----------------------------------------------------------------------------- pqComboBoxEventPlayer::~pqComboBoxEventPlayer() {} //----------------------------------------------------------------------------- bool pqComboBoxEventPlayer::playEvent( QObject* object, const QString& command, const QString& arguments, int eventType, bool& error) { QComboBox* comboBox = qobject_cast(object); if (!comboBox) { return false; } if (eventType == pqEventTypes::ACTION_EVENT) { if (command == "activated" || command == "editTextChanged") { int index = comboBox->findText(arguments); if (index != -1) { comboBox->setCurrentIndex(index); if (command == "activated") { Q_EMIT comboBox->activated(index); } } else if (comboBox->isEditable() && command == "editTextChanged") { comboBox->setCurrentText(arguments); } else { QString possibles; for (int i = 0; i < comboBox->count(); i++) { possibles += QString("\t") + comboBox->itemText(i) + QString("\n"); } qCritical() << "Unable to find " << arguments << " in combo box: " << pqObjectNaming::GetName(*comboBox) << "\nPossible values are:\n" << possibles; error = true; } } return true; } return this->Superclass::playEvent(object, command, arguments, eventType, error); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqComboBoxEventPlayer.h000066400000000000000000000020541526070500000257550ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef __pqComboBoxEventPlayer_h #define __pqComboBoxEventPlayer_h #include "pqWidgetEventPlayer.h" /// pqComboBoxEventPlayer is a player for QComboBoxWidget. Plays back the state /// recorded using pqComboBoxEventTranslator. class QTTESTING_EXPORT pqComboBoxEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pqComboBoxEventPlayer(QObject* parent = 0); ~pqComboBoxEventPlayer() override; /// Play an event on a QComboBox using Superclass::playEvent; bool playEvent(QObject* object, const QString& command, const QString& arguments, int eventType, bool& error) override; Q_SIGNALS: // Transition signal to call combo box activated signal void activated(int index); private: pqComboBoxEventPlayer(const pqComboBoxEventPlayer&); // Not implemented. void operator=(const pqComboBoxEventPlayer&); // Not implemented. }; #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqComboBoxEventTranslator.cxx000066400000000000000000000032321526070500000272240ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqComboBoxEventTranslator.h" #include #include pqComboBoxEventTranslator::pqComboBoxEventTranslator(QObject* p) : pqWidgetEventTranslator(p) , CurrentObject(0) { } bool pqComboBoxEventTranslator::translateEvent(QObject* Object, QEvent* Event, bool& Error) { QComboBox* combo = NULL; for (QObject* test = Object; combo == NULL && test != NULL; test = test->parent()) { combo = qobject_cast(test); } if (!combo) { // not for me return false; } if (Event->type() == QEvent::Enter && Object == combo) { if (this->CurrentObject != Object) { if (this->CurrentObject) { disconnect(this->CurrentObject, 0, this, 0); } this->CurrentObject = Object; connect(combo, &QObject::destroyed, this, &pqComboBoxEventTranslator::onDestroyed); connect(combo, &QComboBox::currentTextChanged, this, &pqComboBoxEventTranslator::onActivated); connect( combo, &QComboBox::editTextChanged, this, &pqComboBoxEventTranslator::onEditTextChanged); } return true; } return this->Superclass::translateEvent(Object, Event, Error); } void pqComboBoxEventTranslator::onDestroyed(QObject* /*Object*/) { this->CurrentObject = 0; } void pqComboBoxEventTranslator::onActivated(const QString& text) { Q_EMIT recordEvent(this->CurrentObject, "activated", text); } void pqComboBoxEventTranslator::onEditTextChanged(const QString& text) { Q_EMIT recordEvent(this->CurrentObject, "editTextChanged", text); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqComboBoxEventTranslator.h000066400000000000000000000020341526070500000266500ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqComboBoxEventTranslator_h #define _pqComboBoxEventTranslator_h #include "pqWidgetEventTranslator.h" /** Translates low-level Qt events into high-level ParaView events that can be recorded as test cases. \sa pqEventTranslator */ class QTTESTING_EXPORT pqComboBoxEventTranslator : public pqWidgetEventTranslator { Q_OBJECT typedef pqWidgetEventTranslator Superclass; public: pqComboBoxEventTranslator(QObject* p = 0); using Superclass::translateEvent; bool translateEvent(QObject* Object, QEvent* Event, bool& Error) override; private: pqComboBoxEventTranslator(const pqComboBoxEventTranslator&); pqComboBoxEventTranslator& operator=(const pqComboBoxEventTranslator&); QObject* CurrentObject; private Q_SLOTS: void onDestroyed(QObject*); void onActivated(const QString&); void onEditTextChanged(const QString&); }; #endif // !_pqComboBoxEventTranslator_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqCommentEventPlayer.cxx000066400000000000000000000021231526070500000262170ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqCommentEventPlayer.h" #include // ---------------------------------------------------------------------------- pqCommentEventPlayer::pqCommentEventPlayer(pqTestUtility* testUtility, QObject* parent) : pqWidgetEventPlayer(parent) { this->TestUtility = testUtility; } // ---------------------------------------------------------------------------- pqCommentEventPlayer::~pqCommentEventPlayer() { this->TestUtility = 0; } // ---------------------------------------------------------------------------- bool pqCommentEventPlayer::playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) { Q_UNUSED(Object); Q_UNUSED(Error); if (!Command.startsWith("comment")) { return false; } if (!Arguments.isEmpty()) { Q_EMIT this->comment(Arguments); } if (Command.split("-").contains("block")) { this->TestUtility->dispatcher()->run(false); } return true; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqCommentEventPlayer.h000066400000000000000000000021341526070500000256460ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef __pqCommentEventPlayer_h #define __pqCommentEventPlayer_h // QtTesting includes #include "pqTestUtility.h" #include "pqWidgetEventPlayer.h" /// This class is a comment class. /// Do no action on Object. /// Emit comment wrote in the xml, which can be catch by someone else. class QTTESTING_EXPORT pqCommentEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pqCommentEventPlayer(pqTestUtility* testUtility, QObject* p = 0); ~pqCommentEventPlayer() override; using Superclass::playEvent; bool playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) override; Q_SIGNALS: void comment(const QString&); private: pqCommentEventPlayer(const pqCommentEventPlayer&); // Not implemented pqCommentEventPlayer& operator=(const pqCommentEventPlayer&); // Not implemented pqTestUtility* TestUtility; }; #endif // __pqCommentEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqDoubleSpinBoxEventTranslator.cxx000066400000000000000000000044521526070500000302360ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqDoubleSpinBoxEventTranslator.h" #include #include #include #include #include // ---------------------------------------------------------------------------- pqDoubleSpinBoxEventTranslator::pqDoubleSpinBoxEventTranslator(QObject* p) : pqWidgetEventTranslator(p) , CurrentObject(0) { } // ---------------------------------------------------------------------------- bool pqDoubleSpinBoxEventTranslator::translateEvent(QObject* Object, QEvent* Event, bool& Error) { QDoubleSpinBox* const object = qobject_cast(Object); // consume line edit events if part of spin box if (!object && qobject_cast(Object->parent())) { return true; } if (!object) return false; if (Event->type() == QEvent::Enter && Object == object) { if (this->CurrentObject != Object) { if (this->CurrentObject) { disconnect(this->CurrentObject, 0, this, 0); } this->CurrentObject = Object; this->Value = object->value(); connect(object, SIGNAL(valueChanged(double)), this, SLOT(onValueChanged(double))); connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(onDestroyed(QObject*))); } return true; } if (Event->type() == QEvent::KeyRelease && Object == object) { QKeyEvent* ke = static_cast(Event); QString keyText = ke->text(); if (keyText.length() && keyText.at(0).isPrint()) { Q_EMIT recordEvent(object, "set_double", QString("%1").arg(object->value())); } else { Q_EMIT recordEvent(object, "key", QString("%1").arg(ke->key())); } return true; } return this->Superclass::translateEvent(Object, Event, Error); } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslator::onDestroyed(QObject* /*Object*/) { this->CurrentObject = 0; } // ---------------------------------------------------------------------------- void pqDoubleSpinBoxEventTranslator::onValueChanged(double number) { Q_EMIT recordEvent(this->CurrentObject, "set_double", QString("%1").arg(number)); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqDoubleSpinBoxEventTranslator.h000066400000000000000000000020561526070500000276610ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqDoubleSpinBoxEventTranslator_h #define _pqDoubleSpinBoxEventTranslator_h #include "pqWidgetEventTranslator.h" /** Translates low-level Qt events into high-level ParaView events that can be recorded as test cases. \sa pqEventTranslator */ class QTTESTING_EXPORT pqDoubleSpinBoxEventTranslator : public pqWidgetEventTranslator { Q_OBJECT typedef pqWidgetEventTranslator Superclass; public: pqDoubleSpinBoxEventTranslator(QObject* p = 0); using Superclass::translateEvent; bool translateEvent(QObject* Object, QEvent* Event, bool& Error) override; private: pqDoubleSpinBoxEventTranslator(const pqDoubleSpinBoxEventTranslator&); pqDoubleSpinBoxEventTranslator& operator=(const pqDoubleSpinBoxEventTranslator&); int Value; QObject* CurrentObject; private Q_SLOTS: void onDestroyed(QObject*); void onValueChanged(double number); }; #endif // !_pqDoubleSpinBoxEventTranslator_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventComment.cxx000066400000000000000000000025311526070500000250450ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include // QtTesting includes #include "pqEventComment.h" // ---------------------------------------------------------------------------- pqEventComment::pqEventComment(pqTestUtility* util, QObject* parent) : Superclass(parent) { this->TestUtility = util; } // ---------------------------------------------------------------------------- pqEventComment::~pqEventComment() { this->TestUtility = 0; } // ---------------------------------------------------------------------------- void pqEventComment::recordComment(const QString& arguments) { this->recordComment(QString("comment"), arguments); } // ---------------------------------------------------------------------------- void pqEventComment::recordCommentBlock(const QString& arguments) { this->recordComment(QString("comment-block"), arguments); } // ---------------------------------------------------------------------------- void pqEventComment::recordComment( const QString& command, const QString& arguments, QObject* object) { if (arguments.isEmpty()) { qCritical() << "The comment is empty ! No comment has been added !"; return; } Q_EMIT this->recordComment(object, command, arguments); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventComment.h000066400000000000000000000025651526070500000245010ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef __pqEventComment_h #define __pqEventComment_h // Qt includes #include // QtTesting inlcudes #include "QtTestingExport.h" #include "pqTestUtility.h" /// pqEventComment is responsible for adding any kind of events that are not added /// by widgets. /// For exemple, you can add an event to block the playback, to show a custom /// comment etc ... class QTTESTING_EXPORT pqEventComment : public QObject { Q_OBJECT typedef QObject Superclass; public: pqEventComment(pqTestUtility* util, QObject* parent = 0); ~pqEventComment() override; /// Call this function to add an event comment, which will display a message, /// during the playback in the log. void recordComment(const QString& arguments); /// Call this function to add an event comment, which will display a message, /// and then pause the macro during the playback. void recordCommentBlock(const QString& arguments); Q_SIGNALS: /// All functions should emit this signal whenever they wish to record comment event void recordComment(QObject* widget, const QString& type, const QString& argument); protected: void recordComment(const QString& command, const QString& arguments, QObject* = 0); pqTestUtility* TestUtility; }; #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventDispatcher.cxx000066400000000000000000000262611526070500000255370ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqEventDispatcher.h" #include "pqEventPlayer.h" #include "pqEventSource.h" #include #include #include #include #include #include #include #include #include #include #include using namespace std; //----------------------------------------------------------------------------- namespace { static QList> RegisteredTimers; void processTimers() { Q_FOREACH (QTimer* timer, RegisteredTimers) { if (timer && timer->isActive()) { QTimerEvent event(timer->timerId()); qApp->notify(timer, &event); } } } static int EventPlaybackDelay = QT_TESTING_EVENT_PLAYBACK_DELAY; }; bool pqEventDispatcher::DeferMenuTimeouts = false; bool pqEventDispatcher::DeferEventsIfBlocked = false; bool pqEventDispatcher::PlayingBlockingEvent = false; //----------------------------------------------------------------------------- pqEventDispatcher::pqEventDispatcher(QObject* parentObject) : Superclass(parentObject) { this->ActiveSource = NULL; this->ActivePlayer = NULL; this->PlayBackStatus = true; this->PlayBackFinished = false; this->PlayBackPaused = false; this->PlayBackOneStep = false; this->PlayBackStoped = false; #ifdef __APPLE__ this->BlockTimer.setInterval(1000); #else this->BlockTimer.setInterval(100); #endif this->BlockTimer.setSingleShot(true); QObject::connect(&this->BlockTimer, SIGNAL(timeout()), this, SLOT(playEventOnBlocking())); } //----------------------------------------------------------------------------- pqEventDispatcher::~pqEventDispatcher() {} //----------------------------------------------------------------------------- void pqEventDispatcher::setEventPlaybackDelay(int milliseconds) { EventPlaybackDelay = (milliseconds <= 0) ? 0 : milliseconds; } //----------------------------------------------------------------------------- int pqEventDispatcher::eventPlaybackDelay() { return EventPlaybackDelay; } //----------------------------------------------------------------------------- void pqEventDispatcher::registerTimer(QTimer* timer) { if (timer) { RegisteredTimers.push_back(timer); } } //----------------------------------------------------------------------------- void pqEventDispatcher::deferEventsIfBlocked(bool enable) { pqEventDispatcher::DeferEventsIfBlocked = enable; } //----------------------------------------------------------------------------- void pqEventDispatcher::aboutToBlock() { // if (!pqEventDispatcher::DeferMenuTimeouts) { if (!this->BlockTimer.isActive()) { // cout << "aboutToBlock" << endl; // Request a delayed playback for an event. this->BlockTimer.start(); } } } //----------------------------------------------------------------------------- void pqEventDispatcher::awake() { // if (!pqEventDispatcher::DeferMenuTimeouts) // { // // cout << "awake" << endl; // // this->BlockTimer.stop(); // } } //----------------------------------------------------------------------------- void pqEventDispatcher::setTimeStep(int value) { EventPlaybackDelay = value; } //----------------------------------------------------------------------------- void pqEventDispatcher::run(bool value) { this->PlayBackPaused = !value; if (value) { Q_EMIT this->restarted(); } else { Q_EMIT this->paused(); } } //----------------------------------------------------------------------------- void pqEventDispatcher::stop() { this->PlayBackPaused = false; this->PlayBackFinished = true; } //----------------------------------------------------------------------------- bool pqEventDispatcher::isPaused() const { return this->PlayBackPaused; } //----------------------------------------------------------------------------- bool pqEventDispatcher::status() const { return this->PlayBackStatus; } //----------------------------------------------------------------------------- void pqEventDispatcher::oneStep() { this->PlayBackOneStep = true; } //----------------------------------------------------------------------------- bool pqEventDispatcher::playEvents(pqEventSource& source, pqEventPlayer& player) { if (this->ActiveSource || this->ActivePlayer) { qCritical() << "Event dispatcher is already playing"; return false; } this->ActiveSource = &source; this->ActivePlayer = &player; QApplication::setEffectEnabled(Qt::UI_General, false); QApplication::setEffectEnabled(Qt::UI_AnimateMenu, false); // Show animated menus. QApplication::setEffectEnabled(Qt::UI_FadeMenu, false); // Show faded menus. QApplication::setEffectEnabled(Qt::UI_AnimateCombo, false); // Show animated comboboxes. QApplication::setEffectEnabled(Qt::UI_AnimateTooltip, false); // Show tooltip animations. QApplication::setEffectEnabled(Qt::UI_FadeTooltip, false); // Show tooltip fading effects. QObject::connect( QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(aboutToBlock())); QObject::connect(QAbstractEventDispatcher::instance(), SIGNAL(awake()), this, SLOT(awake())); // This is how the playback logic works: // * In here, we continuously keep on playing one event after another until // we are done processing all the events. // * If a modal dialog pops up, then this->aboutToBlock() gets called. To me // accurate, aboutToBlock() is called everytime the sub-event loop is entered // and more modal dialogs that loop is entered after processing of each event // (not merely when the dialog pops up). // * In this->aboutToBlock() we start a timer which on timeout processes just 1 event. // * After executing that event, if the dialog still is up, them aboutToBlock() will // be called again and the cycle continues. If not, the control returns to this main // playback loop, and it continues. this->PlayBackStatus = true; // success. this->PlayBackFinished = false; while (!this->PlayBackFinished) { if (!this->PlayBackPaused) { // cerr << "=== playEvent(1) ===" << endl; this->playEvent(); } else { if (this->PlayBackOneStep) { this->PlayBackOneStep = false; this->playEvent(); } else { this->processEventsAndWait(100); } } } this->ActiveSource = NULL; this->ActivePlayer = NULL; QObject::disconnect( QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(aboutToBlock())); QObject::disconnect(QAbstractEventDispatcher::instance(), SIGNAL(awake()), this, SLOT(awake())); return this->PlayBackStatus; } //----------------------------------------------------------------------------- void pqEventDispatcher::playEventOnBlocking() { // if(this->PlayingBlockingEvent) // { // qDebug() << "Event blocking already playing ...."; // return; // } if (pqEventDispatcher::DeferMenuTimeouts || pqEventDispatcher::DeferEventsIfBlocked) { // cerr << "=== playEventOnBlocking ===" << endl; this->BlockTimer.start(); return; } pqEventDispatcher::PlayingBlockingEvent = true; // cout << "---blocked event: " << endl; // if needed for debugging, I can print blocking annotation here. // cerr << "=== playEvent(2) ===" << endl; this->playEvent(1); // if (!this->BlockTimer.isActive()) // { // this->BlockTimer.start(); // } pqEventDispatcher::PlayingBlockingEvent = false; } //----------------------------------------------------------------------------- void pqEventDispatcher::playEvent(int indent) { this->BlockTimer.stop(); if (this->PlayBackFinished) { return; } if (!this->ActiveSource) { this->PlayBackFinished = true; this->PlayBackStatus = false; // failure. qCritical("Internal error: playEvent called without a valid event source."); return; } QString object; QString command; QString arguments; int eventType; int result = this->ActiveSource->getNextEvent(object, command, arguments, eventType); if (result == pqEventSource::DONE) { this->PlayBackFinished = true; return; } else if (result == pqEventSource::FAILURE) { this->PlayBackFinished = true; this->PlayBackStatus = false; // failure. return; } static unsigned long counter = 0; unsigned long local_counter = counter++; QString pretty_name = object.mid(object.lastIndexOf('/')); bool print_debug = getenv("PV_DEBUG_TEST") != NULL; if (print_debug) { QString eventString = "Event"; if (eventType == pqEventTypes::CHECK_EVENT) { eventString = "Check Event"; } cout << QTime::currentTime().toString("hh:mm:ss").toStdString().c_str() << " : " << QString().fill(' ', 4 * indent).toStdString().c_str() << local_counter << ": Test (" << indent << "): " << eventString.toUtf8().data() << ": " << pretty_name.toStdString().c_str() << ": " << command.toStdString().c_str() << " : " << arguments.toStdString().c_str() << endl; } bool error = false; this->ActivePlayer->playEvent(object, command, arguments, eventType, error); this->BlockTimer.stop(); // process any posted events. We call processEvents() so that any slots // connected using QueuedConnection also get handled. this->processEventsAndWait(EventPlaybackDelay); // We explicitly timeout timers that have been registered with us. processTimers(); this->BlockTimer.stop(); if (print_debug) { cout << QTime::currentTime().toString("hh:mm:ss").toStdString().c_str() << " : " << QString().fill(' ', 4 * indent).toStdString().c_str() << local_counter << ": Done" << endl; } if (error) { this->PlayBackStatus = false; this->PlayBackFinished = true; return; } } //----------------------------------------------------------------------------- void pqEventDispatcher::processEventsAndWait(int ms) { bool prev = pqEventDispatcher::DeferMenuTimeouts; pqEventDispatcher::DeferMenuTimeouts = true; if (ms > 0) { QApplication::sendPostedEvents(); QEventLoop loop; QTimer::singleShot(ms, &loop, SLOT(quit())); loop.exec(); } // When this gets called during playback from a blocking event loop (e.g. a modal dialog) // calling `QApplication::processEvents()` has a sideeffect on Qt 5 + OsX where it does // not quit the eventloop for the modal dialog until a mouse event (for example) is // received by the application. Avoiding calling QApplication::processEvents when already // processing a event loop other the apps main event loop avoids that problem. if (!pqEventDispatcher::PlayingBlockingEvent) { QApplication::processEvents(); } QApplication::sendPostedEvents(); if (!pqEventDispatcher::PlayingBlockingEvent) { QApplication::processEvents(); } pqEventDispatcher::DeferMenuTimeouts = prev; } //----------------------------------------------------------------------------- void pqEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) { bool prev = pqEventDispatcher::DeferMenuTimeouts; pqEventDispatcher::DeferMenuTimeouts = true; QApplication::processEvents(flags); pqEventDispatcher::DeferMenuTimeouts = prev; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventDispatcher.h000066400000000000000000000113071526070500000251570ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqEventDispatcher_h #define _pqEventDispatcher_h #include "QtTestingExport.h" #include #include #include #include class pqEventPlayer; class pqEventSource; /// pqEventDispatcher is responsible for taking each "event" from the test and /// then "playing" it using the player. The dispatcher is the critical component /// of this playback since it decides when it's time to dispatch the next /// "event" from the test. /// After an event is posted, there are two options: /// \li the default option is to simply wait for a small amount of time before /// processing the next event. The hope is that within that time any pending /// requests such as timers, slots connected using Qt::QueuedConnection etc. /// will be handled and all will work well. This however it fraught with /// problems resulting is large number of random test failures especially in /// large and complex applications such as ParaView. In such cases the better /// option is the second option. /// \li we only process already posted events (using a call to /// QApplication::processEvents() and then rely on timers being registered using /// registerTimer(). All these timers are explicitly timed-out, if active, before /// processing the next event. /// /// To enable the second mode simply set the eventPlaybackDelay to 0. /// In either mode, all timers registered using registerTimer() will be /// timed-out before dispatching next event. /// /// To make it easier to register timers, one can directly use pqTimer instead /// of QTimer. class QTTESTING_EXPORT pqEventDispatcher : public QObject { Q_OBJECT typedef QObject Superclass; public: pqEventDispatcher(QObject* parent = 0); ~pqEventDispatcher() override; /// Retrieves events from the given event source, dispatching them to /// the given event player for test case playback. This call blocks until all /// the events from the source have been played back (or failure). Returns /// true if playback was successful. bool playEvents(pqEventSource& source, pqEventPlayer& player); /// Set the delay between dispatching successive events. Default is set using /// CMake variable QT_TESTING_EVENT_PLAYBACK_DELAY. static void setEventPlaybackDelay(int milliseconds); static int eventPlaybackDelay(); /** Wait function provided for players that need to wait for the GUI to perform a certain action. Note: the minimum wait time is 100ms. This is set to avoid timiing issues on slow processors that hang tests.*/ static void processEventsAndWait(int ms); /** proccessEvents method for widgets and paraview to use instead of calling Qt version, since that will break test playback*/ static void processEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents); /// register a timer that needs to be ensured to have timed-out after every /// event dispatch. static void registerTimer(QTimer* timer); /// Disables the behavior where more test events may be dispatched /// if Qt starts waiting in an event loop. Warning: Setting this to /// true will prevent modal dialogs from functioning correctly. static void deferEventsIfBlocked(bool defer); /// Return if the Dispatcher is not playing events bool isPaused() const; /// Return Dispatcher's status bool status() const; Q_SIGNALS: /// signal when playback starts void restarted(); /// signal when playback pauses void paused(); protected Q_SLOTS: void playEventOnBlocking(); /// Called when the mainThread is about to block. void aboutToBlock(); /// Called when the mainThread wakes up. void awake(); public Q_SLOTS: /// Change the TimeStep void setTimeStep(int value); /// Method to be able to stop/pause/play the current playback script void run(bool value); void stop(); void oneStep(); /// Plays a single event. this->PlayBackFinished and this->PlayBackStatus are /// updated by this method. void playEvent(int indent = 0); protected: bool PlayBackFinished; bool PlayBackPaused; bool PlayBackStatus; bool PlayBackOneStep; bool PlayBackStoped; static bool DeferMenuTimeouts; /// This variable says that we should not continue to process test events /// when the application is blocked in a Qt event loop - it is either blocked /// in a modal dialog or is in a long wait while also processing events /// (such as when waiting from Insitu server @see pqLiveInsituManager). static bool DeferEventsIfBlocked; static bool PlayingBlockingEvent; pqEventSource* ActiveSource; pqEventPlayer* ActivePlayer; QTimer BlockTimer; }; #endif // !_pqEventDispatcher_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventObserver.cxx000066400000000000000000000010071526070500000252270ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqEventObserver.h" #include //////////////////////////////////////////////////////////////////////////////////// // pqEventObserver pqEventObserver::pqEventObserver(QObject* p) : QObject(p) , Stream(NULL) { } pqEventObserver::~pqEventObserver() {} void pqEventObserver::setStream(QTextStream* stream) { this->Stream = stream; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventObserver.h000066400000000000000000000025031526070500000246560ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqEventObserver_h #define _pqEventObserver_h #include "QtTestingExport.h" #include #include class QTextStream; /** Observes high-level ParaView events, and serializes them to a stream for possible playback (as a test-case, demo, tutorial, etc). To use, connect the onRecordEvent() slot to the pqEventTranslator::recordEvent() signal. \sa pqEventTranslator, pqStdoutEventObserver */ class QTTESTING_EXPORT pqEventObserver : public QObject { Q_OBJECT public: pqEventObserver(QObject* p); ~pqEventObserver() override; public: virtual void setStream(QTextStream* stream); public Q_SLOTS: // Slot called when recording an event // Event Type can be pqEventTypes::ACTION_EVENT or pqEventType::CHECK_EVENT // Widget, Command/Property and Arguments are QString // THis method has to be redefined by subclasses virtual void onRecordEvent(const QString& Widget, const QString& Command, const QString& Arguments, const int& eventType) = 0; Q_SIGNALS: void eventRecorded( const QString& Widget, const QString& Command, const QString& Arguments, const int& eventType); protected: QTextStream* Stream; }; #endif // !_pqEventObserver_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventPlayer.cxx000066400000000000000000000151311526070500000246770ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqEventPlayer.h" #include "pq3DViewEventPlayer.h" #include "pqAbstractActivateEventPlayer.h" #include "pqAbstractBooleanEventPlayer.h" #include "pqAbstractDoubleEventPlayer.h" #include "pqAbstractIntEventPlayer.h" #include "pqAbstractItemViewEventPlayer.h" #include "pqAbstractMiscellaneousEventPlayer.h" #include "pqAbstractStringEventPlayer.h" #include "pqBasicWidgetEventPlayer.h" #include "pqComboBoxEventPlayer.h" #include "pqCommentEventPlayer.h" #include "pqEventTypes.h" #include "pqListViewEventPlayer.h" #include "pqNativeFileDialogEventPlayer.h" #include "pqObjectNaming.h" #include "pqTabBarEventPlayer.h" #include "pqTableViewEventPlayer.h" #include "pqTreeViewEventPlayer.h" #include #include #include // ---------------------------------------------------------------------------- pqEventPlayer::pqEventPlayer() {} // ---------------------------------------------------------------------------- pqEventPlayer::~pqEventPlayer() {} // ---------------------------------------------------------------------------- void pqEventPlayer::addDefaultWidgetEventPlayers(pqTestUtility* util) { addWidgetEventPlayer(new pqCommentEventPlayer(util)); addWidgetEventPlayer(new pqBasicWidgetEventPlayer()); addWidgetEventPlayer(new pqAbstractActivateEventPlayer()); addWidgetEventPlayer(new pqAbstractBooleanEventPlayer()); addWidgetEventPlayer(new pqAbstractDoubleEventPlayer()); addWidgetEventPlayer(new pqAbstractIntEventPlayer()); addWidgetEventPlayer(new pqAbstractItemViewEventPlayer()); addWidgetEventPlayer(new pqAbstractStringEventPlayer()); addWidgetEventPlayer(new pqTabBarEventPlayer()); addWidgetEventPlayer(new pqComboBoxEventPlayer()); addWidgetEventPlayer(new pqTreeViewEventPlayer()); addWidgetEventPlayer(new pqTableViewEventPlayer()); addWidgetEventPlayer(new pqListViewEventPlayer()); addWidgetEventPlayer(new pqAbstractMiscellaneousEventPlayer(util)); addWidgetEventPlayer(new pq3DViewEventPlayer("QGLWidget")); addWidgetEventPlayer(new pqNativeFileDialogEventPlayer(util)); } // ---------------------------------------------------------------------------- QList pqEventPlayer::players() const { return this->Players; } // ---------------------------------------------------------------------------- void pqEventPlayer::addWidgetEventPlayer(pqWidgetEventPlayer* Player) { if (Player) { // We Check if the Player has already been added previously int index = this->getWidgetEventPlayerIndex(QString(Player->metaObject()->className())); if (index != -1) { return; } this->Players.push_front(Player); Player->setParent(this); } } // ---------------------------------------------------------------------------- bool pqEventPlayer::removeWidgetEventPlayer(const QString& className) { int index = this->getWidgetEventPlayerIndex(className); if (index == -1) { return false; } this->Players.removeAt(index); return true; } // ---------------------------------------------------------------------------- pqWidgetEventPlayer* pqEventPlayer::getWidgetEventPlayer(const QString& className) { int index = this->getWidgetEventPlayerIndex(className); if (index == -1) { return 0; } return this->Players.at(index); } // ---------------------------------------------------------------------------- int pqEventPlayer::getWidgetEventPlayerIndex(const QString& className) { for (int i = 0; i < this->Players.count(); ++i) { if (this->Players.at(i)->metaObject()->className() == className) { return i; } } return -1; } // ---------------------------------------------------------------------------- void pqEventPlayer::playEvent( const QString& objectString, const QString& command, const QString& arguments, bool& error) { this->playEvent(objectString, command, arguments, pqEventTypes::ACTION_EVENT, error); } // ---------------------------------------------------------------------------- void pqEventPlayer::playEvent(const QString& objectString, const QString& command, const QString& arguments, int eventType, bool& error) { Q_EMIT this->eventAboutToBePlayed(objectString, command, arguments); // If we can't find an object with the right name, we're done ... QObject* const object = pqObjectNaming::GetObject(objectString); // Scroll bar depends on monitor's resolution if (!object && objectString.contains(QString("QScrollBar"))) { Q_EMIT this->eventPlayed(objectString, command, arguments); error = false; return; } if (!object && !command.startsWith("comment")) { QString errorMsg = QString("In event 'object=%1' 'command=%2' 'arguments=%3':\n%4") .arg(objectString, command, arguments, pqObjectNaming::lastErrorMessage()); qCritical() << qUtf8Printable(errorMsg); Q_EMIT this->errorMessage(errorMsg); error = true; return; } // Loop through players until the event gets handled ... bool accepted = false; bool tmpError = false; if (command.startsWith("comment")) { pqWidgetEventPlayer* widgetPlayer = this->getWidgetEventPlayer(QString("pqCommentEventPlayer")); pqCommentEventPlayer* commentPlayer = qobject_cast(widgetPlayer); if (commentPlayer) { accepted = commentPlayer->playEvent(object, command, arguments, tmpError); } } else { for (int i = 0; i != this->Players.size(); ++i) { accepted = this->Players[i]->playEvent(object, command, arguments, eventType, tmpError); if (accepted) { break; } } } // The event wasn't handled at all ... if (!accepted) { QString errorMessage = QString("In event 'object=%1' 'command=%2' 'arguments=%3':\nUnhandled event.\n%4") .arg(object ? object->objectName() : objectString, command, arguments, pqObjectNaming::lastErrorMessage()); qCritical() << qUtf8Printable(errorMessage); Q_EMIT this->errorMessage(errorMessage); error = true; return; } // The event was handled, but there was a problem ... if (accepted && tmpError) { QString errorMessage = QString("In event 'object=%1' 'command=%2' 'arguments=%3':\nUnhandled error.") .arg(object ? object->objectName() : objectString, command, arguments); qCritical() << qUtf8Printable(errorMessage); Q_EMIT this->errorMessage(errorMessage); error = true; return; } // The event was handled successfully ... Q_EMIT this->eventPlayed(objectString, command, arguments); error = false; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventPlayer.h000066400000000000000000000067571526070500000243420ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqEventPlayer_h #define _pqEventPlayer_h #include "QtTestingExport.h" #include #include #include class pqWidgetEventPlayer; class pqTestUtility; /** Manages playback of test-cases, demos, tutorials, etc. pqEventPlayer converts high-level ParaView events (button click, row selection, etc) into low-level Qt events that drive the user interface. The high-level events created by pqEventTranslator are fed to pqEventPlayer::playEvent() one-by-one, which passes each event through a collection of pqWidgetEventPlayer objects. Each pqWidgetEventPlayer has the chance to ignore the event or accept and update the program state using low-level Qt events. pqEventDispatcher is an example of an object that can retrieve high-level events from a pqEventSource object, feeding them to pqEventPlayer. For specialized Qt widgets it may be necessary to create "custom" pqWidgetEventPlayer derivatives, which can be added to pqEventPlayer using the addWidgetEventPlayer() method. pqWidgetEventPlayer objects are searched in order for event playback, so you can also use this mechanism to "override" the builtin event players. \sa pqWidgetEventPlayer, pqEventTranslator, pqEventDispatcher, pqEventSource, pqXMLEventSource */ class QTTESTING_EXPORT pqEventPlayer : public QObject { Q_OBJECT public: pqEventPlayer(); ~pqEventPlayer() override; /** Adds the default set of widget players to the current working set. Players are executed in-order, so you can call addWidgetEventPlayer() before this function to override default players. */ void addDefaultWidgetEventPlayers(pqTestUtility* util); /** Adds a new player to the current working set of widget players. pqEventPlayer assumes control of the lifetime of the supplied object. */ void addWidgetEventPlayer(pqWidgetEventPlayer*); /** Method to get a specific player */ bool removeWidgetEventPlayer(const QString& className); /** Method to get a specific player */ pqWidgetEventPlayer* getWidgetEventPlayer(const QString& className); /** Method to return the list of widget event players added previously*/ QList players() const; /** This method is called with each high-level ParaView event, which will invoke the corresponding low-level Qt functionality in-turn. If there was an error playing the event, Error argument will be set to "true". Note: Currently there is no guarantee that playEvent() will return immediately, since the functionality it invokes may enter a separate event loop (a modal dialog or context menu, for example). Check event will not modify ui but check a widget value*/ void playEvent(const QString& object, const QString& command, const QString& arguments, int eventType, bool& Error); void playEvent( const QString& object, const QString& command, const QString& arguments, bool& Error); Q_SIGNALS: void eventAboutToBePlayed( const QString& Object, const QString& Command, const QString& Arguments); void eventPlayed(const QString& Object, const QString& Command, const QString& Arguments); void errorMessage(const QString&); private: int getWidgetEventPlayerIndex(const QString& className); pqEventPlayer(const pqEventPlayer&); pqEventPlayer& operator=(const pqEventPlayer&); /// Stores the working set of widget players QList Players; }; #endif // !_pqEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventRecorder.cxx000066400000000000000000000130251526070500000252100ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include #include // QtTesting includes #include "pqEventObserver.h" #include "pqEventRecorder.h" #include "pqEventTranslator.h" #include "pqEventTypes.h" // ---------------------------------------------------------------------------- pqEventRecorder::pqEventRecorder(QObject* parent) : Superclass(parent) { this->ActiveObserver = 0; this->ActiveTranslator = 0; this->File = 0; this->ContinuousFlush = false; this->RecordInteractionTimings = false; } // ---------------------------------------------------------------------------- pqEventRecorder::~pqEventRecorder() { this->ActiveObserver = 0; this->ActiveTranslator = 0; } // ---------------------------------------------------------------------------- void pqEventRecorder::setContinuousFlush(bool value) { if (!this->ActiveObserver) { return; } if (value) { QObject::connect(this->ActiveObserver, SIGNAL(eventRecorded(QString, QString, QString, int)), this, SLOT(flush())); } else { QObject::disconnect(this->ActiveObserver, SIGNAL(eventRecorded(QString, QString, QString, int)), this, SLOT(flush())); } this->ContinuousFlush = value; } // ---------------------------------------------------------------------------- bool pqEventRecorder::continuousFlush() const { return this->ContinuousFlush; } // ---------------------------------------------------------------------------- void pqEventRecorder::setRecordInteractionTimings(bool value) { this->RecordInteractionTimings = value; if (this->ActiveTranslator) { this->ActiveTranslator->recordInteractionTimings(value); } } // ---------------------------------------------------------------------------- bool pqEventRecorder::recordInteractionTimings() const { return this->RecordInteractionTimings; } // ---------------------------------------------------------------------------- void pqEventRecorder::check(bool value) { this->ActiveTranslator->check(value); } // ---------------------------------------------------------------------------- void pqEventRecorder::setFile(QIODevice* file) { this->File = file; } // ---------------------------------------------------------------------------- QIODevice* pqEventRecorder::file() const { return this->File; } // ---------------------------------------------------------------------------- void pqEventRecorder::setObserver(pqEventObserver* observer) { this->ActiveObserver = observer; } // ---------------------------------------------------------------------------- pqEventObserver* pqEventRecorder::observer() const { return this->ActiveObserver; } // ---------------------------------------------------------------------------- void pqEventRecorder::setTranslator(pqEventTranslator* translator) { this->ActiveTranslator = translator; if (this->ActiveTranslator != NULL) { this->ActiveTranslator->recordInteractionTimings(this->RecordInteractionTimings); } } // ---------------------------------------------------------------------------- pqEventTranslator* pqEventRecorder::translator() const { return this->ActiveTranslator; } // ---------------------------------------------------------------------------- bool pqEventRecorder::isRecording() const { if (this->ActiveTranslator != NULL) { return this->ActiveTranslator->isRecording(); } else { return false; } } // ---------------------------------------------------------------------------- void pqEventRecorder::recordEvents( pqEventTranslator* translator, pqEventObserver* observer, QIODevice* file, bool continuousFlush) { this->setTranslator(translator); this->setObserver(observer); this->setFile(file); this->setContinuousFlush(continuousFlush); this->start(); } // ---------------------------------------------------------------------------- void pqEventRecorder::flush() { this->Stream.flush(); } // ---------------------------------------------------------------------------- void pqEventRecorder::start() { if (!this->File || !this->ActiveObserver || !this->ActiveTranslator) { return; } QObject::connect(this->ActiveTranslator, SIGNAL(recordEvent(QString, QString, QString, int)), this->ActiveObserver, SLOT(onRecordEvent(QString, QString, QString, int))); // Set the device this->Stream.setDevice(this->File); #if QT_VERSION < 0x060000 // Set UTF8 Codec this->Stream.setCodec("UTF-8"); #endif // Set the Stream to the Observer this->ActiveObserver->setStream(&this->Stream); // Start the Translator this->ActiveTranslator->start(); this->ActiveTranslator->record(true); Q_EMIT this->started(); } // ---------------------------------------------------------------------------- void pqEventRecorder::stop(int value) { QObject::disconnect(this->ActiveTranslator, SIGNAL(recordEvent(QString, QString, QString, int)), this->ActiveObserver, SLOT(onRecordEvent(QString, QString, QString, int))); this->ActiveObserver->setStream(NULL); this->ActiveTranslator->stop(); this->ActiveTranslator->record(false); if (!value) { return; } this->flush(); Q_EMIT this->stopped(); } // ---------------------------------------------------------------------------- void pqEventRecorder::unpause(bool value) { this->pause(!value); } // ---------------------------------------------------------------------------- void pqEventRecorder::pause(bool value) { this->ActiveTranslator->record(!value); Q_EMIT this->paused(value); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventRecorder.h000066400000000000000000000054261526070500000246430ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqEventRecorder_h #define _pqEventRecorder_h // Qt includes #include #include #include // QtTesting includes #include "QtTestingExport.h" class pqEventObserver; class pqEventTranslator; /// Class to provide the recording. /// Two behaviors : /// - Either Continuous Flush is true, the file is written after each new actions /// Indeed if the QtTesting/Application crashs, part of the script is written. /// - Or the file is written only when we stop the record. /// A simple call to the function "recordEvent" with good parameters, will start /// the record. class QTTESTING_EXPORT pqEventRecorder : public QObject { Q_OBJECT Q_PROPERTY(bool continuousFlush READ continuousFlush WRITE setContinuousFlush) typedef QObject Superclass; public: explicit pqEventRecorder(QObject* parent = 0); ~pqEventRecorder() override; bool continuousFlush() const; bool recordInteractionTimings() const; void setFile(QIODevice* file); QIODevice* file() const; void setObserver(pqEventObserver* observer); pqEventObserver* observer() const; void setTranslator(pqEventTranslator* translator); pqEventTranslator* translator() const; bool isRecording() const; void recordEvents(pqEventTranslator* translator, pqEventObserver* observer, QIODevice* file, bool continuousFlush); Q_SIGNALS: void started(); void stopped(); void paused(bool); public Q_SLOTS: void flush(); void start(); void stop(int value); // Pause the recording if value is False // Keep recording if value is True void unpause(bool value); // Pause the recording if value is True // Keep recording if value is False void pause(bool value); // Set/Unset the recorder into Check mode // Connection signal into the correct slots void check(bool value); // Set the continuous flush value // and connect/disconnect the current observer with // this recorder // If true, events are written on file as soon // as they are recorded. // False by default void setContinuousFlush(bool value); // Set the record interaction timings value // and pass it to current active translator // if any. // When set to true user's pause between interaction events // are recorded and thus will be reproduced during playback. // When enabled, timing starts to be recorded only after the // next recorded event. // False by default void setRecordInteractionTimings(bool value); protected: pqEventObserver* ActiveObserver; pqEventTranslator* ActiveTranslator; QIODevice* File; bool ContinuousFlush; bool RecordInteractionTimings; QTextStream Stream; }; #endif // !_pqEventRecorder_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventSource.h000066400000000000000000000022111526070500000243230ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqEventSource_h #define _pqEventSource_h #include "QtTestingExport.h" #include "pqEventTypes.h" #include class QString; /// Abstract interface for objects that can supply high-level testing events class QTTESTING_EXPORT pqEventSource : public QObject { Q_OBJECT public: pqEventSource(QObject* p) : QObject(p) { } ~pqEventSource() override {} enum eventReturnFlag { SUCCESS, FAILURE, DONE }; /** Retrieves the next available event. Returns SUCCESS if an event was returned and can be processed, FAILURE if there was a problem, DONE, if there are no more events. */ virtual int getNextEvent( QString& object, QString& command, QString& arguments, int& eventType) = 0; /** Set the filename for contents. Returns true for valid file, false for invalid file */ virtual void setContent(const QString& filename) = 0; /** tell the source to stop feeding in events */ virtual void stop() {} }; #endif // !_pqEventSource_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventTranslator.cxx000066400000000000000000000550351526070500000256030ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqEventTranslator.h" #include "pq3DViewEventTranslator.h" #include "pqAbstractButtonEventTranslator.h" #include "pqAbstractItemViewEventTranslator.h" #include "pqAbstractSliderEventTranslator.h" #include "pqBasicWidgetEventTranslator.h" #include "pqCheckEventOverlay.h" #include "pqComboBoxEventTranslator.h" #include "pqDoubleSpinBoxEventTranslator.h" #include "pqEventComment.h" #include "pqEventTypes.h" #include "pqLineEditEventTranslator.h" #include "pqListViewEventTranslator.h" #include "pqMenuEventTranslator.h" #include "pqNativeFileDialogEventTranslator.h" #include "pqObjectNaming.h" #include "pqSpinBoxEventTranslator.h" #include "pqTabBarEventTranslator.h" #include "pqTableViewEventTranslator.h" #include "pqTreeViewEventTranslator.h" #include #include #include #include #include #include #include //////////////////////////////////////////////////////////////////////////////// // pqEventTranslator::pqImplementation struct pqEventTranslator::pqImplementation { pqImplementation() { this->EventComment = 0; this->Checking = false; this->Recording = false; // Create overlay and hide it this->CheckOverlay = new pqCheckEventOverlay(NULL); this->hideOverlay(); this->RecordInteractionTimings = false; } ~pqImplementation() { if (this->EventComment) { delete this->EventComment; } delete this->CheckOverlay; this->CheckOverlayWidgetOn = NULL; } void hideOverlay() { // Hide the overlay this->CheckOverlay->hide(); // Nullified it's parent this->CheckOverlay->setParent(NULL); // Set the overlaid widget to null this->CheckOverlayWidgetOn = NULL; } pqEventComment* EventComment; /// Stores the working set of widget translators QList Translators; /// Stores the set of objects that should be ignored when translating events QMap IgnoredObjects; // list of widgets for which mouse propagation will happen // we'll only translate the first and ignore the rest QList MouseParents; // Checking Flag bool Checking; // Recording flag bool Recording; // Pointer to the overlay QPointer CheckOverlay; // Pointer to the overlaid widget QPointer CheckOverlayWidgetOn; // Record interaction timings flag bool RecordInteractionTimings; // Timer to track time between user interactions QElapsedTimer InteractionsTimer; }; //////////////////////////////////////////////////////////////////////////////// // pqEventTranslator // ---------------------------------------------------------------------------- pqEventTranslator::pqEventTranslator(QObject* p) : QObject(p) , Implementation(new pqImplementation()) { // Ignore the overlay so it is transparent to events. this->ignoreObject(this->Implementation->CheckOverlay); } // ---------------------------------------------------------------------------- pqEventTranslator::~pqEventTranslator() { this->stop(); delete Implementation; } // ---------------------------------------------------------------------------- void pqEventTranslator::start() { QCoreApplication::instance()->installEventFilter(this); Q_EMIT this->started(); } // ---------------------------------------------------------------------------- void pqEventTranslator::stop() { QCoreApplication::instance()->removeEventFilter(this); this->check(false); Q_EMIT this->stopped(); } // ---------------------------------------------------------------------------- void pqEventTranslator::addDefaultWidgetEventTranslators(pqTestUtility* util) { // Add general translator first, then specific, in order for this to work addWidgetEventTranslator(new pqBasicWidgetEventTranslator()); addWidgetEventTranslator(new pqAbstractButtonEventTranslator()); addWidgetEventTranslator(new pqAbstractItemViewEventTranslator()); addWidgetEventTranslator(new pqAbstractSliderEventTranslator()); addWidgetEventTranslator(new pqComboBoxEventTranslator()); addWidgetEventTranslator(new pqDoubleSpinBoxEventTranslator()); addWidgetEventTranslator(new pqLineEditEventTranslator()); addWidgetEventTranslator(new pqMenuEventTranslator()); addWidgetEventTranslator(new pqSpinBoxEventTranslator()); addWidgetEventTranslator(new pqTabBarEventTranslator()); addWidgetEventTranslator(new pqTreeViewEventTranslator()); addWidgetEventTranslator(new pqTableViewEventTranslator()); addWidgetEventTranslator(new pqListViewEventTranslator()); addWidgetEventTranslator(new pq3DViewEventTranslator("QGLWidget")); addWidgetEventTranslator(new pqNativeFileDialogEventTranslator(util)); } // ---------------------------------------------------------------------------- void pqEventTranslator::addWidgetEventTranslator(pqWidgetEventTranslator* Translator) { if (Translator) { // We Check if the translator has already been added previously. int index = this->getWidgetEventTranslatorIndex(Translator->metaObject()->className()); if (index != -1) { return; } this->Implementation->Translators.push_front(Translator); Translator->setParent(this); // Legacy Connection, for translator not using event types QObject::connect(Translator, SIGNAL(recordEvent(QObject*, const QString&, const QString&)), this, SLOT(onRecordEvent(QObject*, const QString&, const QString&))); // Connect record event QObject::connect(Translator, SIGNAL(recordEvent(QObject*, const QString&, const QString&, int)), this, SLOT(onRecordEvent(QObject*, const QString&, const QString&, int))); // Connect resize specific overlay QObject::connect(Translator, SIGNAL(specificOverlay(const QRect&)), this, SLOT(setOverlayGeometry(const QRect&))); } } // ---------------------------------------------------------------------------- bool pqEventTranslator::removeWidgetEventTranslator(const QString& className) { int index = this->getWidgetEventTranslatorIndex(className); if (index == -1) { return false; } this->Implementation->Translators.removeAt(index); return true; } // ---------------------------------------------------------------------------- pqWidgetEventTranslator* pqEventTranslator::getWidgetEventTranslator(const QString& className) { int index = this->getWidgetEventTranslatorIndex(className); if (index == -1) { return 0; } return this->Implementation->Translators.at(index); } // ---------------------------------------------------------------------------- int pqEventTranslator::getWidgetEventTranslatorIndex(const QString& className) { for (int i = 0; i < this->Implementation->Translators.count(); ++i) { if (this->Implementation->Translators.at(i)->metaObject()->className() == className) { return i; } } return -1; } // ---------------------------------------------------------------------------- QList pqEventTranslator::translators() const { return this->Implementation->Translators; } // ---------------------------------------------------------------------------- void pqEventTranslator::addDefaultEventManagers(pqTestUtility* util) { this->Implementation->EventComment = new pqEventComment(util); QObject::connect(this->Implementation->EventComment, SIGNAL(recordComment(QObject*, QString, QString)), this, SLOT(onRecordEvent(QObject*, QString, QString))); } // ---------------------------------------------------------------------------- pqEventComment* pqEventTranslator::eventComment() const { return this->Implementation->EventComment; } // ---------------------------------------------------------------------------- void pqEventTranslator::ignoreObject(QObject* object, QRegularExpression commandFilter) { this->Implementation->IgnoredObjects.insert(object, commandFilter); } // ---------------------------------------------------------------------------- bool pqEventTranslator::eventFilter(QObject* object, QEvent* event) { if (this->Implementation->Recording) { if (object->isWindowType()) { return false; } // Only widgets QWidget* widget = qobject_cast(object); if (widget != NULL) { // mouse events are propagated to parents // our event translators/players don't quite like that, // so lets consume those extra ones if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick || event->type() == QEvent::MouseMove || event->type() == QEvent::Enter || event->type() == QEvent::Leave || event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::ContextMenu) { if (!this->Implementation->MouseParents.empty() && this->Implementation->MouseParents.first() == object) { // right on track this->Implementation->MouseParents.removeFirst(); return false; } // find the chain of parent that will get this mouse event this->Implementation->MouseParents.clear(); for (QWidget* w = widget->parentWidget(); w; w = w->parentWidget()) { this->Implementation->MouseParents.append(w); if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation)) { break; } } } // Checking mode if (this->Implementation->Checking) { // In Gl Case, parentless widget is not transparent to mouse event // The event is applied to the overlaid widget or an another top widget // (before ignoredObjects) // TODO : use mask instead // Look behind the overlay widget, this is relevant only if : // There is already an overlay drawn // This is the gl case // This is a mouse event we manage // The overlay receive the event if (this->Implementation->CheckOverlayWidgetOn != NULL && this->Implementation->CheckOverlay->GlWidget && widget == this->Implementation->CheckOverlay && (event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseMove)) { // We are about to look for another top widget window behind the mouse cursor bool foundTop = false; QWidget* topWidget; // recover all top widgets QWidgetList topWidgets = QApplication::topLevelWidgets(); Q_FOREACH (topWidget, topWidgets) { // only the visible ones if (!topWidget->isHidden()) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) auto pos = static_cast(event)->globalPos(); #else auto pos = static_cast(event)->globalPosition().toPoint(); #endif // Check it is not the overlay, and it contains the mouse cursor if (topWidget != this->Implementation->CheckOverlay && topWidget->geometry().contains(pos, true)) { // Recover the child widget under the cursor, if any QWidget* childWidget = topWidget->childAt(topWidget->mapFromGlobal(pos)); // If child exist, check it is not the overlaid widget and indeed a new widget if (childWidget == NULL || (childWidget != NULL && childWidget != this->Implementation->CheckOverlayWidgetOn)) { // if a child exist, use it if (childWidget != NULL) { topWidget = childWidget; } // Position top widget flag foundTop = true; break; } } } } if (foundTop) { // If we found a top widget behind the cursor, use it widget = topWidget; } else { // If not, use the widget behind the overlay widget = this->Implementation->CheckOverlayWidgetOn; } } // Leaving the checkOverlay when a widget without grand parent // then hiding overlay (before ignoredObjects) if (this->Implementation->CheckOverlay == widget && !this->Implementation->CheckOverlay->Specific) { if (event->type() == QEvent::Leave) { this->Implementation->hideOverlay(); } } // Ignore object if specified if (this->Implementation->IgnoredObjects.contains(widget)) { return false; } // Do not check QToolBar as they can generate buggy overlay if (qobject_cast(widget) != NULL) { return false; } // Mouse Move on a non-previously overlaid widget if (event->type() == QEvent::MouseMove && this->Implementation->CheckOverlayWidgetOn != widget) { // Check for any valid translator bool validTranslator = false; bool error; for (int i = 0; i != this->Implementation->Translators.size(); ++i) { // This will not record a check event, only check if a translator can record a check // event if (this->Implementation->Translators[i]->translateEvent( widget, event, pqEventTypes::CHECK_EVENT, error)) { validTranslator = true; break; } } // Draw overlay this->Implementation->hideOverlay(); // Only on non-window widget // TODO handle the overlay on window widget if (!widget->isWindow() && widget->parent() != NULL) { // Check if widget is glWidget this->Implementation->CheckOverlay->GlWidget = widget->inherits("QVTKWidget"); // Check if widget is parent to gl widget QList children = widget->findChildren(); Q_FOREACH (QWidget* child, children) { if (child->inherits("QVTKWidget")) { // Ignore widget containing a Gl widget as a child this->ignoreObject(widget); return false; } } // Check widget size is valid, if not do not draw overlay // Widget can still be clicked and checked int sizeThreshold = pqCheckEventOverlay::OVERLAY_MARGIN + 2 * pqCheckEventOverlay::OVERLAY_PEN_WIDTH; if (widget->width() < sizeThreshold || widget->height() < sizeThreshold) { return false; } // Set the validity of the overlay this->Implementation->CheckOverlay->Valid = validTranslator; // Set parent of the overlay to be parent of the overlaid widget this->Implementation->CheckOverlay->setParent(qobject_cast(widget->parent())); if (this->Implementation->CheckOverlay->GlWidget) { // Cannot draw QPainter directive in OpenGL context, bust use another context, aka // another window // this->Implementation->CheckOverlay->setWindowFlags(Qt::ToolTip | // Qt::FramelessWindowHint); // ToolTip is always on top this->Implementation->CheckOverlay->setWindowFlags( Qt::Tool | Qt::FramelessWindowHint); // Tool generate avatar this->Implementation->CheckOverlay->setAttribute(Qt::WA_NoSystemBackground, true); this->Implementation->CheckOverlay->setAttribute(Qt::WA_TranslucentBackground, true); this->Implementation->CheckOverlay->setAttribute(Qt::WA_PaintOnScreen, true); // Resize and move widget QRect geometry = widget->geometry(); geometry.moveTo(widget->mapToGlobal(QPoint(0, 0))); this->setOverlayGeometry(geometry, false); } else { // Restore window flags this->Implementation->CheckOverlay->setWindowFlags(Qt::Widget); this->Implementation->CheckOverlay->setAttribute(Qt::WA_NoSystemBackground, false); this->Implementation->CheckOverlay->setAttribute(Qt::WA_TranslucentBackground, false); this->Implementation->CheckOverlay->setAttribute(Qt::WA_PaintOnScreen, false); // Set overlay geometry to be the same as overlaid widget this->setOverlayGeometry(widget->geometry(), false); } // Show and Register overlay this->Implementation->CheckOverlay->show(); this->Implementation->CheckOverlayWidgetOn = widget; } } // Resize event if (event->type() == QEvent::Resize) { // Set overlay geometry QRect geometry = widget->geometry(); if (this->Implementation->CheckOverlay->GlWidget) { geometry.moveTo(widget->mapToGlobal(QPoint(0, 0))); } this->setOverlayGeometry(geometry, false); } // Mouse button release -> Check Event if (event->type() == QEvent::MouseButtonRelease) { // Check Translators for (int i = 0; i != this->Implementation->Translators.size(); ++i) { bool error = false; if (this->Implementation->Translators[i]->translateEvent( widget, event, pqEventTypes::CHECK_EVENT, error)) { if (error) { qWarning() << "Error translating a check event for object " << widget; } return true; } } // Cannot check widget , Inform user trying to check uncheckable widget qWarning() << "Error checking an event for object, widget type not supported."; qWarning() << "Name of the widget:" << widget->objectName() << ". Type of the widget:" << widget->metaObject()->className(); if (widget->parent() != NULL) { qWarning() << "Type of parent widget:" << widget->parent()->metaObject()->className(); } } // Block all input events, so the UI is static but still drawn. // Except for MouseMove if (dynamic_cast(event) != NULL && event->type() != QEvent::MouseMove) { return true; } } else { // Event Recording for (int i = 0; i != this->Implementation->Translators.size(); ++i) { bool error = false; if (this->Implementation->Translators[i]->translateEvent( object, event, pqEventTypes::ACTION_EVENT, error)) { if (error) { qWarning() << "Error translating an event for object " << object; } return false; } } } } } return false; } // ---------------------------------------------------------------------------- void pqEventTranslator::onRecordEvent( QObject* Object, const QString& Command, const QString& Arguments) { this->onRecordEvent(Object, Command, Arguments, pqEventTypes::ACTION_EVENT); } // ---------------------------------------------------------------------------- void pqEventTranslator::onRecordEvent( QObject* Object, const QString& Command, const QString& Arguments, int eventType) { if (this->Implementation->IgnoredObjects.contains(Object)) { QRegularExpression commandFilter = this->Implementation->IgnoredObjects.value(Object); if (Command.contains(commandFilter)) { return; } } QString name; if (Object) { QVariant blockRecordCommands = Object->property("BlockRecordCommands"); if (blockRecordCommands.isValid() && Command.contains(blockRecordCommands.toRegularExpression())) { return; } if (eventType == pqEventTypes::ACTION_EVENT) { // When sender is pqEventObject, the Object name can be NULL. if (!qobject_cast(this->sender()) || Object) { name = pqObjectNaming::GetName(*Object); if (name.isEmpty()) return; } } else { // Check the QObject does have a name name = pqObjectNaming::GetName(*Object); if (name.isEmpty()) { return; } } } // Record user interaction time if (this->Implementation->RecordInteractionTimings) { if (this->Implementation->InteractionsTimer.isValid()) { Q_EMIT recordEvent(name, "pause", QString::number(this->Implementation->InteractionsTimer.restart()), pqEventTypes::ACTION_EVENT); } else { this->Implementation->InteractionsTimer.start(); } } // Record the event Q_EMIT recordEvent(name, Command, Arguments, eventType); } // ---------------------------------------------------------------------------- void pqEventTranslator::check(bool value) { this->Implementation->Checking = value; // Hide overlay when not checking if (!value) { this->Implementation->hideOverlay(); } } // ---------------------------------------------------------------------------- void pqEventTranslator::record(bool value) { this->Implementation->Recording = value; // Hide overlay when not recording if (!value) { this->Implementation->hideOverlay(); } } // ---------------------------------------------------------------------------- bool pqEventTranslator::isRecording() { return this->Implementation->Recording; } // ---------------------------------------------------------------------------- void pqEventTranslator::recordInteractionTimings(bool value) { if (value != this->Implementation->RecordInteractionTimings) { this->Implementation->RecordInteractionTimings = value; this->Implementation->InteractionsTimer.invalidate(); } } // ---------------------------------------------------------------------------- void pqEventTranslator::setOverlayGeometry(const QRect& geometry, bool specific) { if (this->Implementation->CheckOverlay != NULL) { this->Implementation->CheckOverlay->setGeometry(geometry); } this->Implementation->CheckOverlay->Specific = specific; } // ---------------------------------------------------------------------------- void pqEventTranslator::recordDashboardModeToggle(QObject* object, bool toggle) { QString name = pqObjectNaming::GetName(*object); if (name.isEmpty()) { qWarning() << "Error recording a dashboard mode event"; return; } Q_EMIT recordEvent( name, "dashboard_mode", QVariant(toggle).toString(), pqEventTypes::ACTION_EVENT); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventTranslator.h000066400000000000000000000116401526070500000252220ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqEventTranslator_h #define _pqEventTranslator_h #include "QtTestingExport.h" #include #include #include class pqEventComment; class pqTestUtility; class pqWidgetEventTranslator; /** Manages serialization of user interaction for test-cases, demos, tutorials, etc. pqEventTranslator installs itself as a global Qt event "filter" that receives notification of every Qt event. Each event is passed through a collection of pqWidgetEventTranslator objects, until one of them "handles" the event. The pqWidgetEventTranslator objects convert low-level Qt events (mouse move, button down, key released, etc) into high-level ParaView events (button clicked, row selected, etc) that can be serialized as text. Once an event translator is found, the recordEvent() signal is emitted with the name of the widget that is receiving the event, plus the serialized event. Observers such as pqEventObserverXML connect to the recordEvent() signal and handle storage of the events. \sa pqWidgetEventTranslator, pqEventObserverStdout, pqEventObserverXML, pqEventPlayer. */ class QTTESTING_EXPORT pqEventTranslator : public QObject { Q_OBJECT public: pqEventTranslator(QObject* p = 0); ~pqEventTranslator() override; /** Adds the default set of widget translators to the working set. Translators are executed in order, so you may call addWidgetEventTranslator() with your own custom translators before calling this method, to "override" the default translators. */ void addDefaultWidgetEventTranslators(pqTestUtility* util); /** Adds a new translator to the current working set of widget translators. pqEventTranslator assumes control of the lifetime of the supplied object.*/ void addWidgetEventTranslator(pqWidgetEventTranslator*); /** Method to get a specific player */ bool removeWidgetEventTranslator(const QString& className); /** Method to get a specific player */ pqWidgetEventTranslator* getWidgetEventTranslator(const QString& className); /// Return a QList of all the Translators previously added. QList translators() const; /// Add a new default eventComment in the scenario/recording to inform, /// intract with the user during the play back. void addDefaultEventManagers(pqTestUtility* util); /// Return the pqEventComment, to be able to add any comment events pqEventComment* eventComment() const; /// Adds @a object to a list of objects that will be ignored when /// translating events that have a command matching @a commandFilter /// (useful to prevent recording UI events from being /// captured as part of the recording) /// /// You may also choose to ignore commands by setting the /// "BlockRecordCommands" property of @a object to a QRegExp that will /// match the commands to block. This is useful for temporarily blocking /// a command when a programatically change will fire a signal that generates /// a command. void ignoreObject(QObject* object, QRegularExpression commandFilter = QRegularExpression( ".*", QRegularExpression::CaseInsensitiveOption)); /// start listening to the GUI and translating events void start(); /// stop listening to the GUI and translating events void stop(); /// Record check event instead of events void check(bool value); /// Activate/Deactivate recording void record(bool value); bool isRecording(); /// Set the record interaction timings flag void recordInteractionTimings(bool value); /// Record a dashboard mode toggle event void recordDashboardModeToggle(QObject* object, bool toggle); Q_SIGNALS: /// This signal will be emitted every time a translator generates a /// high-level ParaView event. Observers should connect to this signal /// to serialize high-level events. void recordEvent( const QString& Object, const QString& Command, const QString& Arguments, int eventType); /// this signals when recording starts void started(); /// this signals when recording stops void stopped(); private Q_SLOTS: // Slot called when recording an event void onRecordEvent( QObject* Object, const QString& Command, const QString& Arguments, int eventType); // Legacy convenient slot for pqEventTypes::ACTION_EVENT events void onRecordEvent(QObject* Object, const QString& Command, const QString& Arguments); // Slots called when widget request a specific size for the check overlay void setOverlayGeometry(const QRect& geometry, bool specific = true); private: pqEventTranslator(const pqEventTranslator&); pqEventTranslator& operator=(const pqEventTranslator&); bool eventFilter(QObject* Object, QEvent* Event) override; int getWidgetEventTranslatorIndex(const QString& className); struct pqImplementation; pqImplementation* const Implementation; }; #endif // !_pqEventTranslator_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqEventTypes.h000066400000000000000000000004771526070500000242030ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqEventTypes_h #define _pqEventTypes_h namespace pqEventTypes { enum eventType { ACTION_EVENT = 0, CHECK_EVENT = 1 }; }; #endif // !_pqEventTypes_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqLineEditEventTranslator.cxx000066400000000000000000000065061526070500000272200ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqLineEditEventTranslator.h" #include #include #include #include #include #include #include #include #include "pqEventTypes.h" pqLineEditEventTranslator::pqLineEditEventTranslator(QObject* p) : pqWidgetEventTranslator(p) { } bool pqLineEditEventTranslator::translateEvent( QObject* object, QEvent* event, int eventType, bool& error) { QObject* tmpObject = object; QLineEdit* leObject = qobject_cast(object); QTextEdit* teObject = qobject_cast(object); QPlainTextEdit* pteObject = qobject_cast(object); if (!leObject && !teObject && !pteObject && object->parent() != NULL) { // MouseEvent can be received by viewport tmpObject = object->parent(); leObject = qobject_cast(tmpObject); teObject = qobject_cast(tmpObject); pteObject = qobject_cast(tmpObject); } if (!leObject && !teObject && !pteObject) { return false; } if (eventType == pqEventTypes::ACTION_EVENT) { // If this line edit is part of a spinbox, don't translate events // (the spinbox translator will receive the final value directly) if (qobject_cast(tmpObject->parent())) { return false; } switch (event->type()) { case QEvent::KeyRelease: { QKeyEvent* ke = static_cast(event); QString keyText = ke->text(); if (keyText.length() && keyText.at(0).isPrint()) { if (leObject) { Q_EMIT recordEvent(tmpObject, "set_string", leObject->text()); } else if (teObject) { Q_EMIT recordEvent(tmpObject, "set_string", teObject->document()->toPlainText()); } else if (pteObject) { Q_EMIT recordEvent(tmpObject, "set_string", pteObject->document()->toPlainText()); } } // if we record F2 event, will cause some issue with the TreeView // Need test to know if we need to record those events else if (ke->key() != Qt::Key_F2) { Q_EMIT recordEvent(tmpObject, "key", QString("%1").arg(ke->key())); } return true; break; } default: break; } } else if (eventType == pqEventTypes::CHECK_EVENT) { // TextEdit only, LineEdit does not need specific check if (teObject != NULL || pteObject != NULL) { if (event->type() == QEvent::MouseMove) { return true; } // Clicking while checking, actual check event if (event->type() == QEvent::MouseButtonRelease) { if (teObject != NULL) { Q_EMIT this->recordEvent(teObject, "plainText", teObject->toPlainText().replace("\t", " "), pqEventTypes::CHECK_EVENT); } else /* if (pteObject != NULL)*/ { Q_EMIT this->recordEvent(pteObject, "plainText", pteObject->toPlainText().replace("\t", " "), pqEventTypes::CHECK_EVENT); } return true; } } } return this->Superclass::translateEvent(object, event, eventType, error); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqLineEditEventTranslator.h000066400000000000000000000016221526070500000266370ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqLineEditEventTranslator_h #define _pqLineEditEventTranslator_h #include "pqWidgetEventTranslator.h" /** Translates low-level Qt events into high-level ParaView events that can be recorded as test cases. \sa pqEventTranslator */ class QTTESTING_EXPORT pqLineEditEventTranslator : public pqWidgetEventTranslator { Q_OBJECT typedef pqWidgetEventTranslator Superclass; public: pqLineEditEventTranslator(QObject* p = 0); using Superclass::translateEvent; bool translateEvent(QObject* object, QEvent* event, int eventType, bool& error) override; private: pqLineEditEventTranslator(const pqLineEditEventTranslator&); pqLineEditEventTranslator& operator=(const pqLineEditEventTranslator&); }; #endif // !_pqLineEditEventTranslator_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqListViewEventPlayer.cxx000066400000000000000000000020541526070500000263660ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqListViewEventPlayer.h" #include //----------------------------------------------------------------------------- pqListViewEventPlayer::pqListViewEventPlayer(QObject* parentObject) : Superclass(parentObject) { } //----------------------------------------------------------------------------- pqListViewEventPlayer::~pqListViewEventPlayer() {} //-----------------------------------------------------------------------------0000000 bool pqListViewEventPlayer::playEvent( QObject* object, const QString& command, const QString& arguments, int eventType, bool& error) { QListView* listView = qobject_cast(object); if (!listView) { // mouse events go to the viewport widget listView = qobject_cast(object->parent()); } if (!listView) { return false; } return this->Superclass::playEvent(object, command, arguments, eventType, error); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqListViewEventPlayer.h000066400000000000000000000017151526070500000260160ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef __pqListViewEventPlayer_h #define __pqListViewEventPlayer_h #include "pqAbstractItemViewEventPlayerBase.h" /// pqListViewEventPlayer is a player for QTableWidget. Plays back the state /// recorded using pqListViewEventTranslator. class QTTESTING_EXPORT pqListViewEventPlayer : public pqAbstractItemViewEventPlayerBase { Q_OBJECT typedef pqAbstractItemViewEventPlayerBase Superclass; public: pqListViewEventPlayer(QObject* parent = 0); ~pqListViewEventPlayer() override; using Superclass::playEvent; bool playEvent(QObject* object, const QString& command, const QString& arguments, int eventType, bool& error) override; private: pqListViewEventPlayer(const pqListViewEventPlayer&); // Not implemented. void operator=(const pqListViewEventPlayer&); // Not implemented. }; #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqListViewEventTranslator.cxx000066400000000000000000000033471526070500000272710ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqListViewEventTranslator.h" #include #include //----------------------------------------------------------------------------- pqListViewEventTranslator::pqListViewEventTranslator(QObject* parentObject) : Superclass(parentObject) { } //----------------------------------------------------------------------------- pqListViewEventTranslator::~pqListViewEventTranslator() {} //----------------------------------------------------------------------------- void pqListViewEventTranslator::onEnteredCheck(const QModelIndex& item) { // Recover list View QListView* listView = qobject_cast(this->AbstractItemView); // Get a visual rectangle of the item QRect visualRect = listView->visualRect(item); // Translate the rect of margins and headers visualRect.translate(listView->contentsMargins().left(), listView->contentsMargins().top()); // Stor item and signal that a specific overlay is ready to be drawn this->ModelItemCheck = QPersistentModelIndex(item); Q_EMIT this->specificOverlay(visualRect); } //----------------------------------------------------------------------------- QAbstractItemView* pqListViewEventTranslator::findCorrectedAbstractItemView(QObject* object) const { // Ignore QHeaderView event specifically if (qobject_cast(object)) { return NULL; } QAbstractItemView* abstractItemView = qobject_cast(object); if (!abstractItemView) { // mouse events go to the viewport widget abstractItemView = qobject_cast(object->parent()); } return abstractItemView; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqListViewEventTranslator.h000066400000000000000000000022401526070500000267050ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef __pqListViewEventTranslator_h #define __pqListViewEventTranslator_h #include "pqAbstractItemViewEventTranslatorBase.h" /// Event recorder for QTableView. Records the toggling of the check states for /// Table widget items. The recorded state can be played back using /// pqListViewEventPlayer. class QTTESTING_EXPORT pqListViewEventTranslator : public pqAbstractItemViewEventTranslatorBase { Q_OBJECT typedef pqAbstractItemViewEventTranslatorBase Superclass; public: pqListViewEventTranslator(QObject* parent = 0); ~pqListViewEventTranslator() override; /// find and set the corrected abstract item view QAbstractItemView* findCorrectedAbstractItemView(QObject* object) const override; protected Q_SLOTS: /// Compute a visual rectangle for the item and signal it void onEnteredCheck(const QModelIndex&) override; private: pqListViewEventTranslator(const pqListViewEventTranslator&); // Not implemented. void operator=(const pqListViewEventTranslator&); // Not implemented. }; #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqMenuEventTranslator.cxx000066400000000000000000000077461526070500000264360ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqMenuEventTranslator.h" #include #include #include #include #include #include pqMenuEventTranslator::pqMenuEventTranslator(QObject* p) : pqWidgetEventTranslator(p) { } pqMenuEventTranslator::~pqMenuEventTranslator() {} bool pqMenuEventTranslator::translateEvent(QObject* Object, QEvent* Event, bool& Error) { QMenu* const menu = qobject_cast(Object); QMenuBar* const menubar = qobject_cast(Object); if (!menu && !menubar) { return false; } if (menubar) { QMouseEvent* e = dynamic_cast(Event); if (e && e->button() == Qt::LeftButton) { QAction* action = menubar->actionAt(e->pos()); if (action && action->menu()) { QString which = action->menu()->objectName(); if (which.isEmpty()) { which = action->text(); } Q_EMIT recordEvent(menubar, "activate", which); } } return true; } const auto actionArgument = [](QAction* action) -> QString { QString argument = action->objectName(); if (argument.isNull()) { argument = action->text(); } return argument; }; if (Event->type() == QEvent::Show) { // If this menu has any sub-menu's record this menu as the parent for subsequent enter event. for (auto action : menu->actions()) { if (action->menu()) { this->SubMenuParent[action] = menu; } } return true; } else if (Event->type() == QEvent::Enter) { // Note: Using QEvent::Enter instead of QEvent::FocusIn here because the menu // can be activated without first getting focus. if (this->SubMenuParent.find(menu->menuAction()) != this->SubMenuParent.end()) { // Then a previous menu has recorded this action as a sub-menu Q_EMIT recordEvent( this->SubMenuParent[menu->menuAction()], "activate", actionArgument(menu->menuAction())); } } else if (Event->type() == QEvent::Close || Event->type() == QEvent::Hide) { // Clean up sub-menu mapping for (auto it = this->SubMenuParent.begin(); it != this->SubMenuParent.end();) { if (it->second == menu) { it = this->SubMenuParent.erase(it); } else { ++it; } } return true; } else if (Event->type() == QEvent::KeyPress) { QKeyEvent* e = static_cast(Event); if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { QAction* action = menu->activeAction(); if (action) { Q_EMIT recordEvent(menu, "activate", actionArgument(action)); } } else if (e->key() == Qt::Key_Right) { QAction* action = menu->activeAction(); if (action && action->menu()) { Q_EMIT recordEvent(menu, "activate", actionArgument(action)); } } else { for (auto action : menu->actions()) { const QKeySequence mnemonic = QKeySequence::mnemonic(action->text()); if (!mnemonic.isEmpty()) { // Then the action has a keyboard accelerator #if QT_VERSION >= 0x060000 if (mnemonic == QKeySequence(QKeyCombination(e->modifiers(), static_cast(e->key())))) #else if (mnemonic == QKeySequence(e->modifiers() + e->key())) #endif { Q_EMIT recordEvent(menu, "activate", actionArgument(action)); } } } } return true; } else if (Event->type() == QEvent::MouseButtonRelease) { QMouseEvent* e = static_cast(Event); if (e->button() == Qt::LeftButton) { QAction* action = menu->actionAt(e->pos()); if (action && !action->menu()) { Q_EMIT recordEvent(menu, "activate", actionArgument(action)); } } return true; } return this->Superclass::translateEvent(Object, Event, Error); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqMenuEventTranslator.h000066400000000000000000000020051526070500000260420ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqMenuEventTranslator_h #define _pqMenuEventTranslator_h #include "pqWidgetEventTranslator.h" #include class QMenu; class QAction; /** Translates low-level Qt events into high-level ParaView events that can be recorded as test cases. \sa pqEventTranslator */ class QTTESTING_EXPORT pqMenuEventTranslator : public pqWidgetEventTranslator { Q_OBJECT typedef pqWidgetEventTranslator Superclass; public: pqMenuEventTranslator(QObject* p = 0); ~pqMenuEventTranslator() override; using Superclass::translateEvent; bool translateEvent(QObject* Object, QEvent* Event, bool& Error) override; private: pqMenuEventTranslator(const pqMenuEventTranslator&); pqMenuEventTranslator& operator=(const pqMenuEventTranslator&); // A sub-menu action -> parent map std::map SubMenuParent; }; #endif // !_pqMenuEventTranslator_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqNativeFileDialogEventPlayer.cxx000066400000000000000000000125131526070500000277670ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqNativeFileDialogEventPlayer.h" #include "pqEventDispatcher.h" #include "pqTestUtility.h" #include #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 3, 0) typedef QString (*_qt_filedialog_existing_directory_hook)( QWidget* parent, const QString& caption, const QString& dir, QFileDialog::Options options); extern Q_DECL_IMPORT _qt_filedialog_existing_directory_hook qt_filedialog_existing_directory_hook; typedef QString (*_qt_filedialog_open_filename_hook)(QWidget* parent, const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options); extern Q_DECL_IMPORT _qt_filedialog_open_filename_hook qt_filedialog_open_filename_hook; typedef QStringList (*_qt_filedialog_open_filenames_hook)(QWidget* parent, const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options); extern Q_DECL_IMPORT _qt_filedialog_open_filenames_hook qt_filedialog_open_filenames_hook; typedef QString (*_qt_filedialog_save_filename_hook)(QWidget* parent, const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options); extern Q_DECL_IMPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook; namespace { pqNativeFileDialogEventPlayer* self; _qt_filedialog_existing_directory_hook old_existing_directory_hook; _qt_filedialog_open_filename_hook old_open_filename_hook; _qt_filedialog_open_filenames_hook old_open_filenames_hook; _qt_filedialog_save_filename_hook old_save_filename_hook; QEventLoop* loop = 0; QString filename; QStringList filenames; QString dir_hook(QWidget* pqNotUsed(parent), const QString& pqNotUsed(caption), const QString& pqNotUsed(dir), QFileDialog::Options pqNotUsed(options)) { // wait for next event played to give us a filename loop->exec(); return filename; } QString filename_hook(QWidget* pqNotUsed(parent), const QString& pqNotUsed(caption), const QString& pqNotUsed(dir), const QString& pqNotUsed(filter), QString* pqNotUsed(selectedFilter), QFileDialog::Options pqNotUsed(options)) { // wait for next event played to give us a filename loop->exec(); return filename; } QStringList filenames_hook(QWidget* pqNotUsed(parent), const QString& pqNotUsed(caption), const QString& pqNotUsed(dir), const QString& pqNotUsed(filter), QString* pqNotUsed(selectedFilter), QFileDialog::Options pqNotUsed(options)) { // wait for next event played to give us a filename loop->exec(); return filenames; } } pqNativeFileDialogEventPlayer::pqNativeFileDialogEventPlayer(pqTestUtility* util, QObject* p) : pqWidgetEventPlayer(p) , mUtil(util) { if (!loop) { loop = new QEventLoop(); } QObject::connect(util, SIGNAL(playbackStarted()), this, SLOT(start())); QObject::connect(util, SIGNAL(playbackStopped()), this, SLOT(stop())); } pqNativeFileDialogEventPlayer::~pqNativeFileDialogEventPlayer() { if (loop) { delete loop; loop = NULL; } } void pqNativeFileDialogEventPlayer::start() { self = this; // existing dir hook old_existing_directory_hook = qt_filedialog_existing_directory_hook; qt_filedialog_existing_directory_hook = dir_hook; // open file hook old_open_filename_hook = qt_filedialog_open_filename_hook; qt_filedialog_open_filename_hook = filename_hook; // open files hook old_open_filenames_hook = qt_filedialog_open_filenames_hook; qt_filedialog_open_filenames_hook = filenames_hook; // save file hook old_save_filename_hook = qt_filedialog_save_filename_hook; qt_filedialog_save_filename_hook = filename_hook; } void pqNativeFileDialogEventPlayer::stop() { self = NULL; qt_filedialog_existing_directory_hook = old_existing_directory_hook; qt_filedialog_open_filename_hook = old_open_filename_hook; qt_filedialog_open_filenames_hook = old_open_filenames_hook; qt_filedialog_save_filename_hook = old_save_filename_hook; } bool pqNativeFileDialogEventPlayer::playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& pqNotUsed(Error)) { if (!qobject_cast(Object)) { return false; } QStringList normalized_files = Arguments.split(";"); QStringList files; Q_FOREACH (QString file, normalized_files) { files.append(mUtil->convertFromDataDirectory(file)); } if (Command == "FileOpen" || Command == "DirOpen" || Command == "FileSave") { filename = files.join(";"); loop->quit(); return true; } else if (Command == "FilesOpen") { filenames = files; loop->quit(); return true; } return false; } #else //----------------------------------------------------------------------------- pqNativeFileDialogEventPlayer::pqNativeFileDialogEventPlayer(pqTestUtility* util, QObject* p) : pqWidgetEventPlayer(p) , mUtil(util) { } pqNativeFileDialogEventPlayer::~pqNativeFileDialogEventPlayer() {} void pqNativeFileDialogEventPlayer::start() {} void pqNativeFileDialogEventPlayer::stop() {} bool pqNativeFileDialogEventPlayer::playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) { Q_UNUSED(Object); Q_UNUSED(Command); Q_UNUSED(Arguments); Q_UNUSED(Error); return false; } #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqNativeFileDialogEventPlayer.h000066400000000000000000000021141526070500000274100ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqNativeFileDialogEventPlayer_h #define _pqNativeFileDialogEventPlayer_h #include "pqWidgetEventPlayer.h" #include class pqTestUtility; /** Records usage of native file dialogs in test cases. \sa pqEventPlayer */ class QTTESTING_EXPORT pqNativeFileDialogEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pqNativeFileDialogEventPlayer(pqTestUtility* util, QObject* p = 0); ~pqNativeFileDialogEventPlayer() override; using Superclass::playEvent; bool playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) override; protected Q_SLOTS: void start(); void stop(); protected: pqTestUtility* mUtil; private: pqNativeFileDialogEventPlayer(const pqNativeFileDialogEventPlayer&); pqNativeFileDialogEventPlayer& operator=(const pqNativeFileDialogEventPlayer&); }; #endif // !_pqNativeFileDialogEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqNativeFileDialogEventTranslator.cxx000066400000000000000000000137531526070500000306730ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqNativeFileDialogEventTranslator.h" #include "pqEventTranslator.h" #include "pqTestUtility.h" #include #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 3, 0) typedef QString (*_qt_filedialog_existing_directory_hook)( QWidget* parent, const QString& caption, const QString& dir, QFileDialog::Options options); extern Q_DECL_IMPORT _qt_filedialog_existing_directory_hook qt_filedialog_existing_directory_hook; typedef QString (*_qt_filedialog_open_filename_hook)(QWidget* parent, const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options); extern Q_DECL_IMPORT _qt_filedialog_open_filename_hook qt_filedialog_open_filename_hook; typedef QStringList (*_qt_filedialog_open_filenames_hook)(QWidget* parent, const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options); extern Q_DECL_IMPORT _qt_filedialog_open_filenames_hook qt_filedialog_open_filenames_hook; typedef QString (*_qt_filedialog_save_filename_hook)(QWidget* parent, const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options); extern Q_DECL_IMPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook; namespace { pqNativeFileDialogEventTranslator* self; _qt_filedialog_existing_directory_hook old_existing_directory_hook; _qt_filedialog_open_filename_hook old_open_filename_hook; _qt_filedialog_open_filenames_hook old_open_filenames_hook; _qt_filedialog_save_filename_hook old_save_filename_hook; QString existing_directory_hook( QWidget* parent, const QString& caption, const QString& dir, QFileDialog::Options options) { qt_filedialog_existing_directory_hook = 0; QString path = QFileDialog::getExistingDirectory(parent, caption, dir, options); self->record("DirOpen", path); qt_filedialog_existing_directory_hook = existing_directory_hook; return path; } QString open_filename_hook(QWidget* parent, const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options) { qt_filedialog_open_filename_hook = 0; QString file = QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options); self->record("FileOpen", file); qt_filedialog_open_filename_hook = open_filename_hook; return file; } QStringList open_filenames_hook(QWidget* parent, const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options) { qt_filedialog_open_filenames_hook = 0; QStringList files = QFileDialog::getOpenFileNames(parent, caption, dir, filter, selectedFilter, options); self->record("FilesOpen", files.join(";")); qt_filedialog_open_filenames_hook = open_filenames_hook; return files; } QString save_filename_hook(QWidget* parent, const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options) { qt_filedialog_save_filename_hook = 0; QString file = QFileDialog::getSaveFileName(parent, caption, dir, filter, selectedFilter, options); self->record("FileSave", file); qt_filedialog_save_filename_hook = save_filename_hook; return file; } } pqNativeFileDialogEventTranslator::pqNativeFileDialogEventTranslator( pqTestUtility* util, QObject* p) : pqWidgetEventTranslator(p) , mUtil(util) { QObject::connect(mUtil->eventTranslator(), SIGNAL(started()), this, SLOT(start())); QObject::connect(mUtil->eventTranslator(), SIGNAL(stopped()), this, SLOT(stop())); } pqNativeFileDialogEventTranslator::~pqNativeFileDialogEventTranslator() {} void pqNativeFileDialogEventTranslator::start() { self = this; old_existing_directory_hook = qt_filedialog_existing_directory_hook; qt_filedialog_existing_directory_hook = existing_directory_hook; old_open_filename_hook = qt_filedialog_open_filename_hook; qt_filedialog_open_filename_hook = open_filename_hook; old_open_filenames_hook = qt_filedialog_open_filenames_hook; qt_filedialog_open_filenames_hook = open_filenames_hook; old_save_filename_hook = qt_filedialog_save_filename_hook; qt_filedialog_save_filename_hook = save_filename_hook; } void pqNativeFileDialogEventTranslator::stop() { self = NULL; qt_filedialog_existing_directory_hook = old_existing_directory_hook; qt_filedialog_open_filename_hook = old_open_filename_hook; qt_filedialog_open_filenames_hook = old_open_filenames_hook; qt_filedialog_save_filename_hook = old_save_filename_hook; } bool pqNativeFileDialogEventTranslator::translateEvent( QObject* Object, QEvent* pqNotUsed(Event), bool& pqNotUsed(Error)) { // capture events under a filedialog and consume them QObject* tmp = Object; while (tmp) { if (qobject_cast(tmp)) { return true; } tmp = tmp->parent(); } return false; } void pqNativeFileDialogEventTranslator::record(const QString& command, const QString& args) { QStringList files = args.split(";"); QStringList normalized_files; Q_FOREACH (QString file, files) { normalized_files.append(mUtil->convertToDataDirectory(file)); } Q_EMIT this->recordEvent(QApplication::instance(), command, normalized_files.join(";")); } #else pqNativeFileDialogEventTranslator::pqNativeFileDialogEventTranslator( pqTestUtility* util, QObject* p) : pqWidgetEventTranslator(p) , mUtil(util) { } pqNativeFileDialogEventTranslator::~pqNativeFileDialogEventTranslator() {} void pqNativeFileDialogEventTranslator::start() {} void pqNativeFileDialogEventTranslator::stop() {} bool pqNativeFileDialogEventTranslator::translateEvent( QObject* pqNotUsed(Object), QEvent* pqNotUsed(Event), bool& pqNotUsed(Error)) { return false; } void pqNativeFileDialogEventTranslator::record(const QString& command, const QString& args) { Q_UNUSED(command); Q_UNUSED(args); } #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqNativeFileDialogEventTranslator.h000066400000000000000000000022431526070500000303100ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqNativeFileDialogEventTranslator_h #define _pqNativeFileDialogEventTranslator_h #include "pqWidgetEventTranslator.h" #include class pqTestUtility; /** Records usage of native file dialogs in test cases. \sa pqEventTranslator */ class QTTESTING_EXPORT pqNativeFileDialogEventTranslator : public pqWidgetEventTranslator { Q_OBJECT typedef pqWidgetEventTranslator Superclass; public: pqNativeFileDialogEventTranslator(pqTestUtility* util, QObject* p = 0); ~pqNativeFileDialogEventTranslator() override; using Superclass::translateEvent; bool translateEvent(QObject* Object, QEvent* Event, bool& Error) override; void record(const QString& command, const QString& args); protected Q_SLOTS: void start(); void stop(); protected: pqTestUtility* mUtil; private: pqNativeFileDialogEventTranslator(const pqNativeFileDialogEventTranslator&); pqNativeFileDialogEventTranslator& operator=(const pqNativeFileDialogEventTranslator&); }; #endif // !_pqNativeFileDialogEventTranslator_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqObjectNaming.cxx000066400000000000000000000167231526070500000250110ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqObjectNaming.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { QString ErrorMessage; } /** Returns the name of an object as if it was unnamed.*/ static const QString InternalGetNameAsUnnamed(QObject& Object) { QString result; QObjectList siblings; if (Object.parent()) { siblings = Object.parent()->children(); } else { QWidgetList widgets = QApplication::topLevelWidgets(); for (int i = 0; i != widgets.size(); ++i) { siblings.push_back(widgets[i]); } } const QString type = Object.metaObject()->className(); // order of top level widgets is not guarenteed // we can someone counter that by checking visibility, // as we usually only test visible widgets, we would get the right one int invisible_index = 0; int visible_index = 0; for (int i = 0; i != siblings.size(); ++i) { QObject* test = siblings[i]; if (test == &Object) { break; } else if (type == test->metaObject()->className() && test->objectName().isEmpty()) { QWidget* widget = qobject_cast(test); if (widget && widget->isVisible()) { ++visible_index; } else { ++invisible_index; } } } int index = invisible_index; if (QWidget* const widget = qobject_cast(&Object)) { if (widget->isVisible()) { result += QString::number(1); index = visible_index; } else { result += QString::number(0); } } result += type + QString::number(index); result.replace("/", "|"); return result; } /** Returns the name of an object. If the object doesn't have an explicit name, assigns a name as a convenience. Also replaces problematic characters such as '/'. */ static const QString InternalGetName(QObject& Object) { QString result = Object.objectName(); if (result.isEmpty()) { result = InternalGetNameAsUnnamed(Object); } if (qobject_cast(&Object)) { result.append("-app"); } result.replace("/", "|"); return result; } const QString pqObjectNaming::GetName(QObject& Object) { QString name = InternalGetName(Object); if (name.isEmpty()) { qCritical() << "Cannot record event for unnamed object " << &Object; return QString(); } for (QObject* p = Object.parent(); p; p = p->parent()) { const QString parent_name = InternalGetName(*p); if (parent_name.isEmpty()) { qCritical() << "Cannot record event for incompletely-named object " << name << " " << &Object << " with parent " << p; return QString(); } name = parent_name + "/" + name; if (!p->parent() && !QApplication::topLevelWidgets().contains(qobject_cast(p))) { qCritical() << "Unable to to determine name for Object " << &Object << " because a parent " << p << " is not a top-level widget. Name so far = " << name; return QString(); } } return name; } QObject* pqObjectNaming::GetObject(const QString& Name) { QObject* result = 0; QObject* lastObject = 0; if (Name.isEmpty()) { return 0; } const QStringList names = Name.split("/"); // see if QApplication is the requested object QString app_name = InternalGetName(*QApplication::instance()); if (app_name == Name) { return QApplication::instance(); } const QWidgetList top_level_widgets = QApplication::topLevelWidgets(); for (int i = 0; i != top_level_widgets.size(); ++i) { QObject* object = top_level_widgets[i]; const QString name = InternalGetName(*object); const QString alt_name = InternalGetNameAsUnnamed(*object); if (name == names[0] || alt_name == names[0]) { result = object; lastObject = object; break; } } for (int j = 1; j < names.size(); ++j) { const QObjectList& children = result ? result->children() : QObjectList(); result = 0; QString objectName = names[j]; for (int k = 0; k != children.size(); ++k) { QObject* child = children[k]; const QString name = InternalGetName(*child); const QString alt_name = InternalGetNameAsUnnamed(*child); if (name == objectName || alt_name == objectName) { result = child; lastObject = child; break; } // Sometimes, when playing, widget are visible when they were not during recording, // try again with visibility at 1. if (k == children.size() - 1 && result == 0 && !objectName.isEmpty() && objectName[0] == '0') { objectName[0] = '1'; k = 0; } } } if (result) return result; ErrorMessage.clear(); QTextStream stream(&ErrorMessage); stream << "\n"; // a newline to keep horizontal alignment stream << "Couldn't find object `" << Name << "`\n"; if (lastObject) { stream << "Found up to `" << pqObjectNaming::GetName(*lastObject) << "`\n"; } // controls how many matches to dump in error message. QString matchLimitEnv = QString::fromUtf8(qgetenv("PQOBJECTNAMING_MATCH_LIMIT")); const int matchLimit = matchLimitEnv.isEmpty() ? 20 : matchLimitEnv.toInt(); bool foundMatch = false; if (lastObject) { QObjectList matches = lastObject->findChildren(names[names.size() - 1]); for (int cc = 0; (matchLimit <= 0 || cc < matchLimit) && cc < matches.size(); ++cc) { stream << " Possible match: `" << pqObjectNaming::GetName(*matches[cc]) << "`\n"; foundMatch = true; } if (matchLimit > 0 && matches.size() > matchLimit) { stream << " Possible match: .... (and " << (matches.size() - matchLimit) << " more!)\n" << " Set PQOBJECTNAMING_MATCH_LIMIT environment var to a +'ve number to limit " "entries (or 0 for unlimited).\n"; } if (!foundMatch) { matches = lastObject->findChildren(); for (int cc = 0; (matchLimit <= 0 || cc < matchLimit) && cc < matches.size(); ++cc) { stream << " Available widget: `" << pqObjectNaming::GetName(*matches[cc]) << "`\n"; } if (matchLimit > 0 && matches.size() > matchLimit) { stream << " Available widget: .... (and " << (matches.size() - matchLimit) << " more!)\n" << " Set PQOBJECTNAMING_MATCH_LIMIT environment var to a +'ve number to limit " "entries (or 0 for unlimited).\n"; } } } return 0; } void pqObjectNaming::DumpHierarchy(QStringList& results) { const QWidgetList widgets = QApplication::topLevelWidgets(); for (int i = 0; i != widgets.size(); ++i) { DumpHierarchy(*widgets[i], results); } } void pqObjectNaming::DumpHierarchy(QObject& object, QStringList& results) { results << GetName(object); const QObjectList children = object.children(); for (int i = 0; i != children.size(); ++i) { DumpHierarchy(*children[i], results); } } QString pqObjectNaming::lastErrorMessage() { return ErrorMessage; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqObjectNaming.h000066400000000000000000000022101526070500000244200ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqObjectNaming_h #define _pqObjectNaming_h #include #include "QtTestingExport.h" class QObject; #if QT_VERSION < 0x060000 class QStringList; #endif /// Provides functionality to ensuring that Qt objects can be uniquely identified for recording and /// playback of regression tests class QTTESTING_EXPORT pqObjectNaming { public: /// Returns a unique identifier for the given object that can be serialized for later regression /// test playback static const QString GetName(QObject& Object); /// Given a unique identifier returned by GetName(), returns the corresponding object, or NULL static QObject* GetObject(const QString& Name); /** Dumps the widget hierarchy to a string */ static void DumpHierarchy(QStringList& results); /** Dumps a subtree of the widget hierarchy to a string */ static void DumpHierarchy(QObject& Object, QStringList& results); /// Recover the last error message static QString lastErrorMessage(); }; #endif // !_pqObjectNaming_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqObjectPlayer.cxx000066400000000000000000000026221526070500000250250ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-License-Identifier: BSD-3-Clause #include "pqObjectPlayer.h" #include "pqEventTypes.h" #include #include // ---------------------------------------------------------------------------- pqObjectPlayer::pqObjectPlayer(QObject* parent) : Superclass(parent) { } // ---------------------------------------------------------------------------- bool pqObjectPlayer::playEvent( QObject* object, const QString& command, const QString& arguments, int eventType, bool& error) { if (!object) { return false; } if (eventType == pqEventTypes::CHECK_EVENT) { QVariant propertyValue = object->property(command.toUtf8().data()); if (!propertyValue.isValid()) { return false; } if (propertyValue.toString().replace("\t", " ") != arguments) { QString errorMessage = object->objectName() + " property value is: " + propertyValue.toString() + ". Expecting: " + arguments + "."; qCritical() << errorMessage.toUtf8().data(); error = true; } return true; } if (eventType == pqEventTypes::ACTION_EVENT) { return this->playEvent(object, command, arguments, error); } return false; } // ---------------------------------------------------------------------------- bool pqObjectPlayer::playEvent(QObject*, const QString&, const QString&, bool&) { return false; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqObjectPlayer.h000066400000000000000000000026041526070500000244520ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqObjectPlayer_h #define _pqObjectPlayer_h #include "QtTestingExport.h" #include class QString; /** * Base Player class. * It defines the API to play events. * It handles the playback of "check" events for QObject, looking for QObject::property. */ class QTTESTING_EXPORT pqObjectPlayer : public QObject { Q_OBJECT typedef QObject Superclass; public: pqObjectPlayer(QObject* parent = nullptr); ~pqObjectPlayer() override = default; /** * Entry point to handle events. * * If type is pqEventTypes::CHECK_EVENT, look for a QObject::property * named as the "command" and test its value against "arguments". * * pqEventTypes::ACTION_EVENT is forwarded to playEvent(QObject*, QString, QString, bool&) * * Returns true if event was handled. * Returns false if object is nullptr. */ virtual bool playEvent( QObject* object, const QString& command, const QString& arguments, int eventType, bool& error); /** * Entry point for the pqEventTypes::ACTION_EVENT type only. * Default implementation is no op and return false. */ virtual bool playEvent(QObject*, const QString&, const QString&, bool&); private: pqObjectPlayer(const pqObjectPlayer&); pqObjectPlayer& operator=(const pqObjectPlayer&); }; #endif // _pqBasicObjectPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqPlayBackEventsDialog.cxx000066400000000000000000000373351526070500000264460ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqPlayBackEventsDialog.h" #include "pqCommentEventPlayer.h" #include "pqEventDispatcher.h" #include "pqEventPlayer.h" #include "pqTestUtility.h" #include "ui_pqPlayBackEventsDialog.h" #include #include #include #include #include #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////////// // pqImplementation struct pqPlayBackEventsDialog::pqImplementation { public: pqImplementation( pqEventPlayer& player, pqEventDispatcher& dispatcher, pqTestUtility* testUtility); ~pqImplementation(); void init(pqPlayBackEventsDialog* dialog); void setProgressBarsValue(int value); void setProgressBarValue(int row, int value); QString setMaxLenght(const QString& name, int max); Ui::pqPlayBackEventsDialog Ui; pqEventPlayer& Player; pqEventDispatcher& Dispatcher; pqTestUtility* TestUtility; int CurrentLine; // Add counter to the Dispatcher int MaxLines; int CurrentFile; QStringList Filenames; QStringList CurrentEvent; QRect OldRect; }; // ---------------------------------------------------------------------------- pqPlayBackEventsDialog::pqImplementation::pqImplementation( pqEventPlayer& player, pqEventDispatcher& dispatcher, pqTestUtility* testUtility) : Player(player) , Dispatcher(dispatcher) , TestUtility(testUtility) { this->CurrentLine = 0; this->MaxLines = 0; this->CurrentFile = 0; this->Filenames = QStringList(); this->CurrentEvent = QStringList(); } // ---------------------------------------------------------------------------- pqPlayBackEventsDialog::pqImplementation::~pqImplementation() {} // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::pqImplementation::init(pqPlayBackEventsDialog* dialog) { this->Ui.setupUi(dialog); this->Ui.loadFileButton->setIcon(QApplication::style()->standardIcon(QStyle::SP_DirOpenIcon)); this->Ui.playerErrorTextLabel->setVisible(false); this->Ui.playerErrorIconLabel->setVisible(false); this->Ui.infoErrorTextLabel->setVisible(false); this->Ui.infoErrorIconLabel->setVisible(false); this->Ui.logBrowser->setVisible(false); pqWidgetEventPlayer* widgetPlayer = this->Player.getWidgetEventPlayer(QString("pqCommentEventPlayer")); pqCommentEventPlayer* commentPlayer = qobject_cast(widgetPlayer); if (commentPlayer) { QObject::connect( commentPlayer, SIGNAL(comment(QString)), this->Ui.logBrowser, SLOT(append(QString))); } dialog->setMaximumHeight(dialog->minimumSizeHint().height()); QObject::connect(&this->Player, SIGNAL(eventAboutToBePlayed(QString, QString, QString)), dialog, SLOT(onEventAboutToBePlayed(QString, QString, QString))); QObject::connect( this->Ui.timeStepSpinBox, SIGNAL(valueChanged(int)), &this->Dispatcher, SLOT(setTimeStep(int))); QObject::connect(this->Ui.loadFileButton, SIGNAL(clicked()), dialog, SLOT(loadFiles())); QObject::connect(this->Ui.plusButton, SIGNAL(clicked()), dialog, SLOT(insertFiles())); QObject::connect(this->Ui.minusButton, SIGNAL(clicked()), dialog, SLOT(removeFiles())); QObject::connect( this->Ui.playPauseButton, SIGNAL(toggled(bool)), dialog, SLOT(onPlayOrPause(bool))); QObject::connect( this->Ui.playPauseButton, SIGNAL(toggled(bool)), &this->Dispatcher, SLOT(run(bool))); QObject::connect(this->Ui.stopButton, SIGNAL(clicked()), this->TestUtility, SLOT(stopTests())); QObject::connect(this->Ui.stepButton, SIGNAL(clicked()), dialog, SLOT(onOneStep())); QObject::connect( this->TestUtility, SIGNAL(playbackStarted(QString)), dialog, SLOT(onStarted(QString))); QObject::connect(this->TestUtility, SIGNAL(playbackStarted()), dialog, SLOT(onStarted())); QObject::connect(this->TestUtility, SIGNAL(playbackStopped()), dialog, SLOT(onStopped())); QObject::connect(&this->Dispatcher, SIGNAL(paused()), dialog, SLOT(updateUi())); QObject::connect(&this->Dispatcher, SIGNAL(restarted()), dialog, SLOT(updateUi())); QObject::connect( &this->Player, SIGNAL(errorMessage(QString)), this->Ui.logBrowser, SLOT(append(QString))); } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::pqImplementation::setProgressBarsValue(int value) { for (int i = 0; i < this->Ui.tableWidget->rowCount(); ++i) { this->setProgressBarValue(i, value); } } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::pqImplementation::setProgressBarValue(int row, int value) { QWidget* widget = this->Ui.tableWidget->cellWidget(row, 2); QProgressBar* progressBar = qobject_cast(widget); progressBar->setValue(value); } // ---------------------------------------------------------------------------- QString pqPlayBackEventsDialog::pqImplementation::setMaxLenght(const QString& name, int max) { if (name.length() > max) { return name.left(max / 2) + "..." + name.right(max / 2); } return name; } /////////////////////////////////////////////////////////////////////////////////// // pqPlayBackEventsDialog // ---------------------------------------------------------------------------- pqPlayBackEventsDialog::pqPlayBackEventsDialog( pqEventPlayer& Player, pqEventDispatcher& Dispatcher, pqTestUtility* TestUtility, QWidget* Parent) : QDialog(Parent) , Implementation(new pqImplementation(Player, Dispatcher, TestUtility)) { this->Implementation->init(this); this->setAttribute(Qt::WA_DeleteOnClose); this->loadFiles(); } // ---------------------------------------------------------------------------- pqPlayBackEventsDialog::~pqPlayBackEventsDialog() { delete Implementation; } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::done(int value) { this->Implementation->TestUtility->stopTests(); QDialog::done(value); } // ---------------------------------------------------------------------------- QStringList pqPlayBackEventsDialog::selectedFileNames() const { QStringList list; for (int i = 0; i < this->Implementation->Ui.tableWidget->rowCount(); ++i) { QCheckBox* box = qobject_cast(this->Implementation->Ui.tableWidget->cellWidget(i, 0)); if (box->isChecked()) { list << this->Implementation->Filenames[i]; } } return list; } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::onEventAboutToBePlayed( const QString& Object, const QString& Command, const QString& Arguments) { ++this->Implementation->CurrentLine; QStringList newEvent; newEvent << Object << Command << Arguments; this->Implementation->CurrentEvent = newEvent; this->updateUi(); } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::loadFiles() { QFileDialog* dialog = new QFileDialog(this, "Macro File Name", QString(), "XML Files (*.xml)"); dialog->setFileMode(QFileDialog::ExistingFiles); if (dialog->exec()) { this->Implementation->Filenames = dialog->selectedFiles(); this->Implementation->Ui.tableWidget->setRowCount(0); this->loadFiles(this->Implementation->Filenames); } delete dialog; } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::insertFiles() { QFileDialog* dialog = new QFileDialog(this, "Macro File Name", QString(), "XML Files (*.xml)"); dialog->setFileMode(QFileDialog::ExistingFiles); if (dialog->exec()) { this->Implementation->Filenames << dialog->selectedFiles(); this->loadFiles(dialog->selectedFiles()); } delete dialog; } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::removeFiles() { if (QMessageBox::Ok == QMessageBox::warning(this, QString("Remove files"), QString("Are you sure you want to \n" "remove all checked files ?\n"), QMessageBox::Ok, QMessageBox::Cancel)) { Q_FOREACH (QString file, this->selectedFileNames()) { int index = this->Implementation->Filenames.indexOf(file); this->Implementation->Ui.tableWidget->removeRow(index); this->Implementation->Filenames.removeAt(index); } this->updateUi(); } } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::loadFiles(const QStringList& filenames) { for (int i = 0; i < filenames.count(); i++) { this->addFile(filenames[i]); } this->Implementation->Ui.tableWidget->resizeColumnToContents(0); } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::addFile(const QString& filename) { QFileInfo info(filename); int newIndex = this->Implementation->Ui.tableWidget->rowCount(); this->Implementation->Ui.tableWidget->insertRow(newIndex); this->Implementation->Ui.tableWidget->setItem(newIndex, 1, new QTableWidgetItem(info.fileName())); this->Implementation->Ui.tableWidget->setCellWidget( newIndex, 2, new QProgressBar(this->Implementation->Ui.tableWidget)); this->Implementation->setProgressBarValue(newIndex, 0); QCheckBox* check = new QCheckBox(this->Implementation->Ui.tableWidget); check->setChecked(true); QObject::connect(check, SIGNAL(toggled(bool)), this, SLOT(updateUi())); this->Implementation->Ui.tableWidget->setCellWidget(newIndex, 0, check); this->updateUi(); } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::onPlayOrPause(bool playOrPause) { if (this->Implementation->TestUtility->playingTest() || !playOrPause) { return; } QStringList newList = this->selectedFileNames(); this->Implementation->TestUtility->playTests(newList); } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::onOneStep() { this->Implementation->Ui.playPauseButton->setChecked(false); if (!this->Implementation->TestUtility->playingTest()) { this->Implementation->Dispatcher.run(false); this->Implementation->Dispatcher.oneStep(); QStringList newList = this->selectedFileNames(); this->Implementation->TestUtility->playTests(newList); } else { this->Implementation->Dispatcher.oneStep(); } } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::onStarted(const QString& filename) { this->Implementation->CurrentFile = this->Implementation->Filenames.indexOf(filename); this->Implementation->Ui.tableWidget->setCurrentCell(this->Implementation->CurrentFile, 1, QItemSelectionModel::Rows | QItemSelectionModel::SelectCurrent); this->Implementation->Ui.logBrowser->clear(); this->Implementation->MaxLines = 0; this->Implementation->CurrentLine = 0; QFile file(filename); QFileInfo infoFile(file); if (!file.open(QIODevice::ReadOnly)) { qCritical() << "Could not open " << filename; return; } this->Implementation->Ui.logBrowser->append(QString("Start file : %1").arg(infoFile.fileName())); QTextStream stream(&file); #if QT_VERSION < 0x060000 stream.setCodec("UTF-8"); #endif this->Implementation->Ui.currentFileLabel->setText(infoFile.fileName()); while (!stream.atEnd()) { QString line = stream.readLine(); if (line.trimmed().startsWith("Implementation->MaxLines; } } } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::onStarted() { this->Implementation->setProgressBarsValue(0); this->updateUi(); } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::onStopped() { this->Implementation->Ui.playPauseButton->setChecked(false); this->updateUi(); } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::updateUi() { // Update Moda/Modeless this->onModal(this->Implementation->TestUtility->playingTest() && !(this->Implementation->TestUtility->playingTest() && this->Implementation->Dispatcher.isPaused())); // Update player buttons this->Implementation->Ui.playPauseButton->setChecked( this->Implementation->TestUtility->playingTest() && !this->Implementation->Dispatcher.isPaused()); this->Implementation->Ui.playPauseButton->setEnabled( !this->Implementation->Filenames.isEmpty() && this->selectedFileNames().count() > 0); this->Implementation->Ui.stepButton->setEnabled( !this->Implementation->Filenames.isEmpty() && this->selectedFileNames().count() > 0); this->Implementation->Ui.stopButton->setEnabled(this->Implementation->TestUtility->playingTest()); // loadFile, plus and minus buttons this->Implementation->Ui.loadFileButton->setEnabled( !this->Implementation->TestUtility->playingTest()); this->Implementation->Ui.plusButton->setEnabled( !this->Implementation->TestUtility->playingTest()); this->Implementation->Ui.minusButton->setEnabled( !this->Implementation->TestUtility->playingTest()); // Time step this->Implementation->Ui.timeStepSpinBox->setEnabled(!this->Implementation->Filenames.isEmpty()); // Error feedback this->Implementation->Ui.playerErrorTextLabel->setVisible( !this->Implementation->Dispatcher.status()); this->Implementation->Ui.playerErrorIconLabel->setVisible( !this->Implementation->Dispatcher.status()); this->Implementation->Ui.infoErrorTextLabel->setVisible( !this->Implementation->Dispatcher.status()); this->Implementation->Ui.infoErrorIconLabel->setVisible( !this->Implementation->Dispatcher.status()); QString command = tr("Command : "); QString argument = tr("Argument(s) : "); QString object = tr("Object : "); if (this->Implementation->TestUtility->playingTest() && !this->Implementation->CurrentEvent.isEmpty()) { command += this->Implementation->setMaxLenght(this->Implementation->CurrentEvent[1], 40); argument += this->Implementation->setMaxLenght(this->Implementation->CurrentEvent[2], 40); object += this->Implementation->setMaxLenght(this->Implementation->CurrentEvent[0], 40); this->Implementation->setProgressBarValue(this->Implementation->CurrentFile, static_cast((static_cast(this->Implementation->CurrentLine) / static_cast(this->Implementation->MaxLines - 1)) * 100)); } else { this->Implementation->Ui.currentFileLabel->setText(QString("No Test is playing ...")); } this->Implementation->Ui.commandLabel->setText(command); this->Implementation->Ui.argumentsLabel->setText(argument); this->Implementation->Ui.objectLabel->setText(object); this->update(); } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::onModal(bool value) { // From modal to modeless we don't need to hide() show() the dialog if (value) { this->setAttribute(Qt::WA_WState_Visible, false); this->setAttribute(Qt::WA_WState_Hidden, true); } this->setModal(value); if (value) { this->Implementation->OldRect = this->frameGeometry(); this->setVisible(true); this->Implementation->OldRect = QRect(); } this->raise(); } // ---------------------------------------------------------------------------- void pqPlayBackEventsDialog::moveEvent(QMoveEvent* event) { if (this->Implementation->OldRect.isValid()) { QPoint oldPos = this->Implementation->OldRect.topLeft(); this->Implementation->OldRect = QRect(); this->move(oldPos); } else { this->Superclass::moveEvent(event); } } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqPlayBackEventsDialog.h000066400000000000000000000032331526070500000260610ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqPlayBackEventsDialog_h #define _pqPlayBackEventsDialog_h #include "QtTestingExport.h" #include class pqEventPlayer; class pqEventDispatcher; class pqTestUtility; /// Provides a standard dialog that will PlayBack user input to an XML file as long as the dialog /// remains open class QTTESTING_EXPORT pqPlayBackEventsDialog : public QDialog { Q_OBJECT typedef QDialog Superclass; public: /** Creates the dialog and begins translating user input with the supplied translator. */ pqPlayBackEventsDialog( pqEventPlayer& Player, pqEventDispatcher& Source, pqTestUtility* TestUtility, QWidget* Parent); ~pqPlayBackEventsDialog() override; private Q_SLOTS: void onEventAboutToBePlayed(const QString&, const QString&, const QString&); void loadFiles(); void insertFiles(); void removeFiles(); void onPlayOrPause(bool); void onOneStep(); void onStarted(); void onStarted(const QString&); void onStopped(); void onModal(bool value); public Q_SLOTS: void done(int) override; void updateUi(); protected: void moveEvent(QMoveEvent* event) override; private: void loadFiles(const QStringList& filenames); void addFile(const QString& filename); QStringList selectedFileNames() const; pqPlayBackEventsDialog(const pqPlayBackEventsDialog&); // Not Implemented pqPlayBackEventsDialog& operator=(const pqPlayBackEventsDialog&); // Not Implemented struct pqImplementation; pqImplementation* const Implementation; }; #endif // !_pqPlayBackEventsDialog_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqPlayBackEventsDialog.ui000066400000000000000000000550441526070500000262560ustar00rootroot00000000000000 pqPlayBackEventsDialog Qt::NonModal 0 0 392 332 0 0 0 0 16777215 16777215 PlayBack Information false false QLayout::SetDefaultConstraint 0 0 0 0 16777215 16777215 QTabWidget::North QTabWidget::Rounded 0 15 16 Qt::ElideNone false true :/Icons/timePlay.png:/Icons/timePlay.png Player QLayout::SetMaximumSize true 0 0 0 0 16777215 16777215 QFrame::NoFrame QFrame::Sunken Qt::ScrollBarAsNeeded true true QAbstractItemView::NoSelection Qt::NoPen false 3 false true 150 true 15 false true false Files false Progress 18 18 :/Icons/clear.svg true 170 0 0 170 0 0 106 104 100 75 true Error occured Qt::Horizontal 200 20 Add scripts to the list :/Icons/plus.png:/Icons/plus.png 24 24 false Remove checked scripts :/Icons/minus.png:/Icons/minus.png 0 0 Open scripts Open Scripts Information about the current event :/Icons/info.png:/Icons/info.png Info QLayout::SetMaximumSize QLayout::SetDefaultConstraint 0 0 No file is playing Qt::Horizontal 40 20 0 0 18 18 :/Icons/clear.svg true 170 0 0 0 0 0 170 0 0 0 0 0 106 104 100 190 190 190 75 true Error occured true 0 0 Current Event false false false QLayout::SetNoConstraint 0 0 Object : 0 0 Command : 0 0 Argument(s) : Qt::Vertical 20 0 Qt::Horizontal QLayout::SetFixedSize false Play/Pause :/Icons/timePlay.png :/Icons/pause.png:/Icons/timePlay.png true false false false false Play step by step :/Icons/frameForward.png:/Icons/frameForward.png false false false false 0 0 Stop :/Icons/playback-stop.png:/Icons/playback-stop.png false Qt::Horizontal 40 20 Time step : false 0 0 Time step between each events ms 0 1000 10 100 Show/Hide log browser Logs 0 0 checkBox toggled(bool) logBrowser setVisible(bool) 381 220 161 270 qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqPythonEventObserver.cxx000066400000000000000000000030031526070500000264270ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqPythonEventObserver.h" #include //////////////////////////////////////////////////////////////////////////////////// // pqPythonEventObserver pqPythonEventObserver::pqPythonEventObserver(QObject* p) : pqEventObserver(p) { } pqPythonEventObserver::~pqPythonEventObserver() {} void pqPythonEventObserver::setStream(QTextStream* stream) { pqEventObserver::setStream(stream); if (this->Stream) { *this->Stream << "#/usr/bin/env python\n\n"; *this->Stream << "import QtTesting\n\n"; } } void pqPythonEventObserver::onRecordEvent( const QString& Widget, const QString& Command, const QString& Arguments, const int& eventType) { if (this->Stream) { QString varname = this->Names[Widget]; if (varname.isEmpty()) { varname = QString("object%1").arg(this->Names.count()); this->Names.insert(Widget, varname); QString objname("%1 = '%2'"); objname = objname.arg(varname); objname = objname.arg(Widget); *this->Stream << objname << "\n"; } QString pycommand("QtTesting.playCommand(%1, '%2', '%3', '%4')"); pycommand = pycommand.arg(varname); pycommand = pycommand.arg(Command); pycommand = pycommand.arg(Arguments); pycommand = pycommand.arg(eventType); *this->Stream << pycommand << "\n"; Q_EMIT eventRecorded(widget, command, arguments, eventType); } } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqPythonEventObserver.h000066400000000000000000000022741526070500000260650ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqPythonEventObserver_h #define _pqPythonEventObserver_h #include "pqEventObserver.h" #include #include /** Observes high-level ParaView events, and serializes them to a stream as Python for possible playback (as a test-case, demo, tutorial, etc). To use, connect the onRecordEvent() slot to the pqEventTranslator::recordEvent() signal. \note Output is sent to the stream from this object's destructor, so you must ensure that it goes out of scope before trying to playback the stream. \sa pqEventTranslator, pqStdoutEventObserver, pqPythonEventSource. */ class QTTESTING_EXPORT pqPythonEventObserver : public pqEventObserver { Q_OBJECT public: pqPythonEventObserver(QObject* p = 0); ~pqPythonEventObserver(); void onRecordEvent( const QString& Widget, const QString& Command, const QString& Arguments, const int& eventType); void setStream(QTextStream*); private: /// Stores a stream that will be used to store the Python output QHash Names; }; #endif // !_pqPythonEventObserver_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqPythonEventSource.cxx000066400000000000000000000322131526070500000261050ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause /* Use the "documented" trick involving checking for _DEBUG and undefined that symbol while we include Python headers. Update: this method does not fool Microsoft Visual C++ 8 anymore; two of its header files (crtdefs.h and use_ansi.h) check if _DEBUG was set or not, and set flags accordingly (_CRT_MANIFEST_RETAIL, _CRT_MANIFEST_DEBUG, _CRT_MANIFEST_INCONSISTENT). The next time the check is performed in the same compilation unit, and the flags are found, and error is triggered. Let's prevent that by setting _CRT_NOFORCE_MANIFEST. */ #ifdef _DEBUG #undef _DEBUG #if defined(_MSC_VER) && _MSC_VER >= 1400 #define _CRT_NOFORCE_MANIFEST 1 #endif #include #define _DEBUG #else #include #endif #ifndef PyMODINIT_FUNC #define PyMODINIT_FUNC extern "C" void #endif // PyMODINIT_FUNC // self include #include "pqPythonEventSource.h" // system includes #include // Qt include #include #include #include #include #include #include #include #include #include #include // Qt testing includes #include "pqEventDispatcher.h" #include "pqObjectNaming.h" #include "pqWidgetEventPlayer.h" // TODO not have a global instance pointer? static pqPythonEventSource* Instance = NULL; static QString PropertyObject; static QString PropertyResult; static QString PropertyValue; static QStringList ObjectList; static PyObject* QtTesting_playCommand(PyObject* /*self*/, PyObject* args) { // this gives the main thread some time to refresh before we start sending // commands. Avoids crazy hangs in QDialog::exec() calls. pqThreadedEventSource::msleep(500); // void QtTesting.playCommand('object', 'command', 'arguments') // an exception is thrown in this fails const char* object = 0; const char* command = 0; const char* arguments = 0; if (!PyArg_ParseTuple(args, const_cast("sss"), &object, &command, &arguments)) { PyErr_SetString(PyExc_TypeError, "bad arguments to playCommand()"); return NULL; } if (Instance) { if (!Instance->postNextEvent(object, command, arguments)) { PyErr_SetString(PyExc_AssertionError, "error processing event"); return NULL; } } else { PyErr_SetString(PyExc_AssertionError, "pqPythonEventSource not defined"); return NULL; } return Py_BuildValue(const_cast("")); } static PyObject* QtTesting_getProperty(PyObject* /*self*/, PyObject* args) { // string QtTesting.getProperty('object', 'property') // returns the string value of the property const char* object = 0; const char* property = 0; if (!PyArg_ParseTuple(args, const_cast("ss"), &object, &property)) { return NULL; } PropertyObject = object; PropertyResult = property; PropertyValue = QString(); if (Instance && QThread::currentThread() != QApplication::instance()->thread()) { QMetaObject::invokeMethod(Instance, "threadGetProperty", Qt::QueuedConnection); if (!Instance->waitForGUI()) { PyErr_SetString(PyExc_ValueError, "error getting property"); return NULL; } } else if (QThread::currentThread() == QApplication::instance()->thread()) { PropertyValue = pqPythonEventSource::getProperty(PropertyObject, PropertyResult); } else { PyErr_SetString(PyExc_AssertionError, "pqPythonEventSource not defined"); return NULL; } if (PropertyObject.isEmpty()) { PyErr_SetString(PyExc_ValueError, "object not found"); return NULL; } if (PropertyResult.isEmpty()) { PyErr_SetString(PyExc_ValueError, "property not found"); return NULL; } return Py_BuildValue(const_cast("s"), PropertyValue.toUtf8().data()); } static PyObject* QtTesting_setProperty(PyObject* /*self*/, PyObject* args) { // string QtTesting.setProperty('object', 'property', 'value') // returns the string value of the property const char* object = 0; const char* property = 0; const char* value = 0; if (!PyArg_ParseTuple(args, const_cast("sss"), &object, &property, &value)) { return NULL; } PropertyObject = object; PropertyResult = property; PropertyValue = value; if (Instance && QThread::currentThread() != QApplication::instance()->thread()) { QMetaObject::invokeMethod(Instance, "threadSetProperty", Qt::QueuedConnection); if (!Instance->waitForGUI()) { PyErr_SetString(PyExc_ValueError, "error setting property"); return NULL; } } else if (QThread::currentThread() == QApplication::instance()->thread()) { pqPythonEventSource::setProperty(PropertyObject, PropertyResult, PropertyValue); } else { PyErr_SetString(PyExc_AssertionError, "pqPythonEventSource not defined"); return NULL; } if (PropertyObject.isEmpty()) { PyErr_SetString(PyExc_ValueError, "object not found"); return NULL; } if (PropertyResult.isEmpty()) { PyErr_SetString(PyExc_ValueError, "property not found"); return NULL; } return Py_BuildValue(const_cast("s"), ""); } static PyObject* QtTesting_getQtVersion(PyObject* /*self*/, PyObject* /*args*/) { // string QtTesting.getQtVersion() // returns the Qt version as a string return Py_BuildValue(const_cast("s"), qVersion()); } static PyObject* QtTesting_getChildren(PyObject* /*self*/, PyObject* args) { // string QtTesting.getChildren('object') // returns the a list of strings with object names const char* object = 0; if (!PyArg_ParseTuple(args, const_cast("s"), &object)) { return NULL; } PropertyObject = object; ObjectList.clear(); if (Instance && QThread::currentThread() != QApplication::instance()->thread()) { QMetaObject::invokeMethod(Instance, "threadGetChildren", Qt::QueuedConnection); if (!Instance->waitForGUI()) { PyErr_SetString(PyExc_ValueError, "error getting children"); return NULL; } } else if (QThread::currentThread() == QApplication::instance()->thread()) { ObjectList = pqPythonEventSource::getChildren(PropertyObject); } else { PyErr_SetString(PyExc_AssertionError, "pqPythonEventSource not defined"); return NULL; } if (PropertyObject.isEmpty()) { PyErr_SetString(PyExc_ValueError, "object not found"); return NULL; } QString objs = ObjectList.join(", "); QString ret = QString("[%1]").arg(objs); return Py_BuildValue(const_cast("s"), ret.toUtf8().data()); } static PyObject* QtTesting_invokeMethod(PyObject* /*self*/, PyObject* args) { // string QtTesting.invokeMethod('object', 'method') // calls a method and returns its value const char* object = 0; const char* method = 0; if (!PyArg_ParseTuple(args, const_cast("ss"), &object, &method)) { return NULL; } PropertyObject = object; PropertyValue = method; PropertyResult = QString(); if (Instance && QThread::currentThread() != QApplication::instance()->thread()) { QMetaObject::invokeMethod(Instance, "threadInvokeMethod", Qt::QueuedConnection); if (!Instance->waitForGUI()) { PyErr_SetString(PyExc_ValueError, "error invoking method"); return NULL; } } else if (QThread::currentThread() == QApplication::instance()->thread()) { PropertyResult = pqPythonEventSource::invokeMethod(PropertyObject, PropertyValue); } else { PyErr_SetString(PyExc_AssertionError, "pqPythonEventSource not defined"); return NULL; } if (PropertyObject.isEmpty()) { PyErr_SetString(PyExc_ValueError, "object not found"); return NULL; } else if (PropertyValue.isEmpty()) { PyErr_SetString(PyExc_ValueError, "method not found"); return NULL; } return Py_BuildValue(const_cast("s"), PropertyResult.toUtf8().data()); } static PyMethodDef QtTestingMethods[] = { { const_cast("playCommand"), QtTesting_playCommand, METH_VARARGS, const_cast("Play a test command.") }, { const_cast("getProperty"), QtTesting_getProperty, METH_VARARGS, const_cast("Get a property of an object.") }, { const_cast("setProperty"), QtTesting_setProperty, METH_VARARGS, const_cast("Set a property of an object.") }, { const_cast("getQtVersion"), QtTesting_getQtVersion, METH_VARARGS, const_cast("Get the version of Qt being used.") }, { const_cast("getChildren"), QtTesting_getChildren, METH_VARARGS, const_cast("Return a list of child objects.") }, { const_cast("invokeMethod"), QtTesting_invokeMethod, METH_VARARGS, const_cast("Invoke a Qt slot with the signature \"QVariant foo()\".") }, { NULL, NULL, 0, NULL } // Sentinal }; PyMODINIT_FUNC initQtTesting(void) { Py_InitModule(const_cast("QtTesting"), QtTestingMethods); } class pqPythonEventSource::pqInternal { public: QString FileName; }; pqPythonEventSource::pqPythonEventSource(QObject* p) : pqThreadedEventSource(p) { this->Internal = new pqInternal; } pqPythonEventSource::~pqPythonEventSource() { delete this->Internal; } void pqPythonEventSource::initPythonIfNeeded() { int initPy = Py_IsInitialized(); if (!initPy) { // initialize python Py_Initialize(); #ifdef SIGINT signal(SIGINT, SIG_DFL); #endif } // add QtTesting to python's inittab, so it is // available to all interpreters PyImport_AppendInittab(const_cast("QtTesting"), initQtTesting); } void pqPythonEventSource::setContent(const QString& path) { // start the python thread this->Internal->FileName = path; this->start(); } QString pqPythonEventSource::getProperty(QString& object, QString& prop) { // ensure other tasks have been completed pqEventDispatcher::processEventsAndWait(1); QVariant ret; QObject* qobject = pqObjectNaming::GetObject(object); if (!qobject) { object = QString(); return QString(); } int idx = qobject->metaObject()->indexOfProperty(prop.toUtf8().data()); if (idx == -1) { prop = QString(); return QString(); } else { QMetaProperty metaProp = qobject->metaObject()->property(idx); ret = metaProp.read(qobject); if (metaProp.type() == QVariant::List || metaProp.type() == QVariant::StringList) { return ret.toStringList().join(";"); } return ret.toString(); } } void pqPythonEventSource::threadGetProperty() { PropertyValue = this->getProperty(PropertyObject, PropertyResult); this->guiAcknowledge(); } void pqPythonEventSource::setProperty(QString& object, QString& prop, const QString& value) { // ensure other tasks have been completed pqEventDispatcher::processEventsAndWait(1); QVariant ret; QObject* qobject = pqObjectNaming::GetObject(object); if (!qobject) { object = QString(); return; } int idx = qobject->metaObject()->indexOfProperty(prop.toUtf8().data()); if (idx == -1) { prop = QString(); return; } else { QVariant val = value; QMetaProperty metaProp = qobject->metaObject()->property(idx); if (metaProp.type() == QVariant::List || metaProp.type() == QVariant::StringList) { val = value.split(";"); } qobject->setProperty(prop.toUtf8().data(), val); } } void pqPythonEventSource::threadSetProperty() { this->setProperty(PropertyObject, PropertyResult, PropertyValue); this->guiAcknowledge(); } QStringList pqPythonEventSource::getChildren(QString& object) { // ensure other tasks have been completed pqEventDispatcher::processEventsAndWait(1); QStringList ret; QObject* qobject = pqObjectNaming::GetObject(object); if (!qobject) { object = QString(); } else { const QObjectList& children = qobject->children(); Q_FOREACH (QObject* child, children) { ret.append(pqObjectNaming::GetName(*child)); } } return ret; } void pqPythonEventSource::threadGetChildren() { ObjectList = this->getChildren(PropertyObject); this->guiAcknowledge(); } void pqPythonEventSource::start() { this->initPythonIfNeeded(); PyEval_InitThreads(); PyEval_ReleaseLock(); pqThreadedEventSource::start(); } void pqPythonEventSource::run() { QFile file(this->Internal->FileName); if (!file.open(QFile::ReadOnly | QFile::Text)) { printf("Unable to open python script\n"); return; } this->initPythonIfNeeded(); Instance = this; PyGILState_STATE gstate = PyGILState_Ensure(); // finally run the script QByteArray wholeFile = file.readAll(); int result = PyRun_SimpleString(wholeFile.data()) == 0 ? 0 : 1; PyGILState_Release(gstate); PyEval_ReleaseLock(); this->done(result); } void pqPythonEventSource::threadInvokeMethod() { PropertyResult = this->invokeMethod(PropertyObject, PropertyValue); this->guiAcknowledge(); } QString pqPythonEventSource::invokeMethod(QString& object, QString& method) { // ensure other tasks have been completed pqEventDispatcher::processEventsAndWait(1); QVariant ret; QObject* qobject = pqObjectNaming::GetObject(object); if (!qobject) { object = QString(); } else { if (!QMetaObject::invokeMethod(qobject, method.toUtf8().data(), Q_RETURN_ARG(QVariant, ret))) { method = QString(); } } return ret.toString(); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqPythonEventSource.h000066400000000000000000000024061526070500000255330ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqPythonEventSource_h #define _pqPythonEventSource_h #include "pqThreadedEventSource.h" #include /** Concrete implementation of pqEventSource that retrieves events recorded by pqPythonEventObserver */ class QTTESTING_EXPORT pqPythonEventSource : public pqThreadedEventSource { Q_OBJECT public: pqPythonEventSource(QObject* p = 0); ~pqPythonEventSource(); void setContent(const QString& path); static QString getProperty(QString& object, QString& prop); static void setProperty(QString& object, QString& prop, const QString& value); static QStringList getChildren(QString& object); static QString invokeMethod(QString& object, QString& method); protected: virtual void run(); virtual void start(); protected Q_SLOTS: void threadGetProperty(); void threadSetProperty(); void threadGetChildren(); void threadInvokeMethod(); private: class pqInternal; pqInternal* Internal; /// method called to initialize Python. This can be called several times. It /// will init Python only if it hasn't been already. void initPythonIfNeeded(); }; #endif // !_pqPythonEventSource_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqRecordEventsDialog.cxx000066400000000000000000000132711526070500000261670ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include #include #include #include #include #include #include // QtTesting includes #include "pqEventComment.h" #include "pqEventRecorder.h" #include "pqEventTypes.h" #include "pqRecordEventsDialog.h" #include "pqTestUtility.h" #include "ui_pqRecordEventsDialog.h" ////////////////////////////////////////////////////////////////////////////////// // pqImplementation struct pqRecordEventsDialog::pqImplementation { public: pqImplementation(pqEventRecorder* recorder, pqTestUtility* testUtility) : Recorder(recorder) , TestUtility(testUtility) { } ~pqImplementation() { this->Recorder = 0; this->TestUtility = 0; } Ui::pqRecordEventsDialog Ui; pqEventRecorder* Recorder; pqTestUtility* TestUtility; }; /////////////////////////////////////////////////////////////////////////////////// // pqRecordEventsDialog // ---------------------------------------------------------------------------- pqRecordEventsDialog::pqRecordEventsDialog( pqEventRecorder* recorder, pqTestUtility* testUtility, QWidget* Parent) : QDialog(Parent) , Implementation(new pqImplementation(recorder, testUtility)) { this->Implementation->Ui.setupUi(this); this->setWindowFlags(this->windowFlags().setFlag(Qt::WindowContextHelpButtonHint, false)); this->setWindowFlags(this->windowFlags().setFlag(Qt::WindowStaysOnTopHint, true)); this->ignoreObject(this); this->setWindowTitle(tr("Recording User Input")); this->setObjectName(""); QObject::connect(this->Implementation->TestUtility->eventTranslator(), SIGNAL(recordEvent(QString, QString, QString, int)), this, SLOT(onEventRecorded(QString, QString, QString, int))); QObject::connect( this->Implementation->Ui.commentAddButton, SIGNAL(clicked()), this, SLOT(addComment())); QObject::connect(this->Implementation->Ui.checkButton, SIGNAL(toggled(bool)), this->Implementation->Recorder, SLOT(check(bool))); QObject::connect(this->Implementation->Ui.recordPauseButton, SIGNAL(toggled(bool)), this->Implementation->Recorder, SLOT(unpause(bool))); QObject::connect(this->Implementation->Ui.continuousFlush, SIGNAL(toggled(bool)), this->Implementation->Recorder, SLOT(setContinuousFlush(bool))); if (this->Implementation->TestUtility->supportsDashboardMode()) { QObject::connect(this->Implementation->Ui.dashboardMode, SIGNAL(toggled(bool)), this, SLOT(onDashboardModeToggled(bool))); } else { this->Implementation->Ui.dashboardMode->setVisible(false); } QObject::connect(this->Implementation->Ui.recordInteractionTimings, SIGNAL(toggled(bool)), this->Implementation->Recorder, SLOT(setRecordInteractionTimings(bool))); QObject::connect(this->Implementation->Recorder, SIGNAL(started()), this, SLOT(updateUi())); QObject::connect(this->Implementation->Recorder, SIGNAL(stopped()), this, SLOT(updateUi())); } // ---------------------------------------------------------------------------- pqRecordEventsDialog::~pqRecordEventsDialog() { delete Implementation; } // ---------------------------------------------------------------------------- void pqRecordEventsDialog::ignoreObject(QObject* object) { this->Implementation->TestUtility->eventTranslator()->ignoreObject(object); Q_FOREACH (QObject* child, object->children()) { this->ignoreObject(child); } } // ---------------------------------------------------------------------------- void pqRecordEventsDialog::done(int value) { this->Implementation->TestUtility->stopRecords(value); QDialog::done(value); } // ---------------------------------------------------------------------------- void pqRecordEventsDialog::onEventRecorded( const QString& widget, const QString& command, const QString& argument, int /*eventType*/) { if (!this->Implementation->Recorder->isRecording()) { return; } this->Implementation->Ui.eventWidgetEdit->setText(widget); this->Implementation->Ui.eventCommandEdit->setText(command); this->Implementation->Ui.eventArgumentEdit->setText(argument); int newValue = this->Implementation->Ui.nbEvents->value() + 1; this->Implementation->Ui.nbEvents->display(newValue); } // ---------------------------------------------------------------------------- void pqRecordEventsDialog::addComment() { if (this->Implementation->Ui.blockingCheckBox->isChecked()) { this->Implementation->Recorder->translator()->eventComment()->recordCommentBlock( this->Implementation->Ui.commentTextEdit->toPlainText()); } else { this->Implementation->Recorder->translator()->eventComment()->recordComment( this->Implementation->Ui.commentTextEdit->toPlainText()); } this->Implementation->Ui.commentTextEdit->clear(); } // ---------------------------------------------------------------------------- void pqRecordEventsDialog::updateUi() { bool recording = this->Implementation->Recorder->isRecording(); this->Implementation->Ui.recordPauseButton->setChecked(recording); this->Implementation->Ui.dashboardMode->setEnabled(recording); } // ---------------------------------------------------------------------------- void pqRecordEventsDialog::onDashboardModeToggled(bool toggle) { this->Implementation->TestUtility->setDashboardMode(toggle); const QWidgetList& list = QApplication::topLevelWidgets(); QMainWindow* mainWindow = nullptr; for (QWidget* widg : list) { mainWindow = qobject_cast(widg); if (mainWindow) { break; } } this->Implementation->Recorder->translator()->recordDashboardModeToggle(mainWindow, toggle); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqRecordEventsDialog.h000066400000000000000000000026111526070500000256100ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqRecordEventsDialog_h #define _pqRecordEventsDialog_h #include "QtTestingExport.h" #include class pqEventRecorder; class pqTestUtility; /// Provides a standard dialog that will record user input to an XML file as long as the dialog /// remains open class QTTESTING_EXPORT pqRecordEventsDialog : public QDialog { Q_OBJECT public: /** Creates the dialog and begins translating user input with the supplied translator. */ pqRecordEventsDialog(pqEventRecorder* recorder, pqTestUtility* testUtility, QWidget* Parent); private Q_SLOTS: void done(int) override; void onEventRecorded(const QString&, const QString&, const QString&, int eventType); void addComment(); /** * Called when dashboard mode is toggled. * Call setDashboardMode on the test utility * and record a dashboard mode toggle event on the main window */ void onDashboardModeToggled(bool toggle); public Q_SLOTS: void updateUi(); private: pqRecordEventsDialog(const pqRecordEventsDialog&); pqRecordEventsDialog& operator=(const pqRecordEventsDialog&); ~pqRecordEventsDialog() override; void ignoreObject(QObject* object); struct pqImplementation; pqImplementation* const Implementation; }; #endif // !_pqRecordEventsDialog_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqRecordEventsDialog.ui000066400000000000000000000306061526070500000260030ustar00rootroot00000000000000 pqRecordEventsDialog 0 0 393 256 Dialog 0 0 QTabWidget::Rounded 0 Qt::ElideNone false true :/Icons/info.png:/Icons/info.png Last event 2 2 Last widget recorded Widget : true false true true 0 0 Last argument recorded Argument : true false true Last command recorded / property checked Command/Property : true false true :/Icons/plus.png:/Icons/plus.png Add comment Add your custom comment : 0 0 16777215 80 Write the comment that you want to add Add option block to you comment Blocking Qt::Horizontal 40 20 0 0 Add your comment Add to macro :/Icons/plus.png:/Icons/plus.png Qt::Horizontal 6 QLayout::SetMinimumSize 0 Continuous Flush Write events to file as soon as they are recorded Dashboard mode When checked/unchecked, will trigger dashboard mode accordingly and record corresponding event true Record Interaction Timings When activated, each pause between interactions will be recorded as a pause event, with the correct timing 6 QLayout::SetMinimumSize 0 numbers of events recorded false 5 Events recorded Qt::Horizontal QSizePolicy::Expanding 133 31 Check default property of a widget instead of recording event :/Icons/check.png:/Icons/check.png true Start/Pause record :/Icons/record.png :/Icons/pause.png:/Icons/record.png true 0 0 Stop record Stop Recording :/Icons/playback-stop.png:/Icons/playback-stop.png stopButton clicked() pqRecordEventsDialog accept() 374 273 84 36 qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqSpinBoxEventTranslator.cxx000066400000000000000000000045341526070500000271040ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqSpinBoxEventTranslator.h" #include #include #include #include #include // ---------------------------------------------------------------------------- pqSpinBoxEventTranslator::pqSpinBoxEventTranslator(QObject* p) : pqWidgetEventTranslator(p) { this->CurrentObject = 0; } // ---------------------------------------------------------------------------- bool pqSpinBoxEventTranslator::translateEvent(QObject* Object, QEvent* Event, bool& Error) { QSpinBox* object = qobject_cast(Object); // consume line edit events if part of spin box if (!object && qobject_cast(Object->parent())) { return true; } if (!object) return false; if (Event->type() == QEvent::Enter && Object == object) { if (this->CurrentObject != Object) { if (this->CurrentObject) { disconnect(this->CurrentObject, 0, this, 0); } this->CurrentObject = Object; connect(object, SIGNAL(valueChanged(int)), this, SLOT(onValueChanged(int))); connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(onDestroyed(QObject*))); } return true; } if (Event->type() == QEvent::Leave && Object == object) { disconnect(this->CurrentObject, 0, this, 0); this->CurrentObject = 0; return true; } if (Event->type() == QEvent::KeyRelease && Object == object) { QKeyEvent* ke = static_cast(Event); QString keyText = ke->text(); if (keyText.length() && keyText.at(0).isPrint()) { Q_EMIT recordEvent(object, "set_int", QString("%1").arg(object->value())); } else { Q_EMIT recordEvent(object, "key", QString("%1").arg(ke->key())); } return true; } return this->Superclass::translateEvent(Object, Event, Error); } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslator::onDestroyed(QObject* /*Object*/) { this->CurrentObject = 0; } // ---------------------------------------------------------------------------- void pqSpinBoxEventTranslator::onValueChanged(int number) { Q_EMIT recordEvent(this->CurrentObject, "set_int", QString("%1").arg(number)); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqSpinBoxEventTranslator.h000066400000000000000000000017501526070500000265260ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqSpinBoxEventTranslator_h #define _pqSpinBoxEventTranslator_h #include "pqWidgetEventTranslator.h" /** Translates low-level Qt events into high-level ParaView events that can be recorded as test cases. \sa pqEventTranslator */ class QTTESTING_EXPORT pqSpinBoxEventTranslator : public pqWidgetEventTranslator { Q_OBJECT typedef pqWidgetEventTranslator Superclass; public: pqSpinBoxEventTranslator(QObject* p = 0); using Superclass::translateEvent; bool translateEvent(QObject* Object, QEvent* Event, bool& Error) override; private: pqSpinBoxEventTranslator(const pqSpinBoxEventTranslator&); pqSpinBoxEventTranslator& operator=(const pqSpinBoxEventTranslator&); QObject* CurrentObject; private Q_SLOTS: void onDestroyed(QObject*); void onValueChanged(int number); }; #endif // !_pqSpinBoxEventTranslator_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqStdoutEventObserver.cxx000066400000000000000000000007401526070500000264350ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqStdoutEventObserver.h" #include void pqStdoutEventObserver::onRecordEvent( const QString& Widget, const QString& Command, const QString& Arguments, const int& eventType) { printf("event: %s %s %s %i\n", Widget.toUtf8().data(), Command.toUtf8().data(), Arguments.toUtf8().data(), eventType); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqStdoutEventObserver.h000066400000000000000000000013721526070500000260640ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqStdoutEventObserver_h #define _pqStdoutEventObserver_h #include "QtTestingExport.h" #include /** Observes high-level ParaView "events" and writes them to stdout, mainly for debugging purposes. To use, connect the onRecordEvent() slot to the pqEventTranslator::recordEvent() signal. \sa pqEventTranslator, pqEventObserverXML */ class QTTESTING_EXPORT pqStdoutEventObserver : public QObject { Q_OBJECT public Q_SLOTS: void onRecordEvent( const QString& Widget, const QString& Command, const QString& Arguments, const int& eventType); }; #endif // !_pqStdoutEventObserver_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTabBarEventPlayer.cxx000066400000000000000000000062541526070500000257610ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqTabBarEventPlayer.h" #include #include #include #include #include "pqObjectNaming.h" pqTabBarEventPlayer::pqTabBarEventPlayer(QObject* p) : pqWidgetEventPlayer(p) { } bool pqTabBarEventPlayer::playEvent( QObject* target, const QString& command, const QString& arguments, bool& error_flag) { const QString value = arguments; QTabBar* const tab_bar = qobject_cast(target); QMainWindow* const main_window = qobject_cast(target); if (!(tab_bar || main_window)) { return false; } if (command == "set_tab") { if (!tab_bar) { qCritical() << "calling set_tab on unhandled type " << target; error_flag = true; } // "set_tab" saves tab index. This was done in the past. Newly recorded // tests will use set_tab_with_text for more reliable playback. bool ok = false; int which = value.toInt(&ok); if (!ok) { qCritical() << "calling set_tab with invalid argument on " << target; error_flag = true; } else if (tab_bar->count() < which) { qCritical() << "calling set_tab with out of bounds index on " << target; error_flag = true; } else { tab_bar->setCurrentIndex(which); } return true; } else if (command == "set_tab_with_text") { if (tab_bar) { for (int cc = 0; cc < tab_bar->count(); cc++) { if (tab_bar->tabText(cc) == value) { tab_bar->setCurrentIndex(cc); return true; } } QString error_message; QTextStream errorStream(&error_message); errorStream << "calling set_tab_with_text with unknown tab " << value << "Available tabs are (count=" << tab_bar->count() << ")"; for (int tab_index = 0; tab_index < tab_bar->count(); tab_index++) { errorStream << '\t' << tab_bar->tabText(tab_index); } qCritical() << error_message; error_flag = true; } else if (main_window) { // Special code for DockWidget tabs (and other unnamaed QMainWindow tabs). See comment in // pqTabBarEventTranslator for full explanation. QList main_window_tab_bars = main_window->findChildren(QString(), Qt::FindDirectChildrenOnly); for (QTabBar* possible_dock_widget_tab : main_window_tab_bars) { if (possible_dock_widget_tab->objectName().isEmpty()) { for (int tab_index = 0; tab_index < possible_dock_widget_tab->count(); ++tab_index) { if (possible_dock_widget_tab->tabText(tab_index) == value) { possible_dock_widget_tab->setCurrentIndex(tab_index); return true; } } } } qCritical() << "Could not find any tabs named " << value << " in the main window"; error_flag = true; } else { qCritical() << "calling set_tab_with_text on unhandled type " << target; error_flag = true; } return true; } return false; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTabBarEventPlayer.h000066400000000000000000000015541526070500000254040ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqTabBarEventPlayer_h #define _pqTabBarEventPlayer_h #include "pqWidgetEventPlayer.h" /** Concrete implementation of pqWidgetEventPlayer that translates high-level ParaView events into low-level Qt events. \sa pqEventPlayer */ class QTTESTING_EXPORT pqTabBarEventPlayer : public pqWidgetEventPlayer { Q_OBJECT typedef pqWidgetEventPlayer Superclass; public: pqTabBarEventPlayer(QObject* p = 0); using Superclass::playEvent; bool playEvent( QObject* Object, const QString& Command, const QString& Arguments, bool& Error) override; private: pqTabBarEventPlayer(const pqTabBarEventPlayer&); pqTabBarEventPlayer& operator=(const pqTabBarEventPlayer&); }; #endif // !_pqTabBarEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTabBarEventTranslator.cxx000066400000000000000000000027711526070500000266560ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqTabBarEventTranslator.h" #include #include #include pqTabBarEventTranslator::pqTabBarEventTranslator(QObject* p) : pqWidgetEventTranslator(p) , CurrentObject(0) { } bool pqTabBarEventTranslator::translateEvent(QObject* Object, QEvent* Event, bool& Error) { QTabBar* const object = qobject_cast(Object); if (!object) { return false; } switch (Event->type()) { case QEvent::Enter: { if (this->CurrentObject != Object) { if (this->CurrentObject) { disconnect(this->CurrentObject, 0, this, 0); } this->CurrentObject = object; connect(object, SIGNAL(currentChanged(int)), this, SLOT(indexChanged(int))); } return true; break; } default: break; } return this->Superclass::translateEvent(Object, Event, Error); } void pqTabBarEventTranslator::indexChanged(int which) { QObject* recordedObject = this->CurrentObject; QObject* parent = this->CurrentObject->parent(); if (parent && this->CurrentObject->objectName().isEmpty()) { QMainWindow* mainWindow = qobject_cast(this->CurrentObject->parent()); if (mainWindow) { recordedObject = mainWindow; } } Q_EMIT recordEvent(recordedObject, "set_tab_with_text", this->CurrentObject->tabText(which)); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTabBarEventTranslator.h000066400000000000000000000033751526070500000263040ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqTabBarEventTranslator_h #define _pqTabBarEventTranslator_h #include "pqWidgetEventTranslator.h" #include class QTabBar; /** \brief Records selection of a tab in a QTabBar \note A QMainMainWindow has hidden QTabBar's that it uses to manage QDockWidgets and other widgets that can be tabified. These hidden QTabBars are not named, can be numerous, and are instantiated in an unspecified order. This makes finding the correct QTabBar difficult and sometimes impossible. Therefore when recording selection of one of these hidden QTabBar's, the QMainWindow is recorded as the object instead of the QTabBar itself. During playback, if a QMainWindow was recorded then all hidden QTabBar direct children will be searched for the tab with the recorded name. The risk with this approach is that when multiple DockWidgets have the same windowTitle() (which determines the tab name) then it is possible to select the wrong one. This can be mediated in client code by ensuring that each DockWidget has a unique windowTitle() \sa pqEventTranslator */ class QTTESTING_EXPORT pqTabBarEventTranslator : public pqWidgetEventTranslator { Q_OBJECT typedef pqWidgetEventTranslator Superclass; public: pqTabBarEventTranslator(QObject* p = 0); using Superclass::translateEvent; bool translateEvent(QObject* Object, QEvent* Event, bool& Error) override; protected Q_SLOTS: void indexChanged(int); private: pqTabBarEventTranslator(const pqTabBarEventTranslator&); pqTabBarEventTranslator& operator=(const pqTabBarEventTranslator&); QPointer CurrentObject; }; #endif // !_pqTabBarEventTranslator_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTableViewEventPlayer.cxx000066400000000000000000000020721526070500000265020ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqTableViewEventPlayer.h" #include //----------------------------------------------------------------------------- pqTableViewEventPlayer::pqTableViewEventPlayer(QObject* parentObject) : Superclass(parentObject) { } //----------------------------------------------------------------------------- pqTableViewEventPlayer::~pqTableViewEventPlayer() {} //-----------------------------------------------------------------------------0000000 bool pqTableViewEventPlayer::playEvent( QObject* object, const QString& command, const QString& arguments, int eventType, bool& error) { QTableView* tableView = qobject_cast(object); if (!tableView) { // mouse events go to the viewport widget tableView = qobject_cast(object->parent()); } if (!tableView) { return false; } return this->Superclass::playEvent(object, command, arguments, eventType, error); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTableViewEventPlayer.h000066400000000000000000000017301526070500000261270ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef __pqTableViewEventPlayer_h #define __pqTableViewEventPlayer_h #include "pqAbstractItemViewEventPlayerBase.h" /// pqTableViewEventPlayer is a player for QTableWidget. Plays back the state /// recorded using pqTableViewEventTranslator. class QTTESTING_EXPORT pqTableViewEventPlayer : public pqAbstractItemViewEventPlayerBase { Q_OBJECT typedef pqAbstractItemViewEventPlayerBase Superclass; public: pqTableViewEventPlayer(QObject* parent = 0); ~pqTableViewEventPlayer() override; using Superclass::playEvent; bool playEvent(QObject* object, const QString& command, const QString& arguments, int eventType, bool& error) override; private: pqTableViewEventPlayer(const pqTableViewEventPlayer&); // Not implemented. void operator=(const pqTableViewEventPlayer&); // Not implemented. }; #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTableViewEventTranslator.cxx000066400000000000000000000035441526070500000274040ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqTableViewEventTranslator.h" #include #include //----------------------------------------------------------------------------- pqTableViewEventTranslator::pqTableViewEventTranslator(QObject* parentObject) : Superclass(parentObject) { } //----------------------------------------------------------------------------- pqTableViewEventTranslator::~pqTableViewEventTranslator() {} //----------------------------------------------------------------------------- void pqTableViewEventTranslator::onEnteredCheck(const QModelIndex& item) { // Recover Table View QTableView* tableView = qobject_cast(this->AbstractItemView); // Get a visual rectangle of the item QRect visualRect = tableView->visualRect(item); // Translate the rect of margins and headers visualRect.translate(tableView->contentsMargins().left(), tableView->contentsMargins().top()); visualRect.translate( tableView->verticalHeader()->width(), tableView->horizontalHeader()->height()); // Stor item and signal that a specific overlay is ready to be drawn this->ModelItemCheck = QPersistentModelIndex(item); Q_EMIT this->specificOverlay(visualRect); } //----------------------------------------------------------------------------- QAbstractItemView* pqTableViewEventTranslator::findCorrectedAbstractItemView(QObject* object) const { // Ignore QHeaderView event specifically if (qobject_cast(object)) { return NULL; } QAbstractItemView* abstractItemView = qobject_cast(object); if (!abstractItemView) { // mouse events go to the viewport widget abstractItemView = qobject_cast(object->parent()); } return abstractItemView; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTableViewEventTranslator.h000066400000000000000000000022521526070500000270240ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef __pqTableViewEventTranslator_h #define __pqTableViewEventTranslator_h #include "pqAbstractItemViewEventTranslatorBase.h" /// Event recorder for QTableView. Records the toggling of the check states for /// Table widget items. The recorded state can be played back using /// pqTableViewEventPlayer. class QTTESTING_EXPORT pqTableViewEventTranslator : public pqAbstractItemViewEventTranslatorBase { Q_OBJECT typedef pqAbstractItemViewEventTranslatorBase Superclass; public: pqTableViewEventTranslator(QObject* parent = 0); ~pqTableViewEventTranslator() override; /// find and set the corrected abstract item view QAbstractItemView* findCorrectedAbstractItemView(QObject* object) const override; protected Q_SLOTS: /// Compute a visual rectangle for the item and signal it void onEnteredCheck(const QModelIndex&) override; private: pqTableViewEventTranslator(const pqTableViewEventTranslator&); // Not implemented. void operator=(const pqTableViewEventTranslator&); // Not implemented. }; #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTestUtility.cxx000066400000000000000000000331041526070500000247440ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause // Qt includes #include #include #include #include #include #include // QtTesting includes #include "pqEventComment.h" #include "pqEventObserver.h" #include "pqEventSource.h" #include "pqEventTranslator.h" #include "pqPlayBackEventsDialog.h" #ifdef QT_TESTING_WITH_PYTHON #include "pqPythonEventObserver.h" #include "pqPythonEventSource.h" #endif #include "pqRecordEventsDialog.h" #include "pqTestUtility.h" #include "QtTestingConfigure.h" //----------------------------------------------------------------------------- pqTestUtility::pqTestUtility(QObject* p) : QObject(p) { this->PlayingTest = false; this->RecordWithDialog = true; this->Filename = ""; this->File = 0; this->FileSuffix = QString(); this->Translator.addDefaultWidgetEventTranslators(this); this->Translator.addDefaultEventManagers(this); this->Player.addDefaultWidgetEventPlayers(this); #ifdef QT_TESTING_WITH_PYTHON // add a python event source this->addEventSource("py", new pqPythonEventSource(this)); this->addEventObserver("py", new pqPythonEventObserver(this)); #endif } //----------------------------------------------------------------------------- pqTestUtility::~pqTestUtility() { this->File = 0; } //----------------------------------------------------------------------------- pqEventDispatcher* pqTestUtility::dispatcher() { return &this->Dispatcher; } //----------------------------------------------------------------------------- pqEventRecorder* pqTestUtility::recorder() { return &this->Recorder; } //----------------------------------------------------------------------------- pqEventPlayer* pqTestUtility::eventPlayer() { return &this->Player; } //----------------------------------------------------------------------------- pqEventTranslator* pqTestUtility::eventTranslator() { return &this->Translator; } //----------------------------------------------------------------------------- void pqTestUtility::addEventSource(const QString& fileExtension, pqEventSource* source) { if (!source) { return; } QMap::iterator iter; iter = this->EventSources.find(fileExtension); if (iter != this->EventSources.end()) { if (iter.value() == source) { return; } pqEventSource* src = iter.value(); this->EventSources.erase(iter); delete src; } this->EventSources.insert(fileExtension, source); source->setParent(this); } //----------------------------------------------------------------------------- QMap pqTestUtility::eventSources() const { return this->EventSources; } //----------------------------------------------------------------------------- void pqTestUtility::addEventObserver(const QString& fileExtension, pqEventObserver* observer) { if (!observer) { return; } QMap::iterator iter; iter = this->EventObservers.find(fileExtension); if (iter != this->EventObservers.end()) { if (iter.value() == observer) { return; } pqEventObserver* src = iter.value(); this->EventObservers.erase(iter); delete src; } this->EventObservers.insert(fileExtension, observer); observer->setParent(this); } //----------------------------------------------------------------------------- QMap pqTestUtility::eventObservers() const { return this->EventObservers; } //----------------------------------------------------------------------------- pqPlayBackEventsDialog* pqTestUtility::openPlayerDialog() { pqPlayBackEventsDialog* dialog = new pqPlayBackEventsDialog(this->Player, this->Dispatcher, this, QApplication::activeWindow()); dialog->show(); return dialog; } //----------------------------------------------------------------------------- void pqTestUtility::stopTests() { this->PlayingTest = false; this->Dispatcher.stop(); } //----------------------------------------------------------------------------- void pqTestUtility::stopRecords(int value) { this->Recorder.stop(value); } //----------------------------------------------------------------------------- void pqTestUtility::pauseRecords(bool value) { this->Recorder.pause(value); } //----------------------------------------------------------------------------- void pqTestUtility::onRecordStopped() { QTemporaryFile* file = qobject_cast(this->File); if (file) { QFileDialog* dialog = new QFileDialog(0, tr("Macro File Name"), QString("macro"), tr("XML Files (*.xml)")); dialog->setAcceptMode(QFileDialog::AcceptSave); dialog->setDefaultSuffix("xml"); if (dialog->exec() == QDialog::Rejected) { return; } QStringList newFilename = dialog->selectedFiles(); if (newFilename[0].isEmpty()) { return; } if (!newFilename[0].endsWith(QString(".%1").arg(this->FileSuffix))) { newFilename[0] += QString(".%1").arg(this->FileSuffix); } // QFile::copy doesn't overwrite if the file already exist, and return false if (QFile::exists(newFilename[0])) { QFile::remove(newFilename[0]); } QFile::copy(file->fileName(), newFilename[0]); delete dialog; } this->File->close(); this->setDashboardMode(false); this->updateTranslators(); } //----------------------------------------------------------------------------- bool pqTestUtility::playTests(const QString& filename) { QStringList files; files << filename; return this->playTests(files); } //----------------------------------------------------------------------------- bool pqTestUtility::playTests(const QStringList& filenames) { if (this->PlayingTest) { qCritical("playTests() cannot be called recursively."); return false; } this->setDashboardMode(true); this->updatePlayers(); this->PlayingTest = true; Q_EMIT this->playbackStarted(); bool success = true; Q_FOREACH (QString filename, filenames) { this->Filename = filename; if (!this->playingTest()) { break; } QFileInfo info(filename); if (!info.exists()) { qCritical() << filename << " does not exists, aborting"; return false; } Q_EMIT this->playbackStarted(filename); QString suffix = info.completeSuffix(); QMap::iterator iter; iter = this->EventSources.find(suffix); if (info.isReadable() && iter != this->EventSources.end()) { iter.value()->setContent(filename); // QEventLoop loop; // QTimer::singleShot(100, &loop, SLOT(quit())); // loop.exec(); QApplication::processEvents(); if (!this->Dispatcher.playEvents(*iter.value(), this->Player)) { // dispatcher returned failure, don't continue with rest of the tests // and flag error. success = false; Q_EMIT this->playbackStopped(info.fileName(), success); break; } Q_EMIT this->playbackStopped(info.fileName(), success); qDebug() << "Test " << info.fileName() << "is finished. Success = " << success; } } this->Filename = ""; this->PlayingTest = false; this->setDashboardMode(false); this->updatePlayers(); Q_EMIT this->playbackStopped(); return success; } //----------------------------------------------------------------------------- void pqTestUtility::recordTests() { #if defined(Q_WS_MAC) // check for native or non-native menu bar. // testing framework doesn't work with native menu bar, so let's warn if we // get that. if (!getenv("QT_MAC_NO_NATIVE_MENUBAR")) { qWarning("Recording menu events for native Mac menus doesn't work.\n" "Set the QT_MAC_NO_NATIVE_MENUBAR environment variable to" " correctly record menus"); } #endif this->setDashboardMode(true); this->updateTranslators(); pqEventObserver* observer = this->EventObservers.value(this->FileSuffix); if (!observer) { return; } if (!this->File->open(QIODevice::WriteOnly)) { qCritical() << "File cannot be opened"; return; } QObject::connect( &this->Recorder, SIGNAL(stopped()), this, SLOT(onRecordStopped()), Qt::UniqueConnection); 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); } //----------------------------------------------------------------------------- void pqTestUtility::recordTests(const QString& filename) { this->Filename = filename; this->File = new QFile(filename); QFileInfo info(filename); this->FileSuffix = info.suffix(); this->recordTests(); } //----------------------------------------------------------------------------- void pqTestUtility::recordTestsBySuffix(const QString& suffix) { QString tempFilename(QString("%1/macro.%2").arg(QDir::tempPath(), suffix)); this->File = new QTemporaryFile(tempFilename); this->FileSuffix = suffix; this->recordTests(); } // ---------------------------------------------------------------------------- void pqTestUtility::addObjectStateProperty(QObject* object, const QString& property) { if (!object) { return; } if (property.isEmpty() || !object->property(property.toUtf8()).isValid()) { return; } if (this->objectStatePropertyAlreadyAdded(object, property)) { return; } this->ObjectStateProperty[object].append(property); } // ---------------------------------------------------------------------------- bool pqTestUtility::objectStatePropertyAlreadyAdded(QObject* object, const QString& property) { // Check if this property already exist for this object QMap::iterator iter = this->ObjectStateProperty.find(object); if (iter != this->ObjectStateProperty.end()) { return this->ObjectStateProperty[object].contains(property); } return false; } // ---------------------------------------------------------------------------- QMap pqTestUtility::objectStateProperty() const { return this->ObjectStateProperty; } //----------------------------------------------------------------------------- void pqTestUtility::addDataDirectory(const QString& label, const QDir& path) { // To simplify, we allow only absolute path for the moment. if (label.isEmpty()) { return; } // Find better way to check if the path seams to be valid. // But as long as we would like to label some path, to allow a cross // platform use of QtTesting, a simple path.exist() seams not good. // not working ! if (!path.isAbsolute()) { return; } this->DataDirectories[label] = path; } //----------------------------------------------------------------------------- bool pqTestUtility::removeDataDirectory(const QString& label) { return this->DataDirectories.remove(label); } //----------------------------------------------------------------------------- QMap pqTestUtility::dataDirectory() const { return this->DataDirectories; } //----------------------------------------------------------------------------- QMap::iterator pqTestUtility::findBestIterator( const QString& file, QMap::iterator startIter) { QMap::iterator currentIter; QMap::iterator iter; int size = file.size(); bool find = false; for (iter = startIter; iter != this->DataDirectories.end(); ++iter) { if (file.startsWith(iter.value().path())) { QString relativePos = iter.value().relativeFilePath(file); if (relativePos.size() < size) { find = true; size = relativePos.size(); currentIter = iter; } } } if (!find) { return this->DataDirectories.end(); } return currentIter; } //----------------------------------------------------------------------------- QString pqTestUtility::convertToDataDirectory(const QString& file) { QMap::iterator iter = this->findBestIterator(file, this->DataDirectories.begin()); // If iterator at the end, we didn't find a match. if (iter == this->DataDirectories.end()) { return file; } QString rel_file = iter.value().relativeFilePath(file); return QString("${%1}/%2").arg(iter.key()).arg(rel_file); } //----------------------------------------------------------------------------- QString pqTestUtility::convertFromDataDirectory(const QString& file) { QString filename = file; QMap::iterator iter; for (iter = this->DataDirectories.begin(); iter != this->DataDirectories.end(); ++iter) { QString label = QString("${%1}").arg(iter.key()); if (filename.contains(label)) { filename.replace(label, iter.value().absolutePath()); break; } } return filename; } //----------------------------------------------------------------------------- bool pqTestUtility::recordWithDialog() const { return this->RecordWithDialog; } //----------------------------------------------------------------------------- void pqTestUtility::setRecordWithDialog(bool withDialog) { this->RecordWithDialog = withDialog; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTestUtility.h000066400000000000000000000134501526070500000243730ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqTestUtility_h #define _pqTestUtility_h // Qt includes #include #include #include #include #include #include #include // QtTesting includes #include "pqEventDispatcher.h" #include "pqEventPlayer.h" #include "pqEventRecorder.h" #include "pqEventTranslator.h" #include "QtTestingExport.h" class pqEventObserver; class pqEventSource; class pqPlayBackEventsDialog; /// Organizes basic functionality for regression testing 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() override; public: /// Get the event dispatcher. Dispatcher is used to play tests back. pqEventDispatcher* dispatcher(); /// Get the event recorder. Recorder is used to record tests. pqEventRecorder* recorder(); /// Get the event player. This the test-file-interpreter (if you will), that /// parses the test file and creates events from it that can be dispatched by /// the pqEventDispatcher. pqEventPlayer* eventPlayer(); /// Get the event translator. This is used for recording tests. pqEventTranslator* eventTranslator(); /// add an event source for playback of files /// An pqXMLEventSource is automatically added if XML support is enabled. /// A pqPythonEventSource is automatically added if Python support is enabled. void addEventSource(const QString& fileExtension, pqEventSource* source); /// Return a QMap of all the eventSources. QMap eventSources() const; /// add an event observer for recording files /// An pqXMLEventObserver is automatically added if XML support is enabled. /// A pqPythonEventObserver is automatically added if Python support is enabled. void addEventObserver(const QString& fileExtension, pqEventObserver* translator); /// Return a QMap of all the event Observers. QMap eventObservers() const; /// Returns if the utility is currently playing a test. bool playingTest() const { return this->PlayingTest; } /// Plays back the tests given by the filename(s). This is a blocking call i.e. /// it does not return until all the tests have been played or any of the test aborted due to /// failure. Returns true if the tests exist and played successfully. virtual bool playTests(const QStringList& filenames); /// start the recording of tests to a file void recordTests(); Q_INVOKABLE void recordTests(const QString& filename); Q_INVOKABLE void recordTestsBySuffix(const QString& suffix); /// Add custom object properties, which will be saved during the recording /// and restored before the playback void addObjectStateProperty(QObject* object, const QString& property); QMap objectStateProperty() const; /// add a directory for recording/playback of file dialogs void addDataDirectory(const QString& label, const QDir& path); /// remove a directory for recording/playback of file dialogs bool removeDataDirectory(const QString& label); /// recover all dataDirectories QMap dataDirectory() const; /// given filename convert to one of the data directories QString convertToDataDirectory(const QString& file); /// give a filename convert from one of the data directories QString convertFromDataDirectory(const QString& file); // Get current test filname if any const QString& filename() const { return this->Filename; }; /// 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); /** * Wether a pqTestUtility implementation supports * dashboard mode. Always return false in this implementation. */ virtual bool supportsDashboardMode() { return false; }; public Q_SLOTS: bool playTests(const QString& filename); /// @note Dialog is deleted on close. pqPlayBackEventsDialog* openPlayerDialog(); void stopTests(); void stopRecords(int value); void pauseRecords(bool value); void onRecordStopped(); /** * Slot called when the dashboard mode checkbox is changed * and just before recording / stopping recording events. * Not implemented in this implementation. */ virtual void setDashboardMode(bool){}; /** * Update the players if needed by the environnement * called before playing events. * Not implemented in this implementation. */ virtual void updatePlayers(){}; /** * Update the translators if needed by the environnement * called before and after recording events. * Not implemented in this implementation. */ virtual void updateTranslators(){}; Q_SIGNALS: void playbackStarted(); void playbackStopped(); void playbackStarted(const QString& filename); void playbackStopped(const QString& filename, bool error); private: QMap::iterator findBestIterator( const QString& file, QMap::iterator startIter); bool objectStatePropertyAlreadyAdded(QObject* object, const QString& property); protected: pqEventRecorder Recorder; pqEventDispatcher Dispatcher; pqEventPlayer Player; pqEventTranslator Translator; bool PlayingTest; bool RecordWithDialog; QString Filename; QIODevice* File; QString FileSuffix; QMap EventSources; QMap EventObservers; QMap DataDirectories; QMap ObjectStateProperty; }; #endif // !_pqTestUtility_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqThreadedEventSource.cxx000066400000000000000000000063651526070500000263550ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqThreadedEventSource.h" #include #include #include #include #include "pqEventDispatcher.h" class pqThreadedEventSource::pqInternal : public QThread { friend class pqThreadedEventSource; public: pqInternal(pqThreadedEventSource& source) : Source(source) , ShouldStop(0) , GotEvent(0) { } void run() override { Source.run(); } pqThreadedEventSource& Source; QWaitCondition WaitCondition; int Waiting; int ShouldStop; int GotEvent; QString CurrentObject; QString CurrentCommand; QString CurrentArgument; class ThreadHelper : public QThread { public: static void msleep(int msecs) { QThread::msleep(msecs); } }; }; pqThreadedEventSource::pqThreadedEventSource(QObject* p) : pqEventSource(p) { this->Internal = new pqInternal(*this); } pqThreadedEventSource::~pqThreadedEventSource() { // wait a second for this thread to finish, if it hasn't yet this->Internal->wait(1000); delete this->Internal; } int pqThreadedEventSource::getNextEvent(QString& object, QString& command, QString& arguments) { while (!this->Internal->GotEvent) { // wait for the other thread to post an event, while // we keep the GUI alive. pqEventDispatcher::processEventsAndWait(100); } object = this->Internal->CurrentObject; command = this->Internal->CurrentCommand; arguments = this->Internal->CurrentArgument; this->Internal->GotEvent = 0; this->guiAcknowledge(); if (object.isEmpty()) { if (arguments == "failure") { return FAILURE; } return DONE; } return SUCCESS; } void pqThreadedEventSource::relayEvent(QString object, QString command, QString arguments) { this->Internal->CurrentObject = object; this->Internal->CurrentCommand = command; this->Internal->CurrentArgument = arguments; this->Internal->GotEvent = 1; } bool pqThreadedEventSource::postNextEvent( const QString& object, const QString& command, const QString& argument) { QMetaObject::invokeMethod(this, "relayEvent", Qt::QueuedConnection, Q_ARG(QString, object), Q_ARG(QString, command), Q_ARG(QString, argument)); return this->waitForGUI(); } void pqThreadedEventSource::start() { this->Internal->ShouldStop = 0; this->Internal->start(QThread::LowestPriority); } void pqThreadedEventSource::stop() { this->Internal->ShouldStop = 1; this->Internal->wait(); } bool pqThreadedEventSource::waitForGUI() { this->Internal->Waiting = 1; while (this->Internal->Waiting == 1 && this->Internal->ShouldStop == 0) { pqInternal::ThreadHelper::msleep(50); } this->Internal->Waiting = 0; return !this->Internal->ShouldStop; } void pqThreadedEventSource::guiAcknowledge() { while (this->Internal->Waiting == 0) { pqInternal::ThreadHelper::msleep(50); } this->Internal->Waiting = 0; } void pqThreadedEventSource::msleep(int msec) { pqInternal::ThreadHelper::msleep(msec); } void pqThreadedEventSource::done(int success) { if (success == 0) { this->postNextEvent(QString(), QString(), QString()); return; } this->postNextEvent(QString(), QString(), "failure"); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqThreadedEventSource.h000066400000000000000000000044231526070500000257730ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqThreadedEventSource_h #define _pqThreadedEventSource_h #include "QtTestingExport.h" #include "pqEventSource.h" class QString; class QMutex; /// Abstract interface for objects that can supply high-level testing events /// on a separte thread. This class is derived from, and run() is /// implemented. class QTTESTING_EXPORT pqThreadedEventSource : public pqEventSource { Q_OBJECT public: pqThreadedEventSource(QObject* p); ~pqThreadedEventSource() override; using pqEventSource::getNextEvent; /** Called by the dispatcher on the GUI thread. Retrieves the next available event. Returns true if an event was returned, false if there are no more events. In the case of a threaded event source, this function is called by the GUI thread and waits for the other thread to pos and event. */ virtual int getNextEvent(QString& object, QString& command, QString& arguments); /** The testing thread may post an event for the GUI to process. This function blocks until there are no previously queued events to play. If the event plays successfully, true is returned. */ bool postNextEvent(const QString& object, const QString& command, const QString& argument); /** tell this source to stop */ void stop() override; /** Wait for the GUI thread to acknowledge an event. A previously locked mutex must be passed in. For use by the testing thread. If return value is false, an error occurred and the testing thread should terminate. */ bool waitForGUI(); /** Give the testing thread an acknowledgement. For use by the GUI thread */ void guiAcknowledge(); // helper method to sleep. static void msleep(int msecs); private Q_SLOTS: void relayEvent(QString object, QString command, QString arguments); protected: // start the thread virtual void start(); // called by the testing thread to signify it is done // pass in zero for success, non-zero for failure void done(int); // run the thread, return virtual void run() = 0; private: class pqInternal; pqInternal* Internal; friend class pqInternal; }; #endif // !_pqThreadedEventSource_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTimer.cxx000066400000000000000000000022741526070500000235250ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqTimer.h" #include "pqEventDispatcher.h" //----------------------------------------------------------------------------- pqTimer::pqTimer(QObject* parentObject) : Superclass(parentObject) { pqEventDispatcher::registerTimer(this); } //----------------------------------------------------------------------------- pqTimer::~pqTimer() {} //----------------------------------------------------------------------------- void pqTimer::timerEvent(QTimerEvent* evt) { // here we can consume the timer event and reschedule it for another time if // timers are blocked. this->Superclass::timerEvent(evt); } //----------------------------------------------------------------------------- void pqTimer::singleShot(int msec, QObject* receiver, const char* member) { if (receiver && member) { pqTimer* timer = new pqTimer(receiver); QObject::connect(timer, SIGNAL(timeout()), receiver, member); QObject::connect(timer, SIGNAL(timeout()), timer, SLOT(deleteLater())); timer->setSingleShot(true); timer->start(msec); } } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTimer.h000066400000000000000000000022141526070500000231440ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef __pqTimer_h #define __pqTimer_h #include "QtTestingExport.h" #include /// pqTimer is a extension for QTimer which ensures that the timer is registered /// with the pqEventDispatcher. Register timers with pqEventDispatcher ensures /// that when tests are being played back, the timer will be ensured to have /// timed out if active after every step in the playback. This provides a means /// to reproduce the timer behaviour in the real world, during test playback. class QTTESTING_EXPORT pqTimer : public QTimer { Q_OBJECT typedef QTimer Superclass; public: pqTimer(QObject* parent = 0); ~pqTimer() override; /// This static function calls a slot after a given time interval. static void singleShot(int msec, QObject* receiver, const char* member); protected: /// overridden to support blocking timer events in future (current /// implementation merely forwards to superclass). void timerEvent(QTimerEvent* evt) override; private: Q_DISABLE_COPY(pqTimer) }; #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTreeViewEventPlayer.cxx000066400000000000000000000055051526070500000263560ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqTreeViewEventPlayer.h" #include #include #include //----------------------------------------------------------------------------- pqTreeViewEventPlayer::pqTreeViewEventPlayer(QObject* parentObject) : Superclass(parentObject) { } //----------------------------------------------------------------------------- pqTreeViewEventPlayer::~pqTreeViewEventPlayer() {} //----------------------------------------------------------------------------- bool pqTreeViewEventPlayer::playEvent( QObject* object, const QString& command, const QString& arguments, int eventType, bool& error) { QTreeView* treeView = qobject_cast(object); QMenu* contextMenu = qobject_cast(object); // if this a QMenu (potentially a context menu of the view), // we should not move onto parent if (!treeView && !contextMenu) { // mouse events go to the viewport widget treeView = qobject_cast(object->parent()); } if (!treeView) { return false; } QRegularExpression regExp0("^([\\d\\.]+),(\\d+),(\\d+)$"); QRegularExpressionMatch match = regExp0.match(arguments); if (command == "setTreeItemCheckState" && match.hasMatch()) { // legacy command recorded from tree widgets. QTreeWidget* treeWidget = qobject_cast(object); if (!treeWidget) { return false; } QString str_index = match.captured(1); int column = match.captured(2).toInt(); int check_state = match.captured(3).toInt(); #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) QStringList indices = str_index.split(".", Qt::SkipEmptyParts); #else QStringList indices = str_index.split(".", QString::SkipEmptyParts); #endif QTreeWidgetItem* cur_item = NULL; Q_FOREACH (QString cur_index, indices) { int index = cur_index.toInt(); if (!cur_item) { cur_item = treeWidget->topLevelItem(index); } else { cur_item = cur_item->child(index); } if (!cur_item) { error = true; qCritical() << "ERROR: Tree widget must have changed. " << "Indices recorded in the test are no longer valid. Cannot playback."; return true; } } cur_item->setCheckState(column, static_cast(check_state)); return true; } if (command == "expand" || command == "collapse") { QString str_index = arguments; QModelIndex index = pqTreeViewEventPlayer::GetIndex(str_index, treeView, error); if (error) { return true; } treeView->setExpanded(index, (command == "expand")); return true; } return this->Superclass::playEvent(object, command, arguments, eventType, error); } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTreeViewEventPlayer.h000066400000000000000000000017141526070500000260010ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef __pqTreeViewEventPlayer_h #define __pqTreeViewEventPlayer_h #include "pqAbstractItemViewEventPlayerBase.h" /// pqTreeViewEventPlayer is a player for QTreeWidget. Plays back the state /// recorded using pqTreeViewEventTranslator. class QTTESTING_EXPORT pqTreeViewEventPlayer : public pqAbstractItemViewEventPlayerBase { Q_OBJECT typedef pqAbstractItemViewEventPlayerBase Superclass; public: pqTreeViewEventPlayer(QObject* parent = 0); ~pqTreeViewEventPlayer() override; using Superclass::playEvent; bool playEvent(QObject* object, const QString& command, const QString& arguments, int eventType, bool& error) override; private: pqTreeViewEventPlayer(const pqTreeViewEventPlayer&); // Not implemented. void operator=(const pqTreeViewEventPlayer&); // Not implemented. }; #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTreeViewEventTranslator.cxx000066400000000000000000000057541526070500000272610ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqTreeViewEventTranslator.h" #include #include //----------------------------------------------------------------------------- pqTreeViewEventTranslator::pqTreeViewEventTranslator(QObject* parentObject) : Superclass(parentObject) { } //----------------------------------------------------------------------------- pqTreeViewEventTranslator::~pqTreeViewEventTranslator() {} //----------------------------------------------------------------------------- void pqTreeViewEventTranslator::monitorSignalsInternal(QAbstractItemView* abstractItemView) { QObject::connect(abstractItemView, SIGNAL(expanded(const QModelIndex&)), this, SLOT(onExpanded(const QModelIndex&))); QObject::connect(abstractItemView, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(onCollapsed(const QModelIndex&))); } //----------------------------------------------------------------------------- void pqTreeViewEventTranslator::onExpanded(const QModelIndex& index) { QTreeView* treeView = qobject_cast(this->sender()); // record the check state change if the item is user-checkable. Q_EMIT this->recordEvent(treeView, "expand", this->getIndexAsString(index)); } //----------------------------------------------------------------------------- void pqTreeViewEventTranslator::onCollapsed(const QModelIndex& index) { QTreeView* treeView = qobject_cast(this->sender()); // record the check state change if the item is user-checkable. Q_EMIT this->recordEvent(treeView, "collapse", this->getIndexAsString(index)); } //----------------------------------------------------------------------------- void pqTreeViewEventTranslator::onEnteredCheck(const QModelIndex& item) { // Recover treeview QTreeView* treeView = qobject_cast(this->AbstractItemView); // Recover a visual rectangle corresponding to the item QRect visualRect = treeView->visualRect(item); // Translating it of margins, as they are missing from visual rect visualRect.translate(treeView->contentsMargins().left(), treeView->contentsMargins().top()); // As well as header visualRect.translate(0, treeView->header()->height()); // store item and signal that a specific overlay is ready to be drawn this->ModelItemCheck = QPersistentModelIndex(item); Q_EMIT this->specificOverlay(visualRect); } //----------------------------------------------------------------------------- QAbstractItemView* pqTreeViewEventTranslator::findCorrectedAbstractItemView(QObject* object) const { // Ignore QHeaderView event specifically if (qobject_cast(object)) { return NULL; } QAbstractItemView* abstractItemView = qobject_cast(object); if (!abstractItemView) { // mouse events go to the viewport widget abstractItemView = qobject_cast(object->parent()); } return abstractItemView; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqTreeViewEventTranslator.h000066400000000000000000000025671526070500000267050ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef __pqTreeViewEventTranslator_h #define __pqTreeViewEventTranslator_h #include "pqAbstractItemViewEventTranslatorBase.h" /// Event recorder for QTreeView. Records the toggling of the check states for /// tree widget items. The recorded state can be played back using /// pqTreeViewEventPlayer. class QTTESTING_EXPORT pqTreeViewEventTranslator : public pqAbstractItemViewEventTranslatorBase { Q_OBJECT typedef pqAbstractItemViewEventTranslatorBase Superclass; public: pqTreeViewEventTranslator(QObject* parent = 0); ~pqTreeViewEventTranslator() override; /// find and set the corrected abstract item view QAbstractItemView* findCorrectedAbstractItemView(QObject* object) const override; protected Q_SLOTS: void onExpanded(const QModelIndex&); void onCollapsed(const QModelIndex&); /// Compute a visual rectangle for the item and signal it void onEnteredCheck(const QModelIndex&) override; protected: /// Connect QTree signals to this class slots void monitorSignalsInternal(QAbstractItemView* abstractItemView) override; private: pqTreeViewEventTranslator(const pqTreeViewEventTranslator&); // Not implemented. void operator=(const pqTreeViewEventTranslator&); // Not implemented. }; #endif qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqWidgetEventPlayer.cxx000066400000000000000000000043551526070500000260510ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqWidgetEventPlayer.h" #include #include #include #include #include #include // for std::abs // ---------------------------------------------------------------------------- pqWidgetEventPlayer::pqWidgetEventPlayer(QObject* parent) : Superclass(parent) { } // ---------------------------------------------------------------------------- bool pqWidgetEventPlayer::playEvent( QObject* object, const QString& command, const QString& arguments, bool& error) { QWidget* widget = qobject_cast(object); if (widget) { if (command == "contextMenu") { QPoint pt(widget->x(), widget->y()); QPoint globalPt = widget->mapToGlobal(pt); QContextMenuEvent e(QContextMenuEvent::Other, pt, globalPt); qApp->notify(widget, &e); return true; } else if (command == "size") { QStringList entries = arguments.split(','); if (entries.size() == 2) { QSize sz = widget->size(); error = (sz.width() != entries[0].toInt() || sz.height() != entries[1].toInt()); if (error) { qCritical() << "Size mismatch: (" << arguments << ") != " << sz; } return true; } } else if (command == "sizeGreaterOrEqual") { QStringList entries = arguments.split(','); if (entries.size() == 2) { QSize sz = widget->size(); error = (sz.width() < entries[0].toInt() || sz.height() < entries[1].toInt()); if (error) { qCritical() << "Size mismatch: (" << arguments << ") > " << sz; } return true; } } else if (command == "aspectRatio") { double targetAspectRatio = arguments.toDouble(); QSize sz = widget->size(); double aspectRatio = static_cast(sz.width()) / sz.height(); error = (std::abs(targetAspectRatio - aspectRatio) > 1e-2); if (error) { qCritical() << "Ratio mismatch: (" << targetAspectRatio << ") != " << aspectRatio; } return true; } } return false; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqWidgetEventPlayer.h000066400000000000000000000015231526070500000254700ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqWidgetEventPlayer_h #define _pqWidgetEventPlayer_h #include "QtTestingExport.h" #include "pqObjectPlayer.h" class QString; /** * Implements pqObjectPlayer for QWidgets. * * \sa pqEventPlayer */ class QTTESTING_EXPORT pqWidgetEventPlayer : public pqObjectPlayer { Q_OBJECT typedef pqObjectPlayer Superclass; public: pqWidgetEventPlayer(QObject* parent); ~pqWidgetEventPlayer() override = default; using Superclass::playEvent; /** * Handle generics command action, like resize and context menu trigger. */ bool playEvent( QObject* object, const QString& command, const QString& arguments, bool& error) override; }; #endif // !_pqWidgetEventPlayer_h qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqWidgetEventTranslator.cxx000066400000000000000000000024461526070500000267450ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #include "pqWidgetEventTranslator.h" #include "pqEventTypes.h" #include #include #include //----------------------------------------------------------------------------- pqWidgetEventTranslator::pqWidgetEventTranslator(QObject* parentObject) : Superclass(parentObject) { } //----------------------------------------------------------------------------- pqWidgetEventTranslator::~pqWidgetEventTranslator() {} bool pqWidgetEventTranslator::translateEvent(QObject* object, QEvent* event, bool& error) { Q_UNUSED(error); QWidget* widget = qobject_cast(object); if (!widget) { return false; } switch (event->type()) { case QEvent::ContextMenu: { Q_EMIT recordEvent(widget, "contextMenu", ""); break; } default: { break; } } return true; } //----------------------------------------------------------------------------- bool pqWidgetEventTranslator::translateEvent( QObject* object, QEvent* event, int eventType, bool& error) { if (eventType == pqEventTypes::ACTION_EVENT) { return this->translateEvent(object, event, error); } return false; } qttesting-v1.0.1-c7bb5d372133e94c75cbdc70b04e039b864ea379/pqWidgetEventTranslator.h000066400000000000000000000031341526070500000263650ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright (c) Kitware Inc. // SPDX-FileCopyrightText: Copyright (c) Sandia Corporation // SPDX-License-Identifier: BSD-3-Clause #ifndef _pqWidgetEventTranslator_h #define _pqWidgetEventTranslator_h #include "QtTestingExport.h" #include #include /** Abstract interface for an object that can translate low-level Qt events into high-level, serializable ParaView events, for test-cases, demos, tutorials, etc. \sa pqEventTranslator */ class QTTESTING_EXPORT pqWidgetEventTranslator : public QObject { Q_OBJECT typedef QObject Superclass; public: pqWidgetEventTranslator(QObject* p = 0); ~pqWidgetEventTranslator() override; /** Derivatives should implement this and translate events into commands, returning "true" if they handled the event, and setting Error to "true" if there were any problems. eventType allow to specify different types of events like check event*/ virtual bool translateEvent(QObject* object, QEvent* event, bool& error); virtual bool translateEvent(QObject* object, QEvent* event, int eventType, bool& error); Q_SIGNALS: /// Derivatives should emit this signal whenever they wish to record a high-level event void recordEvent( QObject* Object, const QString& Command, const QString& Arguments, int eventType); void recordEvent(QObject* Object, const QString& Command, const QString& Arguments); void specificOverlay(const QRect& geometry); protected: pqWidgetEventTranslator(const pqWidgetEventTranslator&); pqWidgetEventTranslator& operator=(const pqWidgetEventTranslator&); }; #endif // !_pqWidgetEventTranslator_h