Unity 8
 All Classes Functions Properties
dash.py
1 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2 #
3 # Unity Autopilot Test Suite
4 # Copyright (C) 2012, 2013, 2014 Canonical
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #
19 
20 import logging
21 
22 from unity8.shell import emulators
23 
24 from autopilot import logging as autopilot_logging
25 from autopilot.introspection import dbus
26 from testtools.matchers import MatchesAny, Equals
27 from ubuntuuitoolkit import emulators as toolkit_emulators
28 
29 
30 logger = logging.getLogger(__name__)
31 
32 
34  """An emulator that understands the Dash."""
35 
36  def __init__(self, *args):
37  super(Dash, self).__init__(*args)
38  self.dash_content_list = self.wait_select_single(
39  'QQuickListView', objectName='dashContentList')
40 
41  def get_applications_grid(self):
42  get_grid = self.get_scope('clickscope').wait_select_single(
43  'CardFilterGrid', objectName='local')
44  return get_grid
45 
46  def get_application_icon(self, text):
47  """Returns a 'Tile' icon that has the text 'text' from the application
48  grid.
49 
50  :param text: String containing the text of the icon to search for.
51 
52  """
53  app_grid = self.get_applications_grid()
54  resp_grid = app_grid.wait_select_single('ResponsiveGridView')
55  return resp_grid.select_single('Tile', text=text)
56 
57  def get_scope(self, scope_name='clickscope'):
58  return self.dash_content_list.select_single(
59  'QQuickLoader', scopeId=scope_name)
60 
61  @autopilot_logging.log_action(logger.info)
62  def open_scope(self, scope_id):
63  """Open a dash scope.
64 
65  :parameter scope_id: The id of the scope.
66  :return: The scope.
67 
68  """
69  scope_loader = self._get_scope_loader(scope_id)
70  if scope_loader.isCurrent:
71  logger.info('The scope is already open.')
72  return self._get_scope_from_loader(scope_loader)
73  else:
74  return self._open_scope_scrolling(scope_loader)
75 
76  def _get_scope_loader(self, scope_id):
77  try:
78  return self.dash_content_list.select_single(
79  'QQuickLoader', scopeId=scope_id)
80  except dbus.StateNotFoundError:
82  'No scope found with id {0}'.format(scope_id))
83 
84  def _get_scope_from_loader(self, loader):
85  return loader.get_children()[0]
86 
87  def _open_scope_scrolling(self, scope_loader):
88  scroll = self._get_scroll_direction(scope_loader)
89 
90  while not scope_loader.isCurrent:
91  scroll()
92  self.dash_content_list.moving.wait_for(False)
93 
94  scope = self._get_scope_from_loader(scope_loader)
95  scope.isCurrent.wait_for(True)
96  return scope
97 
98  def _get_scroll_direction(self, scope_loader):
99  current_scope_loader = self.dash_content_list.select_single(
100  'QQuickLoader', isCurrent=True)
101  if scope_loader.globalRect.x < current_scope_loader.globalRect.x:
102  return self._scroll_to_left_scope
103  elif scope_loader.globalRect.x > current_scope_loader.globalRect.x:
104  return self._scroll_to_right_scope
105  else:
106  raise emulators.UnityEmulatorException('The scope is already open')
107 
108  @autopilot_logging.log_action(logger.info)
109  def _scroll_to_left_scope(self):
110  original_index = self.dash_content_list.currentIndex
111  # Scroll on the border of the page header, because some scopes have
112  # contents that can be scrolled horizontally.
113  page_header = self._get_page_header()
114  border = page_header.select_single('QQuickBorderImage')
115  start_x = border.width / 3
116  stop_x = border.width / 3 * 2
117  start_y = stop_y = border.globalRect.y + border.height / 2
118  self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
119  self.dash_content_list.currentIndex.wait_for(original_index - 1)
120 
121  def _get_page_header(self):
122  return self.select_single('PageHeader', objectName='pageHeader')
123 
124  @autopilot_logging.log_action(logger.info)
125  def _scroll_to_right_scope(self):
126  original_index = self.dash_content_list.currentIndex
127  # Scroll on the border of the page header, because some scopes have
128  # contents that can be scrolled horizontally.
129  page_header = self._get_page_header()
130  border = page_header.select_single('QQuickBorderImage')
131  start_x = border.width / 3 * 2
132  stop_x = border.width / 3
133  start_y = stop_y = border.globalRect.y + border.height / 2
134  self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
135  self.dash_content_list.currentIndex.wait_for(original_index + 1)
136 
137  def enter_search_query(self, query):
138  search_text_field = self._get_search_text_field()
139  search_text_field.write(query)
140  search_text_field.state.wait_for('idle')
141 
142  def _get_search_text_field(self):
143  page_header = self._get_page_header()
144  search_container = page_header.select_single(
145  'QQuickItem', objectName='searchContainer')
146  search_container.state.wait_for(
147  MatchesAny(Equals('narrowActive'), Equals('active')))
148  return search_container.select_single(toolkit_emulators.TextField)
149 
150 
152  """Autopilot emulator for generic scopes."""
153 
154  @autopilot_logging.log_action(logger.info)
155  def open_preview(self, category, app_name):
156  """Open the preview of an application.
157 
158  :parameter category: The name of the category where the application is.
159  :app_name: The name of the application.
160  :return: The opened preview.
161 
162  """
163  category_element = self._get_category_element(category)
164  icon = category_element.select_single('AbstractButton', title=app_name)
165  # FIXME some categories need a long press in order to see the preview.
166  # Some categories do not show previews, like recent apps.
167  # --elopio - 2014-1-14
168  self.pointing_device.click_object(icon)
169  preview_list = self.get_root_instance().wait_select_single(
170  'PreviewListView', objectName='dashContentPreviewList')
171  preview_list.x.wait_for(0)
172  return preview_list.select_single(
173  Preview, objectName='preview{}'.format(preview_list.currentIndex))
174 
175  def _get_category_element(self, category):
176  try:
177  return self.wait_select_single(
178  'Base', objectName='dashCategory{}'.format(category))
179  except dbus.StateNotFoundError:
181  'No category found with name {}'.format(category))
182 
183 
185  """Autopilot emulator for the applications scope."""
186 
187  def get_applications(self, category):
188  """Return the list of applications on a category.
189 
190  :parameter category: The name of the category.
191 
192  """
193  category_element = self._get_category_element(category)
194  application_cards = category_element.select_many('AbstractButton')
195 
196  # sort by y, x
197  application_cards = sorted(
198  application_cards,
199  key=lambda card: (card.globalRect.y, card.globalRect.x))
200 
201  result = []
202  for card in application_cards:
203  if card.objectName != 'cardToolCard':
204  result.append(card.title)
205  return result
206 
207 
209  """Autopilot custom proxy object for generic previews."""