def __init__(self, mainwindow): #: :class:`.MainWindow` self.mainwindow = mainwindow #: :class:`.Document` self.document = mainwindow.document self._original_names = [] self._filtered_names = [] self._search_query = '' #: *int*. Currently selected index in the filtered/ordered list. self.selected_index = 0 self.view = NoopGUI()
def __init__(self, mainwindow): self.mainwindow = mainwindow self.document = mainwindow.document self._original_names = [] self._filtered_names = [] self._search_query = '' self.selected_index = 0 self.view = NoopGUI()
class Lookup: """Fuzzily-filtered list of items that match the few letters that the user typed. A Lookup allows the user to quickly find a object he looks for by name by typing only a few letters from that name. When first invoked, we start with a list of all possible items, and as letters are typed, those items and filtered *and* ordered in a way that fuzzily matches what our user typed. The list's filter is very inclusive and will include object that very remotely can match user's input, but the order is based on what matches the most. For example, if the user types "ab", the lookup list would contain both "barber", "absolute", and "albinos" (all those names contain both "a" and "b"), but would be ordered so that "absolute" comes first because it's the closest match. Pressing Return will "activate" (see :meth:`go`) the first item in the list, but the user can also navigate the list with the arrow keys (or click on the wanted item), which is why we keep track of :attr:`selected_index`. This class is designed to be subclassed with concrete named objects to lookup in. It does nothing by itself. """ def __init__(self, mainwindow): #: :class:`.MainWindow` self.mainwindow = mainwindow #: :class:`.Document` self.document = mainwindow.document self._original_names = [] self._filtered_names = [] self._search_query = '' #: *int*. Currently selected index in the filtered/ordered list. self.selected_index = 0 self.view = NoopGUI() def _apply_query(self): # On top, we want exact matches (the name starts with the query). Then, we want matches # that contain all the letters, sorted in order of names that have query letters as close # to each other as possible. q = sort_string(self._search_query) matches1, rest = extract(lambda n: n.startswith(q), self._original_names) matches2, rest = extract(lambda n: q in n, rest) matches3, rest = extract(lambda n: has_letters(n, q), rest) matches3.sort(key=lambda n: letters_distance(n, q)) self._filtered_names = matches1 + matches2 + matches3 self.selected_index = max(self.selected_index, 0) self.selected_index = min(self.selected_index, len(self._filtered_names) - 1) def _generate_lookup_names(self): """*Virtual*. Return a list of names in which we'll search.""" return [] def _go(self, name): """*Virtual*. Select an item named ``name``. The nature of this action depends on what kind of object we perform the lookup on. Were those accounts? Then open up the account named ``name``. """ def _refresh(self): self._search_query = '' self.selected_index = 0 names = self._generate_lookup_names() normalized_names = [sort_string(n) for n in names] self._normalized2original = {} for normalized, original in zip(normalized_names, names): self._normalized2original[normalized] = original self._original_names = normalized_names self._filtered_names = normalized_names def go(self): """Activate the :attr:`selected item <selected_index>` and close the lookup. To "activate", we call :meth:`_go` with the name of our selected item. """ try: name = self.names[self.selected_index] self._go(name) except IndexError: pass # No result, do nothing self.view.hide() def show(self): """Refreshes the name list and show the lookup.""" self._refresh() self.view.refresh() self.view.show() # --- Properties @property def names(self): """List of filtered/ordered names based on :attr:`search_query`.""" return [self._normalized2original[n] for n in self._filtered_names] @property def search_query(self): """*get/set*. *str*. Search query typed by the user.""" return self._search_query @search_query.setter def search_query(self, value): if value == self._search_query: return self._search_query = value self._apply_query() self.view.refresh()
class Lookup: def __init__(self, mainwindow): self.mainwindow = mainwindow self.document = mainwindow.document self._original_names = [] self._filtered_names = [] self._search_query = '' self.selected_index = 0 self.view = NoopGUI() def _apply_query(self): # On top, we want exact matches (the name starts with the query). Then, we want matches # that contain all the letters, sorted in order of names that have query letters as close # to each other as possible. q = sort_string(self._search_query) matches1, rest = extract(lambda n: n.startswith(q), self._original_names) matches2, rest = extract(lambda n: q in n, rest) matches3, rest = extract(lambda n: has_letters(n, q), rest) matches3.sort(key=lambda n: letters_distance(n, q)) self._filtered_names = matches1 + matches2 + matches3 self.selected_index = max(self.selected_index, 0) self.selected_index = min(self.selected_index, len(self._filtered_names)-1) def _generate_lookup_names(self): # Virtual return [] def _go(self, name): #Virtual pass def _refresh(self): self._search_query = '' self.selected_index = 0 names = self._generate_lookup_names() normalized_names = [sort_string(n) for n in names] self._normalized2original = {} for normalized, original in zip(normalized_names, names): self._normalized2original[normalized] = original self._original_names = normalized_names self._filtered_names = normalized_names def go(self): try: name = self.names[self.selected_index] self._go(name) except IndexError: pass # No result, do nothing self.view.hide() def show(self): self._refresh() self.view.refresh() self.view.show() #--- Properties @property def names(self): return [self._normalized2original[n] for n in self._filtered_names] @property def search_query(self): return self._search_query @search_query.setter def search_query(self, value): if value == self._search_query: return self._search_query = value self._apply_query() self.view.refresh()
class Lookup: """Fuzzily-filtered list of items that match the few letters that the user typed. A Lookup allows the user to quickly find a object he looks for by name by typing only a few letters from that name. When first invoked, we start with a list of all possible items, and as letters are typed, those items and filtered *and* ordered in a way that fuzzily matches what our user typed. The list's filter is very inclusive and will include object that very remotely can match user's input, but the order is based on what matches the most. For example, if the user types "ab", the lookup list would contain both "barber", "absolute", and "albinos" (all those names contain both "a" and "b"), but would be ordered so that "absolute" comes first because it's the closest match. Pressing Return will "activate" (see :meth:`go`) the first item in the list, but the user can also navigate the list with the arrow keys (or click on the wanted item), which is why we keep track of :attr:`selected_index`. This class is designed to be subclassed with concrete named objects to lookup in. It does nothing by itself. """ def __init__(self, mainwindow): #: :class:`.MainWindow` self.mainwindow = mainwindow #: :class:`.Document` self.document = mainwindow.document self._original_names = [] self._filtered_names = [] self._search_query = '' #: *int*. Currently selected index in the filtered/ordered list. self.selected_index = 0 self.view = NoopGUI() def _apply_query(self): # On top, we want exact matches (the name starts with the query). Then, we want matches # that contain all the letters, sorted in order of names that have query letters as close # to each other as possible. q = sort_string(self._search_query) matches1, rest = extract(lambda n: n.startswith(q), self._original_names) matches2, rest = extract(lambda n: q in n, rest) matches3, rest = extract(lambda n: has_letters(n, q), rest) matches3.sort(key=lambda n: letters_distance(n, q)) self._filtered_names = matches1 + matches2 + matches3 self.selected_index = max(self.selected_index, 0) self.selected_index = min(self.selected_index, len(self._filtered_names)-1) def _generate_lookup_names(self): """*Virtual*. Return a list of names in which we'll search.""" return [] def _go(self, name): """*Virtual*. Select an item named ``name``. The nature of this action depends on what kind of object we perform the lookup on. Were those accounts? Then open up the account named ``name``. """ def _refresh(self): self._search_query = '' self.selected_index = 0 names = self._generate_lookup_names() normalized_names = [sort_string(n) for n in names] self._normalized2original = {} for normalized, original in zip(normalized_names, names): self._normalized2original[normalized] = original self._original_names = normalized_names self._filtered_names = normalized_names def go(self): """Activate the :attr:`selected item <selected_index>` and close the lookup. To "activate", we call :meth:`_go` with the name of our selected item. """ try: name = self.names[self.selected_index] self._go(name) except IndexError: pass # No result, do nothing self.view.hide() def show(self): """Refreshes the name list and show the lookup.""" self._refresh() self.view.refresh() self.view.show() # --- Properties @property def names(self): """List of filtered/ordered names based on :attr:`search_query`.""" return [self._normalized2original[n] for n in self._filtered_names] @property def search_query(self): """*get/set*. *str*. Search query typed by the user.""" return self._search_query @search_query.setter def search_query(self, value): if value == self._search_query: return self._search_query = value self._apply_query() self.view.refresh()
def __init__(self, mainwindow): self.mainwindow = mainwindow self.document = mainwindow.document self.app = mainwindow.document.app self.view = NoopGUI() self._old_date_range = None
class DateRangeSelector: def __init__(self, mainwindow): self.mainwindow = mainwindow self.document = mainwindow.document self.app = mainwindow.document.app self.view = NoopGUI() self._old_date_range = None # --- Private def _date_range_starting_point(self): if self.mainwindow.selected_transactions: return self.mainwindow.selected_transactions[0].date elif datetime.date.today() in self.document.date_range: return datetime.date.today() else: return self.document.date_range # --- Public def select_month_range(self): self.document.select_month_range(starting_point=self._date_range_starting_point()) def select_quarter_range(self): self.document.select_quarter_range(starting_point=self._date_range_starting_point()) def select_year_range(self): self.document.select_year_range(starting_point=self._date_range_starting_point()) def select_year_to_date_range(self): self.document.select_year_to_date_range() def select_running_year_range(self): self.document.select_running_year_range() def select_all_transactions_range(self): self.document.select_all_transactions_range() def select_custom_date_range(self): self.document.select_custom_date_range() def select_prev_date_range(self): self.document.select_prev_date_range() def select_next_date_range(self): self.document.select_next_date_range() def select_today_date_range(self): self.document.select_today_date_range() def select_saved_range(self, slot): saved_range = self.app.saved_custom_ranges[slot] if saved_range: self.document.select_custom_date_range(saved_range.start, saved_range.end) def remember_current_range(self): self._old_date_range = self.document.date_range def refresh(self): self.view.refresh() old = self._old_date_range if old is not None: new = self.document.date_range if type(new) == type(old): if new.start > old.start: self.view.animate_forward() else: self.view.animate_backward() def refresh_custom_ranges(self): self.view.refresh_custom_ranges() # --- Properties @property def can_navigate(self): return self.document.date_range.can_navigate @property def custom_range_names(self): return [(r.name if r else None) for r in self.app.saved_custom_ranges] @property def display(self): return self.document.date_range.display
class DateRangeSelector: def __init__(self, mainwindow): self.mainwindow = mainwindow self.document = mainwindow.document self.app = mainwindow.document.app self.view = NoopGUI() self._old_date_range = None # --- Private def _date_range_starting_point(self): if self.mainwindow.selected_transactions: return self.mainwindow.selected_transactions[0].date elif datetime.date.today() in self.document.date_range: return datetime.date.today() else: return self.document.date_range # --- Public def select_month_range(self): self.document.select_month_range( starting_point=self._date_range_starting_point()) def select_quarter_range(self): self.document.select_quarter_range( starting_point=self._date_range_starting_point()) def select_year_range(self): self.document.select_year_range( starting_point=self._date_range_starting_point()) def select_year_to_date_range(self): self.document.select_year_to_date_range() def select_running_year_range(self): self.document.select_running_year_range() def select_all_transactions_range(self): self.document.select_all_transactions_range() def select_custom_date_range(self): self.document.select_custom_date_range() def select_prev_date_range(self): self.document.select_prev_date_range() def select_next_date_range(self): self.document.select_next_date_range() def select_today_date_range(self): self.document.select_today_date_range() def select_saved_range(self, slot): saved_range = self.app.saved_custom_ranges[slot] if saved_range: self.document.select_custom_date_range(saved_range.start, saved_range.end) def remember_current_range(self): self._old_date_range = self.document.date_range def refresh(self): self.view.refresh() old = self._old_date_range if old is not None: new = self.document.date_range if type(new) == type(old): if new.start > old.start: self.view.animate_forward() else: self.view.animate_backward() def refresh_custom_ranges(self): self.view.refresh_custom_ranges() # --- Properties @property def can_navigate(self): return self.document.date_range.can_navigate @property def custom_range_names(self): return [(r.name if r else None) for r in self.app.saved_custom_ranges] @property def display(self): return self.document.date_range.display