1
# Copyright (C) 2014 Canonical Ltd
3
# This file is part of Ubuntu Clock App
5
# Ubuntu Clock App is free software: you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License version 3 as
7
# published by the Free Software Foundation.
9
# Ubuntu Clock App is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
from autopilot import logging as autopilot_logging
21
from ubuntuuitoolkit import pickers
22
import ubuntuuitoolkit
24
logger = logging.getLogger(__name__)
27
class ClockEmulatorException(ubuntuuitoolkit.ToolkitException):
29
"""Exception raised when there is an error with the emulator."""
32
class MainView(ubuntuuitoolkit.MainView):
34
@autopilot_logging.log_action(logger.info)
36
"""Open the Clock Page.
38
:return the Clock Page
41
return self.wait_select_single(ClockPage)
43
@autopilot_logging.log_action(logger.info)
45
"""Open the Alarm Page.
47
:return: the Alarm Page.
50
clockPage = self.wait_select_single(ClockPage)
51
clockPage.drag_bottomEdge_up()
52
self.get_header().visible.wait_for(True)
53
return self.wait_select_single(Page11)
55
def get_AlarmList(self):
56
""" Get the AlarmList object. """
57
return AlarmList.select(self)
60
class Page(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
62
"""Autopilot helper for Pages."""
64
def __init__(self, *args):
65
super(Page, self).__init__(*args)
66
# XXX we need a better way to keep reference to the main view.
67
# --elopio - 2014-01-31
68
self.main_view = self.get_root_instance().select_single(MainView)
71
class ClockPage(Page):
73
"""Autopilot helper for the Clock page."""
75
@autopilot_logging.log_action(logger.info)
76
def drag_bottomEdge_up(self):
77
"""Function to drag the bottom edge up."""
78
self._click_bottomEdge()
80
x, y, w, h = self.globalRect
81
start_x = stop_x = x + (w / 2)
85
self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
87
self._wait_for_ClockPage_to_close()
89
def _click_bottomEdge(self):
90
"""Function to click on the bottom edge."""
91
bottomEdge = self.wait_select_single(
92
'QQuickItem', objectName='bottomEdgeTip')
93
self.pointing_device.click_object(bottomEdge)
95
def _wait_for_ClockPage_to_close(self):
96
self.isCollapsed.wait_for(False)
101
"""Autopilot helper for the Alarm page."""
103
@autopilot_logging.log_action(logger.info)
104
def add_single_alarm(self, name, day, time_to_set, test_sound_name):
105
"""Add a single type alarm
107
:param name: name of alarm
108
:param day: day on which the alarm should be triggered
109
:param time_to_set: time to set alarm to
110
:param test_sound_name: sound to set in alarm
113
alarmListPage = AlarmList.select(self.main_view)
114
old_alarm_count = alarmListPage.get_num_of_alarms()
116
edit_alarm_page = self._click_add_alarm_button()
117
edit_alarm_page.set_alarm_time(time_to_set)
119
alarm_repeat_page = edit_alarm_page.open_alarmRepeat_page()
120
alarm_repeat_page.set_single_alarm_day(day)
121
self._click_header_backButton()
123
alarm_label_page = edit_alarm_page.open_alarmLabel_page()
124
alarm_label_page.set_alarm_label(name)
125
self._click_header_customBackButton()
127
alarm_sound_page = edit_alarm_page.open_alarmSound_page()
128
alarm_sound_page.set_alarm_sound(test_sound_name)
129
self._click_header_customBackButton()
130
edit_alarm_page._check_sound_changed(test_sound_name)
133
self._confirm_alarm_creation(old_alarm_count)
135
def _click_add_alarm_button(self):
136
"""Click the add alarm header button."""
137
header = self.main_view.get_header()
138
header.click_action_button('addAlarmAction')
139
return self.main_view.wait_select_single(EditAlarmPage)
141
def _click_header_customBackButton(self):
142
"""Click the header button: 'customBackButton' """
143
header = self.main_view.get_header()
144
header.click_custom_back_button()
146
def _click_header_backButton(self):
147
"""Click the header button: 'backButton' """
148
header = self.main_view.get_header()
149
header.click_back_button()
151
def _click_save(self):
152
"""Click the save timer header button"""
153
header = self.main_view.get_header()
154
header.click_action_button('saveAlarmAction')
156
def _confirm_alarm_creation(self, count):
157
"""Confirm creation of alarm
159
:param count: alarm count before alarm creation
163
AlarmList.select(self.main_view)._get_saved_alarms_list().\
164
count.wait_for(count + 1)
165
except AssertionError:
166
raise ClockEmulatorException('Error creating alarm.')
169
class EditAlarmPage(Page):
171
"""Autopilot helper for the Add Alarm page."""
173
@autopilot_logging.log_action(logger.info)
174
def set_alarm_time(self, time_to_set):
175
"""Set alarm time on datepicker.
177
:param time_to_set: time to set on datepicker
180
PickerRow_HoursPicker = self.wait_select_single(
181
"Picker", objectName="PickerRow_HoursPicker")
182
self._set_picker(PickerRow_HoursPicker, 'time', time_to_set)
184
def _set_picker(self, field, mode, value):
186
self.pointing_device.click_object(field)
187
# valid options are date or time; assume date if invalid/no option
188
mode_value = 'Hours|Minutes'
189
picker = self.wait_select_single(
190
pickers.DatePicker, mode=mode_value, visible=True)
191
picker.pick_time(value)
193
self.pointing_device.click_object(field)
195
@autopilot_logging.log_action(logger.info)
196
def open_alarmRepeat_page(self):
197
""" Open the alarmRepeat page """
199
alarmRepeatItem = self.wait_select_single(
200
"SubtitledListItem", objectName="alarmRepeat")
201
self.pointing_device.click_object(alarmRepeatItem)
202
return self.main_view.wait_select_single(AlarmRepeat)
204
@autopilot_logging.log_action(logger.info)
205
def open_alarmLabel_page(self):
206
""" Open the alarmLabel page """
208
alarmLabelItem = self.wait_select_single(
209
"SubtitledListItem", objectName="alarmLabel")
210
self.pointing_device.click_object(alarmLabelItem)
211
return AlarmLable.select(self.main_view)
213
@autopilot_logging.log_action(logger.info)
214
def open_alarmSound_page(self):
215
""" Open the alarmSound page """
217
alarmSoundItem = self.wait_select_single(
218
"SubtitledListItem", objectName="alarmSound")
219
self.pointing_device.click_object(alarmSoundItem)
220
return self.main_view.wait_select_single(AlarmSound)
222
def _check_sound_changed(self, test_sound_name):
223
""" function to check that sound has changed.
225
:param test_sound_name = new sound name
228
self.wait_select_single("SubtitledListItem", objectName="alarmSound")\
229
.subText == test_sound_name
232
class AlarmRepeat(Page):
234
"""Autopilot helper for the AlarmRepeat page."""
236
@autopilot_logging.log_action(logger.info)
237
def set_single_alarm_day(self, day):
238
"""Set the alarm day of a single type alarm.
240
:param day: single day on which alarm is triggered
243
self.unselect_selected_days()
245
for index in range(self._get_num_of_days()):
246
if self.wait_select_single(
247
'Label', objectName='alarmDay{}'.format(index))\
249
self._select_single_alarm_day(index)
252
def _get_num_of_days(self):
253
return int(self.wait_select_single(
254
'QQuickRepeater', objectName='alarmDays').count)
256
def _select_single_alarm_day(self, index):
257
""" function for selecting the day passed to the function.
259
:param index: the day to be selected
262
dayCheckbox = self.wait_select_single(
263
'CheckBox', objectName='daySwitch{}'.format(index))
266
@autopilot_logging.log_action(logger.info)
267
def unselect_selected_days(self):
268
""" function for unselecting already selected days. """
269
for index in range(self._get_num_of_days()):
270
dayCheckbox = self.wait_select_single(
271
'CheckBox', objectName='daySwitch{}'.format(index))
272
dayCheckbox.uncheck()
275
class AlarmSound(Page):
277
"""Autopilot helper for the AlarmSound page."""
279
@autopilot_logging.log_action(logger.info)
280
def set_alarm_sound(self, test_sound_name):
283
:param test_sound_name: sound to set for alarm
286
for index in range(self._get_num_of_sounds()):
287
if self.wait_select_single(
288
'Label', objectName='soundName{}'.format(index)).\
289
text == test_sound_name:
290
self._select_alarm_sound(index)
293
def _get_num_of_sounds(self):
294
return int(self.wait_select_single(
295
'QQuickRepeater', objectName='alarmSounds').count)
297
def _select_alarm_sound(self, index):
298
""" function for selecting the sound passed to the function.
300
:param index: the sound to be selected
303
soundCheckbox = self.wait_select_single(
304
'CheckBox', objectName='soundStatus{}'.format(index))
305
soundCheckbox.check()
308
class AlarmLable(object):
310
"""Autopilot helper for the AlarmLabel page."""
312
def __init__(self, proxy_object):
313
super(AlarmLable, self).__init__()
314
self.proxy_object = proxy_object
317
def select(cls, main_view):
318
proxy_object = main_view.wait_select_single(
319
objectName='alarmLabelPage')
320
proxy_object.visible.wait_for(True)
321
return cls(proxy_object)
323
@autopilot_logging.log_action(logger.info)
324
def set_alarm_label(self, name):
327
:param name: label for alarm to set
330
alarmTextfield = self.proxy_object.wait_select_single(
331
"TextField", objectName='labelEntry')
332
# TODO: This wait to ensure that the textfield is visible before
333
# entering text should be part of the SDK emulator. Until then, it has
334
# been added here. http://pad.lv/1289616 --nik90 2014-03-06
335
alarmTextfield.visible.wait_for(True)
336
alarmTextfield.write(name)
339
class AlarmList(object):
341
"""Autopilot helper for the AlarmList."""
343
def __init__(self, proxy_object):
344
super(AlarmList, self).__init__()
345
self.proxy_object = proxy_object
348
def select(cls, main_view):
349
proxy_object = main_view.wait_select_single(
350
objectName='alarmListFlickable')
351
proxy_object.visible.wait_for(True)
352
return cls(proxy_object)
354
def get_num_of_alarms(self):
355
"""Return the number of saved alarms."""
356
return int(self._get_saved_alarms_list().count)
358
def _get_saved_alarms_list(self):
359
"""Return the saved alarm list"""
360
return self.proxy_object.wait_select_single(
361
'QQuickRepeater', objectName='alarmListRepeater')
363
def get_saved_alarms(self):
364
"""Return a list with the information of the saved alarms.
366
Each item of the returned list is a tuple of
367
(name, recurrence, time, enabled).
371
for index in range(self.get_num_of_alarms()):
372
name = self.proxy_object.wait_select_single(
373
'Label', objectName='listAlarmLabel{}'.format(index)).text
374
recurrence = self.proxy_object.wait_select_single(
375
'Label', objectName='listAlarmSubtitle{}'.format(index)).text
376
time = self.proxy_object.wait_select_single(
377
'Label', objectName='listAlarmTime{}'.format(index)).text
378
enabled = self.proxy_object.wait_select_single(
379
ubuntuuitoolkit.CheckBox,
380
objectName='listAlarmStatus{}'.format(index)).checked
381
alarms.append((name, recurrence, enabled, time))
384
@autopilot_logging.log_action(logger.info)
385
def delete_alarm(self, index):
386
"""Delete an alarm at the specified index."""
387
old_alarm_count = self.get_num_of_alarms()
388
alarm = self.proxy_object.wait_select_single(
389
'Base', objectName='alarm{}'.format(index))
390
alarm.swipe_to_delete()
391
alarm.confirm_removal()
393
self._get_saved_alarms_list().count.wait_for(old_alarm_count - 1)
394
except AssertionError:
395
raise ClockEmulatorException('Error deleting alarm.')