|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the test suite of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 |
|
43 //#define QT_TST_QAPP_DEBUG |
|
44 #include <qdebug.h> |
|
45 |
|
46 #include <QtTest/QtTest> |
|
47 |
|
48 #include "qabstracteventdispatcher.h" |
|
49 #include <QtGui> |
|
50 |
|
51 #include "private/qapplication_p.h" |
|
52 #include "private/qstylesheetstyle_p.h" |
|
53 #ifdef Q_OS_WINCE |
|
54 #include <windows.h> |
|
55 #endif |
|
56 |
|
57 //TESTED_CLASS= |
|
58 //TESTED_FILES= |
|
59 |
|
60 #if defined(Q_OS_SYMBIAN) |
|
61 // In Symbian, the PluginsPath doesn't specify the only absolute path; just the dir that can be found on any drive |
|
62 static void addExpectedSymbianPluginsPath(QStringList& expected) |
|
63 { |
|
64 QString installPathPlugins = QDir::fromNativeSeparators(QLibraryInfo::location(QLibraryInfo::PluginsPath)); |
|
65 QFileInfoList driveList = QDir::drives(); |
|
66 QListIterator<QFileInfo> iter(driveList); |
|
67 while (iter.hasNext()) { |
|
68 QFileInfo testFi(iter.next().canonicalPath().append(installPathPlugins)); |
|
69 if (testFi.exists()) |
|
70 expected << testFi.canonicalFilePath(); |
|
71 } |
|
72 } |
|
73 #endif |
|
74 |
|
75 class tst_QApplication : public QObject |
|
76 { |
|
77 Q_OBJECT |
|
78 |
|
79 public: |
|
80 tst_QApplication(); |
|
81 virtual ~tst_QApplication(); |
|
82 |
|
83 public slots: |
|
84 void init(); |
|
85 void cleanup(); |
|
86 private slots: |
|
87 void sendEventsOnProcessEvents(); // this must be the first test |
|
88 void getSetCheck(); |
|
89 void staticSetup(); |
|
90 |
|
91 void alert(); |
|
92 |
|
93 void multiple_data(); |
|
94 void multiple(); |
|
95 |
|
96 void nonGui(); |
|
97 |
|
98 void setFont_data(); |
|
99 void setFont(); |
|
100 |
|
101 void args_data(); |
|
102 void args(); |
|
103 |
|
104 void lastWindowClosed(); |
|
105 void quitOnLastWindowClosed(); |
|
106 void testDeleteLater(); |
|
107 void testDeleteLaterProcessEvents(); |
|
108 |
|
109 void libraryPaths(); |
|
110 void libraryPaths_qt_plugin_path(); |
|
111 void libraryPaths_qt_plugin_path_2(); |
|
112 |
|
113 void sendPostedEvents(); |
|
114 |
|
115 void thread(); |
|
116 void desktopSettingsAware(); |
|
117 |
|
118 void setActiveWindow(); |
|
119 |
|
120 void focusChanged(); |
|
121 void focusOut(); |
|
122 |
|
123 void execAfterExit(); |
|
124 |
|
125 void wheelScrollLines(); |
|
126 |
|
127 void task109149(); |
|
128 |
|
129 void style(); |
|
130 |
|
131 void allWidgets(); |
|
132 |
|
133 void setAttribute(); |
|
134 |
|
135 void windowsCommandLine_data(); |
|
136 void windowsCommandLine(); |
|
137 |
|
138 void touchEventPropagation(); |
|
139 }; |
|
140 |
|
141 class EventSpy : public QObject |
|
142 { |
|
143 Q_OBJECT |
|
144 |
|
145 public: |
|
146 QList<int> recordedEvents; |
|
147 bool eventFilter(QObject *, QEvent *event) |
|
148 { |
|
149 recordedEvents.append(event->type()); |
|
150 return false; |
|
151 } |
|
152 }; |
|
153 |
|
154 void tst_QApplication::sendEventsOnProcessEvents() |
|
155 { |
|
156 int argc = 0; |
|
157 QApplication app(argc, 0, QApplication::GuiServer); |
|
158 |
|
159 EventSpy spy; |
|
160 app.installEventFilter(&spy); |
|
161 |
|
162 QCoreApplication::postEvent(&app, new QEvent(QEvent::Type(QEvent::User + 1))); |
|
163 QCoreApplication::processEvents(); |
|
164 QVERIFY(spy.recordedEvents.contains(QEvent::User + 1)); |
|
165 } |
|
166 |
|
167 class MyInputContext : public QInputContext |
|
168 { |
|
169 public: |
|
170 MyInputContext() : QInputContext() {} |
|
171 QString identifierName() { return QString("NoName"); } |
|
172 QString language() { return QString("NoLanguage"); } |
|
173 void reset() {} |
|
174 bool isComposing() const { return false; } |
|
175 }; |
|
176 |
|
177 // Testing get/set functions |
|
178 void tst_QApplication::getSetCheck() |
|
179 { |
|
180 int argc = 0; |
|
181 QApplication obj1(argc, 0, QApplication::GuiServer); |
|
182 // QInputContext * QApplication::inputContext() |
|
183 // void QApplication::setInputContext(QInputContext *) |
|
184 MyInputContext *var1 = new MyInputContext; |
|
185 obj1.setInputContext(var1); |
|
186 QCOMPARE((QInputContext *)var1, obj1.inputContext()); |
|
187 QTest::ignoreMessage(QtWarningMsg, "QApplication::setInputContext: called with 0 input context"); |
|
188 obj1.setInputContext((QInputContext *)0); |
|
189 QCOMPARE((QInputContext *)var1, obj1.inputContext()); |
|
190 // delete var1; // No delete, since QApplication takes ownership |
|
191 } |
|
192 |
|
193 class CloseEventTestWindow : public QWidget |
|
194 { |
|
195 public: |
|
196 CloseEventTestWindow(QWidget *parent = 0) |
|
197 : QWidget(parent) |
|
198 { |
|
199 } |
|
200 |
|
201 void closeEvent(QCloseEvent *event) |
|
202 { |
|
203 QWidget dialog; |
|
204 dialog.show(); |
|
205 dialog.close(); |
|
206 |
|
207 hide(); |
|
208 event->ignore(); |
|
209 } |
|
210 }; |
|
211 |
|
212 static char *argv0; |
|
213 |
|
214 tst_QApplication::tst_QApplication() |
|
215 { |
|
216 #ifdef Q_OS_WINCE |
|
217 // Clean up environment previously to launching test |
|
218 qputenv("QT_PLUGIN_PATH", QByteArray()); |
|
219 #endif |
|
220 } |
|
221 |
|
222 tst_QApplication::~tst_QApplication() |
|
223 { |
|
224 |
|
225 } |
|
226 |
|
227 void tst_QApplication::init() |
|
228 { |
|
229 // TODO: Add initialization code here. |
|
230 // This will be executed immediately before each test is run. |
|
231 } |
|
232 |
|
233 void tst_QApplication::cleanup() |
|
234 { |
|
235 // TODO: Add cleanup code here. |
|
236 // This will be executed immediately after each test is run. |
|
237 } |
|
238 |
|
239 void tst_QApplication::staticSetup() |
|
240 { |
|
241 QVERIFY(!qApp); |
|
242 |
|
243 QStyle *style = QStyleFactory::create(QLatin1String("Windows")); |
|
244 QVERIFY(style); |
|
245 QApplication::setStyle(style); |
|
246 |
|
247 QPalette pal; |
|
248 QApplication::setPalette(pal); |
|
249 |
|
250 /*QFont font; |
|
251 QApplication::setFont(font);*/ |
|
252 |
|
253 int argc = 0; |
|
254 QApplication app(argc, 0, QApplication::GuiServer); |
|
255 } |
|
256 |
|
257 |
|
258 // QApp subclass that exits the event loop after 150ms |
|
259 class TestApplication : public QApplication |
|
260 { |
|
261 public: |
|
262 TestApplication( int &argc, char **argv ) |
|
263 : QApplication( argc, argv, QApplication::GuiServer ) |
|
264 { |
|
265 startTimer( 150 ); |
|
266 } |
|
267 |
|
268 void timerEvent( QTimerEvent * ) |
|
269 { |
|
270 quit(); |
|
271 } |
|
272 }; |
|
273 |
|
274 void tst_QApplication::alert() |
|
275 { |
|
276 int argc = 0; |
|
277 QApplication app(argc, 0, QApplication::GuiServer); |
|
278 app.alert(0, 0); |
|
279 |
|
280 QWidget widget; |
|
281 QWidget widget2; |
|
282 app.alert(&widget, 100); |
|
283 widget.show(); |
|
284 widget2.show(); |
|
285 #ifdef Q_WS_X11 |
|
286 qt_x11_wait_for_window_manager(&widget); |
|
287 qt_x11_wait_for_window_manager(&widget2); |
|
288 #endif |
|
289 QTest::qWait(100); |
|
290 app.alert(&widget, -1); |
|
291 app.alert(&widget, 250); |
|
292 widget2.activateWindow(); |
|
293 QApplication::setActiveWindow(&widget2); |
|
294 app.alert(&widget, 0); |
|
295 widget.activateWindow(); |
|
296 QApplication::setActiveWindow(&widget); |
|
297 app.alert(&widget, 200); |
|
298 app.syncX(); |
|
299 } |
|
300 |
|
301 void tst_QApplication::multiple_data() |
|
302 { |
|
303 QTest::addColumn<QStringList>("features"); |
|
304 |
|
305 // return a list of things to try |
|
306 QTest::newRow( "data0" ) << QStringList( "" ); |
|
307 QTest::newRow( "data1" ) << QStringList( "QFont" ); |
|
308 QTest::newRow( "data2" ) << QStringList( "QPixmap" ); |
|
309 QTest::newRow( "data3" ) << QStringList( "QWidget" ); |
|
310 } |
|
311 |
|
312 void tst_QApplication::multiple() |
|
313 { |
|
314 QFETCH(QStringList,features); |
|
315 |
|
316 int i = 0; |
|
317 int argc = 0; |
|
318 while ( i++ < 5 ) { |
|
319 TestApplication app( argc, 0 ); |
|
320 |
|
321 if ( features.contains( "QFont" ) ) { |
|
322 // create font and force loading |
|
323 QFont font( "Arial", 12 ); |
|
324 QFontInfo finfo( font ); |
|
325 finfo.exactMatch(); |
|
326 } |
|
327 if ( features.contains( "QPixmap" ) ) { |
|
328 QPixmap pix( 100, 100 ); |
|
329 pix.fill( Qt::black ); |
|
330 } |
|
331 if ( features.contains( "QWidget" ) ) { |
|
332 QWidget widget; |
|
333 } |
|
334 |
|
335 QVERIFY(!app.exec()); |
|
336 } |
|
337 } |
|
338 |
|
339 void tst_QApplication::nonGui() |
|
340 { |
|
341 #ifdef Q_OS_HPUX |
|
342 // ### This is only to allow us to generate a test report for now. |
|
343 QSKIP("This test shuts down the window manager on HP-UX.", SkipAll); |
|
344 #endif |
|
345 |
|
346 int argc = 0; |
|
347 QApplication app(argc, 0, false); |
|
348 QCOMPARE(qApp, &app); |
|
349 } |
|
350 |
|
351 void tst_QApplication::setFont_data() |
|
352 { |
|
353 QTest::addColumn<QString>("family"); |
|
354 QTest::addColumn<int>("pointsize"); |
|
355 QTest::addColumn<bool>("beforeAppConstructor"); |
|
356 |
|
357 int argc = 0; |
|
358 QApplication app(argc, 0, QApplication::GuiServer); // Needed for QFontDatabase |
|
359 |
|
360 int cnt = 0; |
|
361 QFontDatabase fdb; |
|
362 QStringList families = fdb.families(); |
|
363 for (QStringList::const_iterator itr = families.begin(); |
|
364 itr != families.end(); |
|
365 ++itr) { |
|
366 if (cnt < 3) { |
|
367 QString family = *itr; |
|
368 QStringList styles = fdb.styles(family); |
|
369 if (styles.size() > 0) { |
|
370 QString style = styles.first(); |
|
371 QList<int> sizes = fdb.pointSizes(family, style); |
|
372 if (!sizes.size()) |
|
373 sizes = fdb.standardSizes(); |
|
374 if (sizes.size() > 0) { |
|
375 QTest::newRow(QString("data%1a").arg(cnt).toLatin1().constData()) |
|
376 << family |
|
377 << sizes.first() |
|
378 << false; |
|
379 QTest::newRow(QString("data%1b").arg(cnt).toLatin1().constData()) |
|
380 << family |
|
381 << sizes.first() |
|
382 << true; |
|
383 } |
|
384 } |
|
385 } |
|
386 ++cnt; |
|
387 } |
|
388 |
|
389 QTest::newRow("nonexistingfont") << "nosuchfont_probably_quiteunlikely" |
|
390 << 0 << false; |
|
391 QTest::newRow("nonexistingfont") << "nosuchfont_probably_quiteunlikely" |
|
392 << 0 << true; |
|
393 |
|
394 QTest::newRow("largescaleable") << "smoothtimes" << 100 << false; |
|
395 QTest::newRow("largescaleable") << "smoothtimes" << 100 << true; |
|
396 |
|
397 QTest::newRow("largeunscaleale") << "helvetica" << 100 << false; |
|
398 QTest::newRow("largeunscaleale") << "helvetica" << 100 << true; |
|
399 } |
|
400 |
|
401 void tst_QApplication::setFont() |
|
402 { |
|
403 QFETCH( QString, family ); |
|
404 QFETCH( int, pointsize ); |
|
405 QFETCH( bool, beforeAppConstructor ); |
|
406 |
|
407 QFont font( family, pointsize ); |
|
408 if (beforeAppConstructor) { |
|
409 QApplication::setFont( font ); |
|
410 QCOMPARE(QApplication::font(), font); |
|
411 } |
|
412 |
|
413 int argc = 0; |
|
414 QApplication app( argc, 0, QApplication::GuiServer ); |
|
415 if (!beforeAppConstructor) |
|
416 QApplication::setFont( font ); |
|
417 |
|
418 QCOMPARE( app.font(), font ); |
|
419 } |
|
420 |
|
421 void tst_QApplication::args_data() |
|
422 { |
|
423 QTest::addColumn<int>("argc_in"); |
|
424 QTest::addColumn<QString>("args_in"); |
|
425 QTest::addColumn<int>("argc_out"); |
|
426 QTest::addColumn<QString>("args_out"); |
|
427 |
|
428 QTest::newRow( "App name" ) << 1 << "/usr/bin/appname" << 1 << "/usr/bin/appname"; |
|
429 QTest::newRow( "No arguments" ) << 0 << QString() << 0 << QString(); |
|
430 QTest::newRow( "App name, style" ) << 3 << "/usr/bin/appname -style motif" << 1 << "/usr/bin/appname"; |
|
431 QTest::newRow( "App name, style, arbitrary, reverse" ) << 5 << "/usr/bin/appname -style motif -arbitrary -reverse" |
|
432 << 2 << "/usr/bin/appname -arbitrary"; |
|
433 } |
|
434 |
|
435 void tst_QApplication::task109149() |
|
436 { |
|
437 int argc = 0; |
|
438 QApplication app(argc, 0, QApplication::GuiServer); |
|
439 QApplication::setFont(QFont("helvetica", 100)); |
|
440 |
|
441 QWidget w; |
|
442 w.setWindowTitle("hello"); |
|
443 w.show(); |
|
444 |
|
445 app.processEvents(); |
|
446 } |
|
447 |
|
448 static char ** QString2cstrings( const QString &args ) |
|
449 { |
|
450 static QList<QByteArray> cache; |
|
451 |
|
452 int i; |
|
453 char **argarray = 0; |
|
454 QStringList list = args.split(' ');; |
|
455 argarray = new char*[list.count()+1]; |
|
456 |
|
457 for (i = 0; i < (int)list.count(); ++i ) { |
|
458 QByteArray l1 = list[i].toLatin1(); |
|
459 argarray[i] = l1.data(); |
|
460 cache.append(l1); |
|
461 } |
|
462 argarray[i] = 0; |
|
463 |
|
464 return argarray; |
|
465 } |
|
466 |
|
467 static QString cstrings2QString( char **args ) |
|
468 { |
|
469 QString string; |
|
470 if ( !args ) |
|
471 return string; |
|
472 |
|
473 int i = 0; |
|
474 while ( args[i] ) { |
|
475 string += args[i]; |
|
476 if ( args[i+1] ) |
|
477 string += " "; |
|
478 ++i; |
|
479 } |
|
480 return string; |
|
481 } |
|
482 |
|
483 void tst_QApplication::args() |
|
484 { |
|
485 QFETCH( int, argc_in ); |
|
486 QFETCH( QString, args_in ); |
|
487 QFETCH( int, argc_out ); |
|
488 QFETCH( QString, args_out ); |
|
489 |
|
490 char **argv = QString2cstrings( args_in ); |
|
491 |
|
492 QApplication app( argc_in, argv, QApplication::GuiServer ); |
|
493 QString argv_out = cstrings2QString(argv); |
|
494 |
|
495 QCOMPARE( argc_in, argc_out ); |
|
496 QCOMPARE( argv_out, args_out ); |
|
497 |
|
498 delete [] argv; |
|
499 } |
|
500 |
|
501 class CloseWidget : public QWidget |
|
502 { |
|
503 Q_OBJECT |
|
504 public: |
|
505 CloseWidget() |
|
506 { |
|
507 startTimer(500); |
|
508 } |
|
509 |
|
510 protected: |
|
511 void timerEvent(QTimerEvent *) |
|
512 { |
|
513 close(); |
|
514 } |
|
515 |
|
516 }; |
|
517 |
|
518 void tst_QApplication::lastWindowClosed() |
|
519 { |
|
520 int argc = 0; |
|
521 QApplication app(argc, 0, QApplication::GuiServer); |
|
522 |
|
523 QSignalSpy spy(&app, SIGNAL(lastWindowClosed())); |
|
524 |
|
525 QPointer<QDialog> dialog = new QDialog; |
|
526 QVERIFY(dialog->testAttribute(Qt::WA_QuitOnClose)); |
|
527 QTimer::singleShot(1000, dialog, SLOT(accept())); |
|
528 dialog->exec(); |
|
529 QVERIFY(dialog); |
|
530 QCOMPARE(spy.count(), 0); |
|
531 |
|
532 QPointer<CloseWidget>widget = new CloseWidget; |
|
533 QVERIFY(widget->testAttribute(Qt::WA_QuitOnClose)); |
|
534 QObject::connect(&app, SIGNAL(lastWindowClosed()), widget, SLOT(deleteLater())); |
|
535 app.exec(); |
|
536 QVERIFY(!widget); |
|
537 QCOMPARE(spy.count(), 1); |
|
538 spy.clear(); |
|
539 |
|
540 #if 0 |
|
541 // everything is closed, so doing this should not emit lastWindowClosed() again |
|
542 QMetaObject::invokeMethod(dialog, "close", Qt::QueuedConnection); |
|
543 QTimer::singleShot(1000, &app, SLOT(quit())); |
|
544 app.exec(); |
|
545 QCOMPARE(spy.count(), 0); |
|
546 #endif |
|
547 |
|
548 delete dialog; |
|
549 |
|
550 // show 3 windows, close them, should only get lastWindowClosed once |
|
551 QWidget w1; |
|
552 QWidget w2; |
|
553 QWidget w3; |
|
554 w1.show(); |
|
555 w2.show(); |
|
556 w3.show(); |
|
557 |
|
558 QTimer::singleShot(1000, &app, SLOT(closeAllWindows())); |
|
559 app.exec(); |
|
560 QCOMPARE(spy.count(), 1); |
|
561 } |
|
562 |
|
563 class QuitOnLastWindowClosedDialog : public QDialog |
|
564 { |
|
565 Q_OBJECT |
|
566 public: |
|
567 QPushButton *okButton; |
|
568 |
|
569 QuitOnLastWindowClosedDialog() |
|
570 { |
|
571 QHBoxLayout *hbox = new QHBoxLayout(this); |
|
572 okButton = new QPushButton("&ok", this); |
|
573 |
|
574 hbox->addWidget(okButton); |
|
575 connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); |
|
576 connect(okButton, SIGNAL(clicked()), this, SLOT(ok_clicked())); |
|
577 } |
|
578 |
|
579 public slots: |
|
580 void ok_clicked() |
|
581 { |
|
582 QDialog other; |
|
583 |
|
584 QTimer timer; |
|
585 connect(&timer, SIGNAL(timeout()), &other, SLOT(accept())); |
|
586 QSignalSpy spy(&timer, SIGNAL(timeout())); |
|
587 QSignalSpy appSpy(qApp, SIGNAL(lastWindowClosed())); |
|
588 |
|
589 timer.start(1000); |
|
590 other.exec(); |
|
591 |
|
592 // verify that the eventloop ran and let the timer fire |
|
593 QCOMPARE(spy.count(), 1); |
|
594 QCOMPARE(appSpy.count(), 1); |
|
595 } |
|
596 }; |
|
597 |
|
598 class QuitOnLastWindowClosedWindow : public QWidget |
|
599 { |
|
600 Q_OBJECT |
|
601 |
|
602 public: |
|
603 QuitOnLastWindowClosedWindow() |
|
604 { } |
|
605 |
|
606 public slots: |
|
607 void execDialogThenShow() |
|
608 { |
|
609 QDialog dialog; |
|
610 QTimer timer1; |
|
611 connect(&timer1, SIGNAL(timeout()), &dialog, SLOT(accept())); |
|
612 QSignalSpy spy1(&timer1, SIGNAL(timeout())); |
|
613 timer1.setSingleShot(true); |
|
614 timer1.start(1000); |
|
615 dialog.exec(); |
|
616 QCOMPARE(spy1.count(), 1); |
|
617 |
|
618 show(); |
|
619 } |
|
620 }; |
|
621 |
|
622 void tst_QApplication::quitOnLastWindowClosed() |
|
623 { |
|
624 { |
|
625 int argc = 0; |
|
626 QApplication app(argc, 0, QApplication::GuiServer); |
|
627 |
|
628 QuitOnLastWindowClosedDialog d; |
|
629 d.show(); |
|
630 QTimer::singleShot(1000, d.okButton, SLOT(animateClick())); |
|
631 |
|
632 QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed())); |
|
633 app.exec(); |
|
634 |
|
635 // lastWindowClosed() signal should only be sent after the last dialog is closed |
|
636 QCOMPARE(appSpy.count(), 2); |
|
637 } |
|
638 { |
|
639 int argc = 0; |
|
640 QApplication app(argc, 0, QApplication::GuiServer); |
|
641 QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed())); |
|
642 |
|
643 QDialog dialog; |
|
644 QTimer timer1; |
|
645 connect(&timer1, SIGNAL(timeout()), &dialog, SLOT(accept())); |
|
646 QSignalSpy spy1(&timer1, SIGNAL(timeout())); |
|
647 timer1.setSingleShot(true); |
|
648 timer1.start(1000); |
|
649 dialog.exec(); |
|
650 QCOMPARE(spy1.count(), 1); |
|
651 QCOMPARE(appSpy.count(), 0); |
|
652 |
|
653 QTimer timer2; |
|
654 connect(&timer2, SIGNAL(timeout()), &app, SLOT(quit())); |
|
655 QSignalSpy spy2(&timer2, SIGNAL(timeout())); |
|
656 timer2.setSingleShot(true); |
|
657 timer2.start(1000); |
|
658 int returnValue = app.exec(); |
|
659 QCOMPARE(returnValue, 0); |
|
660 QCOMPARE(spy2.count(), 1); |
|
661 QCOMPARE(appSpy.count(), 0); |
|
662 } |
|
663 { |
|
664 int argc = 0; |
|
665 QApplication app(argc, 0, QApplication::GuiServer); |
|
666 QTimer timer; |
|
667 timer.setInterval(100); |
|
668 |
|
669 QSignalSpy spy(&app, SIGNAL(aboutToQuit())); |
|
670 QSignalSpy spy2(&timer, SIGNAL(timeout())); |
|
671 |
|
672 QPointer<QMainWindow> mainWindow = new QMainWindow; |
|
673 QPointer<QDialog> dialog = new QDialog(mainWindow); |
|
674 |
|
675 QVERIFY(app.quitOnLastWindowClosed()); |
|
676 QVERIFY(mainWindow->testAttribute(Qt::WA_QuitOnClose)); |
|
677 QVERIFY(dialog->testAttribute(Qt::WA_QuitOnClose)); |
|
678 |
|
679 mainWindow->show(); |
|
680 dialog->show(); |
|
681 |
|
682 timer.start(); |
|
683 QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application |
|
684 QTimer::singleShot(2000, &app, SLOT(quit())); // This makes sure we quit even if it didn't |
|
685 |
|
686 app.exec(); |
|
687 |
|
688 QCOMPARE(spy.count(), 1); |
|
689 QVERIFY(spy2.count() < 15); // Should be around 10 if closing caused the quit |
|
690 } |
|
691 { |
|
692 int argc = 0; |
|
693 QApplication app(argc, 0, QApplication::GuiServer); |
|
694 QTimer timer; |
|
695 timer.setInterval(100); |
|
696 |
|
697 QSignalSpy spy(&app, SIGNAL(aboutToQuit())); |
|
698 QSignalSpy spy2(&timer, SIGNAL(timeout())); |
|
699 |
|
700 QPointer<QMainWindow> mainWindow = new QMainWindow; |
|
701 QPointer<QWidget> invisibleTopLevelWidget = new QWidget; |
|
702 invisibleTopLevelWidget->setAttribute(Qt::WA_DontShowOnScreen); |
|
703 |
|
704 QVERIFY(app.quitOnLastWindowClosed()); |
|
705 QVERIFY(mainWindow->testAttribute(Qt::WA_QuitOnClose)); |
|
706 QVERIFY(invisibleTopLevelWidget->testAttribute(Qt::WA_QuitOnClose)); |
|
707 QVERIFY(invisibleTopLevelWidget->testAttribute(Qt::WA_DontShowOnScreen)); |
|
708 |
|
709 mainWindow->show(); |
|
710 invisibleTopLevelWidget->show(); |
|
711 |
|
712 timer.start(); |
|
713 QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application |
|
714 QTimer::singleShot(2000, &app, SLOT(quit())); // This makes sure we quit even if it didn't |
|
715 |
|
716 app.exec(); |
|
717 |
|
718 QCOMPARE(spy.count(), 1); |
|
719 QVERIFY(spy2.count() < 15); // Should be around 10 if closing caused the quit |
|
720 } |
|
721 { |
|
722 int argc = 0; |
|
723 QApplication app(argc, 0, QApplication::GuiServer); |
|
724 QTimer timer; |
|
725 timer.setInterval(100); |
|
726 |
|
727 QSignalSpy spy(&app, SIGNAL(aboutToQuit())); |
|
728 QSignalSpy spy2(&timer, SIGNAL(timeout())); |
|
729 |
|
730 QPointer<CloseEventTestWindow> mainWindow = new CloseEventTestWindow; |
|
731 |
|
732 QVERIFY(app.quitOnLastWindowClosed()); |
|
733 QVERIFY(mainWindow->testAttribute(Qt::WA_QuitOnClose)); |
|
734 |
|
735 mainWindow->show(); |
|
736 |
|
737 timer.start(); |
|
738 QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application |
|
739 QTimer::singleShot(2000, &app, SLOT(quit())); // This makes sure we quit even if it didn't |
|
740 |
|
741 app.exec(); |
|
742 |
|
743 QCOMPARE(spy.count(), 1); |
|
744 QVERIFY(spy2.count() > 15); // Should be around 20 if closing did not caused the quit |
|
745 } |
|
746 { |
|
747 int argc = 0; |
|
748 QApplication app(argc, 0, QApplication::GuiServer); |
|
749 QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed())); |
|
750 |
|
751 // exec a dialog for 1 second, then show the window |
|
752 QuitOnLastWindowClosedWindow window; |
|
753 QTimer::singleShot(0, &window, SLOT(execDialogThenShow())); |
|
754 |
|
755 QTimer timer; |
|
756 QSignalSpy timerSpy(&timer, SIGNAL(timeout())); |
|
757 connect(&timer, SIGNAL(timeout()), &window, SLOT(close())); |
|
758 timer.setSingleShot(true); |
|
759 timer.start(2000); |
|
760 int returnValue = app.exec(); |
|
761 QCOMPARE(returnValue, 0); |
|
762 // failure here means the timer above didn't fire, and the |
|
763 // quit was caused the the dialog being closed (not the window) |
|
764 QCOMPARE(timerSpy.count(), 1); |
|
765 QCOMPARE(appSpy.count(), 2); |
|
766 } |
|
767 } |
|
768 |
|
769 bool isPathListIncluded(const QStringList &l, const QStringList &r) |
|
770 { |
|
771 int size = r.count(); |
|
772 if (size > l.count()) |
|
773 return false; |
|
774 #if defined (Q_OS_WIN) |
|
775 Qt::CaseSensitivity cs = Qt::CaseInsensitive; |
|
776 #else |
|
777 Qt::CaseSensitivity cs = Qt::CaseSensitive; |
|
778 #endif |
|
779 int i = 0, j = 0; |
|
780 for ( ; i < l.count() && j < r.count(); ++i) { |
|
781 if (QDir::toNativeSeparators(l[i]).compare(QDir::toNativeSeparators(r[j]), cs) == 0) { |
|
782 ++j; |
|
783 i = -1; |
|
784 } |
|
785 } |
|
786 return j == r.count(); |
|
787 } |
|
788 |
|
789 #define QT_TST_QAPP_DEBUG |
|
790 void tst_QApplication::libraryPaths() |
|
791 { |
|
792 { |
|
793 #ifndef Q_OS_WINCE |
|
794 QString testDir = QDir::current().canonicalPath() + "/test"; |
|
795 #else |
|
796 // On Windows CE we need QApplication object to have valid |
|
797 // current Path. Therefore we need to identify it ourselves |
|
798 // here for the test. |
|
799 QFileInfo filePath; |
|
800 wchar_t module_name[MAX_PATH]; |
|
801 GetModuleFileName(0, module_name, MAX_PATH); |
|
802 filePath = QString::fromWCharArray(module_name); |
|
803 QString testDir = filePath.path() + "/test"; |
|
804 #endif |
|
805 QApplication::setLibraryPaths(QStringList() << testDir); |
|
806 QCOMPARE(QApplication::libraryPaths(), (QStringList() << testDir)); |
|
807 |
|
808 // creating QApplication adds the applicationDirPath to the libraryPath |
|
809 int argc = 1; |
|
810 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
811 QString appDirPath = QDir(app.applicationDirPath()).canonicalPath(); |
|
812 |
|
813 QStringList actual = QApplication::libraryPaths(); |
|
814 actual.sort(); |
|
815 QStringList expected = QSet<QString>::fromList((QStringList() << testDir << appDirPath)).toList(); |
|
816 expected.sort(); |
|
817 |
|
818 QVERIFY2(isPathListIncluded(actual, expected), |
|
819 qPrintable("actual:\n - " + actual.join("\n - ") + |
|
820 "\nexpected:\n - " + expected.join("\n - "))); |
|
821 } |
|
822 { |
|
823 // creating QApplication adds the applicationDirPath and plugin install path to the libraryPath |
|
824 int argc = 1; |
|
825 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
826 QString appDirPath = app.applicationDirPath(); |
|
827 QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); |
|
828 |
|
829 QStringList actual = QApplication::libraryPaths(); |
|
830 actual.sort(); |
|
831 |
|
832 #if defined(Q_OS_SYMBIAN) |
|
833 QStringList expected; |
|
834 addExpectedSymbianPluginsPath(expected); |
|
835 expected << appDirPath; |
|
836 #else |
|
837 QStringList expected = QSet<QString>::fromList((QStringList() << installPathPlugins << appDirPath)).toList(); |
|
838 #endif |
|
839 expected.sort(); |
|
840 |
|
841 QVERIFY2(isPathListIncluded(actual, expected), |
|
842 qPrintable("actual:\n - " + actual.join("\n - ") + |
|
843 "\nexpected:\n - " + expected.join("\n - "))); |
|
844 |
|
845 // setting the library paths overrides everything |
|
846 QString testDir = QDir::currentPath() + "/test"; |
|
847 QApplication::setLibraryPaths(QStringList() << testDir); |
|
848 QVERIFY2(isPathListIncluded(QApplication::libraryPaths(), (QStringList() << testDir)), |
|
849 qPrintable("actual:\n - " + QApplication::libraryPaths().join("\n - ") + |
|
850 "\nexpected:\n - " + testDir)); |
|
851 } |
|
852 { |
|
853 #ifdef QT_TST_QAPP_DEBUG |
|
854 qDebug() << "Initial library path:" << QApplication::libraryPaths(); |
|
855 #endif |
|
856 |
|
857 int count = QApplication::libraryPaths().count(); |
|
858 #if 0 |
|
859 // this test doesn't work if KDE 4 is installed |
|
860 QCOMPARE(count, 1); // before creating QApplication, only the PluginsPath is in the libraryPaths() |
|
861 #endif |
|
862 QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); |
|
863 QApplication::addLibraryPath(installPathPlugins); |
|
864 #ifdef QT_TST_QAPP_DEBUG |
|
865 qDebug() << "installPathPlugins" << installPathPlugins; |
|
866 qDebug() << "After adding plugins path:" << QApplication::libraryPaths(); |
|
867 #endif |
|
868 QCOMPARE(QApplication::libraryPaths().count(), count); |
|
869 |
|
870 QApplication::addLibraryPath(QDir::currentPath() + "/test"); |
|
871 QCOMPARE(QApplication::libraryPaths().count(), count + 1); |
|
872 |
|
873 // creating QApplication adds the applicationDirPath to the libraryPath |
|
874 int argc = 1; |
|
875 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
876 QString appDirPath = app.applicationDirPath(); |
|
877 qDebug() << QApplication::libraryPaths(); |
|
878 // On Windows CE these are identical and might also be the case for other |
|
879 // systems too |
|
880 if (appDirPath != installPathPlugins) |
|
881 QCOMPARE(QApplication::libraryPaths().count(), count + 2); |
|
882 } |
|
883 { |
|
884 int argc = 1; |
|
885 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
886 |
|
887 #ifdef QT_TST_QAPP_DEBUG |
|
888 qDebug() << "Initial library path:" << app.libraryPaths(); |
|
889 #endif |
|
890 int count = app.libraryPaths().count(); |
|
891 QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); |
|
892 app.addLibraryPath(installPathPlugins); |
|
893 #ifdef QT_TST_QAPP_DEBUG |
|
894 qDebug() << "installPathPlugins" << installPathPlugins; |
|
895 qDebug() << "After adding plugins path:" << app.libraryPaths(); |
|
896 #endif |
|
897 QCOMPARE(app.libraryPaths().count(), count); |
|
898 |
|
899 QString appDirPath = app.applicationDirPath(); |
|
900 |
|
901 app.addLibraryPath(appDirPath); |
|
902 #ifdef Q_OS_WINCE |
|
903 app.addLibraryPath(appDirPath + "/../.."); |
|
904 #else |
|
905 app.addLibraryPath(appDirPath + "/.."); |
|
906 #endif |
|
907 #ifdef QT_TST_QAPP_DEBUG |
|
908 qDebug() << "appDirPath" << appDirPath; |
|
909 qDebug() << "After adding appDirPath && appDirPath + /..:" << app.libraryPaths(); |
|
910 #endif |
|
911 QCOMPARE(app.libraryPaths().count(), count + 1); |
|
912 #ifdef Q_OS_MAC |
|
913 app.addLibraryPath(appDirPath + "/../MacOS"); |
|
914 #else |
|
915 app.addLibraryPath(appDirPath + "/tmp/.."); |
|
916 #endif |
|
917 #ifdef QT_TST_QAPP_DEBUG |
|
918 qDebug() << "After adding appDirPath + /tmp/..:" << app.libraryPaths(); |
|
919 #endif |
|
920 QCOMPARE(app.libraryPaths().count(), count + 1); |
|
921 } |
|
922 } |
|
923 |
|
924 void tst_QApplication::libraryPaths_qt_plugin_path() |
|
925 { |
|
926 int argc = 1; |
|
927 |
|
928 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
929 QString appDirPath = app.applicationDirPath(); |
|
930 |
|
931 // Our hook into libraryPaths() initialization: Set the QT_PLUGIN_PATH environment variable |
|
932 QString installPathPluginsDeCanon = appDirPath + QString::fromLatin1("/tmp/.."); |
|
933 QByteArray ascii = installPathPluginsDeCanon.toAscii(); |
|
934 qputenv("QT_PLUGIN_PATH", ascii); |
|
935 |
|
936 QVERIFY(!app.libraryPaths().contains(appDirPath + QString::fromLatin1("/tmp/.."))); |
|
937 } |
|
938 |
|
939 void tst_QApplication::libraryPaths_qt_plugin_path_2() |
|
940 { |
|
941 #ifdef Q_OS_SYMBIAN |
|
942 QByteArray validPath = "C:\\data"; |
|
943 QByteArray nonExistentPath = "Z:\\nonexistent"; |
|
944 QByteArray pluginPath = validPath + ";" + nonExistentPath; |
|
945 #elif defined(Q_OS_UNIX) |
|
946 QByteArray validPath = QDir("/tmp").canonicalPath().toLatin1(); |
|
947 QByteArray nonExistentPath = "/nonexistent"; |
|
948 QByteArray pluginPath = validPath + ":" + nonExistentPath; |
|
949 #elif defined(Q_OS_WIN) |
|
950 # ifdef Q_OS_WINCE |
|
951 QByteArray validPath = "/Temp"; |
|
952 QByteArray nonExistentPath = "/nonexistent"; |
|
953 QByteArray pluginPath = validPath + ";" + nonExistentPath; |
|
954 # else |
|
955 QByteArray validPath = "C:\\windows"; |
|
956 QByteArray nonExistentPath = "Z:\\nonexistent"; |
|
957 QByteArray pluginPath = validPath + ";" + nonExistentPath; |
|
958 # endif |
|
959 #endif |
|
960 |
|
961 { |
|
962 // Our hook into libraryPaths() initialization: Set the QT_PLUGIN_PATH environment variable |
|
963 qputenv("QT_PLUGIN_PATH", pluginPath); |
|
964 |
|
965 int argc = 1; |
|
966 |
|
967 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
968 |
|
969 // library path list should contain the default plus the one valid path |
|
970 #if defined(Q_OS_SYMBIAN) |
|
971 // In Symbian, the PluginsPath doesn't specify the only absolute path; just the dir that can be found on any drive |
|
972 QStringList expected; |
|
973 addExpectedSymbianPluginsPath(expected); |
|
974 expected << QDir(app.applicationDirPath()).canonicalPath() |
|
975 << QDir(QDir::fromNativeSeparators(QString::fromLatin1(validPath))).canonicalPath(); |
|
976 #else |
|
977 QStringList expected = |
|
978 QStringList() |
|
979 << QLibraryInfo::location(QLibraryInfo::PluginsPath) |
|
980 << QDir(app.applicationDirPath()).canonicalPath() |
|
981 << QDir(QDir::fromNativeSeparators(QString::fromLatin1(validPath))).canonicalPath(); |
|
982 # ifdef Q_OS_WINCE |
|
983 expected = QSet<QString>::fromList(expected).toList(); |
|
984 # endif |
|
985 #endif |
|
986 QVERIFY2(isPathListIncluded(app.libraryPaths(), expected), |
|
987 qPrintable("actual:\n - " + app.libraryPaths().join("\n - ") + |
|
988 "\nexpected:\n - " + expected.join("\n - "))); |
|
989 } |
|
990 |
|
991 { |
|
992 int argc = 1; |
|
993 |
|
994 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
995 |
|
996 // library paths are initialized by the QApplication, setting |
|
997 // the environment variable here doesn't work |
|
998 qputenv("QT_PLUGIN_PATH", pluginPath); |
|
999 |
|
1000 // library path list should contain the default |
|
1001 #if defined(Q_OS_SYMBIAN) |
|
1002 QStringList expected; |
|
1003 addExpectedSymbianPluginsPath(expected); |
|
1004 expected << app.applicationDirPath(); |
|
1005 #else |
|
1006 QStringList expected = |
|
1007 QStringList() |
|
1008 << QLibraryInfo::location(QLibraryInfo::PluginsPath) |
|
1009 << app.applicationDirPath(); |
|
1010 # ifdef Q_OS_WINCE |
|
1011 expected = QSet<QString>::fromList(expected).toList(); |
|
1012 # endif |
|
1013 #endif |
|
1014 QVERIFY(isPathListIncluded(app.libraryPaths(), expected)); |
|
1015 |
|
1016 qputenv("QT_PLUGIN_PATH", QByteArray()); |
|
1017 } |
|
1018 } |
|
1019 |
|
1020 class SendPostedEventsTester : public QObject |
|
1021 { |
|
1022 Q_OBJECT |
|
1023 public: |
|
1024 QList<int> eventSpy; |
|
1025 bool event(QEvent *e); |
|
1026 private slots: |
|
1027 void doTest(); |
|
1028 }; |
|
1029 |
|
1030 bool SendPostedEventsTester::event(QEvent *e) |
|
1031 { |
|
1032 eventSpy.append(e->type()); |
|
1033 return QObject::event(e); |
|
1034 } |
|
1035 |
|
1036 void SendPostedEventsTester::doTest() |
|
1037 { |
|
1038 QPointer<SendPostedEventsTester> p = this; |
|
1039 QApplication::postEvent(this, new QEvent(QEvent::User)); |
|
1040 // DeferredDelete should not be delivered until returning from this function |
|
1041 QApplication::postEvent(this, new QEvent(QEvent::DeferredDelete)); |
|
1042 |
|
1043 QEventLoop eventLoop; |
|
1044 QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); |
|
1045 eventLoop.exec(); |
|
1046 QVERIFY(p != 0); |
|
1047 |
|
1048 QCOMPARE(eventSpy.count(), 2); |
|
1049 QCOMPARE(eventSpy.at(0), int(QEvent::MetaCall)); |
|
1050 QCOMPARE(eventSpy.at(1), int(QEvent::User)); |
|
1051 eventSpy.clear(); |
|
1052 } |
|
1053 |
|
1054 void tst_QApplication::sendPostedEvents() |
|
1055 { |
|
1056 int argc = 0; |
|
1057 QApplication app(argc, 0, QApplication::GuiServer); |
|
1058 SendPostedEventsTester *tester = new SendPostedEventsTester; |
|
1059 QMetaObject::invokeMethod(tester, "doTest", Qt::QueuedConnection); |
|
1060 QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection); |
|
1061 QPointer<SendPostedEventsTester> p = tester; |
|
1062 (void) app.exec(); |
|
1063 QVERIFY(p == 0); |
|
1064 } |
|
1065 |
|
1066 void tst_QApplication::thread() |
|
1067 { |
|
1068 QThread *currentThread = QThread::currentThread(); |
|
1069 // no app, but still have a valid thread |
|
1070 QVERIFY(currentThread != 0); |
|
1071 |
|
1072 // the thread should be running and not finished |
|
1073 QVERIFY(currentThread->isRunning()); |
|
1074 QVERIFY(!currentThread->isFinished()); |
|
1075 |
|
1076 // this should probably be in the tst_QObject::thread() test, but |
|
1077 // we put it here since we want to make sure that objects created |
|
1078 // *before* the QApplication has a thread |
|
1079 QObject object; |
|
1080 QObject child(&object); |
|
1081 QVERIFY(object.thread() == currentThread); |
|
1082 QVERIFY(child.thread() == currentThread); |
|
1083 |
|
1084 { |
|
1085 int argc = 0; |
|
1086 QApplication app(argc, 0, QApplication::GuiServer); |
|
1087 |
|
1088 // current thread still valid |
|
1089 QVERIFY(QThread::currentThread() != 0); |
|
1090 // thread should be the same as before |
|
1091 QCOMPARE(QThread::currentThread(), currentThread); |
|
1092 |
|
1093 // app's thread should be the current thread |
|
1094 QCOMPARE(app.thread(), currentThread); |
|
1095 |
|
1096 // the thread should still be running and not finished |
|
1097 QVERIFY(currentThread->isRunning()); |
|
1098 QVERIFY(!currentThread->isFinished()); |
|
1099 |
|
1100 QTestEventLoop::instance().enterLoop(1); |
|
1101 } |
|
1102 |
|
1103 // app dead, current thread still valid |
|
1104 QVERIFY(QThread::currentThread() != 0); |
|
1105 QCOMPARE(QThread::currentThread(), currentThread); |
|
1106 |
|
1107 // the thread should still be running and not finished |
|
1108 QVERIFY(currentThread->isRunning()); |
|
1109 QVERIFY(!currentThread->isFinished()); |
|
1110 |
|
1111 // should still have a thread |
|
1112 QVERIFY(object.thread() == currentThread); |
|
1113 QVERIFY(child.thread() == currentThread); |
|
1114 |
|
1115 // do the test again, making sure that the thread is the same as |
|
1116 // before |
|
1117 { |
|
1118 int argc = 0; |
|
1119 QApplication app(argc, 0, QApplication::GuiServer); |
|
1120 |
|
1121 // current thread still valid |
|
1122 QVERIFY(QThread::currentThread() != 0); |
|
1123 // thread should be the same as before |
|
1124 QCOMPARE(QThread::currentThread(), currentThread); |
|
1125 |
|
1126 // app's thread should be the current thread |
|
1127 QCOMPARE(app.thread(), currentThread); |
|
1128 |
|
1129 // the thread should be running and not finished |
|
1130 QVERIFY(currentThread->isRunning()); |
|
1131 QVERIFY(!currentThread->isFinished()); |
|
1132 |
|
1133 // should still have a thread |
|
1134 QVERIFY(object.thread() == currentThread); |
|
1135 QVERIFY(child.thread() == currentThread); |
|
1136 |
|
1137 QTestEventLoop::instance().enterLoop(1); |
|
1138 } |
|
1139 |
|
1140 // app dead, current thread still valid |
|
1141 QVERIFY(QThread::currentThread() != 0); |
|
1142 QCOMPARE(QThread::currentThread(), currentThread); |
|
1143 |
|
1144 // the thread should still be running and not finished |
|
1145 QVERIFY(currentThread->isRunning()); |
|
1146 QVERIFY(!currentThread->isFinished()); |
|
1147 |
|
1148 // should still have a thread |
|
1149 QVERIFY(object.thread() == currentThread); |
|
1150 QVERIFY(child.thread() == currentThread); |
|
1151 } |
|
1152 |
|
1153 class DeleteLaterWidget : public QWidget |
|
1154 { |
|
1155 Q_OBJECT |
|
1156 public: |
|
1157 DeleteLaterWidget(QApplication *_app, QWidget *parent = 0) |
|
1158 : QWidget(parent) { app = _app; child_deleted = false; } |
|
1159 |
|
1160 bool child_deleted; |
|
1161 QApplication *app; |
|
1162 |
|
1163 public slots: |
|
1164 void runTest(); |
|
1165 void checkDeleteLater(); |
|
1166 void childDeleted() { child_deleted = true; } |
|
1167 }; |
|
1168 |
|
1169 |
|
1170 void DeleteLaterWidget::runTest() |
|
1171 { |
|
1172 QObject *stillAlive = qFindChild<QObject*>(this, "deleteLater"); |
|
1173 |
|
1174 QWidget *w = new QWidget(this); |
|
1175 connect(w, SIGNAL(destroyed()), this, SLOT(childDeleted())); |
|
1176 |
|
1177 w->deleteLater(); |
|
1178 QVERIFY(!child_deleted); |
|
1179 |
|
1180 QDialog dlg; |
|
1181 QTimer::singleShot(500, &dlg, SLOT(reject())); |
|
1182 dlg.exec(); |
|
1183 |
|
1184 QVERIFY(!child_deleted); |
|
1185 app->processEvents(); |
|
1186 QVERIFY(!child_deleted); |
|
1187 |
|
1188 QTimer::singleShot(500, this, SLOT(checkDeleteLater())); |
|
1189 |
|
1190 app->processEvents(); |
|
1191 |
|
1192 QVERIFY(!stillAlive); // verify at the end to make test terminate |
|
1193 } |
|
1194 |
|
1195 void DeleteLaterWidget::checkDeleteLater() |
|
1196 { |
|
1197 QVERIFY(child_deleted); |
|
1198 |
|
1199 close(); |
|
1200 } |
|
1201 |
|
1202 void tst_QApplication::testDeleteLater() |
|
1203 { |
|
1204 int argc = 0; |
|
1205 QApplication app(argc, 0, QApplication::GuiServer); |
|
1206 connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); |
|
1207 |
|
1208 DeleteLaterWidget *wgt = new DeleteLaterWidget(&app); |
|
1209 QTimer::singleShot(500, wgt, SLOT(runTest())); |
|
1210 |
|
1211 QObject *object = new QObject(wgt); |
|
1212 object->setObjectName("deleteLater"); |
|
1213 object->deleteLater(); |
|
1214 |
|
1215 QObject *stillAlive = qFindChild<QObject*>(wgt, "deleteLater"); |
|
1216 QVERIFY(stillAlive); |
|
1217 |
|
1218 app.exec(); |
|
1219 |
|
1220 delete wgt; |
|
1221 |
|
1222 } |
|
1223 |
|
1224 class EventLoopNester : public QObject |
|
1225 { |
|
1226 Q_OBJECT |
|
1227 public slots: |
|
1228 void deleteLaterAndEnterLoop() |
|
1229 { |
|
1230 QEventLoop eventLoop; |
|
1231 QPointer<QObject> p(this); |
|
1232 deleteLater(); |
|
1233 /* |
|
1234 DeferredDelete events are compressed, meaning this second |
|
1235 deleteLater() will *not* delete the object in the nested |
|
1236 event loop |
|
1237 */ |
|
1238 QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); |
|
1239 QTimer::singleShot(1000, &eventLoop, SLOT(quit())); |
|
1240 eventLoop.exec(); |
|
1241 QVERIFY(p); |
|
1242 } |
|
1243 void deleteLaterAndExitLoop() |
|
1244 { |
|
1245 // Check that 'p' is not deleted before exec returns, since the call |
|
1246 // to QEventLoop::quit() should stop 'eventLoop' from processing |
|
1247 // any more events (that is, delete later) until we return to the |
|
1248 // _current_ event loop: |
|
1249 QEventLoop eventLoop; |
|
1250 QPointer<QObject> p(this); |
|
1251 QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); |
|
1252 QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); |
|
1253 eventLoop.exec(); |
|
1254 QVERIFY(p); // not dead yet |
|
1255 } |
|
1256 |
|
1257 void processEventsOnly() |
|
1258 { |
|
1259 QApplication::processEvents(); |
|
1260 } |
|
1261 void processEventsWithDeferredDeletion() |
|
1262 { |
|
1263 QApplication::processEvents(QEventLoop::DeferredDeletion); |
|
1264 } |
|
1265 void sendPostedEventsWithDeferredDelete() |
|
1266 { |
|
1267 QApplication::sendPostedEvents(0, QEvent::DeferredDelete); |
|
1268 } |
|
1269 void deleteLaterAndProcessEvents1() |
|
1270 { |
|
1271 QEventLoop eventLoop; |
|
1272 |
|
1273 QPointer<QObject> p = this; |
|
1274 deleteLater(); |
|
1275 |
|
1276 // trying to delete this object in a deeper eventloop just won't work |
|
1277 QMetaObject::invokeMethod(this, |
|
1278 "processEventsOnly", |
|
1279 Qt::QueuedConnection); |
|
1280 QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); |
|
1281 eventLoop.exec(); |
|
1282 QVERIFY(p); |
|
1283 QMetaObject::invokeMethod(this, |
|
1284 "processEventsWithDeferredDeletion", |
|
1285 Qt::QueuedConnection); |
|
1286 QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); |
|
1287 eventLoop.exec(); |
|
1288 QVERIFY(p); |
|
1289 QMetaObject::invokeMethod(this, |
|
1290 "sendPostedEventsWithDeferredDelete", |
|
1291 Qt::QueuedConnection); |
|
1292 QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); |
|
1293 eventLoop.exec(); |
|
1294 QVERIFY(p); |
|
1295 |
|
1296 // trying to delete it from this eventloop still doesn't work |
|
1297 QApplication::processEvents(); |
|
1298 QVERIFY(p); |
|
1299 |
|
1300 // however, it *will* work with this magic incantation |
|
1301 QApplication::processEvents(QEventLoop::DeferredDeletion); |
|
1302 QVERIFY(!p); |
|
1303 } |
|
1304 |
|
1305 void deleteLaterAndProcessEvents2() |
|
1306 { |
|
1307 QEventLoop eventLoop; |
|
1308 |
|
1309 QPointer<QObject> p = this; |
|
1310 deleteLater(); |
|
1311 |
|
1312 // trying to delete this object in a deeper eventloop just won't work |
|
1313 QMetaObject::invokeMethod(this, |
|
1314 "processEventsOnly", |
|
1315 Qt::QueuedConnection); |
|
1316 QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); |
|
1317 eventLoop.exec(); |
|
1318 QVERIFY(p); |
|
1319 QMetaObject::invokeMethod(this, |
|
1320 "processEventsWithDeferredDeletion", |
|
1321 Qt::QueuedConnection); |
|
1322 QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); |
|
1323 eventLoop.exec(); |
|
1324 QVERIFY(p); |
|
1325 QMetaObject::invokeMethod(this, |
|
1326 "sendPostedEventsWithDeferredDelete", |
|
1327 Qt::QueuedConnection); |
|
1328 QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); |
|
1329 eventLoop.exec(); |
|
1330 QVERIFY(p); |
|
1331 |
|
1332 // trying to delete it from this eventloop still doesn't work |
|
1333 QApplication::processEvents(); |
|
1334 QVERIFY(p); |
|
1335 |
|
1336 // however, it *will* work with this magic incantation |
|
1337 QApplication::sendPostedEvents(0, QEvent::DeferredDelete); |
|
1338 QVERIFY(!p); |
|
1339 } |
|
1340 }; |
|
1341 |
|
1342 void tst_QApplication::testDeleteLaterProcessEvents() |
|
1343 { |
|
1344 int argc = 0; |
|
1345 |
|
1346 // Calling processEvents() with no event dispatcher does nothing. |
|
1347 QObject *object = new QObject; |
|
1348 QPointer<QObject> p(object); |
|
1349 object->deleteLater(); |
|
1350 QApplication::processEvents(); |
|
1351 QVERIFY(p); |
|
1352 delete object; |
|
1353 |
|
1354 { |
|
1355 QApplication app(argc, 0, QApplication::GuiServer); |
|
1356 // If you call processEvents() with an event dispatcher present, but |
|
1357 // outside any event loops, deferred deletes are not processed unless |
|
1358 // QEventLoop::DeferredDeletion is passed. |
|
1359 object = new QObject; |
|
1360 p = object; |
|
1361 object->deleteLater(); |
|
1362 app.processEvents(); |
|
1363 QVERIFY(p); |
|
1364 app.processEvents(QEventLoop::ProcessEventsFlag(0x10)); // 0x10 == QEventLoop::DeferredDeletion |
|
1365 QVERIFY(!p); |
|
1366 |
|
1367 // sendPostedEvents(0, DeferredDelete); also works |
|
1368 object = new QObject; |
|
1369 p = object; |
|
1370 object->deleteLater(); |
|
1371 app.processEvents(); |
|
1372 QVERIFY(p); |
|
1373 QApplication::sendPostedEvents(0, QEvent::DeferredDelete); |
|
1374 QVERIFY(!p); |
|
1375 |
|
1376 // If you call deleteLater() on an object when there is no parent |
|
1377 // event loop, and then enter an event loop, the object will get |
|
1378 // deleted. |
|
1379 object = new QObject; |
|
1380 p = object; |
|
1381 object->deleteLater(); |
|
1382 QEventLoop loop; |
|
1383 QTimer::singleShot(1000, &loop, SLOT(quit())); |
|
1384 loop.exec(); |
|
1385 QVERIFY(!p); |
|
1386 } |
|
1387 { |
|
1388 // When an object is in an event loop, then calls deleteLater() and enters |
|
1389 // an event loop recursively, it should not die until the parent event |
|
1390 // loop continues. |
|
1391 QApplication app(argc, 0, QApplication::GuiServer); |
|
1392 QEventLoop loop; |
|
1393 EventLoopNester *nester = new EventLoopNester; |
|
1394 p = nester; |
|
1395 QTimer::singleShot(3000, &loop, SLOT(quit())); |
|
1396 QTimer::singleShot(0, nester, SLOT(deleteLaterAndEnterLoop())); |
|
1397 |
|
1398 loop.exec(); |
|
1399 QVERIFY(!p); |
|
1400 } |
|
1401 |
|
1402 { |
|
1403 // When the event loop that calls deleteLater() is exited |
|
1404 // immediately, the object should die when returning to the |
|
1405 // parent event loop |
|
1406 QApplication app(argc, 0, QApplication::GuiServer); |
|
1407 QEventLoop loop; |
|
1408 EventLoopNester *nester = new EventLoopNester; |
|
1409 p = nester; |
|
1410 QTimer::singleShot(3000, &loop, SLOT(quit())); |
|
1411 QTimer::singleShot(0, nester, SLOT(deleteLaterAndExitLoop())); |
|
1412 |
|
1413 loop.exec(); |
|
1414 QVERIFY(!p); |
|
1415 } |
|
1416 |
|
1417 { |
|
1418 // when the event loop that calls deleteLater() also calls |
|
1419 // processEvents() immediately afterwards, the object should |
|
1420 // not die until the parent loop continues |
|
1421 QApplication app(argc, 0, QApplication::GuiServer); |
|
1422 QEventLoop loop; |
|
1423 EventLoopNester *nester = new EventLoopNester(); |
|
1424 p = nester; |
|
1425 QTimer::singleShot(3000, &loop, SLOT(quit())); |
|
1426 QTimer::singleShot(0, nester, SLOT(deleteLaterAndProcessEvents1())); |
|
1427 |
|
1428 loop.exec(); |
|
1429 QVERIFY(!p); |
|
1430 } |
|
1431 |
|
1432 { |
|
1433 // when the event loop that calls deleteLater() also calls |
|
1434 // processEvents() immediately afterwards, the object should |
|
1435 // not die until the parent loop continues |
|
1436 QApplication app(argc, 0, QApplication::GuiServer); |
|
1437 QEventLoop loop; |
|
1438 EventLoopNester *nester = new EventLoopNester(); |
|
1439 p = nester; |
|
1440 QTimer::singleShot(3000, &loop, SLOT(quit())); |
|
1441 QTimer::singleShot(0, nester, SLOT(deleteLaterAndProcessEvents2())); |
|
1442 |
|
1443 loop.exec(); |
|
1444 QVERIFY(!p); |
|
1445 } |
|
1446 } |
|
1447 |
|
1448 /* |
|
1449 Test for crash whith QApplication::setDesktopSettingsAware(false). |
|
1450 */ |
|
1451 void tst_QApplication::desktopSettingsAware() |
|
1452 { |
|
1453 #ifndef QT_NO_PROCESS |
|
1454 QProcess testProcess; |
|
1455 #ifdef Q_OS_WINCE |
|
1456 int argc = 0; |
|
1457 QApplication tmpApp(argc, 0, QApplication::GuiServer); |
|
1458 testProcess.start("desktopsettingsaware/desktopsettingsaware"); |
|
1459 #else |
|
1460 #if defined(Q_OS_WIN) && defined(QT_DEBUG) |
|
1461 testProcess.start("desktopsettingsaware/debug/desktopsettingsaware"); |
|
1462 #elif defined(Q_OS_WIN) |
|
1463 testProcess.start("desktopsettingsaware/release/desktopsettingsaware"); |
|
1464 #elif defined(Q_OS_SYMBIAN) |
|
1465 testProcess.start("desktopsettingsaware"); |
|
1466 #if defined(Q_CC_NOKIAX86) |
|
1467 QEXPECT_FAIL("", "QProcess on Q_CC_NOKIAX86 cannot launch another Qt application, due to DLL conflicts.", Abort); |
|
1468 // TODO: Remove XFAIL, as soon as we can launch Qt applications from within Qt applications on Symbian |
|
1469 QVERIFY(testProcess.error() != QProcess::FailedToStart); |
|
1470 #endif // defined(Q_CC_NOKIAX86) |
|
1471 #else |
|
1472 testProcess.start("desktopsettingsaware/desktopsettingsaware"); |
|
1473 #endif |
|
1474 #endif |
|
1475 QVERIFY(testProcess.waitForFinished(10000)); |
|
1476 QCOMPARE(int(testProcess.state()), int(QProcess::NotRunning)); |
|
1477 QVERIFY(int(testProcess.error()) != int(QProcess::Crashed)); |
|
1478 #endif |
|
1479 } |
|
1480 |
|
1481 void tst_QApplication::setActiveWindow() |
|
1482 { |
|
1483 int argc = 0; |
|
1484 QApplication MyApp(argc, 0, QApplication::GuiServer); |
|
1485 |
|
1486 QWidget* w = new QWidget; |
|
1487 QVBoxLayout* layout = new QVBoxLayout(w); |
|
1488 |
|
1489 QLineEdit* pb1 = new QLineEdit("Testbutton1", w); |
|
1490 QLineEdit* pb2 = new QLineEdit("Test Line Edit", w); |
|
1491 |
|
1492 layout->addWidget(pb1); |
|
1493 layout->addWidget(pb2); |
|
1494 |
|
1495 pb2->setFocus(); |
|
1496 pb2->setParent(0); |
|
1497 delete pb2; |
|
1498 |
|
1499 w->show(); |
|
1500 QApplication::setActiveWindow(w); // needs this on twm (focus follows mouse) |
|
1501 QVERIFY(pb1->hasFocus()); |
|
1502 delete w; |
|
1503 } |
|
1504 |
|
1505 |
|
1506 /* This might fail on some X11 window managers? */ |
|
1507 void tst_QApplication::focusChanged() |
|
1508 { |
|
1509 int argc = 0; |
|
1510 QApplication app(argc, 0, QApplication::GuiServer); |
|
1511 |
|
1512 QSignalSpy spy(&app, SIGNAL(focusChanged(QWidget *, QWidget *))); |
|
1513 QWidget *now = 0; |
|
1514 QWidget *old = 0; |
|
1515 |
|
1516 QWidget parent1; |
|
1517 QHBoxLayout hbox1(&parent1); |
|
1518 QLabel lb1(&parent1); |
|
1519 QLineEdit le1(&parent1); |
|
1520 QPushButton pb1(&parent1); |
|
1521 hbox1.addWidget(&lb1); |
|
1522 hbox1.addWidget(&le1); |
|
1523 hbox1.addWidget(&pb1); |
|
1524 |
|
1525 QCOMPARE(spy.count(), 0); |
|
1526 |
|
1527 parent1.show(); |
|
1528 QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse) |
|
1529 QCOMPARE(spy.count(), 1); |
|
1530 QCOMPARE(spy.at(0).count(), 2); |
|
1531 old = qVariantValue<QWidget*>(spy.at(0).at(0)); |
|
1532 now = qVariantValue<QWidget*>(spy.at(0).at(1)); |
|
1533 QVERIFY(now == &le1); |
|
1534 QVERIFY(now == QApplication::focusWidget()); |
|
1535 QVERIFY(old == 0); |
|
1536 spy.clear(); |
|
1537 QCOMPARE(spy.count(), 0); |
|
1538 |
|
1539 pb1.setFocus(); |
|
1540 QCOMPARE(spy.count(), 1); |
|
1541 old = qVariantValue<QWidget*>(spy.at(0).at(0)); |
|
1542 now = qVariantValue<QWidget*>(spy.at(0).at(1)); |
|
1543 QVERIFY(now == &pb1); |
|
1544 QVERIFY(now == QApplication::focusWidget()); |
|
1545 QVERIFY(old == &le1); |
|
1546 spy.clear(); |
|
1547 |
|
1548 lb1.setFocus(); |
|
1549 QCOMPARE(spy.count(), 1); |
|
1550 old = qVariantValue<QWidget*>(spy.at(0).at(0)); |
|
1551 now = qVariantValue<QWidget*>(spy.at(0).at(1)); |
|
1552 QVERIFY(now == &lb1); |
|
1553 QVERIFY(now == QApplication::focusWidget()); |
|
1554 QVERIFY(old == &pb1); |
|
1555 spy.clear(); |
|
1556 |
|
1557 lb1.clearFocus(); |
|
1558 QCOMPARE(spy.count(), 1); |
|
1559 old = qVariantValue<QWidget*>(spy.at(0).at(0)); |
|
1560 now = qVariantValue<QWidget*>(spy.at(0).at(1)); |
|
1561 QVERIFY(now == 0); |
|
1562 QVERIFY(now == QApplication::focusWidget()); |
|
1563 QVERIFY(old == &lb1); |
|
1564 spy.clear(); |
|
1565 |
|
1566 QWidget parent2; |
|
1567 QHBoxLayout hbox2(&parent2); |
|
1568 QLabel lb2(&parent2); |
|
1569 QLineEdit le2(&parent2); |
|
1570 QPushButton pb2(&parent2); |
|
1571 hbox2.addWidget(&lb2); |
|
1572 hbox2.addWidget(&le2); |
|
1573 hbox2.addWidget(&pb2); |
|
1574 |
|
1575 parent2.show(); |
|
1576 QApplication::setActiveWindow(&parent2); // needs this on twm (focus follows mouse) |
|
1577 QVERIFY(spy.count() > 0); // one for deactivation, one for activation on Windows |
|
1578 old = qVariantValue<QWidget*>(spy.at(spy.count()-1).at(0)); |
|
1579 now = qVariantValue<QWidget*>(spy.at(spy.count()-1).at(1)); |
|
1580 QVERIFY(now == &le2); |
|
1581 QVERIFY(now == QApplication::focusWidget()); |
|
1582 QVERIFY(old == 0); |
|
1583 spy.clear(); |
|
1584 |
|
1585 QTestKeyEvent tab(QTest::Press, Qt::Key_Tab, 0, 0); |
|
1586 QTestKeyEvent backtab(QTest::Press, Qt::Key_Backtab, 0, 0); |
|
1587 QTestMouseEvent click(QTest::MouseClick, Qt::LeftButton, 0, QPoint(5, 5), 0); |
|
1588 |
|
1589 bool tabAllControls = true; |
|
1590 #ifdef Q_WS_MAC |
|
1591 // Mac has two modes, one where you tab to everything, one where you can |
|
1592 // only tab to input controls, here's what we get. Determine which ones we |
|
1593 // should get. |
|
1594 QSettings appleSettings(QLatin1String("apple.com")); |
|
1595 QVariant appleValue = appleSettings.value(QLatin1String("AppleKeyboardUIMode"), 0); |
|
1596 tabAllControls = (appleValue.toInt() & 0x2); |
|
1597 #endif |
|
1598 |
|
1599 tab.simulate(now); |
|
1600 if (!tabAllControls) { |
|
1601 QVERIFY(spy.count() == 0); |
|
1602 QVERIFY(now == QApplication::focusWidget()); |
|
1603 } else { |
|
1604 QVERIFY(spy.count() > 0); |
|
1605 old = qVariantValue<QWidget*>(spy.at(0).at(0)); |
|
1606 now = qVariantValue<QWidget*>(spy.at(0).at(1)); |
|
1607 QVERIFY(now == &pb2); |
|
1608 QVERIFY(now == QApplication::focusWidget()); |
|
1609 QVERIFY(old == &le2); |
|
1610 spy.clear(); |
|
1611 } |
|
1612 |
|
1613 if (!tabAllControls) { |
|
1614 QVERIFY(spy.count() == 0); |
|
1615 QVERIFY(now == QApplication::focusWidget()); |
|
1616 } else { |
|
1617 tab.simulate(now); |
|
1618 QVERIFY(spy.count() > 0); |
|
1619 old = qVariantValue<QWidget*>(spy.at(0).at(0)); |
|
1620 now = qVariantValue<QWidget*>(spy.at(0).at(1)); |
|
1621 QVERIFY(now == &le2); |
|
1622 QVERIFY(now == QApplication::focusWidget()); |
|
1623 QVERIFY(old == &pb2); |
|
1624 spy.clear(); |
|
1625 } |
|
1626 |
|
1627 if (!tabAllControls) { |
|
1628 QVERIFY(spy.count() == 0); |
|
1629 QVERIFY(now == QApplication::focusWidget()); |
|
1630 } else { |
|
1631 backtab.simulate(now); |
|
1632 QVERIFY(spy.count() > 0); |
|
1633 old = qVariantValue<QWidget*>(spy.at(0).at(0)); |
|
1634 now = qVariantValue<QWidget*>(spy.at(0).at(1)); |
|
1635 QVERIFY(now == &pb2); |
|
1636 QVERIFY(now == QApplication::focusWidget()); |
|
1637 QVERIFY(old == &le2); |
|
1638 spy.clear(); |
|
1639 } |
|
1640 |
|
1641 |
|
1642 if (!tabAllControls) { |
|
1643 QVERIFY(spy.count() == 0); |
|
1644 QVERIFY(now == QApplication::focusWidget()); |
|
1645 old = &pb2; |
|
1646 } else { |
|
1647 backtab.simulate(now); |
|
1648 QVERIFY(spy.count() > 0); |
|
1649 old = qVariantValue<QWidget*>(spy.at(0).at(0)); |
|
1650 now = qVariantValue<QWidget*>(spy.at(0).at(1)); |
|
1651 QVERIFY(now == &le2); |
|
1652 QVERIFY(now == QApplication::focusWidget()); |
|
1653 QVERIFY(old == &pb2); |
|
1654 spy.clear(); |
|
1655 } |
|
1656 |
|
1657 click.simulate(old); |
|
1658 if (!(pb2.focusPolicy() & Qt::ClickFocus)) { |
|
1659 QVERIFY(spy.count() == 0); |
|
1660 QVERIFY(now == QApplication::focusWidget()); |
|
1661 } else { |
|
1662 QVERIFY(spy.count() > 0); |
|
1663 old = qVariantValue<QWidget*>(spy.at(0).at(0)); |
|
1664 now = qVariantValue<QWidget*>(spy.at(0).at(1)); |
|
1665 QVERIFY(now == &pb2); |
|
1666 QVERIFY(now == QApplication::focusWidget()); |
|
1667 QVERIFY(old == &le2); |
|
1668 spy.clear(); |
|
1669 |
|
1670 click.simulate(old); |
|
1671 QVERIFY(spy.count() > 0); |
|
1672 old = qVariantValue<QWidget*>(spy.at(0).at(0)); |
|
1673 now = qVariantValue<QWidget*>(spy.at(0).at(1)); |
|
1674 QVERIFY(now == &le2); |
|
1675 QVERIFY(now == QApplication::focusWidget()); |
|
1676 QVERIFY(old == &pb2); |
|
1677 spy.clear(); |
|
1678 } |
|
1679 |
|
1680 parent1.activateWindow(); |
|
1681 QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse) |
|
1682 QVERIFY(spy.count() == 1 || spy.count() == 2); // one for deactivation, one for activation on Windows |
|
1683 |
|
1684 //on windows, the change of focus is made in 2 steps |
|
1685 //(the focusChanged SIGNAL is emitted twice) |
|
1686 if (spy.count()==1) |
|
1687 old = qVariantValue<QWidget*>(spy.at(spy.count()-1).at(0)); |
|
1688 else |
|
1689 old = qVariantValue<QWidget*>(spy.at(spy.count()-2).at(0)); |
|
1690 now = qVariantValue<QWidget*>(spy.at(spy.count()-1).at(1)); |
|
1691 QVERIFY(now == &le1); |
|
1692 QVERIFY(now == QApplication::focusWidget()); |
|
1693 QVERIFY(old == &le2); |
|
1694 spy.clear(); |
|
1695 } |
|
1696 |
|
1697 class LineEdit : public QLineEdit |
|
1698 { |
|
1699 public: |
|
1700 LineEdit(QWidget *parent = 0) : QLineEdit(parent) { } |
|
1701 |
|
1702 protected: |
|
1703 void focusOutEvent(QFocusEvent *e) { |
|
1704 QLineEdit::focusOutEvent(e); |
|
1705 if (objectName() == "le1") |
|
1706 setStyleSheet(""); |
|
1707 } |
|
1708 |
|
1709 void focusInEvent(QFocusEvent *e) { |
|
1710 QLineEdit::focusInEvent(e); |
|
1711 if (objectName() == "le2") |
|
1712 setStyleSheet(""); |
|
1713 } |
|
1714 }; |
|
1715 |
|
1716 void tst_QApplication::focusOut() |
|
1717 { |
|
1718 int argc = 1; |
|
1719 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
1720 |
|
1721 // Tests the case where the style pointer changes when on focus in/out |
|
1722 // (the above is the case when the stylesheet changes) |
|
1723 QWidget w; |
|
1724 QLineEdit *le1 = new LineEdit(&w); |
|
1725 le1->setObjectName("le1"); |
|
1726 le1->setStyleSheet("background: #fee"); |
|
1727 le1->setFocus(); |
|
1728 |
|
1729 QLineEdit *le2 = new LineEdit(&w); |
|
1730 le2->setObjectName("le2"); |
|
1731 le2->setStyleSheet("background: #fee"); |
|
1732 le2->move(100, 100); |
|
1733 w.show(); |
|
1734 |
|
1735 QTest::qWait(2000); |
|
1736 le2->setFocus(); |
|
1737 QTest::qWait(2000); |
|
1738 } |
|
1739 |
|
1740 void tst_QApplication::execAfterExit() |
|
1741 { |
|
1742 int argc = 1; |
|
1743 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
1744 QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection); |
|
1745 // this should be ignored, as exec() will reset the exitCode |
|
1746 QApplication::exit(1); |
|
1747 int exitCode = app.exec(); |
|
1748 QCOMPARE(exitCode, 0); |
|
1749 |
|
1750 // the quitNow flag should have been reset, so we can spin an |
|
1751 // eventloop after QApplication::exec() returns |
|
1752 QEventLoop eventLoop; |
|
1753 QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); |
|
1754 exitCode = eventLoop.exec(); |
|
1755 QCOMPARE(exitCode, 0); |
|
1756 } |
|
1757 |
|
1758 void tst_QApplication::wheelScrollLines() |
|
1759 { |
|
1760 int argc = 1; |
|
1761 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
1762 // If wheelScrollLines returns 0, the mose wheel will be disabled. |
|
1763 QVERIFY(app.wheelScrollLines() > 0); |
|
1764 } |
|
1765 |
|
1766 void tst_QApplication::style() |
|
1767 { |
|
1768 int argc = 1; |
|
1769 |
|
1770 { |
|
1771 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
1772 QPointer<QStyle> style = app.style(); |
|
1773 app.setStyle(new QWindowsStyle); |
|
1774 QVERIFY(style.isNull()); |
|
1775 } |
|
1776 |
|
1777 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
1778 |
|
1779 // qApp style can never be 0 |
|
1780 QVERIFY(QApplication::style() != 0); |
|
1781 } |
|
1782 |
|
1783 void tst_QApplication::allWidgets() |
|
1784 { |
|
1785 int argc = 1; |
|
1786 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
1787 QWidget *w = new QWidget; |
|
1788 QVERIFY(app.allWidgets().contains(w)); // uncreate widget test |
|
1789 QVERIFY(app.allWidgets().contains(w)); // created widget test |
|
1790 delete w; |
|
1791 w = 0; |
|
1792 QVERIFY(!app.allWidgets().contains(w)); // removal test |
|
1793 } |
|
1794 |
|
1795 |
|
1796 void tst_QApplication::setAttribute() |
|
1797 { |
|
1798 int argc = 1; |
|
1799 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
1800 QVERIFY(!QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation)); |
|
1801 QWidget *w = new QWidget; |
|
1802 QVERIFY(!w->testAttribute(Qt::WA_WState_Created)); |
|
1803 delete w; |
|
1804 |
|
1805 QApplication::setAttribute(Qt::AA_ImmediateWidgetCreation); |
|
1806 QVERIFY(QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation)); |
|
1807 w = new QWidget; |
|
1808 QVERIFY(w->testAttribute(Qt::WA_WState_Created)); |
|
1809 QWidget *w2 = new QWidget(w); |
|
1810 w2->setParent(0); |
|
1811 QVERIFY(w2->testAttribute(Qt::WA_WState_Created)); |
|
1812 delete w; |
|
1813 delete w2; |
|
1814 |
|
1815 QApplication::setAttribute(Qt::AA_ImmediateWidgetCreation, false); |
|
1816 QVERIFY(!QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation)); |
|
1817 w = new QWidget; |
|
1818 QVERIFY(!w->testAttribute(Qt::WA_WState_Created)); |
|
1819 delete w; |
|
1820 } |
|
1821 |
|
1822 void tst_QApplication::windowsCommandLine_data() |
|
1823 { |
|
1824 #if defined(Q_OS_WIN) |
|
1825 QTest::addColumn<QString>("args"); |
|
1826 QTest::addColumn<QString>("expected"); |
|
1827 |
|
1828 QTest::newRow("hello world") |
|
1829 << QString("Hello \"World\"") |
|
1830 << QString("Hello \"World\""); |
|
1831 QTest::newRow("sql") |
|
1832 << QString("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PNR' AND TABLE_TYPE = 'VIEW' ORDER BY TABLE_NAME") |
|
1833 << QString("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PNR' AND TABLE_TYPE = 'VIEW' ORDER BY TABLE_NAME"); |
|
1834 #endif |
|
1835 } |
|
1836 |
|
1837 void tst_QApplication::windowsCommandLine() |
|
1838 { |
|
1839 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) |
|
1840 QFETCH(QString, args); |
|
1841 QFETCH(QString, expected); |
|
1842 |
|
1843 QProcess testProcess; |
|
1844 #if defined(QT_DEBUG) |
|
1845 testProcess.start("wincmdline/debug/wincmdline", QStringList(args)); |
|
1846 #else |
|
1847 testProcess.start("wincmdline/release/wincmdline", QStringList(args)); |
|
1848 #endif |
|
1849 QVERIFY(testProcess.waitForFinished(10000)); |
|
1850 QByteArray error = testProcess.readAllStandardError(); |
|
1851 QString procError(error); |
|
1852 QCOMPARE(procError, expected); |
|
1853 #endif |
|
1854 } |
|
1855 |
|
1856 class TouchEventPropagationTestWidget : public QWidget |
|
1857 { |
|
1858 Q_OBJECT |
|
1859 |
|
1860 public: |
|
1861 bool seenTouchEvent, acceptTouchEvent, seenMouseEvent, acceptMouseEvent; |
|
1862 |
|
1863 TouchEventPropagationTestWidget(QWidget *parent = 0) |
|
1864 : QWidget(parent), seenTouchEvent(false), acceptTouchEvent(false), seenMouseEvent(false), acceptMouseEvent(false) |
|
1865 { } |
|
1866 |
|
1867 void reset() |
|
1868 { |
|
1869 seenTouchEvent = acceptTouchEvent = seenMouseEvent = acceptMouseEvent = false; |
|
1870 } |
|
1871 |
|
1872 bool event(QEvent *event) |
|
1873 { |
|
1874 switch (event->type()) { |
|
1875 case QEvent::MouseButtonPress: |
|
1876 case QEvent::MouseMove: |
|
1877 case QEvent::MouseButtonRelease: |
|
1878 // qDebug() << objectName() << "seenMouseEvent = true"; |
|
1879 seenMouseEvent = true; |
|
1880 event->setAccepted(acceptMouseEvent); |
|
1881 break; |
|
1882 case QEvent::TouchBegin: |
|
1883 case QEvent::TouchUpdate: |
|
1884 case QEvent::TouchEnd: |
|
1885 // qDebug() << objectName() << "seenTouchEvent = true"; |
|
1886 seenTouchEvent = true; |
|
1887 event->setAccepted(acceptTouchEvent); |
|
1888 break; |
|
1889 default: |
|
1890 return QWidget::event(event); |
|
1891 } |
|
1892 return true; |
|
1893 } |
|
1894 }; |
|
1895 |
|
1896 void tst_QApplication::touchEventPropagation() |
|
1897 { |
|
1898 int argc = 1; |
|
1899 QApplication app(argc, &argv0, QApplication::GuiServer); |
|
1900 |
|
1901 QList<QTouchEvent::TouchPoint> pressedTouchPoints; |
|
1902 QTouchEvent::TouchPoint press(0); |
|
1903 press.setState(Qt::TouchPointPressed); |
|
1904 pressedTouchPoints << press; |
|
1905 |
|
1906 QList<QTouchEvent::TouchPoint> releasedTouchPoints; |
|
1907 QTouchEvent::TouchPoint release(0); |
|
1908 release.setState(Qt::TouchPointReleased); |
|
1909 releasedTouchPoints << release; |
|
1910 |
|
1911 { |
|
1912 // touch event behavior on a window |
|
1913 TouchEventPropagationTestWidget window; |
|
1914 window.setObjectName("1. window"); |
|
1915 |
|
1916 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); |
|
1917 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); |
|
1918 QVERIFY(!window.seenTouchEvent); |
|
1919 QVERIFY(!window.seenMouseEvent); |
|
1920 |
|
1921 window.reset(); |
|
1922 window.setAttribute(Qt::WA_AcceptTouchEvents); |
|
1923 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); |
|
1924 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); |
|
1925 QVERIFY(window.seenTouchEvent); |
|
1926 QVERIFY(!window.seenMouseEvent); |
|
1927 |
|
1928 window.reset(); |
|
1929 window.acceptTouchEvent = true; |
|
1930 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); |
|
1931 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); |
|
1932 QVERIFY(window.seenTouchEvent); |
|
1933 QVERIFY(!window.seenMouseEvent); |
|
1934 } |
|
1935 |
|
1936 { |
|
1937 // touch event behavior on a window with a child widget |
|
1938 TouchEventPropagationTestWidget window; |
|
1939 window.setObjectName("2. window"); |
|
1940 TouchEventPropagationTestWidget widget(&window); |
|
1941 widget.setObjectName("2. widget"); |
|
1942 |
|
1943 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); |
|
1944 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); |
|
1945 QVERIFY(!widget.seenTouchEvent); |
|
1946 QVERIFY(!widget.seenMouseEvent); |
|
1947 QVERIFY(!window.seenTouchEvent); |
|
1948 QVERIFY(!window.seenMouseEvent); |
|
1949 |
|
1950 window.reset(); |
|
1951 widget.reset(); |
|
1952 widget.setAttribute(Qt::WA_AcceptTouchEvents); |
|
1953 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); |
|
1954 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); |
|
1955 QVERIFY(widget.seenTouchEvent); |
|
1956 QVERIFY(!widget.seenMouseEvent); |
|
1957 QVERIFY(!window.seenTouchEvent); |
|
1958 QVERIFY(!window.seenMouseEvent); |
|
1959 |
|
1960 window.reset(); |
|
1961 widget.reset(); |
|
1962 widget.acceptMouseEvent = true; |
|
1963 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); |
|
1964 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); |
|
1965 QVERIFY(widget.seenTouchEvent); |
|
1966 QVERIFY(!widget.seenMouseEvent); |
|
1967 QVERIFY(!window.seenTouchEvent); |
|
1968 QVERIFY(!window.seenMouseEvent); |
|
1969 |
|
1970 window.reset(); |
|
1971 widget.reset(); |
|
1972 widget.acceptTouchEvent = true; |
|
1973 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); |
|
1974 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); |
|
1975 QVERIFY(widget.seenTouchEvent); |
|
1976 QVERIFY(!widget.seenMouseEvent); |
|
1977 QVERIFY(!window.seenTouchEvent); |
|
1978 QVERIFY(!window.seenMouseEvent); |
|
1979 |
|
1980 window.reset(); |
|
1981 widget.reset(); |
|
1982 widget.setAttribute(Qt::WA_AcceptTouchEvents, false); |
|
1983 window.setAttribute(Qt::WA_AcceptTouchEvents); |
|
1984 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); |
|
1985 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); |
|
1986 QVERIFY(!widget.seenTouchEvent); |
|
1987 QVERIFY(!widget.seenMouseEvent); |
|
1988 QVERIFY(window.seenTouchEvent); |
|
1989 QVERIFY(!window.seenMouseEvent); |
|
1990 |
|
1991 window.reset(); |
|
1992 widget.reset(); |
|
1993 window.acceptTouchEvent = true; |
|
1994 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); |
|
1995 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); |
|
1996 QVERIFY(!widget.seenTouchEvent); |
|
1997 QVERIFY(!widget.seenMouseEvent); |
|
1998 QVERIFY(window.seenTouchEvent); |
|
1999 QVERIFY(!window.seenMouseEvent); |
|
2000 |
|
2001 window.reset(); |
|
2002 widget.reset(); |
|
2003 widget.acceptMouseEvent = true; // doesn't matter, touch events are propagated first |
|
2004 window.acceptTouchEvent = true; |
|
2005 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); |
|
2006 qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); |
|
2007 QVERIFY(!widget.seenTouchEvent); |
|
2008 QVERIFY(!widget.seenMouseEvent); |
|
2009 QVERIFY(window.seenTouchEvent); |
|
2010 QVERIFY(!window.seenMouseEvent); |
|
2011 } |
|
2012 } |
|
2013 |
|
2014 //QTEST_APPLESS_MAIN(tst_QApplication) |
|
2015 int main(int argc, char *argv[]) |
|
2016 { |
|
2017 tst_QApplication tc; |
|
2018 argv0 = argv[0]; |
|
2019 return QTest::qExec(&tc, argc, argv); |
|
2020 } |
|
2021 |
|
2022 #include "tst_qapplication.moc" |