class TableColumn(Widget): def __init__(self, table, name): Widget.__init__(self, table, name) self.table = table # create a button for the column header # FIXME: It is assumed that all tables have headers in # order to function correctly. self.header = Button(self, "__header__") self.header_region = None self.scrolls_from_left = None self.cell = {} self.load_expected_cells() def capture_screenshots(self): self.header.capture_screenshots() # prompt the user for what cells they expect to see # under this column response = raw_input("Capture screenshot(s) of expected cell(s) under this column? ") if not response.startswith('y'): return expected_cells = raw_input("List the cells you expect to see under this column, " + "separated by commas:\n").replace(' ', '').split(',') for cell_name in expected_cells: cell = Widget(self, cell_name) cell.capture_screenshots() def load_expected_cells(self): self.expected_cell = {} path = self.image_folder() expected_cells = [cell for cell in os.listdir(path) if os.path.isdir(os.path.join(path, cell))] for cell_name in expected_cells: self.expected_cell[cell_name] = Widget(self, cell_name) def exists(self, force_check=False): if self.locate_header(force_check): return True return False def hover(self, offset=None, force_check=False): self.header.hover(offset, force_check) def click(self, offset=None, force_check=False): """ Alias so user doesn't have to say .header.click each time """ self.header.click(offset, force_check) def double_click(self, offset=None, force_check=False): self.header.double_click(offset, force_check) def right_click(self, offset=None, force_check=False): self.header.right_click(offset, force_check) def drag_to(self, x, y, force_check=False): self.header.drag_to(x, y, force_check) def drag_onto(self, widget, force_check=False): self.header.drag_onto(widget, force_check) def locate_header(self, force_check=False): header = self.header.find(force_check) if header: if settings.DEBUG: print "Found column '%s'" % self.name self.header_region = header else: self.header_region = None return header def scroll_to(self): self.table.scroll_to_left() if self.scrolls_from_left is None: self.scrolls_from_left = 0 while not self.exists(force_check=True): self.table.scroll_right() self.scrolls_from_left += 1 else: self.table.scroll_right(self.scrolls_from_left) def cell_in(self, row): if row.index not in self.cell: cell = TableCell(self.table, self, row, self.expected_cell) self.cell[row.index] = cell return self.cell[row.index] def has_cell_matching_in(self, row, cell_value, force_scroll=True): if self.cell_matching_in(row, cell_value, force_scroll): return True return False def cell_matching_in(self, row, cell_value, force_scroll=True): cell = self.cell_in(row) if cell.matches(cell_value, force_scroll): return cell return None def first_cell_matching(self, cell_value, force_scroll=True): return self.next_cell_matching(cell_value, force_scroll).next() def cells_matching(self, cell_value, force_scroll=True): cells = [] cell_gen = self.next_cell_matching(cell_value, force_scroll) cell = cell_gen.next() while cell: cells.append(cell) cell = cell_gen.next() return cells def next_cell_matching(self, cell_value, force_scroll=True): if force_scroll: self.scroll_to() row_scanner = self.table.row_scanner() row = row_scanner.next() while row: cell = self.cell_matching_in(row, cell_value, force_scroll=False) if cell: yield cell row = row_scanner.next() yield None
class ScrollableWidget(Widget): def __init__(self, parent, name): Widget.__init__(self, parent, name) # create a virtual widget to hold our buttons # TODO: is it worth it to create a Scrollbar widget? self._scrollbar = Widget(self, "__scrollbar__") # create the 4 directional scrollbar buttons self._top_button = Button(self._scrollbar, "top") self._bottom_button = Button(self._scrollbar, "bottom") self._left_button = Button(self._scrollbar, "left") self._right_button = Button(self._scrollbar, "right") def capture_screenshots(self): # take screenshots of the scrollbar states self._top_button.capture_screenshots() self._bottom_button.capture_screenshots() self._left_button.capture_screenshots() self._right_button.capture_screenshots() def has_vertical_scrollbar(self): return self._top_button.exists(force_check=True) and self._bottom_button.exists(force_check=True) def has_horizontal_scrollbar(self): return self._left_button.exists(force_check=True) and self._right_button.exists(force_check=True) def is_scrollable(self): """ Although a widget could be scrollable, it may not actually be. First, check if scroll states actually exist. Second, look for them in the current widget. It should be noted that this method checks if a widget is capable of being scrolled *at this moment in time* """ return self.has_vertical_scrollbar() or self.has_horizontal_scrollbar() def scrollbar_at_top(self): if not self.has_vertical_scrollbar(): return True return self._top_button.is_touching() def scrollbar_at_bottom(self): if not self.has_vertical_scrollbar(): return True return self._bottom_button.is_touching() def scrollbar_at_left(self): if not self.has_horizontal_scrollbar(): return True return self._left_button.is_touching() def scrollbar_at_right(self): if not self.has_horizontal_scrollbar(): return True return self._right_button.is_touching() def scroll_up(self, amount=1): for i in range(amount): if self.scrollbar_at_top(): # return how many we scrolled before # reaching the top return i self._top_button.click() # we scrolled the full amount return amount def scroll_down(self, amount=1): for i in range(amount): if self.scrollbar_at_bottom(): return i self._bottom_button.click() return amount def scroll_left(self, amount=1): for i in range(amount): if self.scrollbar_at_left(): return i self._left_button.click() return amount def scroll_right(self, amount=1): for i in range(amount): if self.scrollbar_at_right(): return i self._right_button.click() return amount def scroll_to_top(self): while self.scroll_up(): pass def scroll_to_bottom(self): while self.scroll_down(): pass def scroll_to_left(self): while self.scroll_left(): pass def scroll_to_right(self): while self.scroll_right(): pass