def __init__(self, app): GUITable.__init__(self) DupeGuruGUIObject.__init__(self, app) self.columns = Columns(self, prefaccess=app, savename='ResultTable') self._power_marker = False self._delta_values = False self._sort_descriptors = ('name', True)
def __init__(self, parent_view): ViewChild.__init__(self, parent_view) tree.Tree.__init__(self) self._was_restored = False self.columns = Columns(self, prefaccess=parent_view.document, savename=self.SAVENAME) self.edited = None self._expanded_paths = {(0, ), (1, )}
def toggle_menu_item(self, index): if index == len(self._optional_columns()): debit_visible = self.column_is_visible('debit') self.set_column_visible('debit', not debit_visible) self.set_column_visible('credit', not debit_visible) self.set_column_visible('increase', debit_visible) self.set_column_visible('decrease', debit_visible) else: Columns.toggle_menu_item(self, index)
def menu_items(self): items = Columns.menu_items(self) marked = self.column_is_visible('debit') items.append((tr("Debit/Credit"), marked)) return items
def save_columns(self): Columns.save_columns(self) pref_name = '{}.Columns.debit_credit_mode'.format(self.savename) value = self.column_is_visible('debit') self.prefaccess.set_default(pref_name, value)
class ResultTable(GUITable, DupeGuruGUIObject): def __init__(self, app): GUITable.__init__(self) DupeGuruGUIObject.__init__(self, app) self.columns = Columns(self, prefaccess=app, savename='ResultTable') self._power_marker = False self._delta_values = False self._sort_descriptors = ('name', True) #--- Override def _view_updated(self): self._refresh_with_view() def _restore_selection(self, previous_selection): if self.app.selected_dupes: to_find = set(self.app.selected_dupes) indexes = [i for i, r in enumerate(self) if r._dupe in to_find] self.selected_indexes = indexes def _update_selection(self): rows = self.selected_rows self.app._select_dupes(list(map(attrgetter('_dupe'), rows))) def _fill(self): if not self.power_marker: for group in self.app.results.groups: self.append(DupeRow(self, group, group.ref)) for dupe in group.dupes: self.append(DupeRow(self, group, dupe)) else: for dupe in self.app.results.dupes: group = self.app.results.get_group_of_duplicate(dupe) self.append(DupeRow(self, group, dupe)) def _refresh_with_view(self): self.refresh() self.view.show_selected_row() #--- Public def get_row_value(self, index, column): try: row = self[index] except IndexError: return '---' if self.delta_values: return row.data_delta[column] else: return row.data[column] def rename_selected(self, newname): row = self.selected_row if row is None: # There's all kinds of way the current row can be swept off during rename. When it # happens, selected_row will be None. return False row._data = None row._data_delta = None return self.app.rename_selected(newname) def sort(self, key, asc): if self.power_marker: self.app.results.sort_dupes(key, asc, self.delta_values) else: self.app.results.sort_groups(key, asc) self._sort_descriptors = (key, asc) self._refresh_with_view() #--- Properties @property def power_marker(self): return self._power_marker @power_marker.setter def power_marker(self, value): if value == self._power_marker: return self._power_marker = value key, asc = self._sort_descriptors self.sort(key, asc) # no need to refresh, it has happened in sort() @property def delta_values(self): return self._delta_values @delta_values.setter def delta_values(self, value): if value == self._delta_values: return self._delta_values = value self.refresh() @property def selected_dupe_count(self): return sum(1 for row in self.selected_rows if not row.isref) #--- Event Handlers def marking_changed(self): self.view.invalidate_markings() def results_changed(self): self._refresh_with_view() def results_changed_but_keep_selection(self): # What we want to to here is that instead of restoring selected *dupes* after refresh, we # restore selected *paths*. indexes = self.selected_indexes self.refresh(refresh_view=False) self.select(indexes) self.view.refresh() def save_session(self): self.columns.save_columns()
def toggle_menu_item(self, index): if index == len(self._optional_columns()): debit_visible = self.column_is_visible('debit') self._set_debit_credit_mode(not debit_visible) else: Columns.toggle_menu_item(self, index)
def restore_columns(self): Columns.restore_columns(self) pref_name = '{}.Columns.debit_credit_mode'.format(self.savename) debit_credit_mode = bool(self.prefaccess.get_default(pref_name)) self._set_debit_credit_mode(debit_credit_mode)
def __init__(self, document): GUITableBase.__init__(self) self.document = document self.columns = Columns(self, prefaccess=document, savename=self.SAVENAME)
class Report(ViewChild, tree.Tree, SheetViewNotificationsMixin): SAVENAME = '' COLUMNS = [] INVALIDATING_MESSAGES = MESSAGES_DOCUMENT_CHANGED | { 'accounts_excluded', 'date_range_changed' } def __init__(self, parent_view): ViewChild.__init__(self, parent_view) tree.Tree.__init__(self) self._was_restored = False self.columns = Columns(self, prefaccess=parent_view.document, savename=self.SAVENAME) self.edited = None self._expanded_paths = {(0, ), (1, )} # --- Override def _do_restore_view(self): if not self.document.can_restore_from_prefs(): return False prefname = '{}.ExpandedPaths'.format(self.SAVENAME) expanded = self.document.get_default(prefname, list()) if expanded: self._expanded_paths = {tuple(p) for p in expanded} self.view.refresh_expanded_paths() self.columns.restore_columns() return True def _revalidate(self): self.refresh(refresh_view=False) self._update_selection() self.view.refresh() self.restore_view() # --- Virtual def _compute_account_node(self, node): pass def _make_node(self, name): node = Node(name) node.account_number = '' return node def _refresh(self): pass # --- Protected def _node_of_account(self, account): return self.find(lambda n: getattr(n, 'account', None) is account) def _prune_invalid_expanded_paths(self): newpaths = set() for path in self._expanded_paths: try: node = self.get_node(path) if node.is_group or node.is_type: newpaths.add(path) except IndexError: pass self._expanded_paths = newpaths def _select_first(self): for type_node in self: if len(type_node) > 2: # total + blank self.selected = type_node[0] break def _update_selection(self): if not (isinstance(self.selected, Node) and self.selected.is_account): self._select_first() # --- Public def add_account(self): self.view.stop_editing() self.save_edits() node = self.selected if isinstance(node, Node) and node.is_group: account_type = node.group.type account_group = node.group elif isinstance(node, Node) and node.is_account: account_type = node.account.type account_group = node.account.group else: # there are only 2 types per report path = self.selected_path account_type = self[1].type if path and path[0] == 1 else self[ 0].type account_group = None if account_group is not None: account_group.expanded = True account = self.document.new_account( account_type, account_group) # refresh happens on account_added self.selected = self._node_of_account(account) self.view.update_selection() self.view.start_editing() def add_account_group(self): self.view.stop_editing() self.save_edits() node = self.selected if isinstance(node, Node) and node.is_group: account_type = node.group.type elif isinstance(node, Node) and node.is_account: account_type = node.account.type else: path = self.selected_path account_type = self[1].type if path and path[0] == 1 else self[ 0].type group = self.document.new_group(account_type) self.selected = self.find(lambda n: getattr(n, 'group', None) is group) self.view.update_selection() self.view.start_editing() def can_delete(self): node = self.selected return isinstance(node, Node) and (node.is_account or node.is_group) def can_move(self, source_paths, dest_path): """Returns whether it's possible to move the nodes at 'source_paths' under the node at 'dest_path'. """ if not dest_path: # Don't move under the root return False dest_node = self.get_node(dest_path) if not (dest_node.is_group or dest_node.is_type): # Move only under a group node or a type node return False for source_path in source_paths: source_node = self.get_node(source_path) if not source_node.is_account: return False if source_node.parent is dest_node: # Don't move under the same node return False return True def cancel_edits(self): node = self.edited if node is None: return assert node.is_account or node.is_group node.name = node.account.name if node.is_account else node.group.name self.edited = None def collapse_node(self, node): self._expanded_paths.discard(tuple(node.path)) if node.is_group: self.parent_view.collapse_group(node.group) def delete(self): if not self.can_delete(): return self.view.stop_editing() selected_nodes = self.selected_nodes gnodes = [n for n in selected_nodes if n.is_group] if gnodes: groups = [n.group for n in gnodes] self.document.delete_groups(groups) anodes = [n for n in selected_nodes if n.is_account] if anodes: accounts = [n.account for n in anodes] if any(a.entries for a in accounts): panel = self.parent_view.get_account_reassign_panel() panel.load(accounts) else: self.document.delete_accounts(accounts) def expand_node(self, node): self._expanded_paths.add(tuple(node.path)) if node.is_group: self.parent_view.expand_group(node.group) def make_account_node(self, account): node = self._make_node(account.name) node.account = account node.is_account = True node.account_number = account.account_number node.is_excluded = account in self.document.excluded_accounts if not node.is_excluded: self._compute_account_node(node) return node def make_blank_node(self): node = self._make_node(None) node.is_blank = True return node def make_group_node(self, group): node = self._make_node(group.name) node.group = group node.is_group = True accounts = self.document.accounts.filter(group=group) for account in sorted(accounts): node.append(self.make_account_node(account)) node.is_excluded = bool(accounts) and set( accounts ) <= self.document.excluded_accounts # all accounts excluded if not node.is_excluded: node.append(self.make_total_node(node, tr('Total ') + group.name)) node.append(self.make_blank_node()) return node def make_total_node(self, name): node = self._make_node(name) node.is_total = True return node def make_type_node(self, name, type): node = self._make_node(name) node.type = type node.is_type = True for group in sorted(self.document.groups.filter(type=type)): node.append(self.make_group_node(group)) for account in sorted( self.document.accounts.filter(type=type, group=None)): node.append(self.make_account_node(account)) accounts = self.document.accounts.filter(type=type) node.is_excluded = bool(accounts) and set( accounts ) <= self.document.excluded_accounts # all accounts excluded if not node.is_excluded: node.append(self.make_total_node(node, tr('TOTAL ') + name)) node.append(self.make_blank_node()) return node def move(self, source_paths, dest_path): """Moves the nodes at 'source_paths' under the node at 'dest_path'.""" assert self.can_move(source_paths, dest_path) accounts = [self.get_node(p).account for p in source_paths] dest_node = self.get_node(dest_path) if dest_node.is_type: self.document.change_accounts(accounts, group=None, type=dest_node.type) elif dest_node.is_group: self.document.change_accounts(accounts, group=dest_node.group, type=dest_node.group.type) def refresh(self, refresh_view=True): selected_accounts = self.selected_accounts selected_paths = self.selected_paths self._refresh() selected_nodes = [] for account in selected_accounts: node_of_account = self._node_of_account(account) if node_of_account is not None: selected_nodes.append(node_of_account) if selected_nodes: self.selected_nodes = selected_nodes else: self.selected_paths = selected_paths self._prune_invalid_expanded_paths() if refresh_view: self.view.refresh() def restore_view(self): if not self._was_restored: if self._do_restore_view(): self._was_restored = True def save_edits(self): node = self.edited if node is None: return self.edited = None assert node.is_account or node.is_group try: if node.is_account: self.document.change_accounts([node.account], name=node.name) else: self.document.change_group(node.group, name=node.name) except DuplicateAccountNameError: msg = tr("The account '{0}' already exists.").format(node.name) # we use _name because we don't want to change self.edited node._name = node.account.name if node.is_account else node.group.name self.mainwindow.show_message(msg) def save_preferences(self): # Save node expansion state prefname = '{}.ExpandedPaths'.format(self.SAVENAME) self.document.set_default(prefname, self.expanded_paths) self.columns.save_columns() def selection_as_csv(self): csvrows = [] columns = (self.columns.coldata[colname] for colname in self.columns.colnames) columns = [col for col in columns if col.visible] for node in self.selected_nodes: csvrow = [] for col in columns: try: csvrow.append(getattr(node, col.name)) except AttributeError: pass csvrows.append(csvrow) fp = StringIO() csv.writer(fp, delimiter='\t', quotechar='"').writerows(csvrows) fp.seek(0) return fp.read() def show_selected_account(self): self.mainwindow.open_account(self.selected_account) def show_account(self, path): node = self.get_node(path) self.mainwindow.open_account(node.account) def toggle_excluded(self): nodes = self.selected_nodes affected_accounts = set() for node in nodes: if node.is_type: affected_accounts |= set( self.document.accounts.filter(type=node.type)) elif node.is_group: affected_accounts |= set( self.document.accounts.filter(group=node.group)) elif node.is_account: affected_accounts.add(node.account) if affected_accounts: self.document.toggle_accounts_exclusion(affected_accounts) # --- Event handlers def account_added(self): self.refresh() def account_changed(self): self.refresh() def account_deleted(self): selected_path = self.selected_path self.refresh(refresh_view=False) next_node = self.get_node(selected_path) if not (next_node.is_account or next_node.is_group): selected_path[-1] -= 1 if selected_path[-1] < 0: selected_path = selected_path[:-1] self.selected_path = selected_path self.view.refresh() def accounts_excluded(self): self.refresh() def date_range_changed(self): self.refresh() document_restoring_preferences = restore_view def edition_must_stop(self): self.view.stop_editing() self.save_edits() # account might have been auto-created during import def transactions_imported(self): self.refresh(refresh_view=False) self._select_first() self.view.refresh() def document_changed(self): self.refresh(refresh_view=False) self._select_first() self.view.refresh() def performed_undo_or_redo(self): self.refresh() # --- Properties @property def can_show_selected_account(self): return self.selected_account is not None @property def expanded_paths(self): paths = list(self._expanded_paths) # We want the paths in orthe of length so that the paths are correctly expanded in the gui. paths.sort(key=lambda p: (len(p), ) + p) return paths selected = tree.Tree.selected_node @property def selected_account(self): accounts = self.selected_accounts if accounts: return accounts[0] else: return None @property def selected_accounts(self): nodes = self.selected_nodes return [node.account for node in nodes if node.is_account]
def __init__(self, exclude_list_dialog, app): GUITable.__init__(self) DupeGuruGUIObject.__init__(self, app) self.columns = Columns(self) self.dialog = exclude_list_dialog
def __init__(self, app): GUIObject.__init__(self, app) GUITable.__init__(self) self.columns = Columns(self)
class Report(ViewChild, tree.Tree, SheetViewNotificationsMixin): SAVENAME = '' COLUMNS = [] INVALIDATING_MESSAGES = MESSAGES_DOCUMENT_CHANGED | {'accounts_excluded', 'date_range_changed'} def __init__(self, parent_view): ViewChild.__init__(self, parent_view) tree.Tree.__init__(self) self._was_restored = False self.columns = Columns(self, prefaccess=parent_view.document, savename=self.SAVENAME) self.edited = None self._expanded_paths = {(0, ), (1, )} #--- Override def _do_restore_view(self): if not self.document.can_restore_from_prefs(): return False prefname = '{}.ExpandedPaths'.format(self.SAVENAME) expanded = self.document.get_default(prefname, list()) if expanded: self._expanded_paths = {tuple(p) for p in expanded} self.view.refresh_expanded_paths() self.columns.restore_columns() return True def _revalidate(self): self.refresh(refresh_view=False) self._update_selection() self.view.refresh() self.restore_view() #--- Virtual def _compute_account_node(self, node): pass def _make_node(self, name): node = Node(name) node.account_number = '' return node def _refresh(self): pass #--- Protected def _node_of_account(self, account): return self.find(lambda n: getattr(n, 'account', None) is account) def _prune_invalid_expanded_paths(self): newpaths = set() for path in self._expanded_paths: try: node = self.get_node(path) if node.is_group or node.is_type: newpaths.add(path) except IndexError: pass self._expanded_paths = newpaths def _select_first(self): for type_node in self: if len(type_node) > 2: # total + blank self.selected = type_node[0] break def _update_selection(self): if not (isinstance(self.selected, Node) and self.selected.is_account): self._select_first() #--- Public def add_account(self): self.view.stop_editing() self.save_edits() node = self.selected if isinstance(node, Node) and node.is_group: account_type = node.group.type account_group = node.group elif isinstance(node, Node) and node.is_account: account_type = node.account.type account_group = node.account.group else: # there are only 2 types per report path = self.selected_path account_type = self[1].type if path and path[0] == 1 else self[0].type account_group = None if account_group is not None: account_group.expanded = True account = self.document.new_account(account_type, account_group) # refresh happens on account_added self.selected = self._node_of_account(account) self.view.update_selection() self.view.start_editing() def add_account_group(self): self.view.stop_editing() self.save_edits() node = self.selected if isinstance(node, Node) and node.is_group: account_type = node.group.type elif isinstance(node, Node) and node.is_account: account_type = node.account.type else: path = self.selected_path account_type = self[1].type if path and path[0] == 1 else self[0].type group = self.document.new_group(account_type) self.selected = self.find(lambda n: getattr(n, 'group', None) is group) self.view.update_selection() self.view.start_editing() def can_delete(self): node = self.selected return isinstance(node, Node) and (node.is_account or node.is_group) def can_move(self, source_paths, dest_path): """Returns whether it's possible to move the nodes at 'source_paths' under the node at 'dest_path'. """ if not dest_path: # Don't move under the root return False dest_node = self.get_node(dest_path) if not (dest_node.is_group or dest_node.is_type): # Move only under a group node or a type node return False for source_path in source_paths: source_node = self.get_node(source_path) if not source_node.is_account: return False if source_node.parent is dest_node: # Don't move under the same node return False return True def cancel_edits(self): node = self.edited if node is None: return assert node.is_account or node.is_group node.name = node.account.name if node.is_account else node.group.name self.edited = None def collapse_node(self, node): self._expanded_paths.discard(tuple(node.path)) if node.is_group: self.parent_view.collapse_group(node.group) def delete(self): if not self.can_delete(): return self.view.stop_editing() selected_nodes = self.selected_nodes gnodes = [n for n in selected_nodes if n.is_group] if gnodes: groups = [n.group for n in gnodes] self.document.delete_groups(groups) anodes = [n for n in selected_nodes if n.is_account] if anodes: accounts = [n.account for n in anodes] if any(a.entries for a in accounts): panel = self.parent_view.get_account_reassign_panel() panel.load(accounts) else: self.document.delete_accounts(accounts) def expand_node(self, node): self._expanded_paths.add(tuple(node.path)) if node.is_group: self.parent_view.expand_group(node.group) def make_account_node(self, account): node = self._make_node(account.name) node.account = account node.is_account = True node.account_number = account.account_number node.is_excluded = account in self.document.excluded_accounts if not node.is_excluded: self._compute_account_node(node) return node def make_blank_node(self): node = self._make_node(None) node.is_blank = True return node def make_group_node(self, group): node = self._make_node(group.name) node.group = group node.is_group = True accounts = self.document.accounts.filter(group=group) for account in sorted(accounts): node.append(self.make_account_node(account)) node.is_excluded = bool(accounts) and set(accounts) <= self.document.excluded_accounts # all accounts excluded if not node.is_excluded: node.append(self.make_total_node(node, tr('Total ') + group.name)) node.append(self.make_blank_node()) return node def make_total_node(self, name): node = self._make_node(name) node.is_total = True return node def make_type_node(self, name, type): node = self._make_node(name) node.type = type node.is_type = True for group in sorted(self.document.groups.filter(type=type)): node.append(self.make_group_node(group)) for account in sorted(self.document.accounts.filter(type=type, group=None)): node.append(self.make_account_node(account)) accounts = self.document.accounts.filter(type=type) node.is_excluded = bool(accounts) and set(accounts) <= self.document.excluded_accounts # all accounts excluded if not node.is_excluded: node.append(self.make_total_node(node, tr('TOTAL ') + name)) node.append(self.make_blank_node()) return node def move(self, source_paths, dest_path): """Moves the nodes at 'source_paths' under the node at 'dest_path'.""" assert self.can_move(source_paths, dest_path) accounts = [self.get_node(p).account for p in source_paths] dest_node = self.get_node(dest_path) if dest_node.is_type: self.document.change_accounts(accounts, group=None, type=dest_node.type) elif dest_node.is_group: self.document.change_accounts(accounts, group=dest_node.group, type=dest_node.group.type) def refresh(self, refresh_view=True): selected_accounts = self.selected_accounts selected_paths = self.selected_paths self._refresh() selected_nodes = [] for account in selected_accounts: node_of_account = self._node_of_account(account) if node_of_account is not None: selected_nodes.append(node_of_account) if selected_nodes: self.selected_nodes = selected_nodes else: self.selected_paths = selected_paths self._prune_invalid_expanded_paths() if refresh_view: self.view.refresh() def restore_view(self): if not self._was_restored: if self._do_restore_view(): self._was_restored = True def save_edits(self): node = self.edited if node is None: return self.edited = None assert node.is_account or node.is_group try: if node.is_account: self.document.change_accounts([node.account], name=node.name) else: self.document.change_group(node.group, name=node.name) except DuplicateAccountNameError: msg = tr("The account '{0}' already exists.").format(node.name) # we use _name because we don't want to change self.edited node._name = node.account.name if node.is_account else node.group.name self.mainwindow.show_message(msg) def save_preferences(self): # Save node expansion state prefname = '{}.ExpandedPaths'.format(self.SAVENAME) self.document.set_default(prefname, self.expanded_paths) self.columns.save_columns() def selection_as_csv(self): csvrows = [] columns = (self.columns.coldata[colname] for colname in self.columns.colnames) columns = [col for col in columns if col.visible] for node in self.selected_nodes: csvrow = [] for col in columns: try: csvrow.append(getattr(node, col.name)) except AttributeError: pass csvrows.append(csvrow) fp = StringIO() csv.writer(fp, delimiter='\t', quotechar='"').writerows(csvrows) fp.seek(0) return fp.read() def show_selected_account(self): self.mainwindow.open_account(self.selected_account) def show_account(self, path): node = self.get_node(path) self.mainwindow.open_account(node.account) def toggle_excluded(self): nodes = self.selected_nodes affected_accounts = set() for node in nodes: if node.is_type: affected_accounts |= set(self.document.accounts.filter(type=node.type)) elif node.is_group: affected_accounts |= set(self.document.accounts.filter(group=node.group)) elif node.is_account: affected_accounts.add(node.account) if affected_accounts: self.document.toggle_accounts_exclusion(affected_accounts) #--- Event handlers def account_added(self): self.refresh() def account_changed(self): self.refresh() def account_deleted(self): selected_path = self.selected_path self.refresh(refresh_view=False) next_node = self.get_node(selected_path) if not (next_node.is_account or next_node.is_group): selected_path[-1] -= 1 if selected_path[-1] < 0: selected_path = selected_path[:-1] self.selected_path = selected_path self.view.refresh() def accounts_excluded(self): self.refresh() def date_range_changed(self): self.refresh() document_restoring_preferences = restore_view def edition_must_stop(self): self.view.stop_editing() self.save_edits() # account might have been auto-created during import def transactions_imported(self): self.refresh(refresh_view=False) self._select_first() self.view.refresh() def document_changed(self): self.refresh(refresh_view=False) self._select_first() self.view.refresh() def performed_undo_or_redo(self): self.refresh() #--- Properties @property def can_show_selected_account(self): return self.selected_account is not None @property def expanded_paths(self): paths = list(self._expanded_paths) # We want the paths in orthe of length so that the paths are correctly expanded in the gui. paths.sort(key=lambda p: (len(p), ) + p) return paths selected = tree.Tree.selected_node @property def selected_account(self): accounts = self.selected_accounts if accounts: return accounts[0] else: return None @property def selected_accounts(self): nodes = self.selected_nodes return [node.account for node in nodes if node.is_account]
class GUITable(GUITableBase): SAVENAME = '' COLUMNS = [] def __init__(self, document): GUITableBase.__init__(self) self.document = document self.columns = Columns(self, prefaccess=document, savename=self.SAVENAME) def can_move(self, row_indexes, position): if not 0 <= position <= len(self): return False row_indexes.sort() first_index = row_indexes[0] last_index = row_indexes[-1] has_gap = row_indexes != list(range(first_index, first_index + len(row_indexes))) # When there is a gap, position can be in the middle of row_indexes if not has_gap and position in (row_indexes + [last_index + 1]): return False return True def refresh_and_show_selection(self): self.refresh() self.view.show_selected_row() def selection_as_csv(self): csvrows = [] columns = (self.columns.coldata[colname] for colname in self.columns.colnames) columns = [col for col in columns if col.visible] for row in self.selected_rows: csvrow = [] for col in columns: try: csvrow.append(row.get_cell_value(col.name)) except AttributeError: pass csvrows.append(csvrow) fp = StringIO() csv.writer(fp, delimiter='\t', quotechar='"').writerows(csvrows) fp.seek(0) return fp.read() # --- Event handlers def edition_must_stop(self): self.view.stop_editing() self.save_edits() def document_changed(self): self.refresh() def document_restoring_preferences(self): self.columns.restore_columns() def performed_undo_or_redo(self): self.refresh() # Plug these below to the appropriate event in subclasses def _filter_applied(self): self.refresh(refresh_view=False) self._update_selection() self.view.refresh() def _item_changed(self): self.refresh_and_show_selection() def _item_deleted(self): self.refresh(refresh_view=False) self._update_selection() self.view.refresh()
def __init__(self, ignore_list_dialog): GUITable.__init__(self) self.columns = Columns(self) self.view = None self.dialog = ignore_list_dialog
def __init__(self, problem_dialog): GUITable.__init__(self) self.columns = Columns(self) self.dialog = problem_dialog