""" LDTP v2 Core Table. @author: Eitan Isaacson @author: Nagappan Alagappan @copyright: Copyright (c) 2009 Eitan Isaacson @copyright: Copyright (c) 2009-13 Nagappan Alagappan @license: LGPL http://ldtp.freedesktop.org This file may be distributed and/or modified under the terms of the GNU Lesser General Public License version 2 as published by the Free Software Foundation. This file is distributed without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See 'COPYING' in the source distribution for more information. Headers in this file shall remain intact. """ import re import time import pyatspi from utils import Utils from server_exception import LdtpServerException from keypress_actions import KeyComboAction, KeyPressAction, KeyReleaseAction class Table(Utils): def getrowcount(self, window_name, object_name): """ Get count of rows in table object. @param window_name: Window name to look for, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to look for, either full name, LDTP's name convention, or a Unix glob. Or menu heirarchy @type object_name: string @return: Number of rows. @rtype: integer """ obj = self._get_object(window_name, object_name) try: itable = obj.queryTable() except NotImplementedError: raise LdtpServerException('object %s is not a table' % object_name) return itable.nRows def selectrow(self, window_name, object_name, row_text, partial_match=False): """ Select row @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_text: Row text to select @type row_text: string @return: 1 on success. @rtype: integer """ if partial_match: return self.selectrowpartialmatch(window_name, object_name, row_text) obj = self._get_object(window_name, object_name) try: tablei = obj.queryTable() except NotImplementedError: raise LdtpServerException('Object not table type.') for i in range(0, tablei.nRows): for j in range(0, tablei.nColumns): cell = tablei.getAccessibleAt(i, j) if not cell: continue if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: if self._match_name_to_acc(row_text, child): self._grab_focus(child) return 1 finally: if not flag: self._handle_table_cell = False elif self._match_name_to_acc(row_text, cell): self._grab_focus(cell) return 1 raise LdtpServerException('Unable to select row: %s' % row_text) def selectrowpartialmatch(self, window_name, object_name, row_text): """ Select row partial match @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_text: Row text to select @type row_text: string @return: 1 on success. @rtype: integer """ obj = self._get_object(window_name, object_name) try: tablei = obj.queryTable() except NotImplementedError: raise LdtpServerException('Object not table type.') for i in range(0, tablei.nRows): for j in range(0, tablei.nColumns): cell = tablei.getAccessibleAt(i, j) if not cell: continue if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: if re.search(row_text, child.name): self._grab_focus(child) return 1 finally: if not flag: self._handle_table_cell = False elif self._match_name_to_acc(row_text, cell): self._grab_focus(cell) return 1 raise LdtpServerException('Unable to select row: %s' % row_text) def multiselect(self, window_name, object_name, row_text_list, partial_match=False): """ Select multiple row @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_text_list: Row list with matching text to select @type row_text: string @return: 1 on success. @rtype: integer """ if partial_match: return self.selectrowpartialmatch(window_name, object_name, row_text) obj = self._get_object(window_name, object_name) self._grab_focus(obj) try: tablei = obj.queryTable() except NotImplementedError: raise LdtpServerException('Object not table type.') key_press_action=KeyPressAction(key_name="") key_press_action() try: for row_text in row_text_list: selected_rows = False for i in range(0, tablei.nRows): for j in range(0, tablei.nColumns): cell = tablei.getAccessibleAt(i, j) if not cell: continue if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: if self._match_name_to_acc(row_text, child): time.sleep(1) size = self._get_size(cell) if pyatspi.state.STATE_SELECTED not \ in cell.getState().getStates(): self._mouse_event(size[0] + size[2]/2, size[1] + size[3]/2) else: # Table Cell already selected pass selected_rows = True break finally: if not flag: self._handle_table_cell = False elif self._match_name_to_acc(row_text, cell): time.sleep(1) size = self._get_size(cell) if pyatspi.state.STATE_SELECTED not \ in cell.getState().getStates(): self._mouse_event(size[0] + size[2]/2, size[1] + size[3]/2) selected_rows = True if not selected_rows: raise LdtpServerException('Unable to select row: %s' % row_text) finally: key_release_action=KeyReleaseAction(key_name="") key_release_action() if selected_rows: return 1 raise LdtpServerException('Unable to select rows') def multiremove(self, window_name, object_name, row_text_list, partial_match=False): """ Remove multiple row @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_text_list: Row list with matching text to select @type row_text: string @return: 1 on success. @rtype: integer """ if partial_match: return self.selectrowpartialmatch(window_name, object_name, row_text) obj = self._get_object(window_name, object_name) self._grab_focus(obj) try: tablei = obj.queryTable() except NotImplementedError: raise LdtpServerException('Object not table type.') key_press_action=KeyPressAction(key_name="") key_press_action() try: for row_text in row_text_list: unselected_rows = False for i in range(0, tablei.nRows): for j in range(0, tablei.nColumns): cell = tablei.getAccessibleAt(i, j) if not cell: continue if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: if self._match_name_to_acc(row_text, child): time.sleep(1) size = self._get_size(cell) if pyatspi.state.STATE_SELECTED \ in cell.getState().getStates(): self._mouse_event(size[0] + size[2]/2, size[1] + size[3]/2) else: # Table Cell wasn't selected pass unselected_rows = True break finally: if not flag: self._handle_table_cell = False elif self._match_name_to_acc(row_text, cell): time.sleep(1) size = self._get_size(cell) if pyatspi.state.STATE_SELECTED \ in cell.getState().getStates(): self._mouse_event(size[0] + size[2]/2, size[1] + size[3]/2) unselected_rows = True if not unselected_rows: raise LdtpServerException('Unable to unselect row: %s' % row_text) finally: key_release_action=KeyReleaseAction(key_name="") key_release_action() if unselected_rows: return 1 raise LdtpServerException('Unable to unselect rows') def selectrowindex(self, window_name, object_name, row_index): """ Select row index @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_index: Row index to select @type row_index: integer @return: 1 on success. @rtype: integer """ obj = self._get_object(window_name, object_name) try: tablei = obj.queryTable() except NotImplementedError: raise LdtpServerException('Object not table type.') if row_index < 0 or row_index > tablei.nRows: raise LdtpServerException('Row index out of range: %d' % row_index) cell = tablei.getAccessibleAt(row_index, 0) self._grab_focus(cell) return 1 def selectlastrow(self, window_name, object_name): """ Select last row @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @return: 1 on success. @rtype: integer """ obj = self._get_object(window_name, object_name) try: tablei = obj.queryTable() except NotImplementedError: raise LdtpServerException('Object not table type.') cell = tablei.getAccessibleAt(tablei.nRows - 1, 0) self._grab_focus(cell) return 1 def setcellvalue(self, window_name, object_name, row_index, column = 0, data = None): """ Set cell value @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_index: Row index to get @type row_index: integer @param column: Column index to get, default value 0 @type column: integer @param data: data, default value None None, used for toggle button @type data: string @return: 1 on success. @rtype: integer """ obj = self._get_object(window_name, object_name) cell = self._get_accessible_at_row_column(obj, row_index, column) name = None if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: try: iaction = child.queryAction() except NotImplementedError: iaction = None if iaction: for i in xrange(iaction.nActions): # If the cell is toggle type if re.match('toggle', iaction.getName(i), re.I): iaction.doAction(i) self._grab_focus(child) return 1 elif re.match('edit', iaction.getName(i), re.I): try: texti = cell.queryEditableText() except NotImplementedError: continue self._grab_focus(child) if not data: raise LdtpServerException('data cannot be empty string.') return int(texti.setTextContents(data.encode('utf-8'))) else: raise LdtpServerException('Text cannot be entered into object.') finally: if not flag: self._handle_table_cell = False else: try: iaction = cell.queryAction() except NotImplementedError: iaction = None self._grab_focus(cell) if iaction: for i in xrange(iaction.nActions): # If the cell is toggle type if re.match('toggle', iaction.getName(i), re.I): iaction.doAction(i) return 1 elif re.match('edit', iaction.getName(i), re.I): try: texti = cell.queryEditableText() except NotImplementedError: raise LdtpServerException('Text cannot be entered into object.') if not data: raise LdtpServerException('data cannot be empty string.') return int(texti.setTextContents(data.encode('utf-8'))) raise LdtpServerException('Text cannot be entered into object.') def getcellvalue(self, window_name, object_name, row_index, column = 0): """ Get cell value @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_index: Row index to get @type row_index: integer @param column: Column index to get, default value 0 @type column: integer @return: cell value on success. @rtype: string """ obj = self._get_object(window_name, object_name) cell = self._get_accessible_at_row_column(obj, row_index, column) name = None if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: try: texti = child.queryText() except NotImplementedError: continue name = child.name self._grab_focus(cell) break finally: if not flag: self._handle_table_cell = False else: name = cell.name self._grab_focus(cell) if not name: raise LdtpServerException('Unable to get row text') return name def getcellsize(self, window_name, object_name, row_index, column = 0): """ Get cell size @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_index: Row index to get @type row_index: integer @param column: Column index to get, default value 0 @type column: integer @return: x, y, width, height on success. @rtype: list """ obj=self._get_object(window_name, object_name) cell=self._get_accessible_at_row_column(obj, row_index, column) current_cell=None if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: try: texti = child.queryText() except NotImplementedError: continue current_cell=child self._grab_focus(cell) break finally: if not flag: self._handle_table_cell = False else: current_cell=cell self._grab_focus(cell) if not current_cell: raise LdtpServerException('Unable to find row and/or column') _coordinates=self._get_size(current_cell) return [_coordinates.x, _coordinates.y, \ _coordinates.width, _coordinates.height] def rightclick(self, window_name, object_name, row_text): """ Right click on table cell @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_text: Row text to click @type row_text: string @return: 1 on success. @rtype: integer """ obj = self._get_object(window_name, object_name) try: tablei = obj.queryTable() except NotImplementedError: raise LdtpServerException('Object not table type.') for i in range(0, tablei.nRows): for j in range(0, tablei.nColumns): cell = tablei.getAccessibleAt(i, j) if not cell: continue if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: if self._match_name_to_acc(row_text, child): self._grab_focus(child) size = self._get_size(child) self._mouse_event(size.x + size.width / 2, size.y + size.height / 2, 'b3c') return 1 finally: if not flag: self._handle_table_cell = False elif self._match_name_to_acc(row_text, cell): self._grab_focus(cell) size = self._get_size(cell) self._mouse_event(size.x + size.width / 2, size.y + size.height / 2, 'b3c') return 1 raise LdtpServerException('Unable to right click row: %s' % row_text) def checkrow(self, window_name, object_name, row_index, column = 0): """ Check row @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_index: Row index to get @type row_index: integer @param column: Column index to get, default value 0 @type column: integer @return: cell value on success. @rtype: string """ obj = self._get_object(window_name, object_name) cell = self._get_accessible_at_row_column(obj, row_index, column) flag = None if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: try: actioni = child.queryAction() flag = True if not self._check_state(child, pyatspi.STATE_CHECKED): self._click_object(child, 'toggle') except NotImplementedError: continue self._grab_focus(cell) break finally: if not flag: self._handle_table_cell = False else: try: actioni = cell.queryAction() flag = True if not self._check_state(cell, pyatspi.STATE_CHECKED): self._click_object(cell, 'toggle') except NotImplementedError: raise LdtpServerException('Unable to check row') self._grab_focus(cell) if not flag: raise LdtpServerException('Unable to check row') return 1 def expandtablecell(self, window_name, object_name, row_index, column = 0): """ Expand or contract table cell @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_index: Row index to get @type row_index: integer @param column: Column index to get, default value 0 @type column: integer @return: cell value on success. @rtype: string """ obj = self._get_object(window_name, object_name) cell = self._get_accessible_at_row_column(obj, row_index, column) flag = None if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: try: actioni = child.queryAction() flag = True self._click_object(child, 'expand or contract') self._grab_focus(cell) break except NotImplementedError: continue finally: if not flag: self._handle_table_cell = False else: try: actioni = cell.queryAction() flag = True self._click_object(cell, 'expand or contract') except NotImplementedError: raise LdtpServerException('Unable to check row') self._grab_focus(cell) if not flag: raise LdtpServerException('Unable to check row') return 1 def uncheckrow(self, window_name, object_name, row_index, column = 0): """ Check row @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_index: Row index to get @type row_index: integer @param column: Column index to get, default value 0 @type column: integer @return: 1 on success. @rtype: integer """ obj = self._get_object(window_name, object_name) cell = self._get_accessible_at_row_column(obj, row_index, column) flag = None if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: try: actioni = child.queryAction() flag = True if self._check_state(child, pyatspi.STATE_CHECKED): self._click_object(child, 'toggle') except NotImplementedError: continue self._grab_focus(cell) break finally: if not flag: self._handle_table_cell = False else: try: actioni = cell.queryAction() flag = True if self._check_state(cell, pyatspi.STATE_CHECKED): self._click_object(cell, 'toggle') except NotImplementedError: raise LdtpServerException('Unable to check row') self._grab_focus(cell) if not flag: raise LdtpServerException('Unable to check row') return 1 def gettablerowindex(self, window_name, object_name, row_text): """ Get table row index matching given text @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_text: Row text to select @type row_text: string @return: row index matching the text on success. @rtype: integer """ obj = self._get_object(window_name, object_name) try: tablei = obj.queryTable() except NotImplementedError: raise LdtpServerException('Object not table type.') for i in range(0, tablei.nRows): for j in range(0, tablei.nColumns): cell = tablei.getAccessibleAt(i, j) if not cell: continue if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: if self._match_name_to_acc(row_text, child): self._grab_focus(child) return i finally: if not flag: self._handle_table_cell = False elif self._match_name_to_acc(row_text, cell): self._grab_focus(cell) return i raise LdtpServerException('Unable to get row index: %s' % row_text) def singleclickrow(self, window_name, object_name, row_text): """ Single click row matching given text @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_text: Row text to select @type row_text: string @return: row index matching the text on success. @rtype: integer """ obj = self._get_object(window_name, object_name) try: tablei = obj.queryTable() except NotImplementedError: raise LdtpServerException('Object not table type.') for i in range(0, tablei.nRows): for j in range(0, tablei.nColumns): cell = tablei.getAccessibleAt(i, j) if not cell: continue if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: if self._match_name_to_acc(row_text, child): self._grab_focus(child) size = self._get_size(cell) self._mouse_event(size.x + size.width / 2, size.y + size.height / 2, 'b1c') return i finally: if not flag: self._handle_table_cell = False elif self._match_name_to_acc(row_text, cell): self._grab_focus(cell) size = self._get_size(cell) self._mouse_event(size.x + size.width / 2, size.y + size.height / 2, 'b1c') return i raise LdtpServerException('Unable to get row index: %s' % row_text) def doubleclickrow(self, window_name, object_name, row_text): """ Double click row matching given text @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_text: Row text to select @type row_text: string @return: row index matching the text on success. @rtype: integer """ obj = self._get_object(window_name, object_name) try: tablei = obj.queryTable() except NotImplementedError: raise LdtpServerException('Object not table type.') for i in range(0, tablei.nRows): for j in range(0, tablei.nColumns): cell = tablei.getAccessibleAt(i, j) if not cell: continue if cell.childCount > 0: flag = False try: if self._handle_table_cell: # Was externally set, let us not # touch this value flag = True else: self._handle_table_cell = True children = self._list_objects(cell) for child in children: if self._match_name_to_acc(row_text, child): self._grab_focus(child) size = self._get_size(cell) self._mouse_event(size.x + size.width / 2, size.y + size.height / 2, 'b1d') return i finally: if not flag: self._handle_table_cell = False elif self._match_name_to_acc(row_text, cell): self._grab_focus(cell) size = self._get_size(cell) self._mouse_event(size.x + size.width / 2, size.y + size.height / 2, 'b1d') return i raise LdtpServerException('Unable to get row index: %s' % row_text) def doubleclickrowindex(self, window_name, object_name, row_index, col_index=0): """ Double click row matching given text @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_index: Row index to click @type row_index: integer @param col_index: Column index to click @type col_index: integer @return: row index matching the text on success. @rtype: integer """ obj = self._get_object(window_name, object_name) try: tablei = obj.queryTable() except NotImplementedError: raise LdtpServerException('Object not table type.') if row_index < 0 or row_index > tablei.nRows: raise LdtpServerException('Row index out of range: %d' % row_index) try: cell = tablei.getAccessibleAt(row_index, col_index) self._grab_focus(cell) size = self._get_size(cell) self._mouse_event(size.x + size.width / 2, size.y + size.height / 2, 'b1d') return row_index except: raise LdtpServerException('Unable to access row index: %d column: %d' % \ row_index, col_index) def verifytablecell(self, window_name, object_name, row_index, column_index, row_text): """ Verify table cell value with given text @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_index: Row index to get @type row_index: integer @param column_index: Column index to get, default value 0 @type column_index: integer @param row_text: Row text to match @type string @return: 1 on success 0 on failure. @rtype: integer """ try: text = self.getcellvalue(window_name, object_name, row_index, column_index) return int(self._glob_match(row_text, text)) except: return 0 def doesrowexist(self, window_name, object_name, row_text, partial_match = False): """ Verify table cell value with given text @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_text: Row text to match @type string @param partial_match: Find partial match strings @type boolean @return: 1 on success 0 on failure. @rtype: integer """ try: obj = self._get_object(window_name, object_name, False) def _searchString(acc): try: itext = acc.queryText() except NotImplementedError: return False if partial_match: return bool(re.search(row_text, itext.getText(0, -1), re.M | re.U)) else: return row_text == itext.getText(0, -1) results = pyatspi.findDescendant(obj, _searchString) return int(bool(results)) except: return 0 def verifypartialtablecell(self, window_name, object_name, row_index, column_index, row_text): """ Verify partial table cell value @param window_name: Window name to type in, either full name, LDTP's name convention, or a Unix glob. @type window_name: string @param object_name: Object name to type in, either full name, LDTP's name convention, or a Unix glob. @type object_name: string @param row_index: Row index to get @type row_index: integer @param column_index: Column index to get, default value 0 @type column_index: integer @param row_text: Row text to match @type string @return: 1 on success 0 on failure. @rtype: integer """ try: text = self.getcellvalue(window_name, object_name, row_index, column) if re.search(row_text, text): return 1 except: pass return 0