From 9f1aa866bda7678261f2f441d4cfd5bb524c2411 Mon Sep 17 00:00:00 2001 From: Jo Asplin Date: Thu, 20 Oct 2011 13:17:26 +0200 Subject: Moved tests into integrationtests/ and widgets/ Task-number: QTBUG-19013 Change-Id: Ibb776f5967c0645ce6d22ef7afdc40657c575461 Reviewed-by: Holger Ihrig --- tests/auto/widgets/kernel/qapplication/.gitignore | 3 + .../desktopsettingsaware/desktopsettingsaware.pro | 14 + .../qapplication/desktopsettingsaware/main.cpp | 54 + tests/auto/widgets/kernel/qapplication/heart.svg | 55 + .../widgets/kernel/qapplication/modal/base.cpp | 62 + .../auto/widgets/kernel/qapplication/modal/base.h | 64 + .../widgets/kernel/qapplication/modal/main.cpp | 54 + .../widgets/kernel/qapplication/modal/modal.pro | 9 + .../widgets/kernel/qapplication/qapplication.pro | 7 + .../auto/widgets/kernel/qapplication/test/test.pro | 27 + tests/auto/widgets/kernel/qapplication/tmp/README | 3 + .../kernel/qapplication/tst_qapplication.cpp | 2107 ++++++++++++++++++++ .../kernel/qapplication/wincmdline/main.cpp | 53 + .../kernel/qapplication/wincmdline/wincmdline.pro | 8 + 14 files changed, 2520 insertions(+) create mode 100644 tests/auto/widgets/kernel/qapplication/.gitignore create mode 100644 tests/auto/widgets/kernel/qapplication/desktopsettingsaware/desktopsettingsaware.pro create mode 100644 tests/auto/widgets/kernel/qapplication/desktopsettingsaware/main.cpp create mode 100644 tests/auto/widgets/kernel/qapplication/heart.svg create mode 100644 tests/auto/widgets/kernel/qapplication/modal/base.cpp create mode 100644 tests/auto/widgets/kernel/qapplication/modal/base.h create mode 100644 tests/auto/widgets/kernel/qapplication/modal/main.cpp create mode 100644 tests/auto/widgets/kernel/qapplication/modal/modal.pro create mode 100644 tests/auto/widgets/kernel/qapplication/qapplication.pro create mode 100644 tests/auto/widgets/kernel/qapplication/test/test.pro create mode 100644 tests/auto/widgets/kernel/qapplication/tmp/README create mode 100644 tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp create mode 100644 tests/auto/widgets/kernel/qapplication/wincmdline/main.cpp create mode 100644 tests/auto/widgets/kernel/qapplication/wincmdline/wincmdline.pro (limited to 'tests/auto/widgets/kernel/qapplication') diff --git a/tests/auto/widgets/kernel/qapplication/.gitignore b/tests/auto/widgets/kernel/qapplication/.gitignore new file mode 100644 index 0000000000..ca666e480a --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/.gitignore @@ -0,0 +1,3 @@ +tst_qapplication +desktopsettingsaware/desktopsettingsaware +wincmdline/wincmdline diff --git a/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/desktopsettingsaware.pro b/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/desktopsettingsaware.pro new file mode 100644 index 0000000000..216a9710c7 --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/desktopsettingsaware.pro @@ -0,0 +1,14 @@ +###################################################################### +# Automatically generated by qmake (2.00a) Mon Jul 11 11:30:34 2005 +###################################################################### + +TEMPLATE = app +DEPENDPATH += . +INCLUDEPATH += . +wince*:TARGET = ../desktopsettingsaware + +# Input +QT += widgets +SOURCES += main.cpp +CONFIG += qt warn_on create_prl link_prl +CONFIG -= app_bundle diff --git a/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/main.cpp b/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/main.cpp new file mode 100644 index 0000000000..9e2172829a --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/main.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include + +int main(int argc, char **argv) { + QApplication::setDesktopSettingsAware(false); + QApplication app(argc, argv); + QComboBox box; + box.insertItem(0, "foo"); + box.setEditable(true); + box.show(); + return 0; +} diff --git a/tests/auto/widgets/kernel/qapplication/heart.svg b/tests/auto/widgets/kernel/qapplication/heart.svg new file mode 100644 index 0000000000..8c982cd93c --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/heart.svg @@ -0,0 +1,55 @@ + + + + + +Heart Left-Highlight +This is a normal valentines day heart. + + +holiday +valentines + +valentine +hash(0x8a091c0) +hash(0x8a0916c) +signs_and_symbols +hash(0x8a091f0) +day + + + + +Jon Phillips + + + + +Jon Phillips + + + + +Jon Phillips + + + +image/svg+xml + + +en + + + + + + + + + + + + + + + diff --git a/tests/auto/widgets/kernel/qapplication/modal/base.cpp b/tests/auto/widgets/kernel/qapplication/modal/base.cpp new file mode 100644 index 0000000000..2f7b4ad529 --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/modal/base.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "base.h" + +base::base(QWidget *parent) : + QWidget(parent) +{ + m_timer = new QTimer(this); + m_modalStarted = false; + m_timer->setSingleShot(false); + connect(m_timer, SIGNAL(timeout()), this, SLOT(periodicTimer())); + m_timer->start(5000); +} + +void base::periodicTimer() +{ + if(m_modalStarted) + exit(0); + m_modalDialog = new QDialog(this); + m_modalDialog->setModal(true); + m_modalDialog->show(); + m_modalStarted = true; +} diff --git a/tests/auto/widgets/kernel/qapplication/modal/base.h b/tests/auto/widgets/kernel/qapplication/modal/base.h new file mode 100644 index 0000000000..e1f36e11bd --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/modal/base.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BASE_H +#define BASE_H + +#include +#include +#include + +class base : public QWidget +{ +Q_OBJECT + QTimer *m_timer; + bool m_modalStarted; + QDialog *m_modalDialog; +public: + explicit base(QWidget *parent = 0); + +signals: + +public slots: + void periodicTimer(); +}; + +#endif // BASE_H diff --git a/tests/auto/widgets/kernel/qapplication/modal/main.cpp b/tests/auto/widgets/kernel/qapplication/modal/main.cpp new file mode 100644 index 0000000000..53c6008eb5 --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/modal/main.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include "base.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QApplication::setAttribute(Qt::AA_NativeWindows); //QTBUG-15774 + base *b = new base(); + Q_UNUSED(b); + return app.exec(); +} diff --git a/tests/auto/widgets/kernel/qapplication/modal/modal.pro b/tests/auto/widgets/kernel/qapplication/modal/modal.pro new file mode 100644 index 0000000000..9ed69769bb --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/modal/modal.pro @@ -0,0 +1,9 @@ +TEMPLATE = app +QT += widgets +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +SOURCES += main.cpp \ + base.cpp +DESTDIR = ./ +HEADERS += base.h diff --git a/tests/auto/widgets/kernel/qapplication/qapplication.pro b/tests/auto/widgets/kernel/qapplication/qapplication.pro new file mode 100644 index 0000000000..becc6c6f4b --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/qapplication.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs +SUBDIRS = test \ + desktopsettingsaware \ + modal \ + wincmdline + + diff --git a/tests/auto/widgets/kernel/qapplication/test/test.pro b/tests/auto/widgets/kernel/qapplication/test/test.pro new file mode 100644 index 0000000000..65aae7b0b9 --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/test/test.pro @@ -0,0 +1,27 @@ +load(qttest_p4) + +QT += widgets widgets-private +QT += core-private gui-private + +SOURCES += ../tst_qapplication.cpp +TARGET = ../tst_qapplication + +wince* { + additional.files = ../desktopsettingsaware/desktopsettingsaware.exe + additional.path = desktopsettingsaware + someTest.files = test.pro + someTest.path = test + DEPLOYMENT += additional deploy someTest +} + +win32 { + CONFIG(debug, debug|release) { + TARGET = ../../debug/tst_qapplication +} else { + TARGET = ../../release/tst_qapplication + } +} + +mac*:CONFIG+=insignificant_test + +CONFIG += insignificant_test # QTBUG-21402 diff --git a/tests/auto/widgets/kernel/qapplication/tmp/README b/tests/auto/widgets/kernel/qapplication/tmp/README new file mode 100644 index 0000000000..e758961ddf --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/tmp/README @@ -0,0 +1,3 @@ +this dummy directory is needed for the QApplication::libraryPaths() autotest +that calls QDir(applicationDirPath + "/tmp/..").canonicalPath(). canonicalPath() +stat()'s the given directory, so if the tmp directory doesn't exist it fails... diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp new file mode 100644 index 0000000000..c37dfc609e --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp @@ -0,0 +1,2107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +//#define QT_TST_QAPP_DEBUG +#include + +#include + +#include "qabstracteventdispatcher.h" +#include +#include + +#include "private/qapplication_p.h" +#include "private/qstylesheetstyle_p.h" +#ifdef Q_OS_WINCE +#include +#endif + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QApplication : public QObject +{ +Q_OBJECT + +public: + tst_QApplication(); + virtual ~tst_QApplication(); + +public slots: + void init(); + void cleanup(); +private slots: + void sendEventsOnProcessEvents(); // this must be the first test + void getSetCheck(); + void staticSetup(); + + void alert(); + + void multiple_data(); + void multiple(); + + void nonGui(); + + void setFont_data(); + void setFont(); + + void args_data(); + void args(); + + void lastWindowClosed(); + void quitOnLastWindowClosed(); + void closeAllWindows(); + void testDeleteLater(); + void testDeleteLaterProcessEvents(); + + void libraryPaths(); + void libraryPaths_qt_plugin_path(); + void libraryPaths_qt_plugin_path_2(); + + void sendPostedEvents(); + + void thread(); + void desktopSettingsAware(); + + void setActiveWindow(); + + void focusChanged(); + void focusOut(); + + void execAfterExit(); + + void wheelScrollLines(); + + void task109149(); + + void style(); + + void allWidgets(); + void topLevelWidgets(); + + void setAttribute(); + + void windowsCommandLine_data(); + void windowsCommandLine(); + + void touchEventPropagation(); + + void qtbug_12673(); + + void globalStaticObjectDestruction(); // run this last +}; + +class EventSpy : public QObject +{ + Q_OBJECT + +public: + QList recordedEvents; + bool eventFilter(QObject *, QEvent *event) + { + recordedEvents.append(event->type()); + return false; + } +}; + +void tst_QApplication::sendEventsOnProcessEvents() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + EventSpy spy; + app.installEventFilter(&spy); + + QCoreApplication::postEvent(&app, new QEvent(QEvent::Type(QEvent::User + 1))); + QCoreApplication::processEvents(); + QVERIFY(spy.recordedEvents.contains(QEvent::User + 1)); +} + +class MyInputContext : public QInputContext +{ +public: + MyInputContext() : QInputContext() {} + QString identifierName() { return QString("NoName"); } + QString language() { return QString("NoLanguage"); } + void reset() {} + bool isComposing() const { return false; } +}; + +// Testing get/set functions +void tst_QApplication::getSetCheck() +{ + int argc = 0; + QApplication obj1(argc, 0, QApplication::GuiServer); + MyInputContext *var1 = new MyInputContext; + + // QApplication takes ownership, so check for reparenting: + obj1.setInputContext(var1); + QCOMPARE(var1->parent(), static_cast(&obj1)); + + // Test for self-assignment: + obj1.setInputContext(obj1.inputContext()); + QVERIFY(obj1.inputContext()); + QCOMPARE(static_cast(var1), obj1.inputContext()); + + // Resetting the input context to 0 is not allowed: + QTest::ignoreMessage(QtWarningMsg, "QApplication::setInputContext: called with 0 input context"); + obj1.setInputContext(0); + + QCOMPARE(static_cast(var1), obj1.inputContext()); +} + +class CloseEventTestWindow : public QWidget +{ +public: + CloseEventTestWindow(QWidget *parent = 0) + : QWidget(parent) + { + } + + void closeEvent(QCloseEvent *event) + { + QWidget dialog; + dialog.show(); + dialog.close(); + + hide(); + event->ignore(); + } +}; + +static char *argv0; + +tst_QApplication::tst_QApplication() +{ +#ifdef Q_OS_WINCE + // Clean up environment previously to launching test + qputenv("QT_PLUGIN_PATH", QByteArray()); +#endif +} + +tst_QApplication::~tst_QApplication() +{ + +} + +void tst_QApplication::init() +{ +// TODO: Add initialization code here. +// This will be executed immediately before each test is run. +} + +void tst_QApplication::cleanup() +{ +// TODO: Add cleanup code here. +// This will be executed immediately after each test is run. +} + +void tst_QApplication::staticSetup() +{ + QVERIFY(!qApp); + + QStyle *style = QStyleFactory::create(QLatin1String("Windows")); + QVERIFY(style); + QApplication::setStyle(style); + + QPalette pal; + QApplication::setPalette(pal); + + /*QFont font; + QApplication::setFont(font);*/ + + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); +} + + +// QApp subclass that exits the event loop after 150ms +class TestApplication : public QApplication +{ +public: + TestApplication( int &argc, char **argv ) + : QApplication( argc, argv, QApplication::GuiServer ) + { + startTimer( 150 ); + } + + void timerEvent( QTimerEvent * ) + { + quit(); + } +}; + +void tst_QApplication::alert() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + app.alert(0, 0); + + QWidget widget; + QWidget widget2; + app.alert(&widget, 100); + widget.show(); + widget2.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&widget); + qt_x11_wait_for_window_manager(&widget2); +#endif + QTest::qWait(100); + app.alert(&widget, -1); + app.alert(&widget, 250); + widget2.activateWindow(); + QApplication::setActiveWindow(&widget2); + app.alert(&widget, 0); + widget.activateWindow(); + QApplication::setActiveWindow(&widget); + app.alert(&widget, 200); + app.syncX(); +} + +void tst_QApplication::multiple_data() +{ + QTest::addColumn("features"); + + // return a list of things to try + QTest::newRow( "data0" ) << QStringList( "" ); + QTest::newRow( "data1" ) << QStringList( "QFont" ); + QTest::newRow( "data2" ) << QStringList( "QPixmap" ); + QTest::newRow( "data3" ) << QStringList( "QWidget" ); +} + +void tst_QApplication::multiple() +{ + QFETCH(QStringList,features); + + int i = 0; + int argc = 0; + while ( i++ < 5 ) { + TestApplication app( argc, 0 ); + + if ( features.contains( "QFont" ) ) { + // create font and force loading + QFont font( "Arial", 12 ); + QFontInfo finfo( font ); + finfo.exactMatch(); + } + if ( features.contains( "QPixmap" ) ) { + QPixmap pix( 100, 100 ); + pix.fill( Qt::black ); + } + if ( features.contains( "QWidget" ) ) { + QWidget widget; + } + + QVERIFY(!app.exec()); + } +} + +void tst_QApplication::nonGui() +{ +#ifdef Q_OS_HPUX + // ### This is only to allow us to generate a test report for now. + QSKIP("This test shuts down the window manager on HP-UX.", SkipAll); +#endif + + int argc = 0; + QApplication app(argc, 0, false); + QCOMPARE(qApp, &app); +} + +void tst_QApplication::setFont_data() +{ + QTest::addColumn("family"); + QTest::addColumn("pointsize"); + QTest::addColumn("beforeAppConstructor"); + + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); // Needed for QFontDatabase + + int cnt = 0; + QFontDatabase fdb; + QStringList families = fdb.families(); + for (QStringList::const_iterator itr = families.begin(); + itr != families.end(); + ++itr) { + if (cnt < 3) { + QString family = *itr; + QStringList styles = fdb.styles(family); + if (styles.size() > 0) { + QString style = styles.first(); + QList sizes = fdb.pointSizes(family, style); + if (!sizes.size()) + sizes = fdb.standardSizes(); + if (sizes.size() > 0) { + QTest::newRow(QString("data%1a").arg(cnt).toLatin1().constData()) + << family + << sizes.first() + << false; + QTest::newRow(QString("data%1b").arg(cnt).toLatin1().constData()) + << family + << sizes.first() + << true; + } + } + } + ++cnt; + } + + QTest::newRow("nonexistingfont") << "nosuchfont_probably_quiteunlikely" + << 0 << false; + QTest::newRow("nonexistingfont") << "nosuchfont_probably_quiteunlikely" + << 0 << true; + + QTest::newRow("largescaleable") << "smoothtimes" << 100 << false; + QTest::newRow("largescaleable") << "smoothtimes" << 100 << true; + + QTest::newRow("largeunscaleale") << "helvetica" << 100 << false; + QTest::newRow("largeunscaleale") << "helvetica" << 100 << true; +} + +void tst_QApplication::setFont() +{ + QFETCH( QString, family ); + QFETCH( int, pointsize ); + QFETCH( bool, beforeAppConstructor ); + + QFont font( family, pointsize ); + if (beforeAppConstructor) { + QApplication::setFont( font ); + QCOMPARE(QApplication::font(), font); + } + + int argc = 0; + QApplication app( argc, 0, QApplication::GuiServer ); + if (!beforeAppConstructor) + QApplication::setFont( font ); + + QCOMPARE( app.font(), font ); +} + +void tst_QApplication::args_data() +{ + QTest::addColumn("argc_in"); + QTest::addColumn("args_in"); + QTest::addColumn("argc_out"); + QTest::addColumn("args_out"); + + QTest::newRow( "App name" ) << 1 << "/usr/bin/appname" << 1 << "/usr/bin/appname"; + QTest::newRow( "No arguments" ) << 0 << QString() << 0 << QString(); + QTest::newRow( "App name, style" ) << 3 << "/usr/bin/appname -style motif" << 1 << "/usr/bin/appname"; + QTest::newRow( "App name, style, arbitrary, reverse" ) << 5 << "/usr/bin/appname -style motif -arbitrary -reverse" + << 2 << "/usr/bin/appname -arbitrary"; +} + +void tst_QApplication::task109149() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + QApplication::setFont(QFont("helvetica", 100)); + + QWidget w; + w.setWindowTitle("hello"); + w.show(); + + app.processEvents(); +} + +static char ** QString2cstrings( const QString &args ) +{ + static QList cache; + + int i; + char **argarray = 0; + QStringList list = args.split(' ');; + argarray = new char*[list.count()+1]; + + for (i = 0; i < (int)list.count(); ++i ) { + QByteArray l1 = list[i].toLatin1(); + argarray[i] = l1.data(); + cache.append(l1); + } + argarray[i] = 0; + + return argarray; +} + +static QString cstrings2QString( char **args ) +{ + QString string; + if ( !args ) + return string; + + int i = 0; + while ( args[i] ) { + string += args[i]; + if ( args[i+1] ) + string += " "; + ++i; + } + return string; +} + +void tst_QApplication::args() +{ + QFETCH( int, argc_in ); + QFETCH( QString, args_in ); + QFETCH( int, argc_out ); + QFETCH( QString, args_out ); + + char **argv = QString2cstrings( args_in ); + + QApplication app( argc_in, argv, QApplication::GuiServer ); + QString argv_out = cstrings2QString(argv); + + QCOMPARE( argc_in, argc_out ); + QCOMPARE( argv_out, args_out ); + + delete [] argv; +} + +class CloseWidget : public QWidget +{ + Q_OBJECT +public: + CloseWidget() + { + startTimer(500); + } + +protected: + void timerEvent(QTimerEvent *) + { + close(); + } + +}; + +void tst_QApplication::lastWindowClosed() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + QSignalSpy spy(&app, SIGNAL(lastWindowClosed())); + + QPointer dialog = new QDialog; + QVERIFY(dialog->testAttribute(Qt::WA_QuitOnClose)); + QTimer::singleShot(1000, dialog, SLOT(accept())); + dialog->exec(); + QVERIFY(dialog); + QCOMPARE(spy.count(), 0); + + QPointerwidget = new CloseWidget; + QVERIFY(widget->testAttribute(Qt::WA_QuitOnClose)); + QObject::connect(&app, SIGNAL(lastWindowClosed()), widget, SLOT(deleteLater())); + app.exec(); + QVERIFY(!widget); + QCOMPARE(spy.count(), 1); + spy.clear(); + +#if 0 + // everything is closed, so doing this should not emit lastWindowClosed() again + QMetaObject::invokeMethod(dialog, "close", Qt::QueuedConnection); + QTimer::singleShot(1000, &app, SLOT(quit())); + app.exec(); + QCOMPARE(spy.count(), 0); +#endif + + delete dialog; + + // show 3 windows, close them, should only get lastWindowClosed once + QWidget w1; + QWidget w2; + QWidget w3; + w1.show(); + w2.show(); + w3.show(); + + QTimer::singleShot(1000, &app, SLOT(closeAllWindows())); + app.exec(); + QCOMPARE(spy.count(), 1); +} + +class QuitOnLastWindowClosedDialog : public QDialog +{ + Q_OBJECT +public: + QPushButton *okButton; + + QuitOnLastWindowClosedDialog() + { + QHBoxLayout *hbox = new QHBoxLayout(this); + okButton = new QPushButton("&ok", this); + + hbox->addWidget(okButton); + connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(okButton, SIGNAL(clicked()), this, SLOT(ok_clicked())); + } + +public slots: + void ok_clicked() + { + QDialog other; + + QTimer timer; + connect(&timer, SIGNAL(timeout()), &other, SLOT(accept())); + QSignalSpy spy(&timer, SIGNAL(timeout())); + QSignalSpy appSpy(qApp, SIGNAL(lastWindowClosed())); + + timer.start(1000); + other.exec(); + + // verify that the eventloop ran and let the timer fire + QCOMPARE(spy.count(), 1); + QCOMPARE(appSpy.count(), 1); + } +}; + +class QuitOnLastWindowClosedWindow : public QWidget +{ + Q_OBJECT + +public: + QuitOnLastWindowClosedWindow() + { } + +public slots: + void execDialogThenShow() + { + QDialog dialog; + QTimer timer1; + connect(&timer1, SIGNAL(timeout()), &dialog, SLOT(accept())); + QSignalSpy spy1(&timer1, SIGNAL(timeout())); + timer1.setSingleShot(true); + timer1.start(1000); + dialog.exec(); + QCOMPARE(spy1.count(), 1); + + show(); + } +}; + +void tst_QApplication::quitOnLastWindowClosed() +{ + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + QuitOnLastWindowClosedDialog d; + d.show(); + QTimer::singleShot(1000, d.okButton, SLOT(animateClick())); + + QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed())); + app.exec(); + + // lastWindowClosed() signal should only be sent after the last dialog is closed + QCOMPARE(appSpy.count(), 2); + } + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed())); + + QDialog dialog; + QTimer timer1; + connect(&timer1, SIGNAL(timeout()), &dialog, SLOT(accept())); + QSignalSpy spy1(&timer1, SIGNAL(timeout())); + timer1.setSingleShot(true); + timer1.start(1000); + dialog.exec(); + QCOMPARE(spy1.count(), 1); + QCOMPARE(appSpy.count(), 0); + + QTimer timer2; + connect(&timer2, SIGNAL(timeout()), &app, SLOT(quit())); + QSignalSpy spy2(&timer2, SIGNAL(timeout())); + timer2.setSingleShot(true); + timer2.start(1000); + int returnValue = app.exec(); + QCOMPARE(returnValue, 0); + QCOMPARE(spy2.count(), 1); + QCOMPARE(appSpy.count(), 0); + } + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + QTimer timer; + timer.setInterval(100); + + QSignalSpy spy(&app, SIGNAL(aboutToQuit())); + QSignalSpy spy2(&timer, SIGNAL(timeout())); + + QPointer mainWindow = new QMainWindow; + QPointer dialog = new QDialog(mainWindow); + + QVERIFY(app.quitOnLastWindowClosed()); + QVERIFY(mainWindow->testAttribute(Qt::WA_QuitOnClose)); + QVERIFY(dialog->testAttribute(Qt::WA_QuitOnClose)); + + mainWindow->show(); + dialog->show(); + + timer.start(); + QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application + QTimer::singleShot(2000, &app, SLOT(quit())); // This makes sure we quit even if it didn't + + app.exec(); + + QCOMPARE(spy.count(), 1); + QVERIFY(spy2.count() < 15); // Should be around 10 if closing caused the quit + } + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + QTimer timer; + timer.setInterval(100); + + QSignalSpy spy(&app, SIGNAL(aboutToQuit())); + QSignalSpy spy2(&timer, SIGNAL(timeout())); + + QPointer mainWindow = new CloseEventTestWindow; + + QVERIFY(app.quitOnLastWindowClosed()); + QVERIFY(mainWindow->testAttribute(Qt::WA_QuitOnClose)); + + mainWindow->show(); + + timer.start(); + QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application + QTimer::singleShot(2000, &app, SLOT(quit())); // This makes sure we quit even if it didn't + + app.exec(); + + QCOMPARE(spy.count(), 1); + QVERIFY(spy2.count() > 15); // Should be around 20 if closing did not caused the quit + } + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed())); + + // exec a dialog for 1 second, then show the window + QuitOnLastWindowClosedWindow window; + QTimer::singleShot(0, &window, SLOT(execDialogThenShow())); + + QTimer timer; + QSignalSpy timerSpy(&timer, SIGNAL(timeout())); + connect(&timer, SIGNAL(timeout()), &window, SLOT(close())); + timer.setSingleShot(true); + timer.start(2000); + int returnValue = app.exec(); + QCOMPARE(returnValue, 0); + // failure here means the timer above didn't fire, and the + // quit was caused the the dialog being closed (not the window) + QCOMPARE(timerSpy.count(), 1); + QCOMPARE(appSpy.count(), 2); + } +} + +class PromptOnCloseWidget : public QWidget +{ +public: + void closeEvent(QCloseEvent *event) + { + QMessageBox *messageBox = new QMessageBox(this); + messageBox->setWindowTitle("Unsaved data"); + messageBox->setText("Would you like to save or discard your current data?"); + messageBox->setStandardButtons(QMessageBox::Save|QMessageBox::Discard|QMessageBox::Cancel); + messageBox->setDefaultButton(QMessageBox::Save); + + messageBox->show(); + QTest::qWaitForWindowShown(messageBox); + + // verify that all windows are visible + foreach (QWidget *w, qApp->topLevelWidgets()) + QVERIFY(w->isVisible()); + // flush event queue + qApp->processEvents(); + // close all windows + qApp->closeAllWindows(); + + if (messageBox->standardButton(messageBox->clickedButton()) == QMessageBox::Cancel) + event->ignore(); + else + event->accept(); + + delete messageBox; + } +}; + +void tst_QApplication::closeAllWindows() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + // create some windows + new QWidget; + new QWidget; + new QWidget; + + // show all windows + foreach (QWidget *w, app.topLevelWidgets()) { + w->show(); + QTest::qWaitForWindowShown(w); + } + // verify that they are visible + foreach (QWidget *w, app.topLevelWidgets()) + QVERIFY(w->isVisible()); + // empty event queue + app.processEvents(); + // close all windows + app.closeAllWindows(); + // all windows should no longer be visible + foreach (QWidget *w, app.topLevelWidgets()) + QVERIFY(!w->isVisible()); + + // add a window that prompts the user when closed + PromptOnCloseWidget *promptOnCloseWidget = new PromptOnCloseWidget; + // show all windows + foreach (QWidget *w, app.topLevelWidgets()) { + w->show(); + QTest::qWaitForWindowShown(w); + } + // close the last window to open the prompt (eventloop recurses) + promptOnCloseWidget->close(); + // all windows should not be visible, except the one that opened the prompt + foreach (QWidget *w, app.topLevelWidgets()) { + if (w == promptOnCloseWidget) + QVERIFY(w->isVisible()); + else + QVERIFY(!w->isVisible()); + } + + qDeleteAll(app.topLevelWidgets()); +} + +bool isPathListIncluded(const QStringList &l, const QStringList &r) +{ + int size = r.count(); + if (size > l.count()) + return false; +#if defined (Q_OS_WIN) + Qt::CaseSensitivity cs = Qt::CaseInsensitive; +#else + Qt::CaseSensitivity cs = Qt::CaseSensitive; +#endif + int i = 0, j = 0; + for ( ; i < l.count() && j < r.count(); ++i) { + if (QDir::toNativeSeparators(l[i]).compare(QDir::toNativeSeparators(r[j]), cs) == 0) { + ++j; + i = -1; + } + } + return j == r.count(); +} + +#define QT_TST_QAPP_DEBUG +void tst_QApplication::libraryPaths() +{ + { +#ifndef Q_OS_WINCE + QString testDir = QDir::current().canonicalPath() + "/test"; +#else + // On Windows CE we need QApplication object to have valid + // current Path. Therefore we need to identify it ourselves + // here for the test. + QFileInfo filePath; + wchar_t module_name[MAX_PATH]; + GetModuleFileName(0, module_name, MAX_PATH); + filePath = QString::fromWCharArray(module_name); + QString testDir = filePath.path() + "/test"; +#endif + QApplication::setLibraryPaths(QStringList() << testDir); + QCOMPARE(QApplication::libraryPaths(), (QStringList() << testDir)); + + // creating QApplication adds the applicationDirPath to the libraryPath + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QString appDirPath = QDir(app.applicationDirPath()).canonicalPath(); + + QStringList actual = QApplication::libraryPaths(); + actual.sort(); + QStringList expected = QSet::fromList((QStringList() << testDir << appDirPath)).toList(); + expected.sort(); + + QVERIFY2(isPathListIncluded(actual, expected), + qPrintable("actual:\n - " + actual.join("\n - ") + + "\nexpected:\n - " + expected.join("\n - "))); + } + { + // creating QApplication adds the applicationDirPath and plugin install path to the libraryPath + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QString appDirPath = app.applicationDirPath(); + QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); + + QStringList actual = QApplication::libraryPaths(); + actual.sort(); + + QStringList expected = QSet::fromList((QStringList() << installPathPlugins << appDirPath)).toList(); + expected.sort(); + + QVERIFY2(isPathListIncluded(actual, expected), + qPrintable("actual:\n - " + actual.join("\n - ") + + "\nexpected:\n - " + expected.join("\n - "))); + + // setting the library paths overrides everything + QString testDir = QDir::currentPath() + "/test"; + QApplication::setLibraryPaths(QStringList() << testDir); + QVERIFY2(isPathListIncluded(QApplication::libraryPaths(), (QStringList() << testDir)), + qPrintable("actual:\n - " + QApplication::libraryPaths().join("\n - ") + + "\nexpected:\n - " + testDir)); + } + { +#ifdef QT_TST_QAPP_DEBUG + qDebug() << "Initial library path:" << QApplication::libraryPaths(); +#endif + + int count = QApplication::libraryPaths().count(); +#if 0 + // this test doesn't work if KDE 4 is installed + QCOMPARE(count, 1); // before creating QApplication, only the PluginsPath is in the libraryPaths() +#endif + QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); + QApplication::addLibraryPath(installPathPlugins); +#ifdef QT_TST_QAPP_DEBUG + qDebug() << "installPathPlugins" << installPathPlugins; + qDebug() << "After adding plugins path:" << QApplication::libraryPaths(); +#endif + QCOMPARE(QApplication::libraryPaths().count(), count); + + QApplication::addLibraryPath(QDir::currentPath() + "/test"); + QCOMPARE(QApplication::libraryPaths().count(), count + 1); + + // creating QApplication adds the applicationDirPath to the libraryPath + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QString appDirPath = app.applicationDirPath(); + qDebug() << QApplication::libraryPaths(); + // On Windows CE these are identical and might also be the case for other + // systems too + if (appDirPath != installPathPlugins) + QCOMPARE(QApplication::libraryPaths().count(), count + 2); + } + { + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + +#ifdef QT_TST_QAPP_DEBUG + qDebug() << "Initial library path:" << app.libraryPaths(); +#endif + int count = app.libraryPaths().count(); + QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); + app.addLibraryPath(installPathPlugins); +#ifdef QT_TST_QAPP_DEBUG + qDebug() << "installPathPlugins" << installPathPlugins; + qDebug() << "After adding plugins path:" << app.libraryPaths(); +#endif + QCOMPARE(app.libraryPaths().count(), count); + + QString appDirPath = app.applicationDirPath(); + + app.addLibraryPath(appDirPath); +#ifdef Q_OS_WINCE + app.addLibraryPath(appDirPath + "/../.."); +#else + app.addLibraryPath(appDirPath + "/.."); +#endif +#ifdef QT_TST_QAPP_DEBUG + qDebug() << "appDirPath" << appDirPath; + qDebug() << "After adding appDirPath && appDirPath + /..:" << app.libraryPaths(); +#endif + QCOMPARE(app.libraryPaths().count(), count + 1); +#ifdef Q_OS_MAC + app.addLibraryPath(appDirPath + "/../MacOS"); +#else + app.addLibraryPath(appDirPath + "/tmp/.."); +#endif +#ifdef QT_TST_QAPP_DEBUG + qDebug() << "After adding appDirPath + /tmp/..:" << app.libraryPaths(); +#endif + QCOMPARE(app.libraryPaths().count(), count + 1); + } +} + +void tst_QApplication::libraryPaths_qt_plugin_path() +{ + int argc = 1; + + QApplication app(argc, &argv0, QApplication::GuiServer); + QString appDirPath = app.applicationDirPath(); + + // Our hook into libraryPaths() initialization: Set the QT_PLUGIN_PATH environment variable + QString installPathPluginsDeCanon = appDirPath + QString::fromLatin1("/tmp/.."); + QByteArray ascii = installPathPluginsDeCanon.toAscii(); + qputenv("QT_PLUGIN_PATH", ascii); + + QVERIFY(!app.libraryPaths().contains(appDirPath + QString::fromLatin1("/tmp/.."))); +} + +void tst_QApplication::libraryPaths_qt_plugin_path_2() +{ +#ifdef Q_OS_UNIX + QByteArray validPath = QDir("/tmp").canonicalPath().toLatin1(); + QByteArray nonExistentPath = "/nonexistent"; + QByteArray pluginPath = validPath + ":" + nonExistentPath; +#elif defined(Q_OS_WIN) +# ifdef Q_OS_WINCE + QByteArray validPath = "/Temp"; + QByteArray nonExistentPath = "/nonexistent"; + QByteArray pluginPath = validPath + ";" + nonExistentPath; +# else + QByteArray validPath = "C:\\windows"; + QByteArray nonExistentPath = "Z:\\nonexistent"; + QByteArray pluginPath = validPath + ";" + nonExistentPath; +# endif +#endif + + { + // Our hook into libraryPaths() initialization: Set the QT_PLUGIN_PATH environment variable + qputenv("QT_PLUGIN_PATH", pluginPath); + + int argc = 1; + + QApplication app(argc, &argv0, QApplication::GuiServer); + + // library path list should contain the default plus the one valid path + QStringList expected = + QStringList() + << QLibraryInfo::location(QLibraryInfo::PluginsPath) + << QDir(app.applicationDirPath()).canonicalPath() + << QDir(QDir::fromNativeSeparators(QString::fromLatin1(validPath))).canonicalPath(); +# ifdef Q_OS_WINCE + expected = QSet::fromList(expected).toList(); +# endif + QVERIFY2(isPathListIncluded(app.libraryPaths(), expected), + qPrintable("actual:\n - " + app.libraryPaths().join("\n - ") + + "\nexpected:\n - " + expected.join("\n - "))); + } + + { + int argc = 1; + + QApplication app(argc, &argv0, QApplication::GuiServer); + + // library paths are initialized by the QApplication, setting + // the environment variable here doesn't work + qputenv("QT_PLUGIN_PATH", pluginPath); + + // library path list should contain the default + QStringList expected = + QStringList() + << QLibraryInfo::location(QLibraryInfo::PluginsPath) + << app.applicationDirPath(); +# ifdef Q_OS_WINCE + expected = QSet::fromList(expected).toList(); +# endif + QVERIFY(isPathListIncluded(app.libraryPaths(), expected)); + + qputenv("QT_PLUGIN_PATH", QByteArray()); + } +} + +class SendPostedEventsTester : public QObject +{ + Q_OBJECT +public: + QList eventSpy; + bool event(QEvent *e); +private slots: + void doTest(); +}; + +bool SendPostedEventsTester::event(QEvent *e) +{ + eventSpy.append(e->type()); + return QObject::event(e); +} + +void SendPostedEventsTester::doTest() +{ + QPointer p = this; + QApplication::postEvent(this, new QEvent(QEvent::User)); + // DeferredDelete should not be delivered until returning from this function + QApplication::postEvent(this, new QEvent(QEvent::DeferredDelete)); + + QEventLoop eventLoop; + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p != 0); + + QCOMPARE(eventSpy.count(), 2); + QCOMPARE(eventSpy.at(0), int(QEvent::MetaCall)); + QCOMPARE(eventSpy.at(1), int(QEvent::User)); + eventSpy.clear(); +} + +void tst_QApplication::sendPostedEvents() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + SendPostedEventsTester *tester = new SendPostedEventsTester; + QMetaObject::invokeMethod(tester, "doTest", Qt::QueuedConnection); + QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection); + QPointer p = tester; + (void) app.exec(); + QVERIFY(p == 0); +} + +void tst_QApplication::thread() +{ + QThread *currentThread = QThread::currentThread(); + // no app, but still have a valid thread + QVERIFY(currentThread != 0); + + // the thread should be running and not finished + QVERIFY(currentThread->isRunning()); + QVERIFY(!currentThread->isFinished()); + + // this should probably be in the tst_QObject::thread() test, but + // we put it here since we want to make sure that objects created + // *before* the QApplication has a thread + QObject object; + QObject child(&object); + QVERIFY(object.thread() == currentThread); + QVERIFY(child.thread() == currentThread); + + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + // current thread still valid + QVERIFY(QThread::currentThread() != 0); + // thread should be the same as before + QCOMPARE(QThread::currentThread(), currentThread); + + // app's thread should be the current thread + QCOMPARE(app.thread(), currentThread); + + // the thread should still be running and not finished + QVERIFY(currentThread->isRunning()); + QVERIFY(!currentThread->isFinished()); + + QTestEventLoop::instance().enterLoop(1); + } + + // app dead, current thread still valid + QVERIFY(QThread::currentThread() != 0); + QCOMPARE(QThread::currentThread(), currentThread); + + // the thread should still be running and not finished + QVERIFY(currentThread->isRunning()); + QVERIFY(!currentThread->isFinished()); + + // should still have a thread + QVERIFY(object.thread() == currentThread); + QVERIFY(child.thread() == currentThread); + + // do the test again, making sure that the thread is the same as + // before + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + // current thread still valid + QVERIFY(QThread::currentThread() != 0); + // thread should be the same as before + QCOMPARE(QThread::currentThread(), currentThread); + + // app's thread should be the current thread + QCOMPARE(app.thread(), currentThread); + + // the thread should be running and not finished + QVERIFY(currentThread->isRunning()); + QVERIFY(!currentThread->isFinished()); + + // should still have a thread + QVERIFY(object.thread() == currentThread); + QVERIFY(child.thread() == currentThread); + + QTestEventLoop::instance().enterLoop(1); + } + + // app dead, current thread still valid + QVERIFY(QThread::currentThread() != 0); + QCOMPARE(QThread::currentThread(), currentThread); + + // the thread should still be running and not finished + QVERIFY(currentThread->isRunning()); + QVERIFY(!currentThread->isFinished()); + + // should still have a thread + QVERIFY(object.thread() == currentThread); + QVERIFY(child.thread() == currentThread); +} + +class DeleteLaterWidget : public QWidget +{ + Q_OBJECT +public: + DeleteLaterWidget(QApplication *_app, QWidget *parent = 0) + : QWidget(parent) { app = _app; child_deleted = false; } + + bool child_deleted; + QApplication *app; + +public slots: + void runTest(); + void checkDeleteLater(); + void childDeleted() { child_deleted = true; } +}; + + +void DeleteLaterWidget::runTest() +{ + QObject *stillAlive = qFindChild(this, "deleteLater"); + + QWidget *w = new QWidget(this); + connect(w, SIGNAL(destroyed()), this, SLOT(childDeleted())); + + w->deleteLater(); + QVERIFY(!child_deleted); + + QDialog dlg; + QTimer::singleShot(500, &dlg, SLOT(reject())); + dlg.exec(); + + QVERIFY(!child_deleted); + app->processEvents(); + QVERIFY(!child_deleted); + + QTimer::singleShot(500, this, SLOT(checkDeleteLater())); + + app->processEvents(); + + QVERIFY(!stillAlive); // verify at the end to make test terminate +} + +void DeleteLaterWidget::checkDeleteLater() +{ + QVERIFY(child_deleted); + + close(); +} + +void tst_QApplication::testDeleteLater() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); + + DeleteLaterWidget *wgt = new DeleteLaterWidget(&app); + QTimer::singleShot(500, wgt, SLOT(runTest())); + + QObject *object = new QObject(wgt); + object->setObjectName("deleteLater"); + object->deleteLater(); + + QObject *stillAlive = qFindChild(wgt, "deleteLater"); + QVERIFY(stillAlive); + + app.exec(); + + delete wgt; + +} + +class EventLoopNester : public QObject +{ + Q_OBJECT +public slots: + void deleteLaterAndEnterLoop() + { + QEventLoop eventLoop; + QPointer p(this); + deleteLater(); + /* + DeferredDelete events are compressed, meaning this second + deleteLater() will *not* delete the object in the nested + event loop + */ + QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); + QTimer::singleShot(1000, &eventLoop, SLOT(quit())); + eventLoop.exec(); + QVERIFY(p); + } + void deleteLaterAndExitLoop() + { + // Check that 'p' is not deleted before exec returns, since the call + // to QEventLoop::quit() should stop 'eventLoop' from processing + // any more events (that is, delete later) until we return to the + // _current_ event loop: + QEventLoop eventLoop; + QPointer p(this); + QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); // not dead yet + } + + void processEventsOnly() + { + QApplication::processEvents(); + } + void processEventsWithDeferredDeletion() + { + QApplication::processEvents(QEventLoop::DeferredDeletion); + } + void sendPostedEventsWithDeferredDelete() + { + QApplication::sendPostedEvents(0, QEvent::DeferredDelete); + } + void deleteLaterAndProcessEvents1() + { + QEventLoop eventLoop; + + QPointer p = this; + deleteLater(); + + // trying to delete this object in a deeper eventloop just won't work + QMetaObject::invokeMethod(this, + "processEventsOnly", + Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); + QMetaObject::invokeMethod(this, + "processEventsWithDeferredDeletion", + Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); + QMetaObject::invokeMethod(this, + "sendPostedEventsWithDeferredDelete", + Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); + + // trying to delete it from this eventloop still doesn't work + QApplication::processEvents(); + QVERIFY(p); + + // however, it *will* work with this magic incantation + QApplication::processEvents(QEventLoop::DeferredDeletion); + QVERIFY(!p); + } + + void deleteLaterAndProcessEvents2() + { + QEventLoop eventLoop; + + QPointer p = this; + deleteLater(); + + // trying to delete this object in a deeper eventloop just won't work + QMetaObject::invokeMethod(this, + "processEventsOnly", + Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); + QMetaObject::invokeMethod(this, + "processEventsWithDeferredDeletion", + Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); + QMetaObject::invokeMethod(this, + "sendPostedEventsWithDeferredDelete", + Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); + + // trying to delete it from this eventloop still doesn't work + QApplication::processEvents(); + QVERIFY(p); + + // however, it *will* work with this magic incantation + QApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QVERIFY(!p); + } +}; + +void tst_QApplication::testDeleteLaterProcessEvents() +{ + int argc = 0; + + // Calling processEvents() with no event dispatcher does nothing. + QObject *object = new QObject; + QPointer p(object); + object->deleteLater(); + QApplication::processEvents(); + QVERIFY(p); + delete object; + + { + QApplication app(argc, 0, QApplication::GuiServer); + // If you call processEvents() with an event dispatcher present, but + // outside any event loops, deferred deletes are not processed unless + // QEventLoop::DeferredDeletion is passed. + object = new QObject; + p = object; + object->deleteLater(); + app.processEvents(); + QVERIFY(p); + app.processEvents(QEventLoop::ProcessEventsFlag(0x10)); // 0x10 == QEventLoop::DeferredDeletion + QVERIFY(!p); + + // sendPostedEvents(0, DeferredDelete); also works + object = new QObject; + p = object; + object->deleteLater(); + app.processEvents(); + QVERIFY(p); + QApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QVERIFY(!p); + + // If you call deleteLater() on an object when there is no parent + // event loop, and then enter an event loop, the object will get + // deleted. + object = new QObject; + p = object; + object->deleteLater(); + QEventLoop loop; + QTimer::singleShot(1000, &loop, SLOT(quit())); + loop.exec(); + QVERIFY(!p); + } + { + // When an object is in an event loop, then calls deleteLater() and enters + // an event loop recursively, it should not die until the parent event + // loop continues. + QApplication app(argc, 0, QApplication::GuiServer); + QEventLoop loop; + EventLoopNester *nester = new EventLoopNester; + p = nester; + QTimer::singleShot(3000, &loop, SLOT(quit())); + QTimer::singleShot(0, nester, SLOT(deleteLaterAndEnterLoop())); + + loop.exec(); + QVERIFY(!p); + } + + { + // When the event loop that calls deleteLater() is exited + // immediately, the object should die when returning to the + // parent event loop + QApplication app(argc, 0, QApplication::GuiServer); + QEventLoop loop; + EventLoopNester *nester = new EventLoopNester; + p = nester; + QTimer::singleShot(3000, &loop, SLOT(quit())); + QTimer::singleShot(0, nester, SLOT(deleteLaterAndExitLoop())); + + loop.exec(); + QVERIFY(!p); + } + + { + // when the event loop that calls deleteLater() also calls + // processEvents() immediately afterwards, the object should + // not die until the parent loop continues + QApplication app(argc, 0, QApplication::GuiServer); + QEventLoop loop; + EventLoopNester *nester = new EventLoopNester(); + p = nester; + QTimer::singleShot(3000, &loop, SLOT(quit())); + QTimer::singleShot(0, nester, SLOT(deleteLaterAndProcessEvents1())); + + loop.exec(); + QVERIFY(!p); + } + + { + // when the event loop that calls deleteLater() also calls + // processEvents() immediately afterwards, the object should + // not die until the parent loop continues + QApplication app(argc, 0, QApplication::GuiServer); + QEventLoop loop; + EventLoopNester *nester = new EventLoopNester(); + p = nester; + QTimer::singleShot(3000, &loop, SLOT(quit())); + QTimer::singleShot(0, nester, SLOT(deleteLaterAndProcessEvents2())); + + loop.exec(); + QVERIFY(!p); + } +} + +/* + Test for crash with QApplication::setDesktopSettingsAware(false). +*/ +void tst_QApplication::desktopSettingsAware() +{ +#ifndef QT_NO_PROCESS + QProcess testProcess; +#ifdef Q_OS_WINCE + int argc = 0; + QApplication tmpApp(argc, 0, QApplication::GuiServer); + testProcess.start("desktopsettingsaware/desktopsettingsaware"); +#else +#if defined(Q_OS_WIN) && defined(QT_DEBUG) + testProcess.start("desktopsettingsaware/debug/desktopsettingsaware"); +#elif defined(Q_OS_WIN) + testProcess.start("desktopsettingsaware/release/desktopsettingsaware"); +#else + testProcess.start("desktopsettingsaware/desktopsettingsaware"); +#endif +#endif + QVERIFY(testProcess.waitForFinished(10000)); + QCOMPARE(int(testProcess.state()), int(QProcess::NotRunning)); + QVERIFY(int(testProcess.error()) != int(QProcess::Crashed)); +#endif +} + +void tst_QApplication::setActiveWindow() +{ + int argc = 0; + QApplication MyApp(argc, 0, QApplication::GuiServer); + + QWidget* w = new QWidget; + QVBoxLayout* layout = new QVBoxLayout(w); + + QLineEdit* pb1 = new QLineEdit("Testbutton1", w); + QLineEdit* pb2 = new QLineEdit("Test Line Edit", w); + + layout->addWidget(pb1); + layout->addWidget(pb2); + + pb2->setFocus(); + pb2->setParent(0); + delete pb2; + + w->show(); + QApplication::setActiveWindow(w); // needs this on twm (focus follows mouse) + QVERIFY(pb1->hasFocus()); + delete w; +} + + +/* This might fail on some X11 window managers? */ +void tst_QApplication::focusChanged() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + QSignalSpy spy(&app, SIGNAL(focusChanged(QWidget *, QWidget *))); + QWidget *now = 0; + QWidget *old = 0; + + QWidget parent1; + QHBoxLayout hbox1(&parent1); + QLabel lb1(&parent1); + QLineEdit le1(&parent1); + QPushButton pb1(&parent1); + hbox1.addWidget(&lb1); + hbox1.addWidget(&le1); + hbox1.addWidget(&pb1); + + QCOMPARE(spy.count(), 0); + + parent1.show(); + QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse) + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).count(), 2); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &le1); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == 0); + spy.clear(); + QCOMPARE(spy.count(), 0); + + pb1.setFocus(); + QCOMPARE(spy.count(), 1); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &pb1); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &le1); + spy.clear(); + + lb1.setFocus(); + QCOMPARE(spy.count(), 1); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &lb1); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &pb1); + spy.clear(); + + lb1.clearFocus(); + QCOMPARE(spy.count(), 1); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == 0); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &lb1); + spy.clear(); + + QWidget parent2; + QHBoxLayout hbox2(&parent2); + QLabel lb2(&parent2); + QLineEdit le2(&parent2); + QPushButton pb2(&parent2); + hbox2.addWidget(&lb2); + hbox2.addWidget(&le2); + hbox2.addWidget(&pb2); + + parent2.show(); + QApplication::setActiveWindow(&parent2); // needs this on twm (focus follows mouse) + QVERIFY(spy.count() > 0); // one for deactivation, one for activation on Windows + old = qVariantValue(spy.at(spy.count()-1).at(0)); + now = qVariantValue(spy.at(spy.count()-1).at(1)); + QVERIFY(now == &le2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == 0); + spy.clear(); + + QTestKeyEvent tab(QTest::Press, Qt::Key_Tab, 0, 0); + QTestKeyEvent backtab(QTest::Press, Qt::Key_Backtab, 0, 0); + QTestMouseEvent click(QTest::MouseClick, Qt::LeftButton, 0, QPoint(5, 5), 0); + + bool tabAllControls = true; +#ifdef Q_WS_MAC + // Mac has two modes, one where you tab to everything, one where you can + // only tab to input controls, here's what we get. Determine which ones we + // should get. + QSettings appleSettings(QLatin1String("apple.com")); + QVariant appleValue = appleSettings.value(QLatin1String("AppleKeyboardUIMode"), 0); + tabAllControls = (appleValue.toInt() & 0x2); +#endif + + tab.simulate(now); + if (!tabAllControls) { + QVERIFY(spy.count() == 0); + QVERIFY(now == QApplication::focusWidget()); + } else { + QVERIFY(spy.count() > 0); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &pb2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &le2); + spy.clear(); + } + + if (!tabAllControls) { + QVERIFY(spy.count() == 0); + QVERIFY(now == QApplication::focusWidget()); + } else { + tab.simulate(now); + QVERIFY(spy.count() > 0); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &le2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &pb2); + spy.clear(); + } + + if (!tabAllControls) { + QVERIFY(spy.count() == 0); + QVERIFY(now == QApplication::focusWidget()); + } else { + backtab.simulate(now); + QVERIFY(spy.count() > 0); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &pb2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &le2); + spy.clear(); + } + + + if (!tabAllControls) { + QVERIFY(spy.count() == 0); + QVERIFY(now == QApplication::focusWidget()); + old = &pb2; + } else { + backtab.simulate(now); + QVERIFY(spy.count() > 0); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &le2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &pb2); + spy.clear(); + } + + click.simulate(old); + if (!(pb2.focusPolicy() & Qt::ClickFocus)) { + QVERIFY(spy.count() == 0); + QVERIFY(now == QApplication::focusWidget()); + } else { + QVERIFY(spy.count() > 0); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &pb2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &le2); + spy.clear(); + + click.simulate(old); + QVERIFY(spy.count() > 0); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &le2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &pb2); + spy.clear(); + } + + parent1.activateWindow(); + QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse) + QVERIFY(spy.count() == 1 || spy.count() == 2); // one for deactivation, one for activation on Windows + + //on windows, the change of focus is made in 2 steps + //(the focusChanged SIGNAL is emitted twice) + if (spy.count()==1) + old = qVariantValue(spy.at(spy.count()-1).at(0)); + else + old = qVariantValue(spy.at(spy.count()-2).at(0)); + now = qVariantValue(spy.at(spy.count()-1).at(1)); + QVERIFY(now == &le1); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &le2); + spy.clear(); +} + +class LineEdit : public QLineEdit +{ +public: + LineEdit(QWidget *parent = 0) : QLineEdit(parent) { } + +protected: + void focusOutEvent(QFocusEvent *e) { + QLineEdit::focusOutEvent(e); + if (objectName() == "le1") + setStyleSheet(""); + } + + void focusInEvent(QFocusEvent *e) { + QLineEdit::focusInEvent(e); + if (objectName() == "le2") + setStyleSheet(""); + } +}; + +void tst_QApplication::focusOut() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + + // Tests the case where the style pointer changes when on focus in/out + // (the above is the case when the stylesheet changes) + QWidget w; + QLineEdit *le1 = new LineEdit(&w); + le1->setObjectName("le1"); + le1->setStyleSheet("background: #fee"); + le1->setFocus(); + + QLineEdit *le2 = new LineEdit(&w); + le2->setObjectName("le2"); + le2->setStyleSheet("background: #fee"); + le2->move(100, 100); + w.show(); + + QTest::qWait(2000); + le2->setFocus(); + QTest::qWait(2000); +} + +void tst_QApplication::execAfterExit() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection); + // this should be ignored, as exec() will reset the exitCode + QApplication::exit(1); + int exitCode = app.exec(); + QCOMPARE(exitCode, 0); + + // the quitNow flag should have been reset, so we can spin an + // eventloop after QApplication::exec() returns + QEventLoop eventLoop; + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + exitCode = eventLoop.exec(); + QCOMPARE(exitCode, 0); +} + +void tst_QApplication::wheelScrollLines() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + // If wheelScrollLines returns 0, the mose wheel will be disabled. + QVERIFY(app.wheelScrollLines() > 0); +} + +void tst_QApplication::style() +{ + int argc = 1; + + { + QApplication app(argc, &argv0, QApplication::GuiServer); + QPointer style = app.style(); + app.setStyle(new QWindowsStyle); + QVERIFY(style.isNull()); + } + + QApplication app(argc, &argv0, QApplication::GuiServer); + + // qApp style can never be 0 + QVERIFY(QApplication::style() != 0); +} + +void tst_QApplication::allWidgets() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QWidget *w = new QWidget; + QVERIFY(app.allWidgets().contains(w)); // uncreate widget test + QVERIFY(app.allWidgets().contains(w)); // created widget test + delete w; + w = 0; + QVERIFY(!app.allWidgets().contains(w)); // removal test +} + +void tst_QApplication::topLevelWidgets() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QWidget *w = new QWidget; + w->show(); +#ifndef QT_NO_CLIPBOARD + QClipboard *clipboard = QApplication::clipboard(); + QString originalText = clipboard->text(); + clipboard->setText(QString("newText")); +#endif + app.processEvents(); + QVERIFY(QApplication::topLevelWidgets().contains(w)); + QCOMPARE(QApplication::topLevelWidgets().count(), 1); + delete w; + w = 0; + app.processEvents(); + QCOMPARE(QApplication::topLevelWidgets().count(), 0); +} + + + +void tst_QApplication::setAttribute() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QVERIFY(!QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation)); + QWidget *w = new QWidget; + QVERIFY(!w->testAttribute(Qt::WA_WState_Created)); + delete w; + + QApplication::setAttribute(Qt::AA_ImmediateWidgetCreation); + QVERIFY(QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation)); + w = new QWidget; + QVERIFY(w->testAttribute(Qt::WA_WState_Created)); + QWidget *w2 = new QWidget(w); + w2->setParent(0); + QVERIFY(w2->testAttribute(Qt::WA_WState_Created)); + delete w; + delete w2; + + QApplication::setAttribute(Qt::AA_ImmediateWidgetCreation, false); + QVERIFY(!QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation)); + w = new QWidget; + QVERIFY(!w->testAttribute(Qt::WA_WState_Created)); + delete w; +} + +void tst_QApplication::windowsCommandLine_data() +{ +#if defined(Q_OS_WIN) + QTest::addColumn("args"); + QTest::addColumn("expected"); + + QTest::newRow("hello world") + << QString("Hello \"World\"") + << QString("Hello \"World\""); + QTest::newRow("sql") + << QString("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PNR' AND TABLE_TYPE = 'VIEW' ORDER BY TABLE_NAME") + << QString("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PNR' AND TABLE_TYPE = 'VIEW' ORDER BY TABLE_NAME"); +#endif +} + +void tst_QApplication::windowsCommandLine() +{ +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QFETCH(QString, args); + QFETCH(QString, expected); + + QProcess testProcess; +#if defined(QT_DEBUG) + testProcess.start("wincmdline/debug/wincmdline", QStringList(args)); +#else + testProcess.start("wincmdline/release/wincmdline", QStringList(args)); +#endif + QVERIFY(testProcess.waitForFinished(10000)); + QByteArray error = testProcess.readAllStandardError(); + QString procError(error); + QCOMPARE(procError, expected); +#endif +} + +class TouchEventPropagationTestWidget : public QWidget +{ + Q_OBJECT + +public: + bool seenTouchEvent, acceptTouchEvent, seenMouseEvent, acceptMouseEvent; + + TouchEventPropagationTestWidget(QWidget *parent = 0) + : QWidget(parent), seenTouchEvent(false), acceptTouchEvent(false), seenMouseEvent(false), acceptMouseEvent(false) + { } + + void reset() + { + seenTouchEvent = acceptTouchEvent = seenMouseEvent = acceptMouseEvent = false; + } + + bool event(QEvent *event) + { + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + // qDebug() << objectName() << "seenMouseEvent = true"; + seenMouseEvent = true; + event->setAccepted(acceptMouseEvent); + break; + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + // qDebug() << objectName() << "seenTouchEvent = true"; + seenTouchEvent = true; + event->setAccepted(acceptTouchEvent); + break; + default: + return QWidget::event(event); + } + return true; + } +}; + +void tst_QApplication::touchEventPropagation() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + + QList pressedTouchPoints; + QTouchEvent::TouchPoint press(0); + press.setState(Qt::TouchPointPressed); + pressedTouchPoints << press; + + QList releasedTouchPoints; + QTouchEvent::TouchPoint release(0); + release.setState(Qt::TouchPointReleased); + releasedTouchPoints << release; + + { + // touch event behavior on a window + TouchEventPropagationTestWidget window; + window.setObjectName("1. window"); + + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + window.setAttribute(Qt::WA_AcceptTouchEvents); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + window.acceptTouchEvent = true; + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + } + + { + // touch event behavior on a window with a child widget + TouchEventPropagationTestWidget window; + window.setObjectName("2. window"); + TouchEventPropagationTestWidget widget(&window); + widget.setObjectName("2. widget"); + + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.setAttribute(Qt::WA_AcceptTouchEvents); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.acceptMouseEvent = true; + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.acceptTouchEvent = true; + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.setAttribute(Qt::WA_AcceptTouchEvents, false); + window.setAttribute(Qt::WA_AcceptTouchEvents); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + window.acceptTouchEvent = true; + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.acceptMouseEvent = true; // doesn't matter, touch events are propagated first + window.acceptTouchEvent = true; + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + } +} + +void tst_QApplication::qtbug_12673() +{ + QProcess testProcess; + QStringList arguments; +#ifdef Q_OS_MAC + testProcess.start("modal/modal.app", arguments); +#else + testProcess.start("modal/modal", arguments); +#endif + QVERIFY(testProcess.waitForFinished(20000)); + QCOMPARE(testProcess.exitStatus(), QProcess::NormalExit); +} + +/* + This test is meant to ensure that certain objects (public & commonly used) + can safely be used in a Q_GLOBAL_STATIC such that their destructors are + executed *after* the destruction of QApplication. + */ +Q_GLOBAL_STATIC(QLocale, tst_qapp_locale); +Q_GLOBAL_STATIC(QProcess, tst_qapp_process); +Q_GLOBAL_STATIC(QFileSystemWatcher, tst_qapp_fileSystemWatcher); +Q_GLOBAL_STATIC(QSharedMemory, tst_qapp_sharedMemory); +Q_GLOBAL_STATIC(QElapsedTimer, tst_qapp_elapsedTimer); +Q_GLOBAL_STATIC(QMutex, tst_qapp_mutex); +Q_GLOBAL_STATIC(QWidget, tst_qapp_widget); +Q_GLOBAL_STATIC(QPixmap, tst_qapp_pixmap); +Q_GLOBAL_STATIC(QFont, tst_qapp_font); +Q_GLOBAL_STATIC(QRegion, tst_qapp_region); +Q_GLOBAL_STATIC(QFontDatabase, tst_qapp_fontDatabase); +Q_GLOBAL_STATIC(QCursor, tst_qapp_cursor); + +void tst_QApplication::globalStaticObjectDestruction() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QVERIFY(tst_qapp_locale()); + QVERIFY(tst_qapp_process()); + QVERIFY(tst_qapp_fileSystemWatcher()); + QVERIFY(tst_qapp_sharedMemory()); + QVERIFY(tst_qapp_elapsedTimer()); + QVERIFY(tst_qapp_mutex()); + QVERIFY(tst_qapp_widget()); + QVERIFY(tst_qapp_pixmap()); + QVERIFY(tst_qapp_font()); + QVERIFY(tst_qapp_region()); + QVERIFY(tst_qapp_fontDatabase()); + QVERIFY(tst_qapp_cursor()); +} + +//QTEST_APPLESS_MAIN(tst_QApplication) +int main(int argc, char *argv[]) +{ + tst_QApplication tc; + argv0 = argv[0]; + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_qapplication.moc" diff --git a/tests/auto/widgets/kernel/qapplication/wincmdline/main.cpp b/tests/auto/widgets/kernel/qapplication/wincmdline/main.cpp new file mode 100644 index 0000000000..d0f802231a --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/wincmdline/main.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + if (argc > 1) + fprintf(stderr, "%s", argv[1]); + else + fprintf(stderr, "Failed"); + fflush(stderr); + return 0; +} + diff --git a/tests/auto/widgets/kernel/qapplication/wincmdline/wincmdline.pro b/tests/auto/widgets/kernel/qapplication/wincmdline/wincmdline.pro new file mode 100644 index 0000000000..3ba8f48167 --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/wincmdline/wincmdline.pro @@ -0,0 +1,8 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +QT += widgets +SOURCES += main.cpp + + -- cgit v1.2.3