1#  Copyright (c) 2019, Enthought, Inc.
2#  All rights reserved.
3#
4#  This software is provided without warranty under the terms of the BSD
5#  license included in LICENSE.txt and may be redistributed only
6#  under the conditions described in the aforementioned license.  The license
7#  is also available online at http://www.enthought.com/licenses/BSD.txt
8
9import unittest
10
11from pyface.timer.api import CallbackTimer
12from traits.api import HasTraits, Instance, Int
13from traitsui.api import Handler, Item, UIInfo, View, toolkit
14
15from ._tools import (
16    BaseTestMixin, GuiTestAssistant, is_qt, no_gui_test_assistant
17)
18
19
20class SimpleModel(HasTraits):
21    cell = Int()
22
23
24class ClosableHandler(Handler):
25
26    info = Instance(UIInfo)
27
28    def init(self, info):
29        self.info = info
30        return True
31
32    def test_close(self):
33        self.info.ui.dispose()
34
35
36simple_view = View(
37    Item("cell"), title="Enter IDs and conditions", buttons=["OK", "Cancel"]
38)
39
40
41@unittest.skipIf(no_gui_test_assistant, "No GuiTestAssistant")
42class TestViewApplication(BaseTestMixin, GuiTestAssistant, unittest.TestCase):
43    def setUp(self):
44        BaseTestMixin.setUp(self)
45        GuiTestAssistant.setUp(self)
46        self.model = SimpleModel()
47        self.handler = ClosableHandler()
48        self.event_loop_timeout = False
49        self.closed = False
50
51        if is_qt():
52            if len(self.qt_app.topLevelWidgets()) > 0:
53                with self.event_loop_with_timeout(repeat=5):
54                    self.gui.invoke_later(self.qt_app.closeAllWindows)
55
56    def tearDown(self):
57        GuiTestAssistant.tearDown(self)
58        BaseTestMixin.tearDown(self)
59
60    def view_application(self, kind, button=None):
61        if button is None:
62            self.gui.invoke_later(self.close_dialog)
63        else:
64            self.gui.invoke_later(self.click_button, text=button)
65
66        timer = CallbackTimer.single_shot(
67            callback=self.stop_event_loop, interval=1.0
68        )
69        try:
70            self.result = toolkit().view_application(
71                context=self.model,
72                view=simple_view,
73                kind=kind,
74                handler=self.handler,
75            )
76        finally:
77            timer.stop()
78
79    def view_application_event_loop(self, kind):
80        with self.event_loop_until_condition(lambda: self.closed):
81            self.gui.invoke_later(
82                toolkit().view_application,
83                context=self.model,
84                view=simple_view,
85                kind=kind,
86                handler=self.handler,
87            )
88            self.gui.invoke_after(100, self.close_dialog)
89
90    def close_dialog(self):
91        if is_qt():
92            self.handler.info.ui.control.close()
93            self.closed = True
94        else:
95            raise NotImplementedError("Can't close current backend")
96
97    def click_button(self, text):
98        if is_qt():
99            from pyface.qt.QtGui import QPushButton
100            from pyface.ui.qt4.util.testing import find_qt_widget
101
102            button = find_qt_widget(
103                self.handler.info.ui.control,
104                QPushButton,
105                lambda widget: widget.text() == text,
106            )
107            if button is None:
108                raise RuntimeError("Can't find {} button".format(text))
109            button.click()
110            self.closed = True
111        else:
112            raise NotImplementedError("Can't click current backend")
113
114    def stop_event_loop(self):
115        self.gui.stop_event_loop()
116        self.event_loop_timeout = True
117
118    def test_modal_view_application_close(self):
119        self.view_application("modal")
120
121        self.assertTrue(self.closed)
122        self.assertFalse(self.event_loop_timeout)
123        self.assertFalse(self.result)
124
125    def test_nonmodal_view_application_close(self):
126        self.view_application("nonmodal")
127
128        self.assertTrue(self.closed)
129        self.assertFalse(self.event_loop_timeout)
130        self.assertTrue(self.result)
131
132    def test_livemodal_view_application_close(self):
133        self.view_application("livemodal")
134
135        self.assertTrue(self.closed)
136        self.assertFalse(self.event_loop_timeout)
137        self.assertFalse(self.result)
138
139    def test_live_view_application_close(self):
140        self.view_application("live")
141
142        self.assertTrue(self.closed)
143        self.assertFalse(self.event_loop_timeout)
144        self.assertTrue(self.result)
145
146    def test_modal_view_application_ok(self):
147        self.view_application("modal", button="OK")
148
149        self.assertTrue(self.closed)
150        self.assertFalse(self.event_loop_timeout)
151        self.assertTrue(self.result)
152
153    def test_nonmodal_view_application_ok(self):
154        self.view_application("nonmodal", button="OK")
155
156        self.assertTrue(self.closed)
157        self.assertFalse(self.event_loop_timeout)
158        self.assertTrue(self.result)
159
160    def test_livemodal_view_application_ok(self):
161        self.view_application("livemodal", button="OK")
162
163        self.assertTrue(self.closed)
164        self.assertFalse(self.event_loop_timeout)
165        self.assertTrue(self.result)
166
167    def test_live_view_application_ok(self):
168        self.view_application("live", button="OK")
169
170        self.assertTrue(self.closed)
171        self.assertFalse(self.event_loop_timeout)
172        self.assertTrue(self.result)
173
174    def test_modal_view_application_cancel(self):
175        self.view_application("modal", button="Cancel")
176
177        self.assertTrue(self.closed)
178        self.assertFalse(self.event_loop_timeout)
179        self.assertFalse(self.result)
180
181    def test_nonmodal_view_application_cancel(self):
182        self.view_application("nonmodal", button="Cancel")
183
184        self.assertTrue(self.closed)
185        self.assertFalse(self.event_loop_timeout)
186        self.assertFalse(self.result)
187
188    def test_livemodal_view_application_cancel(self):
189        self.view_application("livemodal", button="Cancel")
190
191        self.assertTrue(self.closed)
192        self.assertFalse(self.event_loop_timeout)
193        self.assertFalse(self.result)
194
195    def test_live_view_application_cancel(self):
196        self.view_application("live", button="Cancel")
197
198        self.assertTrue(self.closed)
199        self.assertFalse(self.event_loop_timeout)
200        self.assertFalse(self.result)
201
202    def test_modal_view_application_eventloop_close(self):
203        self.view_application_event_loop("modal")
204
205        self.assertTrue(self.closed)
206        self.assertFalse(self.event_loop_timeout)
207
208    def test_nonmodal_view_application_eventloop_close(self):
209        self.view_application_event_loop("nonmodal")
210
211        self.assertTrue(self.closed)
212        self.assertFalse(self.event_loop_timeout)
213
214    def test_livemodal_view_application_eventloop_close(self):
215        self.view_application_event_loop("livemodal")
216
217        self.assertTrue(self.closed)
218        self.assertFalse(self.event_loop_timeout)
219
220    def test_live_view_application_eventloop_close(self):
221        self.view_application_event_loop("live")
222
223        self.assertTrue(self.closed)
224        self.assertFalse(self.event_loop_timeout)
225