diff options
author | Friedemann Kleint <Friedemann.Kleint@nokia.com> | 2009-11-12 14:26:03 (GMT) |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@nokia.com> | 2009-11-12 14:26:03 (GMT) |
commit | 58dbae4f9bed45b5657546898f8d0bca5a3d4c56 (patch) | |
tree | 98e032439bfa4db03f5fd1a5260c98e28024613d /tests/auto/guiapplauncher | |
parent | c976e02286eafe9deaa59fdd98d9bb5b35451d44 (diff) | |
download | Qt-58dbae4f9bed45b5657546898f8d0bca5a3d4c56.zip Qt-58dbae4f9bed45b5657546898f8d0bca5a3d4c56.tar.gz Qt-58dbae4f9bed45b5657546898f8d0bca5a3d4c56.tar.bz2 |
Autotests: Add gui application launcher test.
X11/Windows: Launch gui application and stop them
via Windows manager, check stderr, exit codes, etc.
Currently tests Qt Designer, Qt Linguist, Qt Demo and
prominent examples/demos.
Rubber-stamped-by: Jason McDonald <jason.mcdonald@nokia.com>
Diffstat (limited to 'tests/auto/guiapplauncher')
-rw-r--r-- | tests/auto/guiapplauncher/README.txt | 14 | ||||
-rw-r--r-- | tests/auto/guiapplauncher/guiapplauncher.pro | 20 | ||||
-rw-r--r-- | tests/auto/guiapplauncher/test.ts | 973 | ||||
-rw-r--r-- | tests/auto/guiapplauncher/test.ui | 66 | ||||
-rw-r--r-- | tests/auto/guiapplauncher/tst_guiapplauncher.cpp | 513 | ||||
-rw-r--r-- | tests/auto/guiapplauncher/windowmanager.cpp | 508 | ||||
-rw-r--r-- | tests/auto/guiapplauncher/windowmanager.h | 78 |
7 files changed, 2172 insertions, 0 deletions
diff --git a/tests/auto/guiapplauncher/README.txt b/tests/auto/guiapplauncher/README.txt new file mode 100644 index 0000000..317f9d0 --- /dev/null +++ b/tests/auto/guiapplauncher/README.txt @@ -0,0 +1,14 @@ +This test launches gui applications (tools, demos and prominent examples), +keeps them running a while (grabbing their top level from the window manager) +and sends them a Close event via window manager. + +It checks that they do not crash nor produce unexpected error output. + +Note: Do not play with the machine while it is running as otherwise +the top-level find algorithm might get confused (especially on Windows). + +Environment variables are checked to turned off some tests (see code). + +It is currently implemented for X11 (Skips unless DISPLAY is set) and +Windows, pending an implementation of the WindowManager class and deployment +on the other platforms. diff --git a/tests/auto/guiapplauncher/guiapplauncher.pro b/tests/auto/guiapplauncher/guiapplauncher.pro new file mode 100644 index 0000000..27c3553 --- /dev/null +++ b/tests/auto/guiapplauncher/guiapplauncher.pro @@ -0,0 +1,20 @@ +# ------------------------------------------------- +# Project created by QtCreator 2009-11-10T14:39:06 +# ------------------------------------------------- + +# Link against gui for X11,etc. + +DEFINES += SRCDIR=\\\"$$PWD/\\\" +TARGET = tst_guiapplauncher +CONFIG += console +CONFIG -= app_bundle +CONFIG += qtestlib +TEMPLATE = app +SOURCES += tst_guiapplauncher.cpp \ + windowmanager.cpp +HEADERS += windowmanager.h + +win32 { + # process enumeration,etc. + LIBS+=user32.lib +} diff --git a/tests/auto/guiapplauncher/test.ts b/tests/auto/guiapplauncher/test.ts new file mode 100644 index 0000000..79c9c76 --- /dev/null +++ b/tests/auto/guiapplauncher/test.ts @@ -0,0 +1,973 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="de"> +<context> + <name>AssistantServer</name> + <message> + <location filename="../tools/assistant/compat/main.cpp" line="+225"/> + <source>Qt Assistant</source> + <translation>Qt Assistant</translation> + </message> + <message> + <location line="+1"/> + <source>Failed to bind to port %1</source> + <translation>Kann Port %1 nicht binden</translation> + </message> +</context> +<context> + <name>FontPanel</name> + <message> + <location filename="../tools/shared/fontpanel/fontpanel.cpp" line="+63"/> + <source>Font</source> + <translation>Schrift</translation> + </message> + <message> + <location line="+11"/> + <source>&Writing system</source> + <translation>S&kript</translation> + </message> + <message> + <location line="+3"/> + <source>&Family</source> + <translation>&Schriftart</translation> + </message> + <message> + <location line="+4"/> + <source>&Style</source> + <translation>S&chriftschnitt</translation> + </message> + <message> + <location line="+4"/> + <source>&Point size</source> + <translation>Schriftg&rad</translation> + </message> +</context> +<context> + <name>FontSettingsDialog</name> + <message> + <location filename="../tools/assistant/compat/fontsettingsdialog.cpp" line="+63"/> + <source>Font Settings</source> + <translation>Schriftart</translation> + </message> + <message> + <location line="+7"/> + <source>Font settings for:</source> + <translation>Schriftart für:</translation> + </message> + <message> + <location line="+4"/> + <source>Browser</source> + <translation>Hilfeseiten</translation> + </message> + <message> + <location line="+1"/> + <source>Application</source> + <translation>Anwendung</translation> + </message> + <message> + <location line="+6"/> + <source>Use custom settings</source> + <translation>Erweitere Einstellungen nutzen</translation> + </message> +</context> +<context> + <name>HelpDialog</name> + <message> + <location filename="../tools/assistant/compat/helpdialog.ui"/> + <source>Con&tents</source> + <translation>Inhal&t</translation> + </message> + <message> + <location filename="../tools/assistant/compat/helpdialog.cpp" line="+376"/> + <location line="+16"/> + <location line="+661"/> + <source>Qt Assistant</source> + <translation>Qt Assistant</translation> + </message> + <message> + <location line="-771"/> + <source>Open Link in New Window</source> + <translation>Öffne Link in neuem Fenster</translation> + </message> + <message> + <location line="+76"/> + <location line="+82"/> + <source>Prepare...</source> + <translation>Initialisiere...</translation> + </message> + <message> + <location line="-47"/> + <source>Cannot open the index file %1</source> + <translation>Kann Indexdatei %1 nicht öffnen</translation> + </message> + <message> + <location line="+58"/> + <location line="+124"/> + <location line="+8"/> + <source>Warning</source> + <translation>Warnung</translation> + </message> + <message> + <location line="-131"/> + <location line="+124"/> + <source>Documentation file %1 does not exist! +Skipping file.</source> + <translation>Dokumentation %1 existiert nicht! +Überspringe Datei.</translation> + </message> + <message> + <location line="-112"/> + <location line="+133"/> + <source>Parse Error</source> + <translation>Syntaxfehler</translation> + </message> + <message> + <location line="+35"/> + <location line="+469"/> + <source>Done</source> + <translation>Fertig</translation> + </message> + <message> + <location line="-18"/> + <source>Indexing files...</source> + <translation>Indiziere Dokumentation...</translation> + </message> + <message> + <location line="+15"/> + <source>Reading dictionary...</source> + <translation>Lese Suchindex...</translation> + </message> + <message> + <location line="+46"/> + <location line="+9"/> + <source>Full Text Search</source> + <translation>Volltextsuche</translation> + </message> + <message> + <location line="-8"/> + <source>Using a wildcard within phrases is not allowed.</source> + <translation>Wildcards innerhalb von Phrasen sind nicht zugelassen.</translation> + </message> + <message> + <location line="+9"/> + <source>The closing quotation mark is missing.</source> + <translation>Das schließende Anführungszeichen fehlt.</translation> + </message> + <message numerus="yes"> + <location line="+7"/> + <source>%n document(s) found.</source> + <translation> + <numerusform>%n Dokumente gefunden.</numerusform> + <numerusform></numerusform> + </translation> + </message> + <message> + <location line="-882"/> + <source>Open Link in Current Tab</source> + <translation>Link im Aktuellen Tab öffnen</translation> + </message> + <message> + <location line="+6"/> + <source>Open Link in New Tab</source> + <translation>Link in einem neuen Tab öffnen</translation> + </message> + <message> + <location line="+91"/> + <source>Failed to load keyword index file +Assistant will not work!</source> + <translation>Die Indexdatei konnte nicht geladen werden. +Der Assistent ist nicht einsatzbereit!</translation> + </message> + <message> + <location line="+208"/> + <source>Documentation file %1 is not compatible! +Skipping file.</source> + <translation>Dokumentation %1 ist nicht kompatibel! Datei wird übersprungen.</translation> + </message> + <message> + <location line="+470"/> + <source>Failed to save fulltext search index +Assistant will not work!</source> + <translation>Der Index für die Volltextsuche konnte nicht gespeichert werden. +Assistent ist nicht einsatzbereit!</translation> + </message> + <message> + <location filename="../tools/assistant/compat/helpdialog.ui"/> + <source>Help</source> + <translation>Hilfe</translation> + </message> + <message> + <location/> + <source><b>Help</b><p>Choose the topic you want help on from the contents list, or search the index for keywords.</p></source> + <translation><b>Hilfe</b><p>Wählen Sie ein Hilfethema aus dem Inhalt oder suchen Sie im Index nach Schlüsselwörtern.</p></translation> + </message> + <message> + <location/> + <source>Displays help topics organized by category, index or bookmarks. Another tab inherits the full text search.</source> + <translation>Zeigt Hilfethemen geordnet nach Kategorie, Index oder Lesezeichen an. Ein weiterer Abschnitt enthält die Volltextsuche.</translation> + </message> + <message> + <location/> + <source><b>Help topics organized by category.</b><p>Double-click an item to see the topics in that category. To view a topic, just double-click it.</p></source> + <translation><b>Hilfethemen geordnet nach Kategorie.</b><p>Doppelklicken Sie einen Eintrag, um die Themen dieser Kategorie zu sehen. Doppelklicken Sie ein Thema, um es angezeigt zu bekommen.</p></translation> + </message> + <message> + <location/> + <source>column 1</source> + <translation>Spalte 1</translation> + </message> + <message> + <location/> + <source>&Index</source> + <translation>&Index</translation> + </message> + <message> + <location/> + <source>&Look For:</source> + <translation>Suchen &nach:</translation> + </message> + <message> + <location/> + <source>Enter keyword</source> + <translation>Geben Sie ein Schlüsselwort ein</translation> + </message> + <message> + <location/> + <source><b>Enter a keyword.</b><p>The list will select an item that matches the entered string best.</p></source> + <translation><b>Geben Sie ein Schlüsselwort ein.</b><p>Es wird dann der Eintrag aus der Liste ausgewählt, der am besten mit dem eingegebenen Begriff übereinstimmt.</p></translation> + </message> + <message> + <location/> + <source><b>List of available help topics.</b><p>Double-click on an item to open its help page. If more than one is found, you must specify which page you want.</p></source> + <translation><b>Liste aller verfügbaren Hilfethemen.</b><p>Doppelklicken Sie auf einen Eintrag, um die Hilfe zu öffnen. Wenn mehr als eine Seite gefunden wurde, wählen Sie die gewünschte Seite aus.</p></translation> + </message> + <message> + <location/> + <source>&Bookmarks</source> + <translation>L&esezeichen</translation> + </message> + <message> + <location/> + <source>Displays the list of bookmarks.</source> + <translation>Zeigt alle Lesezeichen an.</translation> + </message> + <message> + <location/> + <source>Add new bookmark</source> + <translation>Füge neues Lesezeichen hinzu</translation> + </message> + <message> + <location/> + <source>Add the currently displayed page as a new bookmark.</source> + <translation>Füge aktuelle Seite zu den Lesezeichen hinzu.</translation> + </message> + <message> + <location/> + <source>&New</source> + <translation>&Neu</translation> + </message> + <message> + <location/> + <source>Delete bookmark</source> + <translation>Lösche Lesezeichen</translation> + </message> + <message> + <location/> + <source>Delete the selected bookmark.</source> + <translation>Lösche markiertes Lesezeichen.</translation> + </message> + <message> + <location/> + <source>&Delete</source> + <translation>&Löschen</translation> + </message> + <message> + <location/> + <source>&Search</source> + <translation>&Suche</translation> + </message> + <message> + <location/> + <source>Searching f&or:</source> + <translation>Suche &nach:</translation> + </message> + <message> + <location/> + <source><b>Enter search word(s).</b><p>Enter here the word(s) you are looking for. The words may contain wildcards (*). For a sequence of words quote them.</p></source> + <translation><b>Geben Sie Suchbegriffe ein.</b><p>Geben Sie hier die gesuchten Begriffe ein. Die Begriffe können Wildcards (*) enthalten. Eine Phrase muß in Anführungszeichen stehen.</p></translation> + </message> + <message> + <location/> + <source><b>Found documents</b><p>This list contains all found documents from the last search. The documents are ordered, i.e. the first document has the most matches.</p></source> + <translation><b>Gefundene Dokumente</b><p>Diese Liste beinhaltet alle gefundenen Dokumente der letzten Suche. Die Dokumente sind nach der Häufigkeit der Treffer geordnet.</p></translation> + </message> + <message> + <location/> + <source>Found &Documents:</source> + <translation>Gefundene &Dokumente:</translation> + </message> + <message> + <location/> + <source>Display the help page for the full text search.</source> + <translation>Zeigt die Hilfeseite für die Volltextsuche an.</translation> + </message> + <message> + <location/> + <source>He&lp</source> + <translation>Hi&lfe</translation> + </message> + <message> + <location/> + <source>Pressing this button starts the search.</source> + <translation>Startet die Suche.</translation> + </message> + <message> + <location/> + <source>Preparing...</source> + <translation>Initialisiere...</translation> + </message> + <message> + <location/> + <source>Enter searchword(s)</source> + <translation>Geben Sie Suchbegriffe ein</translation> + </message> + <message> + <location/> + <source>Display the help page</source> + <translation>Hilfeseite anzeigen</translation> + </message> + <message> + <location/> + <source>Start searching</source> + <translation>Suche beginnen</translation> + </message> +</context> +<context> + <name>HelpWindow</name> + <message> + <location filename="../tools/assistant/compat/helpwindow.cpp" line="+97"/> + <source>Help</source> + <translation>Hilfe</translation> + </message> + <message> + <location line="+93"/> + <source>Open Link in New Window Shift+LMB</source> + <translation>Öffne Link in neuem Fenster</translation> + </message> + <message> + <location line="-2"/> + <source>Open Link in New Tab</source> + <translation>Link in einem neuen Tab öffnen</translation> + </message> + <message> + <location line="-90"/> + <source>Unable to launch web browser. +</source> + <translation>Der Webbrowser konnte nicht gestartet werden. +</translation> + </message> + <message> + <location line="+1"/> + <source>OK</source> + <translation>OK</translation> + </message> + <message> + <location line="+27"/> + <source>Failed to open link: '%1'</source> + <translation>Der Link '%1' konnte nicht geöffnet werden</translation> + </message> + <message> + <location line="+1"/> + <source><div align="center"><h1>The page could not be found</h1><br><h3>'%1'</h3></div></source> + <translation><div align="center"><h1>Die Seite wurde nicht gefunden</h1><br><h3>'%1'</h3></div></translation> + </message> + <message> + <location line="+2"/> + <source>Error...</source> + <translation>Fehler ...</translation> + </message> + <message> + <location line="+56"/> + <source>Copy &Link Location</source> + <translation>Link-Adresse kopieren</translation> + </message> +</context> +<context> + <name>Index</name> + <message> + <location filename="../tools/assistant/compat/index.cpp" line="+385"/> + <source>Untitled</source> + <translation>Unbenannt</translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <location filename="../tools/assistant/compat/mainwindow.ui"/> + <source>Toolbar</source> + <translation>Werkzeugleiste</translation> + </message> + <message> + <location/> + <source>&Print...</source> + <translation>&Drucken...</translation> + </message> + <message> + <location/> + <source>E&xit</source> + <translation>&Beenden</translation> + </message> + <message> + <location/> + <source>&Copy</source> + <translation>&Kopieren</translation> + </message> + <message> + <location/> + <source>&Find in Text...</source> + <translation>Text&suche...</translation> + </message> + <message> + <location/> + <source>&Home</source> + <translation>St&artseite</translation> + </message> + <message> + <location/> + <source>&Previous</source> + <translation>&Vorherige</translation> + </message> + <message> + <location/> + <source>&Next</source> + <translation>&Nächste</translation> + </message> + <message> + <location/> + <source>About Qt</source> + <translation>Über Qt</translation> + </message> + <message> + <location/> + <source>Zoom &in</source> + <translation>Vergrößern</translation> + </message> + <message> + <location/> + <source>Zoom &out</source> + <translation>Ver&kleinern</translation> + </message> + <message> + <location/> + <source>New Window</source> + <translation>Neues Fenster...</translation> + </message> + <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="+198"/> + <source>Ctrl+T</source> + <translation>Strg+T +</translation> + </message> + <message> + <location line="+1"/> + <source>Ctrl+I</source> + <translation>Strg+I</translation> + </message> + <message> + <location line="+1"/> + <source>Ctrl+B</source> + <translation>Strg+E</translation> + </message> + <message> + <location line="+129"/> + <location line="+1"/> + <source>Qt Assistant</source> + <translation>Qt Assistant</translation> + </message> + <message> + <location filename="../tools/assistant/compat/mainwindow.ui"/> + <source>&Add Bookmark</source> + <translation>&Füge Lesezeichen hinzu</translation> + </message> + <message> + <location/> + <source>&File</source> + <translation>&Datei</translation> + </message> + <message> + <location/> + <source>&Edit</source> + <translation>&Bearbeiten</translation> + </message> + <message> + <location/> + <source>&View</source> + <translation>&Ansicht</translation> + </message> + <message> + <location/> + <source>&Go</source> + <translation>&Gehe zu</translation> + </message> + <message> + <location/> + <source>Boo&kmarks</source> + <translation>&Lesezeichen</translation> + </message> + <message> + <location/> + <source>Qt Assistant by Nokia</source> + <translation>Qt Assistant von Nokia</translation> + </message> + <message> + <location/> + <source>&Help</source> + <translation>&Hilfe</translation> + </message> + <message> + <location/> + <source>Print the currently displayed page.</source> + <translation>Drucke aktuelle Seite.</translation> + </message> + <message> + <location/> + <source>Ctrl+P</source> + <translation>Strg+P</translation> + </message> + <message> + <location/> + <source>Quit Qt Assistant.</source> + <translation>Qt Assistant beenden.</translation> + </message> + <message> + <location/> + <source>Ctrl+Q</source> + <translation>Strg+Q</translation> + </message> + <message> + <location/> + <source>Copy the selected text to the clipboard.</source> + <translation>Den markierten Text in die Zwischenablage kopieren.</translation> + </message> + <message> + <location/> + <source>Ctrl+C</source> + <translation>Strg+C</translation> + </message> + <message> + <location/> + <source>Open the Find dialog. Qt Assistant will search the currently displayed page for the text you enter.</source> + <translation>Den Suchdialog öffnen. Qt Assistant sucht in der aktuellen Seite nach dem eingegebenen Text.</translation> + </message> + <message> + <location/> + <source>Ctrl+F</source> + <translation>Strg+F</translation> + </message> + <message> + <location/> + <source>Go to the home page. Qt Assistant's home page is the Qt Reference Documentation.</source> + <translation>Zur Startseite gehen. Startseite im Qt Assistant ist die Qt-Referenzdokumentation.</translation> + </message> + <message> + <location/> + <source>Ctrl+Home</source> + <translation>Strg+Pos1</translation> + </message> + <message> + <location/> + <source>Go to the previous page.</source> + <translation>Gehe zur vorherigen Seite.</translation> + </message> + <message> + <location/> + <source>Alt+Left</source> + <translation>Alt+Links</translation> + </message> + <message> + <location/> + <source>Go to the next page.</source> + <translation>Gehe zur nächsten Seite.</translation> + </message> + <message> + <location/> + <source>Alt+Right</source> + <translation>Alt+Rechts</translation> + </message> + <message> + <location/> + <source>Display further information about Qt Assistant.</source> + <translation>Zeigt das Handbuch zum Qt Designer an.</translation> + </message> + <message> + <location/> + <source>Zoom in on the document, i.e. increase the font size.</source> + <translation>Vergrößert die Schrift.</translation> + </message> + <message> + <location/> + <source>Ctrl++</source> + <translation>Strg++</translation> + </message> + <message> + <location/> + <source>Zoom out on the document, i.e. decrease the font size.</source> + <translation>Verkleinert die Schrift.</translation> + </message> + <message> + <location/> + <source>Ctrl+-</source> + <translation>Strg+-</translation> + </message> + <message> + <location/> + <source>Open a new window.</source> + <translation>Öffnet ein neues Fenster.</translation> + </message> + <message> + <location/> + <source>Ctrl+N</source> + <translation>Strg+N</translation> + </message> + <message> + <location/> + <source>&Close</source> + <translation>&Schließen</translation> + </message> + <message> + <location/> + <source>Close the current window.</source> + <translation>Schließt das aktuelle Fenster.</translation> + </message> + <message> + <location/> + <source>Qt Assistant Manual</source> + <translation>Handbuch zu Qt Assistant</translation> + </message> + <message> + <location/> + <source>F1</source> + <translation>F1</translation> + </message> + <message> + <location/> + <source>Add the currently displayed page as a new bookmark.</source> + <translation>Aktuelle Seite zu den Lesezeichen hinzufügen.</translation> + </message> + <message> + <location/> + <source>What's This?</source> + <translation>Direkthilfe</translation> + </message> + <message> + <location/> + <source>"What's This?" context sensitive help.</source> + <translation>Kontextbezogene Direkthilfe.</translation> + </message> + <message> + <location/> + <source>Shift+F1</source> + <translation>Umschalt+F1</translation> + </message> + <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="-129"/> + <source>Ctrl+S</source> + <translation>Strg+S</translation> + </message> + <message> + <location line="-33"/> + <source>Initializing Qt Assistant...</source> + <translation>Qt Assistant wird initialisiert...</translation> + </message> + <message> + <location filename="../tools/assistant/compat/mainwindow.ui"/> + <source>Go</source> + <translation>Gehe zu</translation> + </message> + <message> + <location/> + <source>Find &Next</source> + <translation>Weitersuchen</translation> + </message> + <message> + <location/> + <source>F3</source> + <translation>F3</translation> + </message> + <message> + <location/> + <source>Find &Previous</source> + <translation>Vorheriges suchen</translation> + </message> + <message> + <location/> + <source>Shift+F3</source> + <translation>Umschalt+F3</translation> + </message> + <message> + <location/> + <source>About Qt Assistant</source> + <translation>Über Qt Assistent</translation> + </message> + <message> + <location/> + <source>Add Tab</source> + <translation>Tab einfügen</translation> + </message> + <message> + <location/> + <source>Ctrl+Alt+N</source> + <translation></translation> + </message> + <message> + <location/> + <source>Next Tab</source> + <translation>Nächster Tab</translation> + </message> + <message> + <location/> + <source>Ctrl+Alt+Right</source> + <translation></translation> + </message> + <message> + <location/> + <source>Previous Tab</source> + <translation>Voriger Tab</translation> + </message> + <message> + <location/> + <source>Ctrl+Alt+Left</source> + <translation></translation> + </message> + <message> + <location/> + <source>Close Tab</source> + <translation>Tab schließen</translation> + </message> + <message> + <location/> + <source>Ctrl+Alt+Q</source> + <translation></translation> + </message> + <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="+181"/> + <source>Failed to open about application contents in file: '%1'</source> + <translation>Fehler beim Öffnen des Inhalts in Datei: '%1'</translation> + </message> + <message> + <location line="-246"/> + <source>Sidebar</source> + <translation>Sidebar</translation> + </message> + <message> + <location line="+18"/> + <source>&Window</source> + <translation>&Fenster</translation> + </message> + <message> + <location line="+2"/> + <source>Minimize</source> + <translation>Minimieren</translation> + </message> + <message> + <location line="+1"/> + <source>Ctrl+M</source> + <translation>Strg+M</translation> + </message> + <message> + <location line="+70"/> + <source>SHIFT+CTRL+=</source> + <translation>Umschalt+Strg+=</translation> + </message> + <message> + <location filename="../tools/assistant/compat/mainwindow.ui"/> + <source>Ctrl+W</source> + <translation>Strg+W</translation> + </message> + <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="+8"/> + <source>Ctrl+]</source> + <translation>Strg+AltGr+]</translation> + </message> + <message> + <location line="+1"/> + <source>Ctrl+[</source> + <translation>Strg+AltGr+[</translation> + </message> + <message> + <location line="+7"/> + <source>Views</source> + <translation>Menüleisten/Sidebar</translation> + </message> + <message> + <location line="+80"/> + <source>Displays the main page of a specific documentation set.</source> + <translation>Zeigt die Hauptseite eines Dokumentensets an.</translation> + </message> + <message> + <location line="+262"/> + <source>...</source> + <translation>...</translation> + </message> + <message> + <location line="+238"/> + <location line="+6"/> + <source>Save Page</source> + <translation>Seite speichern</translation> + </message> + <message> + <location line="+0"/> + <source>Cannot open file for writing!</source> + <translation>Die Datei konnte nicht zum Schreiben geöffnet werden.</translation> + </message> + <message> + <location filename="../tools/assistant/compat/mainwindow.ui"/> + <source>Save Page As...</source> + <translation>Seite speichern als...</translation> + </message> + <message> + <location/> + <source>Ctrl+Alt+S</source> + <translation>Strg+Alt+S</translation> + </message> + <message> + <location/> + <source>Sync with Table of Contents</source> + <translation>Seite mit Inhalt-Tab syncronisieren</translation> + </message> + <message> + <location/> + <source>Select the page in contents tab.</source> + <translation>Wählt die Seite im Inhalt-Tab aus.</translation> + </message> + <message> + <location/> + <source>Font Settings...</source> + <translation>Schriftart...</translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <location filename="../tools/assistant/compat/config.cpp" line="+350"/> + <source>Qt Assistant by Nokia</source> + <translation>Qt Assistant von Nokia</translation> + </message> +</context> +<context> + <name>TabbedBrowser</name> + <message> + <location filename="../tools/assistant/compat/tabbedbrowser.ui"/> + <source>TabbedBrowser</source> + <translation></translation> + </message> + <message> + <location/> + <source>Untitled</source> + <translation>Unbenannt</translation> + </message> + <message> + <location filename="../tools/assistant/compat/tabbedbrowser.cpp" line="+235"/> + <source>Add page</source> + <translation>Seite einfügen</translation> + </message> + <message> + <location line="+9"/> + <source>Close page</source> + <translation>Seite schließen</translation> + </message> + <message> + <location line="-95"/> + <source>...</source> + <translation>...</translation> + </message> + <message> + <location line="+338"/> + <source>New Tab</source> + <translation>Neuer Tab</translation> + </message> + <message> + <location line="+1"/> + <source>Close Tab</source> + <translation>Tab schließen</translation> + </message> + <message> + <location line="+1"/> + <source>Close Other Tabs</source> + <translation>Andere Tabs schließen</translation> + </message> + <message> + <location filename="../tools/assistant/compat/tabbedbrowser.ui"/> + <source>Previous</source> + <translation>Vorheriger</translation> + </message> + <message> + <location/> + <source>Next</source> + <translation>Nächster</translation> + </message> + <message> + <location/> + <source>Case Sensitive</source> + <translation>Groß-/Kleinschreibung beachten</translation> + </message> + <message> + <location/> + <source>Whole words</source> + <translation>Ganze Wörter</translation> + </message> + <message> + <location/> + <source><img src=":/trolltech/assistant/images/wrap.png">&nbsp;Search wrapped</source> + <translation><img src=":/trolltech/assistant/images/wrap.png">&nbsp;Seitenende</translation> + </message> +</context> +<context> + <name>TopicChooser</name> + <message> + <location filename="../tools/assistant/compat/topicchooser.cpp" line="+56"/> + <source>Choose a topic for <b>%1</b></source> + <translation>Wählen Sie ein Thema für <b>%1</b></translation> + </message> + <message> + <location filename="../tools/assistant/compat/topicchooser.ui"/> + <source>Choose Topic</source> + <translation>Thema wählen</translation> + </message> + <message> + <location/> + <source>Select a topic from the list and click the <b>Display</b>-button to open the online help.</source> + <translation>Wählen Sie ein Thema aus der Liste aus und klicken Sie <b>Anzeigen</b> um die Hilfe zu öffnen.</translation> + </message> + <message> + <location/> + <source>&Topics</source> + <translation>&Themen</translation> + </message> + <message> + <location/> + <source>Displays a list of available help topics for the keyword.</source> + <translation>Zeigt eine Liste der verfügbaren Hilfethemen für diesen Begriff an.</translation> + </message> + <message> + <location/> + <source>&Display</source> + <translation>&Anzeigen</translation> + </message> + <message> + <location/> + <source>Open the topic selected in the list.</source> + <translation>Öffne das gewählte Thema aus der Liste.</translation> + </message> + <message> + <location/> + <source>&Close</source> + <translation>&Schließen</translation> + </message> + <message> + <location/> + <source>Close the Dialog.</source> + <translation>Schließt den Dialog.</translation> + </message> +</context> +</TS> diff --git a/tests/auto/guiapplauncher/test.ui b/tests/auto/guiapplauncher/test.ui new file mode 100644 index 0000000..02efcd4 --- /dev/null +++ b/tests/auto/guiapplauncher/test.ui @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>600</height> + </rect> + </property> + <property name="windowTitle"> + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QPlainTextEdit" name="plainTextEdit"/> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>23</height> + </rect> + </property> + <widget class="QMenu" name="menuFile"> + <property name="title"> + <string>File</string> + </property> + <addaction name="actionExit"/> + </widget> + <addaction name="menuFile"/> + </widget> + <widget class="QStatusBar" name="statusbar"/> + <action name="actionExit"> + <property name="text"> + <string>Exit</string> + </property> + </action> + </widget> + <resources/> + <connections> + <connection> + <sender>actionExit</sender> + <signal>triggered()</signal> + <receiver>MainWindow</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>399</x> + <y>299</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tests/auto/guiapplauncher/tst_guiapplauncher.cpp b/tests/auto/guiapplauncher/tst_guiapplauncher.cpp new file mode 100644 index 0000000..2a6c1e2 --- /dev/null +++ b/tests/auto/guiapplauncher/tst_guiapplauncher.cpp @@ -0,0 +1,513 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "windowmanager.h" + +#include <QtCore/QDir> +#include <QtCore/QString> +#include <QtTest/QtTest> +#include <QtCore/QProcess> +#include <QtCore/QByteArray> +#include <QtCore/QLibraryInfo> +#include <QtCore/QVariant> +#include <QtCore/QDateTime> +#include <QtCore/QMap> + +// AppLaunch: Launch gui applications, keep them running a while +// (grabbing their top level from the window manager) and send +// them a Close event via window manager. Verify that they do not +// not crash nor produces unexpected error output. +// Note: Do not play with the machine while it is running as otherwise +// the top-level find algorithm might get confused (especially on Windows). +// Environment variables are checked to turned off some tests +// It is currently implemented for X11 and Windows, pending an +// implementation of the WindowManager class and deployment on +// the other platforms. + +enum { defaultUpTimeMS = 3000, defaultTopLevelWindowTimeoutMS = 30000, + defaultTerminationTimeoutMS = 35000 }; + +// List the examples to test (Gui examples only). +struct Example { + const char *name; + const char *directory; + const char *binary; + unsigned priority; // 0-highest + int upTimeMS; +}; + +const struct Example examples[] = { + {"animation/animatedtiles Example", "animation/animatedtiles", "animatedtiles", 0, -1}, + {"animation/appchooser Example", "animation/appchooser", "appchooser", 10, -1}, + {"animation/easing Example", "animation/easing", "easing", 10, -1}, + {"animation/moveblocks Example", "animation/moveblocks", "moveblocks", 10, -1}, + {"animation/states Example", "animation/states", "states", 10, -1}, + {"animation/stickman Example", "animation/stickman", "stickman", 10, -1}, + {"designer/calculatorbuilder Example", "designer/calculatorbuilder", "calculatorbuilder", 10, -1}, + {"dialogs/standarddialogs Example", "dialogs/standarddialogs", "standarddialogs", 10, -1}, + {"draganddrop/dropsite Example", "draganddrop/dropsite", "dropsite", 10, -1}, + {"draganddrop/fridgemagnets Example", "draganddrop/fridgemagnets", "fridgemagnets", 10, -1}, + {"draganddrop/puzzle Example", "draganddrop/puzzle", "puzzle", 10, -1}, + {"effects/blurpicker Example", "effects/blurpicker", "blurpicker", 10, -1}, + {"effects/customshader Example", "effects/customshader", "customshader", 10, -1}, + {"effects/fademessage Example", "effects/fademessage", "fademessage", 10, -1}, + {"effects/lighting Example", "effects/lighting", "lighting", 10, -1}, + {"graphicsview/anchorlayout Example", "graphicsview/anchorlayout", "anchorlayout", 10, -1}, + {"graphicsview/basicgraphicslayouts Example", "graphicsview/basicgraphicslayouts", "basicgraphicslayouts", 0, -1}, + {"graphicsview/collidingmice Example", "graphicsview/collidingmice", "collidingmice", 10, -1}, + {"graphicsview/diagramscene Example", "graphicsview/diagramscene", "diagramscene", 10, -1}, + {"graphicsview/dragdroprobot Example", "graphicsview/dragdroprobot", "dragdroprobot", 10, -1}, + {"graphicsview/elasticnodes Example", "graphicsview/elasticnodes", "elasticnodes", 10, -1}, + {"graphicsview/flowlayout Example", "graphicsview/flowlayout", "flowlayout", 10, -1}, + {"graphicsview/padnavigator Example", "graphicsview/padnavigator", "padnavigator", 0, -1}, + {"graphicsview/portedasteroids Example", "graphicsview/portedasteroids", "portedasteroids", 10, -1}, + {"graphicsview/portedcanvas Example", "graphicsview/portedcanvas", "portedcanvas", 10, -1}, + {"graphicsview/weatheranchorlayout Example", "graphicsview/weatheranchorlayout", "weatheranchorlayout", 10, -1}, + {"itemviews/addressbook Example", "itemviews/addressbook", "addressbook", 0, -1}, + {"itemviews/basicsortfiltermodel Example", "itemviews/basicsortfiltermodel", "basicsortfiltermodel", 10, -1}, + {"itemviews/chart Example", "itemviews/chart", "chart", 0, -1}, + {"itemviews/coloreditorfactory Example", "itemviews/coloreditorfactory", "coloreditorfactory", 10, -1}, + {"itemviews/combowidgetmapper Example", "itemviews/combowidgetmapper", "combowidgetmapper", 6, -1}, + {"itemviews/customsortfiltermodel Example", "itemviews/customsortfiltermodel", "customsortfiltermodel", 6, -1}, + {"itemviews/dirview Example", "itemviews/dirview", "dirview", 0, -1}, + {"itemviews/editabletreemodel Example", "itemviews/editabletreemodel", "editabletreemodel", 0, -1}, + {"itemviews/fetchmore Example", "itemviews/fetchmore", "fetchmore", 10, -1}, + {"itemviews/frozencolumn Example", "itemviews/frozencolumn", "frozencolumn", 10, -1}, + {"itemviews/pixelator Example", "itemviews/pixelator", "pixelator", 10, -1}, + {"itemviews/puzzle Example", "itemviews/puzzle", "puzzle", 10, -1}, + {"itemviews/simpledommodel Example", "itemviews/simpledommodel", "simpledommodel", 10, -1}, + {"itemviews/simpletreemodel Example", "itemviews/simpletreemodel", "simpletreemodel", 10, -1}, + {"itemviews/simplewidgetmapper Example", "itemviews/simplewidgetmapper", "simplewidgetmapper", 10, -1}, + {"itemviews/spinboxdelegate Example", "itemviews/spinboxdelegate", "spinboxdelegate", 0, -1}, + {"itemviews/stardelegate Example", "itemviews/stardelegate", "stardelegate", 10, -1}, + {"layouts/basiclayouts Example", "layouts/basiclayouts", "basiclayouts", 0, -1}, + {"layouts/borderlayout Example", "layouts/borderlayout", "borderlayout", 10, -1}, + {"layouts/dynamiclayouts Example", "layouts/dynamiclayouts", "dynamiclayouts", 10, -1}, + {"layouts/flowlayout Example", "layouts/flowlayout", "flowlayout", 10, -1}, + {"mainwindows/application Example", "mainwindows/application", "application", 6, -1}, + {"mainwindows/dockwidgets Example", "mainwindows/dockwidgets", "dockwidgets", 0, -1}, + {"mainwindows/mdi Example", "mainwindows/mdi", "mdi", 0, -1}, + {"mainwindows/menus Example", "mainwindows/menus", "menus", 10, -1}, + {"mainwindows/recentfiles Example", "mainwindows/recentfiles", "recentfiles", 10, -1}, + {"mainwindows/sdi Example", "mainwindows/sdi", "sdi", 10, -1}, + {"multitouch/dials Example", "multitouch/dials", "dials", 10, -1}, + {"multitouch/fingerpaint Example", "multitouch/fingerpaint", "fingerpaint", 10, -1}, + {"multitouch/knobs Example", "multitouch/knobs", "knobs", 10, -1}, + {"multitouch/pinchzoom Example", "multitouch/pinchzoom", "pinchzoom", 10, -1}, + {"opengl/2dpainting Example", "opengl/2dpainting", "2dpainting", 10, -1}, + {"opengl/grabber Example", "opengl/grabber", "grabber", 10, -1}, + {"opengl/hellogl Example", "opengl/hellogl", "hellogl", 10, -1}, + {"opengl/overpainting Example", "opengl/overpainting", "overpainting", 10, -1}, + {"opengl/samplebuffers Example", "opengl/samplebuffers", "samplebuffers", 10, -1}, + {"opengl/textures Example", "opengl/textures", "textures", 10, -1}, + {"painting/basicdrawing Example", "painting/basicdrawing", "basicdrawing", 10, -1}, + {"painting/concentriccircles Example", "painting/concentriccircles", "concentriccircles", 0, -1}, + {"painting/fontsampler Example", "painting/fontsampler", "fontsampler", 0, -1}, + {"painting/imagecomposition Example", "painting/imagecomposition", "imagecomposition", 10, -1}, + {"painting/painterpaths Example", "painting/painterpaths", "painterpaths", 10, -1}, + {"painting/svggenerator Example", "painting/svggenerator", "svggenerator", 10, -1}, + {"painting/svgviewer Example", "painting/svgviewer", "svgviewer", 0, -1}, + {"painting/transformations Example", "painting/transformations", "transformations", 0, -1}, + {"qtconcurrent/imagescaling Example", "qtconcurrent/imagescaling", "imagescaling", 10, -1}, + {"richtext/calendar Example", "richtext/calendar", "calendar", 0, -1}, + {"richtext/orderform Example", "richtext/orderform", "orderform", 10, -1}, + {"richtext/syntaxhighlighter Example", "richtext/syntaxhighlighter", "syntaxhighlighter", 0, -1}, + {"richtext/textobject Example", "richtext/textobject", "textobject", 10, -1}, + {"script/calculator Example", "script/calculator", "calculator", 6, -1}, + {"script/qstetrix Example", "script/qstetrix", "qstetrix", 0, -1}, + {"statemachine/eventtransitions Example", "statemachine/eventtransitions", "eventtransitions", 10, -1}, + {"statemachine/rogue Example", "statemachine/rogue", "rogue", 10, -1}, + {"statemachine/trafficlight Example", "statemachine/trafficlight", "trafficlight", 0, -1}, + {"statemachine/twowaybutton Example", "statemachine/twowaybutton", "twowaybutton", 10, -1}, + {"tutorials/addressbook/part7 Example", "tutorials/addressbook/part7", "part7", 0, -1}, + {"webkit/fancybrowser Example", "webkit/fancybrowser", "fancybrowser", 0, 7000}, + {"widgets/analogclock Example", "widgets/analogclock", "analogclock", 6, -1}, + {"widgets/calculator Example", "widgets/calculator", "calculator", 6, -1}, + {"widgets/calendarwidget Example", "widgets/calendarwidget", "calendarwidget", 10, -1}, + {"widgets/charactermap Example", "widgets/charactermap", "charactermap", 10, -1}, + {"widgets/codeeditor Example", "widgets/codeeditor", "codeeditor", 0, -1}, + {"widgets/digitalclock Example", "widgets/digitalclock", "digitalclock", 10, -1}, + {"widgets/groupbox Example", "widgets/groupbox", "groupbox", 10, -1}, + {"widgets/icons Example", "widgets/icons", "icons", 10, -1}, + {"widgets/imageviewer Example", "widgets/imageviewer", "imageviewer", 10, -1}, + {"widgets/lineedits Example", "widgets/lineedits", "lineedits", 10, -1}, + {"widgets/scribble Example", "widgets/scribble", "scribble", 10, -1}, + {"widgets/sliders Example", "widgets/sliders", "sliders", 10, -1}, + {"widgets/spinboxes Example", "widgets/spinboxes", "spinboxes", 10, -1}, + {"widgets/styles Example", "widgets/styles", "styles", 0, -1}, + {"widgets/stylesheet Example", "widgets/stylesheet", "stylesheet", 0, -1}, + {"widgets/tablet Example", "widgets/tablet", "tablet", 10, -1}, + {"widgets/tetrix Example", "widgets/tetrix", "tetrix", 0, -1}, + {"widgets/tooltips Example", "widgets/tooltips", "tooltips", 10, -1}, + {"widgets/validators Example", "widgets/validators", "validators", 10, -1}, + {"widgets/wiggly Example", "widgets/wiggly", "wiggly", 10, -1} +}; + +const struct Example demos[] = { + {"Affine Demo", "affine", "affine", 0, -1}, + {"Books Demo", "books", "books", 0, -1}, + {"Browser Demo", "browser", "browser", 0, 0000}, + {"Chip Demo", "chip", "chip", 0, -1}, + {"Composition Demo", "composition", "composition", 0, -1}, + {"Deform Demo", "deform", "deform", 0, -1}, + {"Embeddeddialogs Demo", "embeddeddialogs", "embeddeddialogs", 0, -1}, + {"Gradients Demo", "gradients", "gradients", 0, -1}, + {"Interview Demo", "interview", "interview", 0, -1}, + {"Mainwindow Demo", "mainwindow", "mainwindow", 0, -1}, + {"PathStroke Demo", "pathstroke", "pathstroke", 0, -1}, + {"Spreadsheet Demo", "spreadsheet", "spreadsheet", 0, -1}, + {"Sub-Attac Demo", "sub-attaq", "sub-attaq", 0, -1}, + {"TextEdit Demo", "textedit", "textedit", 0, -1}, + {"Undo Demo", "undo", "undo", 0, -1} +}; + +// Data struct used in tests, specifying paths and timeouts +struct AppLaunchData { + AppLaunchData(); + void clear(); + + QString binary; + QStringList args; + QString workingDirectory; + int upTimeMS; + int topLevelWindowTimeoutMS; + int terminationTimeoutMS; + bool splashScreen; +}; + +AppLaunchData::AppLaunchData() : + upTimeMS(defaultUpTimeMS), + topLevelWindowTimeoutMS(defaultTopLevelWindowTimeoutMS), + terminationTimeoutMS(defaultTerminationTimeoutMS), + splashScreen(false) +{ +} + +void AppLaunchData::clear() +{ + binary.clear(); + args.clear(); + workingDirectory.clear(); + upTimeMS = defaultUpTimeMS; + topLevelWindowTimeoutMS = defaultTopLevelWindowTimeoutMS; + terminationTimeoutMS = defaultTerminationTimeoutMS; + splashScreen = false; +} + +Q_DECLARE_METATYPE(AppLaunchData) + + +class tst_GuiAppLauncher : public QObject +{ + Q_OBJECT + +public: + // Test name (static const char title!) + data + typedef QPair<const char*, AppLaunchData> TestDataEntry; + typedef QList<TestDataEntry> TestDataEntries; + + enum { TestTools = 0x1, TestDemo = 0x2, TestExamples = 0x4, + TestAll = TestTools|TestDemo|TestExamples }; + + tst_GuiAppLauncher(); + +private Q_SLOTS: + void initTestCase(); + + void run(); + void run_data(); + + void cleanupTestCase(); + +private: + QString workingDir() const; + +private: + bool runApp(const AppLaunchData &data, QString *errorMessage) const; + TestDataEntries testData() const; + + const unsigned m_testMask; + const unsigned m_examplePriority; + const QString m_dir; + const QSharedPointer<WindowManager> m_wm; +}; + +// Test mask from enviroment as test lib does not allow options. +static inline unsigned testMask() +{ + unsigned testMask = tst_GuiAppLauncher::TestAll; + if (!qgetenv("QT_TEST_NOTOOLS").isEmpty()) + testMask &= ~ tst_GuiAppLauncher::TestTools; + if (!qgetenv("QT_TEST_NOEXAMPLES").isEmpty()) + testMask &= ~tst_GuiAppLauncher::TestExamples; + if (!qgetenv("QT_TEST_NODEMOS").isEmpty()) + testMask &= ~tst_GuiAppLauncher::TestDemo; + return testMask; +} + +static inline unsigned testExamplePriority() +{ + const QByteArray priorityD = qgetenv("QT_TEST_EXAMPLE_PRIORITY"); + if (!priorityD.isEmpty()) { + bool ok; + const unsigned rc = priorityD.toUInt(&ok); + if (ok) + return rc; + } + return 5; +} + +tst_GuiAppLauncher::tst_GuiAppLauncher() : + m_testMask(testMask()), + m_examplePriority(testExamplePriority()), + m_dir(QLatin1String(SRCDIR)), + m_wm(WindowManager::create()) +{ +} + +void tst_GuiAppLauncher::initTestCase() +{ + QString message = QString::fromLatin1("### App Launcher test on %1 in %2 (%3)"). + arg(QDateTime::currentDateTime().toString(), QDir::currentPath()). + arg(QLibraryInfo::buildKey()); + qDebug("%s", qPrintable(message)); + qWarning("### PLEASE LEAVE THE MACHINE UNATTENDED WHILE THIS TEST IS RUNNING\n"); + + // Does a window manager exist on the platform? + if (!m_wm->openDisplay(&message)) { + QSKIP(message.toLatin1().constData(), SkipAll); + } + + // Paranoia: Do we have our test file? + const QDir workDir(m_dir); + if (!workDir.exists()) { + message = QString::fromLatin1("Invalid working directory %1").arg(m_dir); + QFAIL(message.toLocal8Bit().constData()); + } +} + +void tst_GuiAppLauncher::run() +{ + QString errorMessage; + QFETCH(AppLaunchData, data); + const bool rc = runApp(data, &errorMessage); + if (!rc) // Wait for windows to disappear after kill + WindowManager::sleepMS(500); + QVERIFY2(rc, qPrintable(errorMessage)); +} + +// Cross platform galore! +static inline QString guiBinary(QString in) +{ +#ifdef Q_OS_MAC + return in + QLatin1String(".app/Contents/MacOS/") + in; +#endif + in[0] = in.at(0).toLower(); +#ifdef Q_OS_WIN + in += QLatin1String(".exe"); +#endif + return in; +} + +void tst_GuiAppLauncher::run_data() +{ + QTest::addColumn<AppLaunchData>("data"); + foreach(const TestDataEntry &data, testData()) + QTest::newRow(data.first) << data.second; +} + +// Read out the examples array structures and convert to test data. +static tst_GuiAppLauncher::TestDataEntries exampleData(unsigned priority, + const QString &path, + bool debug, + const Example *exArray, + unsigned n) +{ + Q_UNUSED(debug) + tst_GuiAppLauncher::TestDataEntries rc; + const QChar slash = QLatin1Char('/'); + AppLaunchData data; + for (unsigned e = 0; e < n; e++) { + const Example &example = exArray[e]; + if (example.priority <= priority) { + data.clear(); + const QString examplePath = path + slash + QLatin1String(example.directory); + data.binary = examplePath + slash; +#ifdef Q_OS_WIN + data.binary += debug? QLatin1String("debug/") : QLatin1String("release/"); +#endif + data.binary += guiBinary(QLatin1String(example.binary)); + data.workingDirectory = examplePath; + if (example.upTimeMS > 0) + data.upTimeMS = example.upTimeMS; + rc.append(tst_GuiAppLauncher::TestDataEntry(example.name, data)); + } + } + return rc; +} + +tst_GuiAppLauncher::TestDataEntries tst_GuiAppLauncher::testData() const +{ + TestDataEntries rc; + const QChar slash = QLatin1Char('/'); + const QString binPath = QLibraryInfo::location(QLibraryInfo::BinariesPath) + slash; + const bool debug = QLibraryInfo::buildKey().contains(QLatin1String("debug")); + Q_UNUSED(debug) + + AppLaunchData data; + + if (m_testMask & TestTools) { + data.binary = binPath + guiBinary(QLatin1String("Designer")); + data.args.append(m_dir + QLatin1String("test.ui")); + rc.append(TestDataEntry("Qt Designer", data)); + + data.clear(); + data.binary = binPath + guiBinary(QLatin1String("Linguist")); + data.splashScreen = true; + data.upTimeMS = 5000; // Slow loading + data.args.append(m_dir + QLatin1String("test.ts")); + rc.append(TestDataEntry("Qt Linguist", data)); + } + + if (m_testMask & TestDemo) { + data.clear(); + data.upTimeMS = 5000; // Startup animation + data.binary = binPath + guiBinary(QLatin1String("qtdemo")); + rc.append(TestDataEntry("Qt Demo", data)); + + const QString demosPath = QLibraryInfo::location(QLibraryInfo::DemosPath); + if (!demosPath.isEmpty()) + rc += exampleData(m_examplePriority, demosPath, debug, demos, sizeof(demos)/sizeof(Example)); + } + + if (m_testMask & TestExamples) { + const QString examplesPath = QLibraryInfo::location(QLibraryInfo::ExamplesPath); + if (!examplesPath.isEmpty()) + rc += exampleData(m_examplePriority, examplesPath, debug, examples, sizeof(examples)/sizeof(Example)); + } + qDebug("Running %d tests...", rc.size()); + return rc; +} + +static inline void ensureTerminated(QProcess *p) +{ + if (p->state() != QProcess::Running) + return; + p->terminate(); + if (p->waitForFinished(300)) + return; + p->kill(); + if (!p->waitForFinished(500)) + qWarning("Unable to terminate process"); +} + +bool tst_GuiAppLauncher::runApp(const AppLaunchData &data, QString *errorMessage) const +{ + qDebug("Launching: %s\n", qPrintable(data.binary)); + QProcess process; + process.setProcessChannelMode(QProcess::MergedChannels); + if (!data.workingDirectory.isEmpty()) + process.setWorkingDirectory(data.workingDirectory); + process.start(data.binary, data.args); + process.closeWriteChannel(); + if (!process.waitForStarted()) { + *errorMessage = QString::fromLatin1("Unable to execute %1: %2").arg(data.binary, process.errorString()); + return false; + } + // Get window id. + const QString winId = m_wm->waitForTopLevelWindow(data.splashScreen ? 2 : 1, process.pid(), data.topLevelWindowTimeoutMS, errorMessage); + if (winId.isEmpty()) { + ensureTerminated(&process); + return false; + } + qDebug("Window: %s\n", qPrintable(winId)); + // Wait a bit, then send close + WindowManager::sleepMS(data.upTimeMS); + if (m_wm->sendCloseEvent(winId, process.pid(), errorMessage)) { + qDebug("Sent close to window: %s\n", qPrintable(winId)); + } else { + ensureTerminated(&process); + return false; + } + // Terminate + if (!process.waitForFinished(data.terminationTimeoutMS)) { + *errorMessage = QString::fromLatin1("%1: Timeout %2ms").arg(data.binary).arg(data.terminationTimeoutMS); + ensureTerminated(&process); + return false; + } + if (process.exitStatus() != QProcess::NormalExit) { + *errorMessage = QString::fromLatin1("%1: Startup crash").arg(data.binary); + return false; + } + + const int exitCode = process.exitCode(); + // check stderr + const QStringList stderrOutput = QString::fromLocal8Bit(process.readAllStandardOutput()).split(QLatin1Char('\n')); + foreach(const QString &stderrLine, stderrOutput) { + // Skip expected QPainter warnings from oxygen. + if (stderrLine.startsWith(QLatin1String("QPainter:"))) { + qWarning("%s: stderr: %s\n", qPrintable(data.binary), qPrintable(stderrLine)); + } else { + if (!stderrLine.isEmpty()) { // Split oddity gives empty messages + *errorMessage = QString::fromLatin1("%1: Unexpected output (ex=%2): '%3'").arg(data.binary).arg(exitCode).arg(stderrLine); + return false; + } + } + } + + if (exitCode != 0) { + *errorMessage = QString::fromLatin1("%1: Exit code %2").arg(data.binary).arg(exitCode); + return false; + } + return true; +} + +void tst_GuiAppLauncher::cleanupTestCase() +{ +} + +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) +QTEST_NOOP_MAIN +#else +QTEST_APPLESS_MAIN(tst_GuiAppLauncher) +#endif + +#include "tst_guiapplauncher.moc" diff --git a/tests/auto/guiapplauncher/windowmanager.cpp b/tests/auto/guiapplauncher/windowmanager.cpp new file mode 100644 index 0000000..758a14e --- /dev/null +++ b/tests/auto/guiapplauncher/windowmanager.cpp @@ -0,0 +1,508 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "windowmanager.h" +#include <QtCore/QTime> +#include <QtCore/QThread> +#include <QtCore/QDebug> +#include <QtCore/QTextStream> + +#ifdef Q_WS_X11 +# include <string.h> // memset +# include <X11/Xlib.h> +# include <X11/Xatom.h> // XA_WM_STATE +# include <X11/Xutil.h> +# include <X11/Xmd.h> // CARD32 +#endif + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +# include <windows.h> +#endif + +// Export the sleep function +class FriendlySleepyThread : public QThread { +public: + static void sleepMS(int milliSeconds) { msleep(milliSeconds); } +}; + +#ifdef Q_WS_X11 +// X11 Window manager + +// Register our own error handler to prevent the defult crashing +// behaviour. It simply counts errors in global variables that +// can be checked after calls. + +static unsigned x11ErrorCount = 0; +static const char *currentX11Function = 0; + +int xErrorHandler(Display *, XErrorEvent *e) +{ + x11ErrorCount++; + + QString msg; + QTextStream str(&msg); + str << "An X11 error (#" << x11ErrorCount<< ") occurred: "; + if (currentX11Function) + str << ' ' << currentX11Function << "()"; + str << " code: " << e->error_code; + str.setIntegerBase(16); + str << " resource: 0x" << e->resourceid; + qWarning("%s", qPrintable(msg)); + + return 0; +} + +static bool isMapped(Display *display, Atom xa_wm_state, Window window, bool *isMapped) +{ + Atom actual_type; + int actual_format; + unsigned long nitems; + unsigned long bytes_after; + unsigned char *prop; + + *isMapped = false; + currentX11Function = "XGetWindowProperty"; + const int retv = XGetWindowProperty(display, window, xa_wm_state, 0L, 1L, False, xa_wm_state, + &actual_type, &actual_format, &nitems, &bytes_after, &prop); + + if (retv != Success || actual_type == None || actual_type != xa_wm_state + || nitems != 1 || actual_format != 32) + return false; + + const CARD32 state = * reinterpret_cast<CARD32 *>(prop); + + switch ((int) state) { + case WithdrawnState: + *isMapped = false; + break; + case NormalState: + case IconicState: + *isMapped = true; + break; + default: + *isMapped = true; + break; + } + return true; +} + +// Wait until a X11 top level has been mapped, courtesy of xtoolwait. +static Window waitForTopLevelMapped(Display *display, unsigned count, int timeOutMS, QString * errorMessage) +{ + unsigned mappingsCount = count; + Atom xa_wm_state; + XEvent event; + + // Discard all pending events + currentX11Function = "XSync"; + XSync(display, True); + + // Listen for top level creation + currentX11Function = "XSelectInput"; + XSelectInput(display, DefaultRootWindow(display), SubstructureNotifyMask); + + /* We assume that the window manager provides the WM_STATE property on top-level + * windows, as required by ICCCM 2.0. + * If the window manager has not yet completed its initialisation, the WM_STATE atom + * might not exist, in which case we create it. */ + +#ifdef XA_WM_STATE /* probably in X11R7 */ + xa_wm_state = XA_WM_STATE; +#else + xa_wm_state = XInternAtom(display, "WM_STATE", False); +#endif + + QTime elapsedTime; + elapsedTime.start(); + while (mappingsCount) { + if (elapsedTime.elapsed() > timeOutMS) { + *errorMessage = QString::fromLatin1("X11: Timed out waiting for toplevel %1ms").arg(timeOutMS); + return 0; + } + currentX11Function = "XNextEvent"; + unsigned errorCount = x11ErrorCount; + XNextEvent(display, &event); + if (x11ErrorCount > errorCount) { + *errorMessage = QString::fromLatin1("X11: Error in XNextEvent"); + return 0; + } + switch (event.type) { + case CreateNotify: + // Window created, listen for its mapping now + if (!event.xcreatewindow.send_event && !event.xcreatewindow.override_redirect) + XSelectInput(display, event.xcreatewindow.window, PropertyChangeMask); + break; + case PropertyNotify: + // Watch for map + if (!event.xproperty.send_event && event.xproperty.atom == xa_wm_state) { + bool mapped; + if (isMapped(display, xa_wm_state, event.xproperty.window, &mapped)) { + if (mapped && --mappingsCount == 0) + return event.xproperty.window; + // Past splash screen, listen for next window to be created + XSelectInput(display, DefaultRootWindow(display), SubstructureNotifyMask); + } else { + // Some temporary window disappeared. Listen for next creation + XSelectInput(display, DefaultRootWindow(display), SubstructureNotifyMask); + } + // Main app window opened? + } + break; + default: + break; + } + } + *errorMessage = QString::fromLatin1("X11: Timed out waiting for toplevel %1ms").arg(timeOutMS); + return 0; +} + + +class X11_WindowManager : public WindowManager +{ +public: + X11_WindowManager(); + ~X11_WindowManager(); + +protected: + virtual bool isDisplayOpenImpl() const; + virtual bool openDisplayImpl(QString *errorMessage); + virtual QString waitForTopLevelWindowImpl(unsigned count, Q_PID, int timeOutMS, QString *errorMessage); + virtual bool sendCloseEventImpl(const QString &winId, Q_PID pid, QString *errorMessage); + +private: + Display *m_display; + const QByteArray m_displayVariable; + XErrorHandler m_oldErrorHandler; +}; + +X11_WindowManager::X11_WindowManager() : + m_display(0), + m_displayVariable(qgetenv("DISPLAY")), + m_oldErrorHandler(0) +{ +} + +X11_WindowManager::~X11_WindowManager() +{ + if (m_display) { + XSetErrorHandler(m_oldErrorHandler); + XCloseDisplay(m_display); + } +} + +bool X11_WindowManager::isDisplayOpenImpl() const +{ + return m_display != 0; +} + +bool X11_WindowManager::openDisplayImpl(QString *errorMessage) +{ + if (m_displayVariable.isEmpty()) { + *errorMessage = QLatin1String("X11: Display not set"); + return false; + } + m_display = XOpenDisplay(NULL); + if (!m_display) { + *errorMessage = QString::fromLatin1("X11: Cannot open display %1.").arg(QString::fromLocal8Bit(m_displayVariable)); + return false; + } + + m_oldErrorHandler = XSetErrorHandler(xErrorHandler); + return true; +} + +QString X11_WindowManager::waitForTopLevelWindowImpl(unsigned count, Q_PID, int timeOutMS, QString *errorMessage) +{ + const Window w = waitForTopLevelMapped(m_display, count, timeOutMS, errorMessage); + if (w == 0) + return QString(); + return QLatin1String("0x") + QString::number(w, 16); +} + + bool X11_WindowManager::sendCloseEventImpl(const QString &winId, Q_PID, QString *errorMessage) + { + // Get win id + bool ok; + const Window window = winId.toULong(&ok, 16); + if (!ok) { + *errorMessage = QString::fromLatin1("Invalid win id %1.").arg(winId); + return false; + } + // Send a window manager close event + XEvent ev; + memset(&ev, 0, sizeof (ev)); + ev.xclient.type = ClientMessage; + ev.xclient.window = window; + ev.xclient.message_type = XInternAtom(m_display, "WM_PROTOCOLS", true); + ev.xclient.format = 32; + ev.xclient.data.l[0] = XInternAtom(m_display, "WM_DELETE_WINDOW", false); + ev.xclient.data.l[1] = CurrentTime; + // Window disappeared or some error triggered? + unsigned errorCount = x11ErrorCount; + currentX11Function = "XSendEvent"; + XSendEvent(m_display, window, False, NoEventMask, &ev); + if (x11ErrorCount > errorCount) { + *errorMessage = QString::fromLatin1("Error sending event to win id %1.").arg(winId); + return false; + } + currentX11Function = "XSync"; + errorCount = x11ErrorCount; + XSync(m_display, False); + if (x11ErrorCount > errorCount) { + *errorMessage = QString::fromLatin1("Error sending event to win id %1 (XSync).").arg(winId); + return false; + } + return true; + } + +#endif + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +// Windows + + QString winErrorMessage(unsigned long error) +{ + QString rc = QString::fromLatin1("#%1: ").arg(error); + ushort *lpMsgBuf; + + const int len = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL); + if (len) { + rc = QString::fromUtf16(lpMsgBuf, len); + LocalFree(lpMsgBuf); + } else { + rc += QString::fromLatin1("<unknown error>"); + } + return rc; +} + + class Win_WindowManager : public WindowManager + { + public: + Win_WindowManager() {} + + protected: + virtual bool isDisplayOpenImpl() const; + virtual bool openDisplayImpl(QString *errorMessage); + virtual QString waitForTopLevelWindowImpl(unsigned count, Q_PID, int timeOutMS, QString *errorMessage); + virtual bool sendCloseEventImpl(const QString &winId, Q_PID pid, QString *errorMessage); + + private: + }; + +bool Win_WindowManager::isDisplayOpenImpl() const +{ + return true; +} + +bool Win_WindowManager::openDisplayImpl(QString *) +{ + return true; +} + +// Enumerate window looking for toplevel of process id +struct FindProcessWindowEnumContext { + FindProcessWindowEnumContext(DWORD pid) : window(0),processId(pid) {} + + HWND window; + DWORD processId; +}; + +/* Check for the active main window of the Application + * of class QWidget. */ +static inline bool isQtMainWindow(HWND hwnd) +{ + static char buffer[MAX_PATH]; + if (!GetClassNameA(hwnd, buffer, MAX_PATH) || qstrcmp(buffer, "QWidget")) + return false; + WINDOWINFO windowInfo; + if (!GetWindowInfo(hwnd, &windowInfo)) + return false; + if (!(windowInfo.dwWindowStatus & WS_ACTIVECAPTION)) + return false; + // Check the style for a real mainwindow + const DWORD excluded = WS_DISABLED | WS_POPUP; + const DWORD required = WS_CAPTION | WS_SYSMENU | WS_VISIBLE; + return (windowInfo.dwStyle & excluded) == 0 + && (windowInfo.dwStyle & required) == required; +} + +static BOOL CALLBACK findProcessWindowEnumWindowProc(HWND hwnd, LPARAM lParam) +{ + DWORD processId = 0; + FindProcessWindowEnumContext *context= reinterpret_cast<FindProcessWindowEnumContext *>(lParam); + GetWindowThreadProcessId(hwnd, &processId); + if (context->processId == processId && isQtMainWindow(hwnd)) { + context->window = hwnd; + return FALSE; + } + return TRUE; +} + +QString Win_WindowManager::waitForTopLevelWindowImpl(unsigned /* count */, Q_PID pid, int timeOutMS, QString *errorMessage) +{ + QTime elapsed; + elapsed.start(); + // First, wait until the application is up + if (WaitForInputIdle(pid->hProcess, timeOutMS) != 0) { + *errorMessage = QString::fromLatin1("WaitForInputIdle time out after %1ms").arg(timeOutMS); + return QString(); + } + // Try to locate top level app window. App still might be in splash screen or initialization + // phase. + const int remainingMilliSeconds = qMax(timeOutMS - elapsed.elapsed(), 500); + const int attempts = 10; + const int intervalMilliSeconds = remainingMilliSeconds / attempts; + for (int a = 0; a < attempts; a++) { + FindProcessWindowEnumContext context(pid->dwProcessId); + EnumWindows(findProcessWindowEnumWindowProc, reinterpret_cast<LPARAM>(&context)); + if (context.window) + return QLatin1String("0x") + QString::number(reinterpret_cast<quintptr>(context.window), 16); + sleepMS(intervalMilliSeconds); + } + *errorMessage = QString::fromLatin1("Unable to find toplevel of process %1 after %2ms.").arg(pid->dwProcessId).arg(timeOutMS); + return QString(); +} + +bool Win_WindowManager::sendCloseEventImpl(const QString &winId, Q_PID, QString *errorMessage) +{ + // Convert window back. + quintptr winIdIntPtr; + QTextStream str(const_cast<QString*>(&winId), QIODevice::ReadOnly); + str.setIntegerBase(16); + str >> winIdIntPtr; + if (str.status() != QTextStream::Ok) { + *errorMessage = QString::fromLatin1("Invalid win id %1.").arg(winId); + return false; + } + if (!PostMessage(reinterpret_cast<HWND>(winIdIntPtr), WM_CLOSE, 0, 0)) { + *errorMessage = QString::fromLatin1("Cannot send event to 0x%1: %2").arg(winIdIntPtr, 0, 16).arg(winErrorMessage(GetLastError())); + return false; + } + return true; +} +#endif + +// ------- Default implementation + +WindowManager::WindowManager() +{ +} + +WindowManager::~WindowManager() +{ +} + +QSharedPointer<WindowManager> WindowManager::create() +{ +#ifdef Q_WS_X11 + return QSharedPointer<WindowManager>(new X11_WindowManager); +#endif +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + return QSharedPointer<WindowManager>(new Win_WindowManager); +#else + return QSharedPointer<WindowManager>(new WindowManager); +#endif +} + +static inline QString msgNoDisplayOpen() { return QLatin1String("No display opened."); } + +bool WindowManager::openDisplay(QString *errorMessage) +{ + if (isDisplayOpen()) + return true; + return openDisplayImpl(errorMessage); +} + +bool WindowManager::isDisplayOpen() const +{ + return isDisplayOpenImpl(); +} + + + +QString WindowManager::waitForTopLevelWindow(unsigned count, Q_PID pid, int timeOutMS, QString *errorMessage) +{ + if (!isDisplayOpen()) { + *errorMessage = msgNoDisplayOpen(); + return QString(); + } + return waitForTopLevelWindowImpl(count, pid, timeOutMS, errorMessage); +} + +bool WindowManager::sendCloseEvent(const QString &winId, Q_PID pid, QString *errorMessage) +{ + if (!isDisplayOpen()) { + *errorMessage = msgNoDisplayOpen(); + return false; + } + return sendCloseEventImpl(winId, pid, errorMessage); +} + +// Default Implementation +bool WindowManager::openDisplayImpl(QString *errorMessage) +{ + *errorMessage = QLatin1String("Not implemented."); + return false; +} + +bool WindowManager::isDisplayOpenImpl() const +{ + return false; +} + +QString WindowManager::waitForTopLevelWindowImpl(unsigned, Q_PID, int, QString *errorMessage) +{ + *errorMessage = QLatin1String("Not implemented."); + return QString(); +} + +bool WindowManager::sendCloseEventImpl(const QString &, Q_PID, QString *errorMessage) +{ + *errorMessage = QLatin1String("Not implemented."); + return false; +} + +void WindowManager::sleepMS(int milliSeconds) +{ + FriendlySleepyThread::sleepMS(milliSeconds); +} diff --git a/tests/auto/guiapplauncher/windowmanager.h b/tests/auto/guiapplauncher/windowmanager.h new file mode 100644 index 0000000..56e2eb9 --- /dev/null +++ b/tests/auto/guiapplauncher/windowmanager.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WINDOWMANAGER_H +#define WINDOWMANAGER_H + +#include <QtCore/QSharedPointer> +#include <QtCore/QString> +#include <QtCore/QProcess> + +/* WindowManager: Provides functions to retrieve the top level window of + * an application and send it a close event. */ + +class WindowManager +{ + Q_DISABLE_COPY(WindowManager) +public: + static QSharedPointer<WindowManager> create(); + + virtual ~WindowManager(); + + bool openDisplay(QString *errorMessage); + bool isDisplayOpen() const; + + // Count: Number of toplevels, 1 for normal apps, 2 for apps with a splash screen + QString waitForTopLevelWindow(unsigned count, Q_PID pid, int timeOutMS, QString *errorMessage); + bool sendCloseEvent(const QString &winId, Q_PID pid, QString *errorMessage); + + static void sleepMS(int milliSeconds); + +protected: + WindowManager(); + + virtual bool openDisplayImpl(QString *errorMessage); + virtual bool isDisplayOpenImpl() const; + virtual QString waitForTopLevelWindowImpl(unsigned count, Q_PID pid, int timeOutMS, QString *errorMessage); + virtual bool sendCloseEventImpl(const QString &winId, Q_PID pid, QString *errorMessage); +}; + +#endif // WINDOWMANAGER_H |